Files
crm.clientright.ru/crm_extensions/file_storage/migrate_project_files_final.php

158 lines
5.2 KiB
PHP
Raw Normal View History

<?php
chdir('/var/www/fastuser/data/www/crm.clientright.ru');
require_once 'include/utils/utils.php';
require_once 'include/database/PearDatabase.php';
require_once 'crm_extensions/vendor/autoload.php';
use Aws\S3\S3Client as AwsS3Client;
global $adb;
$options = getopt('', ['dry-run', 'project:']);
$dryRun = isset($options['dry-run']);
$projectId = isset($options['project']) ? (int)$options['project'] : null;
$s3 = new AwsS3Client([
'version' => 'latest',
'region' => 'ru-1',
'endpoint' => 'https://s3.twcstorage.ru',
'use_path_style_endpoint' => true,
'credentials' => [
'key' => '2OMAK5ZNM900TAXM16J7',
'secret' => 'f4ADllb5VZBAt2HdsyB8WcwVEU7U74MwFCa1DARG',
],
]);
$bucket = 'f9825c87-4e3558f6-f9b6-405c-ad3d-d1535c49b61c';
$logFile = __DIR__ . '/logs/migration_final_' . date('Y-m-d_H-i-s') . '.log';
if (!is_dir(__DIR__ . '/logs')) {
mkdir(__DIR__ . '/logs', 0755, true);
}
function writeLog($message) {
global $logFile;
$logMessage = "[" . date('Y-m-d H:i:s') . "] $message\n";
file_put_contents($logFile, $logMessage, FILE_APPEND);
echo $message . "\n";
}
function sanitizeFileName($name) {
$name = str_replace(['/', '\\', ':', '*', '?', '"', '<', '>', '|'], '_', $name);
$name = preg_replace('/\s+/', ' ', $name);
return trim($name);
}
writeLog("🚀 === МИГРАЦИЯ ПРОЕКТА $projectId ===");
if ($dryRun) writeLog("⚠️ DRY-RUN MODE");
// Получаем документы
$sql = "SELECT n.* FROM vtiger_notes n
INNER JOIN vtiger_senotesrel r ON r.notesid = n.notesid
WHERE r.crmid = ? AND n.filelocationtype = 'E'
ORDER BY n.notesid";
$result = $adb->pquery($sql, [$projectId]);
$count = $adb->num_rows($result);
writeLog("📋 Документов: $count");
$newFolderPath = "crm2/CRM_Active_Files/Documents/проекта_{$projectId}";
$stats = ['total' => $count, 'success' => 0, 'errors' => 0, 'skipped' => 0];
$usedNames = [];
for ($i = 0; $i < $count; $i++) {
$doc = $adb->fetchByAssoc($result);
$docId = $doc['notesid'];
$title = sanitizeFileName($doc['title']);
$oldUrl = $doc['filename'];
writeLog("\n📄 [$docId] {$doc['title']}");
// Извлекаем S3 путь из URL
if (strpos($oldUrl, "https://s3.twcstorage.ru/$bucket/") === 0) {
$oldS3PathEncoded = str_replace("https://s3.twcstorage.ru/$bucket/", '', $oldUrl);
$oldS3Path = urldecode($oldS3PathEncoded);
} else {
writeLog(" ⚠️ Нестандартный формат URL");
$stats['skipped']++;
continue;
}
// Формируем новое имя
$extension = pathinfo(basename($oldS3Path), PATHINFO_EXTENSION);
$baseNewName = $title ? "{$title}_{$docId}" : "document_{$docId}";
$newFileName = $baseNewName . ($extension ? ".$extension" : '');
// Проверка дубликатов
$counter = 1;
$finalNewName = $newFileName;
while (isset($usedNames[$finalNewName])) {
$finalNewName = $baseNewName . "_{$counter}" . ($extension ? ".$extension" : '');
$counter++;
}
$usedNames[$finalNewName] = true;
$newS3Path = "$newFolderPath/$finalNewName";
// Проверяем уже мигрирован?
if ($oldS3Path === $newS3Path) {
writeLog(" ⏭️ Уже мигрирован, пропускаю");
$stats['skipped']++;
continue;
}
writeLog(" БЫЛО: $oldS3Path");
writeLog(" БУДЕТ: $newS3Path");
if ($dryRun) {
writeLog(" [DRY-RUN] ✓ Будет скопировано");
$stats['success']++;
continue;
}
// РЕАЛЬНОЕ КОПИРОВАНИЕ
try {
// Проверяем старый файл
$head = $s3->headObject(['Bucket' => $bucket, 'Key' => $oldS3Path]);
$oldSize = $head['ContentLength'];
writeLog(" ✓ Найден, размер: " . number_format($oldSize / 1024, 2) . " KB");
// Копируем
$s3->copyObject([
'Bucket' => $bucket,
'CopySource' => "$bucket/$oldS3Path",
'Key' => $newS3Path,
]);
// Проверяем копию
$headNew = $s3->headObject(['Bucket' => $bucket, 'Key' => $newS3Path]);
$newSize = $headNew['ContentLength'];
if ($newSize !== $oldSize) {
throw new Exception("Размеры не совпадают!");
}
writeLog(" ✅ Скопировано, размер OK");
// Обновляем БД
$newUrl = "https://s3.twcstorage.ru/$bucket/$newS3Path";
$adb->pquery("UPDATE vtiger_notes SET filename = ? WHERE notesid = ?", [$newUrl, $docId]);
writeLog(" ✅ БД обновлена");
writeLog(" ✅ УСПЕХ!");
$stats['success']++;
} catch (Exception $e) {
writeLog(" ❌ ОШИБКА: " . $e->getMessage());
$stats['errors']++;
}
}
writeLog("\n📊 === ИТОГО ===");
writeLog("Всего: {$stats['total']}");
writeLog("Успешно: {$stats['success']}");
writeLog("Ошибок: {$stats['errors']}");
writeLog("Пропущено: {$stats['skipped']}");
writeLog("\n✅ Лог: $logFile");