'latest', 'region' => $config['s3']['region'], 'endpoint' => $config['s3']['endpoint'], 'use_path_style_endpoint' => true, 'credentials' => [ 'key' => $config['s3']['key'], 'secret' => $config['s3']['secret'], ], 'suppress_php_deprecation_warning' => true ]); // Подключение к БД $pdo = new PDO( "mysql:host={$dbconfig['db_server']};port=3306;dbname={$dbconfig['db_name']};charset=utf8", $dbconfig['db_username'], $dbconfig['db_password'], [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION] ); // Получаем все файлы из temp/384256/ echo "1. Поиск файлов в temp/$projectId/...\n"; $tempFiles = []; $objects = $s3Client->listObjectsV2([ 'Bucket' => $s3Bucket, 'Prefix' => "temp/$projectId/", 'MaxKeys' => 1000 ]); if (isset($objects['Contents'])) { foreach ($objects['Contents'] as $object) { $key = $object['Key']; // Пропускаем папки if (substr($key, -1) !== '/') { $tempFiles[] = $key; } } } echo " Найдено файлов в temp/: " . count($tempFiles) . "\n\n"; if (empty($tempFiles)) { die("Файлы не найдены в temp/$projectId/\n"); } // Получаем документы проекта из БД echo "2. Получение документов проекта из БД...\n"; $stmt = $pdo->prepare(' SELECT n.notesid, n.title, n.s3_key, n.filename FROM vtiger_notes n INNER JOIN vtiger_crmentity e ON e.crmid = n.notesid INNER JOIN vtiger_senotesrel snr ON snr.notesid = n.notesid WHERE snr.crmid = ? AND e.deleted = 0 AND n.filelocationtype = "E" ORDER BY n.notesid ASC '); $stmt->execute([$projectId]); $dbDocs = $stmt->fetchAll(PDO::FETCH_ASSOC); echo " Найдено документов в БД: " . count($dbDocs) . "\n\n"; // Сопоставляем файлы из temp/ с документами в БД echo "3. Сопоставление файлов...\n"; $mappings = []; foreach ($tempFiles as $tempFile) { $basename = basename($tempFile); // Извлекаем ID из имени файла (например, 384260 из 384260_8_Dogovor...) if (preg_match('/^(\d+)_/', $basename, $matches)) { $fileDocId = $matches[1]; // Ищем соответствующий документ в БД // Обычно файл с ID 384260 соответствует документу 384259 (ID файла = ID документа + 1) // Но лучше искать по ближайшему ID $matchedDoc = null; foreach ($dbDocs as $doc) { // Проверяем разные варианты соответствия if ($doc['notesid'] == $fileDocId - 1 || $doc['notesid'] == $fileDocId || abs($doc['notesid'] - $fileDocId) <= 2) { // Дополнительная проверка по названию $docTitleLower = mb_strtolower($doc['title']); $fileNameLower = mb_strtolower($basename); // Проверяем совпадение по ключевым словам $keywords = ['dogovor', 'podtverzhdenie', 'skrin', 'zayavlenie', '8', '9', '10', '7']; $foundKeyword = false; foreach ($keywords as $keyword) { if (strpos($docTitleLower, $keyword) !== false && strpos($fileNameLower, $keyword) !== false) { $foundKeyword = true; break; } } if ($foundKeyword || abs($doc['notesid'] - $fileDocId) <= 1) { $matchedDoc = $doc; break; } } } if ($matchedDoc) { $mappings[] = [ 'temp_file' => $tempFile, 'doc_id' => $matchedDoc['notesid'], 'doc_title' => $matchedDoc['title'], 'target_s3_key' => $matchedDoc['s3_key'], 'current_s3_key' => $matchedDoc['s3_key'] ]; echo " ✅ {$basename} -> Документ {$matchedDoc['notesid']}: {$matchedDoc['title']}\n"; } else { echo " ⚠️ {$basename} -> Не найден соответствующий документ (ID файла: $fileDocId)\n"; } } } echo "\n Всего сопоставлено: " . count($mappings) . " файлов\n\n"; if (empty($mappings)) { die("Не удалось сопоставить файлы с документами\n"); } // Перемещаем файлы echo "4. Перемещение файлов в S3...\n"; $moved = 0; $errors = 0; foreach ($mappings as $mapping) { $sourceKey = $mapping['temp_file']; $targetKey = $mapping['target_s3_key']; $docId = $mapping['doc_id']; echo " Перемещение: " . basename($sourceKey) . "\n"; echo " Из: $sourceKey\n"; echo " В: $targetKey\n"; try { // Проверяем, существует ли целевой путь (если да, пропускаем) try { $s3Client->headObject([ 'Bucket' => $s3Bucket, 'Key' => $targetKey ]); echo " ⚠️ Целевой файл уже существует, пропускаем\n\n"; continue; } catch (\Aws\Exception\AwsException $e) { if ($e->getAwsErrorCode() != 'NotFound') { throw $e; } } // Копируем файл в новое место $s3Client->copyObject([ 'Bucket' => $s3Bucket, 'CopySource' => $s3Bucket . '/' . $sourceKey, 'Key' => $targetKey, 'MetadataDirective' => 'COPY' ]); echo " ✅ Файл скопирован\n"; // Удаляем исходный файл из temp/ $s3Client->deleteObject([ 'Bucket' => $s3Bucket, 'Key' => $sourceKey ]); echo " ✅ Исходный файл удален из temp/\n"; // Обновляем filename в БД (если нужно) $newFilename = "https://s3.twcstorage.ru/{$s3Bucket}/" . rawurlencode($targetKey); $updateStmt = $pdo->prepare('UPDATE vtiger_notes SET filename = ? WHERE notesid = ?'); $updateStmt->execute([$newFilename, $docId]); echo " ✅ Путь в БД обновлен\n"; $moved++; } catch (\Aws\Exception\AwsException $e) { echo " ❌ Ошибка: " . $e->getMessage() . " (Code: " . $e->getAwsErrorCode() . ")\n"; $errors++; } catch (Exception $e) { echo " ❌ Ошибка: " . $e->getMessage() . "\n"; $errors++; } echo "\n"; } echo str_repeat("=", 80) . "\n"; echo "РЕЗУЛЬТАТЫ:\n"; echo " Перемещено файлов: $moved\n"; echo " Ошибок: $errors\n"; } catch (Exception $e) { echo "КРИТИЧЕСКАЯ ОШИБКА: " . $e->getMessage() . "\n"; echo "Trace: " . $e->getTraceAsString() . "\n"; }