235 lines
9.0 KiB
PHP
235 lines
9.0 KiB
PHP
|
|
<?php
|
|||
|
|
/**
|
|||
|
|
* Миграция АРХИВНЫХ проектов
|
|||
|
|
* Переносит файлы из старой структуры в новую: Project/название_ID/файл_docID.pdf
|
|||
|
|
*/
|
|||
|
|
|
|||
|
|
// Включаем отображение ошибок
|
|||
|
|
error_reporting(E_ALL);
|
|||
|
|
ini_set('display_errors', 1);
|
|||
|
|
|
|||
|
|
echo "🚀 МИГРАЦИЯ АРХИВНЫХ ПРОЕКТОВ\n";
|
|||
|
|
echo "============================\n\n";
|
|||
|
|
|
|||
|
|
// Подключаем конфигурацию
|
|||
|
|
require_once '/var/www/fastuser/data/www/crm.clientright.ru/config.inc.php';
|
|||
|
|
require_once '/var/www/fastuser/data/www/crm.clientright.ru/vendor/autoload.php';
|
|||
|
|
require_once '/var/www/fastuser/data/www/crm.clientright.ru/crm_extensions/file_storage/FilePathManager.php';
|
|||
|
|
require_once '/var/www/fastuser/data/www/crm.clientright.ru/crm_extensions/shared/EnvLoader.php';
|
|||
|
|
|
|||
|
|
// Загружаем переменные окружения
|
|||
|
|
EnvLoader::load('/var/www/fastuser/data/www/crm.clientright.ru/crm_extensions/.env');
|
|||
|
|
|
|||
|
|
// Создаем PDO подключение напрямую
|
|||
|
|
try {
|
|||
|
|
$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]
|
|||
|
|
);
|
|||
|
|
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 = 'archived'
|
|||
|
|
GROUP BY p.projectid, p.projectname, p.projectstatus, p.projecttype
|
|||
|
|
ORDER BY p.projectname";
|
|||
|
|
|
|||
|
|
$result = $pdo->query($sql);
|
|||
|
|
$archivedProjects = [];
|
|||
|
|
|
|||
|
|
while ($row = $result->fetch(PDO::FETCH_ASSOC)) {
|
|||
|
|
$archivedProjects[] = $row;
|
|||
|
|
echo "• {$row['projectname']}: {$row['file_count']} файлов\n";
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
echo "\n📈 ИТОГО АРХИВНЫХ ПРОЕКТОВ: " . count($archivedProjects) . "\n";
|
|||
|
|
|
|||
|
|
// Подсчитываем общее количество файлов
|
|||
|
|
$totalFiles = 0;
|
|||
|
|
foreach ($archivedProjects 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";
|
|||
|
|
$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 "Мигрировать архивные проекты? (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 ($archivedProjects 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";
|
|||
|
|
|
|||
|
|
$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 " ✅ Файл уже в новой структуре: $fileName\n";
|
|||
|
|
$projectMigratedFiles++;
|
|||
|
|
continue;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
echo " 🔄 Мигрируем: $fileName\n";
|
|||
|
|
echo " Старый путь: $oldS3Key\n";
|
|||
|
|
echo " Новый путь: $newS3Key\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";
|
|||
|
|
echo "✅ Успешность: " . round(($migratedFiles / ($migratedFiles + $errors)) * 100, 2) . "%\n";
|
|||
|
|
|
|||
|
|
echo "\n🚀 Все архивные проекты мигрированы в новую структуру!\n";
|
|||
|
|
?>
|