PDO::ERRMODE_EXCEPTION] ); echo "✅ PDO подключен\n"; } catch (Exception $e) { die("❌ Ошибка PDO: " . $e->getMessage() . "\n"); } // S3 конфигурация $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') ]; try { echo "🔧 Создаем S3 клиент...\n"; $s3 = new Aws\S3\S3Client($s3Config); echo "✅ S3 подключен\n"; } catch (Exception $e) { die("❌ Ошибка S3: " . $e->getMessage() . "\n"); } echo "🔧 Создаем FilePathManager...\n"; $pathMgr = new FilePathManager(); echo "✅ FilePathManager создан\n"; // Получаем завершенные проекты с файлами echo "\n📁 ПОИСК ЗАВЕРШЕННЫХ ПРОЕКТОВ С ФАЙЛАМИ:\n"; echo "========================================\n"; $sql = "SELECT DISTINCT p.projectid, p.projectname, p.projectstatus, p.projecttype, COUNT(n.notesid) as file_count FROM vtiger_project p INNER JOIN vtiger_senotesrel sr ON p.projectid = sr.crmid INNER JOIN vtiger_notes n ON sr.notesid = n.notesid WHERE n.filelocationtype = 'E' AND n.s3_key IS NOT NULL AND p.projectstatus = 'completed' AND n.s3_key NOT LIKE '%/Project/%' GROUP BY p.projectid, p.projectname, p.projectstatus, p.projecttype ORDER BY p.projectname"; $result = $pdo->query($sql); $completedProjects = []; while ($row = $result->fetch(PDO::FETCH_ASSOC)) { $completedProjects[] = $row; echo "• {$row['projectname']}: {$row['file_count']} файлов\n"; } echo "\n📈 ИТОГО ЗАВЕРШЕННЫХ ПРОЕКТОВ: " . count($completedProjects) . "\n"; // Подсчитываем общее количество файлов $totalFiles = 0; foreach ($completedProjects as $project) { $sql = "SELECT COUNT(*) as count FROM vtiger_notes n INNER JOIN vtiger_senotesrel sr ON n.notesid = sr.notesid WHERE sr.crmid = ? AND n.filelocationtype = 'E' AND n.s3_key IS NOT NULL AND n.s3_key NOT LIKE '%/Project/%'"; $stmt = $pdo->prepare($sql); $stmt->execute([$project['projectid']]); $row = $stmt->fetch(PDO::FETCH_ASSOC); $totalFiles += $row['count']; } echo "📁 ИТОГО ФАЙЛОВ: $totalFiles\n"; // Спрашиваем пользователя echo "\n❓ ВОПРОС:\n"; echo "===========\n"; echo "Мигрировать завершенные проекты ($totalFiles файлов)? (y/n): "; $handle = fopen("php://stdin", "r"); $line = fgets($handle); fclose($handle); if (trim(strtolower($line)) !== 'y') { echo "❌ Миграция отменена\n"; exit; } // Начинаем миграцию echo "\n🚀 НАЧИНАЕМ МИГРАЦИЮ ЗАВЕРШЕННЫХ ПРОЕКТОВ:\n"; echo "==========================================\n"; $migratedProjects = 0; $migratedFiles = 0; $errors = 0; foreach ($completedProjects as $project) { $projectId = $project['projectid']; $projectName = $project['projectname']; $projectStatus = $project['projectstatus']; echo "\n📁 Проект: $projectName (ID: $projectId, Статус: $projectStatus)\n"; // Получаем все файлы проекта которые еще не мигрированы $sql = "SELECT n.notesid, n.title, n.filename, n.s3_key, n.s3_bucket FROM vtiger_notes n INNER JOIN vtiger_senotesrel sr ON n.notesid = sr.notesid WHERE sr.crmid = ? AND n.filelocationtype = 'E' AND n.s3_key IS NOT NULL AND n.s3_key NOT LIKE '%/Project/%'"; $stmt = $pdo->prepare($sql); $stmt->execute([$projectId]); $files = []; while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) { $files[] = $row; } echo " 📄 Файлов для миграции: " . count($files) . "\n"; $projectMigratedFiles = 0; $projectErrors = 0; foreach ($files as $file) { $documentId = $file['notesid']; $fileName = $file['filename']; $oldS3Key = $file['s3_key']; $title = $file['title']; // Генерируем новый путь $newFilePath = $pathMgr->getFilePath('Project', $projectId, $documentId, $fileName, $title, $projectName); $newS3Key = $newFilePath; // Проверяем, нужно ли мигрировать if ($oldS3Key === $newS3Key) { echo " ✅ Файл уже в новой структуре: $title\n"; $projectMigratedFiles++; continue; } echo " 🔄 Мигрируем: $title\n"; try { // Проверяем существование старого файла $oldUrl = "https://s3.twcstorage.ru/{$s3Config['bucket']}/{$oldS3Key}"; $headers = @get_headers($oldUrl); if (!$headers || strpos($headers[0], '200') === false) { echo " ⚠️ Файл не найден в S3: $oldUrl\n"; $projectErrors++; continue; } // Скачиваем файл $fileContent = file_get_contents($oldUrl); if ($fileContent === false) { echo " ❌ Не удалось скачать файл\n"; $projectErrors++; continue; } // Загружаем в новое место $uploadResult = $s3->putObject([ 'Bucket' => $s3Config['bucket'], 'Key' => $newS3Key, 'Body' => $fileContent, 'ContentType' => mime_content_type('data://text/plain;base64,' . base64_encode($fileContent)) ]); // Обновляем БД (и s3_key и filename с полным URL) $newFileUrl = "https://s3.twcstorage.ru/{$s3Config['bucket']}/{$newS3Key}"; $updateSql = "UPDATE vtiger_notes SET s3_key = ?, filename = ? WHERE notesid = ?"; $updateStmt = $pdo->prepare($updateSql); $updateStmt->execute([$newS3Key, $newFileUrl, $documentId]); // Удаляем старый файл try { $s3->deleteObject([ 'Bucket' => $s3Config['bucket'], 'Key' => $oldS3Key ]); echo " ✅ Старый файл удален\n"; } catch (Exception $e) { echo " ⚠️ Не удалось удалить старый файл: " . $e->getMessage() . "\n"; } echo " ✅ Файл мигрирован успешно\n"; $projectMigratedFiles++; } catch (Exception $e) { echo " ❌ Ошибка миграции: " . $e->getMessage() . "\n"; $projectErrors++; } } echo " 📊 Результат проекта: $projectMigratedFiles файлов мигрировано, $projectErrors ошибок\n"; $migratedProjects++; $migratedFiles += $projectMigratedFiles; $errors += $projectErrors; } // Итоговая статистика echo "\n🎉 МИГРАЦИЯ ЗАВЕРШЕННЫХ ПРОЕКТОВ ЗАВЕРШЕНА!\n"; echo "===========================================\n"; echo "📁 Проектов обработано: $migratedProjects\n"; echo "📄 Файлов мигрировано: $migratedFiles\n"; echo "❌ Ошибок: $errors\n"; if ($migratedFiles + $errors > 0) { echo "✅ Успешность: " . round(($migratedFiles / ($migratedFiles + $errors)) * 100, 2) . "%\n"; } echo "\n🚀 Все завершенные проекты мигрированы в новую структуру!\n"; ?>