'localhost', 'dbname' => 'ci20465_72new', 'user' => 'ci20465_72new', 'pass' => 'EcY979Rn' ]; try { $pdo = new PDO( "mysql:host={$dbConfig['host']};dbname={$dbConfig['dbname']};charset=utf8", $dbConfig['user'], $dbConfig['pass'] ); $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); echo "✅ Подключено к БД\n\n"; } catch (PDOException $e) { die("❌ Ошибка подключения к БД: " . $e->getMessage() . "\n"); } // Параметры $projectId = isset($argv[1]) ? (int)$argv[1] : null; $dryRun = in_array('--dry-run', $argv); if (!$projectId) { echo "❌ Укажите ID проекта!\n"; echo "Использование: php migrate_project_final.php PROJECT_ID [--dry-run]\n"; echo "\nПример: php migrate_project_final.php 699 --dry-run\n"; exit(1); } echo "🔄 ФИНАЛЬНАЯ МИГРАЦИЯ PROJECT\n"; echo "==========================================\n"; if ($dryRun) { echo "⚠️ РЕЖИМ DRY-RUN - НИЧЕГО НЕ БУДЕТ ИЗМЕНЕНО\n"; } echo "\n"; // Подключаем зависимости require_once(__DIR__ . '/FilePathManager.php'); require_once(__DIR__ . '/S3Client.php'); $pathMgr = new FilePathManager(); // S3 конфигурация - используем ключи из .env require_once(__DIR__ . '/../shared/EnvLoader.php'); EnvLoader::load(__DIR__ . '/../.env'); $s3Config = [ 'version' => 'latest', 'region' => 'ru-1', 'endpoint' => 'https://s3.twcstorage.ru', 'bucket' => 'f9825c87-4e3558f6-f9b6-405c-ad3d-d1535c49b61c', 'use_path_style_endpoint' => true, 'key' => EnvLoader::getRequired('S3_ACCESS_KEY'), 'secret' => EnvLoader::getRequired('S3_SECRET_KEY') ]; $s3 = new S3Client($s3Config); // Получаем проект $stmt = $pdo->prepare("SELECT projectname FROM vtiger_project WHERE projectid = ?"); $stmt->execute([$projectId]); $project = $stmt->fetch(PDO::FETCH_ASSOC); if (!$project) { echo "❌ Проект не найден!\n"; exit(1); } $projectName = $project['projectname']; echo "📁 Проект: $projectName (ID: $projectId)\n\n"; // Получаем файлы проекта с S3 ключами $stmt = $pdo->prepare(" SELECT n.notesid, n.title, n.s3_key, n.s3_bucket, n.filename FROM vtiger_notes n INNER JOIN vtiger_senotesrel sr ON n.notesid = sr.notesid WHERE sr.crmid = ? AND n.s3_key IS NOT NULL AND n.s3_bucket IS NOT NULL AND n.s3_key LIKE 'crm2/CRM_Active_Files/Documents/%' "); $stmt->execute([$projectId]); $files = $stmt->fetchAll(PDO::FETCH_ASSOC); $totalFiles = count($files); echo "📊 Найдено файлов с S3 ключами: $totalFiles\n\n"; if ($totalFiles == 0) { echo "✅ Нет файлов для миграции!\n"; exit(0); } $stats = ['processed' => 0, 'migrated' => 0, 'errors' => 0]; foreach ($files as $file) { $stats['processed']++; $notesId = $file['notesid']; $documentTitle = $file['title'] ?: null; $oldS3Key = $file['s3_key']; $s3Bucket = $file['s3_bucket']; $oldFilename = $file['filename']; echo "[$stats[processed]/$totalFiles] Документ: " . ($documentTitle ?: $notesId) . " (ID: $notesId)\n"; // Извлекаем старое имя файла из S3 ключа $oldFileName = basename($oldS3Key); // Генерируем новый путь через FilePathManager $newFullPath = $pathMgr->getFilePath('Project', $projectId, $notesId, $oldFileName, $documentTitle, $projectName); $newS3Key = $newFullPath; // Новый filename для БД $newFilename = "https://s3.twcstorage.ru/$s3Bucket/" . rawurlencode($newS3Key); echo " Старый S3: $oldS3Key\n"; echo " Новый S3: $newS3Key\n"; echo " Новый URL: " . substr($newFilename, 0, 80) . "...\n"; if (!$dryRun) { try { // Проверяем старый файл через URL $oldUrl = "https://s3.twcstorage.ru/$s3Bucket/" . rawurlencode($oldS3Key); $headers = @get_headers($oldUrl, 1); if (!$headers || strpos($headers[0], '200') === false) { echo " ⚠️ Старый файл не найден в S3 (URL: " . substr($oldUrl, 0, 80) . "...)\n\n"; $stats['errors']++; continue; } // Проверяем новый файл if ($s3->fileExists($newS3Key)) { echo " ⚠️ Целевой файл уже существует\n\n"; $stats['errors']++; continue; } // Скачиваем во временный файл $tempFile = $s3->downloadToTemp($oldS3Key); if (!$tempFile) { throw new Exception("Не удалось скачать файл"); } echo " ✅ Скачан во временный файл\n"; // Загружаем в новое место if (!$s3->uploadFile($tempFile, $newS3Key)) { throw new Exception("Не удалось загрузить файл"); } echo " ✅ Загружен в новое место\n"; // Удаляем временный файл @unlink($tempFile); // Удаляем старый файл в S3 $s3->deleteObject($oldS3Key); echo " ✅ Старый файл удален\n"; // Обновляем БД $updateStmt = $pdo->prepare("UPDATE vtiger_notes SET s3_key = ?, filename = ? WHERE notesid = ?"); $updateStmt->execute([$newS3Key, $newFilename, $notesId]); echo " ✅ БД обновлена\n"; $stats['migrated']++; echo " ✅ УСПЕШНО!\n\n"; } catch (Exception $e) { echo " ❌ ОШИБКА: " . $e->getMessage() . "\n\n"; $stats['errors']++; } } else { echo " [DRY-RUN] Будет выполнено:\n"; echo " - Скачать: $oldS3Key\n"; echo " - Загрузить: $newS3Key\n"; echo " - Удалить: $oldS3Key\n"; echo " - Обновить БД: s3_key='$newS3Key', filename='$newFilename'\n\n"; $stats['migrated']++; } usleep(100000); // 0.1 сек пауза } // Итоги echo "\n==========================================\n"; echo "📊 СТАТИСТИКА:\n"; echo "==========================================\n"; echo "Обработано: $stats[processed]\n"; echo "Мигрировано: $stats[migrated]\n"; echo "Ошибок: $stats[errors]\n"; echo "\n"; if ($dryRun) { echo "⚠️ Это был DRY-RUN. Запустите без --dry-run для реальной миграции.\n"; } else if ($stats['errors'] == 0) { echo "✅ МИГРАЦИЯ ЗАВЕРШЕНА УСПЕШНО!\n"; echo "\n📁 Структура: crm/crm2/CRM_Active_Files/Documents/Project/$projectName" . "_$projectId/файл_docID.ext\n"; } else { echo "⚠️ Миграция завершена с ошибками.\n"; } ?>