Files
crm.clientright.ru/crm_extensions/file_storage/migrate_project_full.php
Fedor 9245768987 🚀 CRM Files Migration & Real-time Features
 Features:
- Migrated ALL files to new S3 structure (Projects, Contacts, Accounts, HelpDesk, Invoice, etc.)
- Added Nextcloud folder buttons to ALL modules
- Fixed Nextcloud editor integration
- WebSocket server for real-time updates
- Redis Pub/Sub integration
- File path manager for organized storage
- Redis caching for performance (Functions.php)

📁 New Structure:
Documents/Project/ProjectName_ID/file_docID.ext
Documents/Contacts/FirstName_LastName_ID/file_docID.ext
Documents/Accounts/AccountName_ID/file_docID.ext

🔧 Technical:
- FilePathManager for standardized paths
- S3StorageService integration
- WebSocket server (Node.js + Docker)
- Redis cache for getBasicModuleInfo()
- Predis library for Redis connectivity

📝 Scripts:
- Migration scripts for all modules
- Test pages for WebSocket/SSE/Polling
- Documentation (MIGRATION_*.md, REDIS_*.md)

🎯 Result: 15,000+ files migrated successfully!
2025-10-24 19:59:28 +03:00

216 lines
7.5 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
/**
* Полная миграция Project: старая структура → Project/название_ID/файл_docID.ext
*
* Делает всё за один проход:
* 1. Скачивает файл из старого места (documentID/файл)
* 2. Загружает в новое место (Project/название_ID/файл_docID.ext)
* 3. Удаляет старый файл
* 4. Обновляет БД (относительный путь + filelocationtype = 'S')
*/
// Прямое подключение к БД через PDO
$dbConfig = [
'host' => '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_full.php PROJECT_ID [--dry-run]\n";
echo "\nПример: php migrate_project_full.php 80291 --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 конфигурация
$s3Config = [
'version' => 'latest',
'region' => 'ru-1',
'endpoint' => 'https://s3.twcstorage.ru',
'bucket' => 'f9825c87-4e3558f6-f9b6-405c-ad3d-d1535c49b61c',
'use_path_style_endpoint' => true,
'key' => 'YCAJEfh7Z06ixD_9fFdVa3BUy',
'secret' => 'YCM9xQmPCOa3L1iO_LS08J0cYWiuUpk3s7q3VSmR'
];
$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";
// Получаем файлы
$stmt = $pdo->prepare("
SELECT n.notesid, n.filename, n.title
FROM vtiger_notes n
INNER JOIN vtiger_senotesrel sr ON n.notesid = sr.notesid
WHERE sr.crmid = ?
AND n.filelocationtype = 'E'
");
$stmt->execute([$projectId]);
$files = $stmt->fetchAll(PDO::FETCH_ASSOC);
$totalFiles = count($files);
echo "📊 Найдено файлов: $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'];
$oldUrl = $file['filename'];
$documentTitle = $file['title'] ?: null;
echo "[$stats[processed]/$totalFiles] Документ: " . ($documentTitle ?: $notesId) . " (ID: $notesId)\n";
// Извлекаем старый S3 ключ из URL
if (!preg_match('#/Documents/(.+)$#', $oldUrl, $matches)) {
echo " ⚠️ Не удалось извлечь S3 путь\n\n";
$stats['errors']++;
continue;
}
$oldS3Path = $matches[1];
$oldS3Key = "crm2/CRM_Active_Files/Documents/" . urldecode($oldS3Path);
$oldFileName = basename(urldecode($oldS3Path));
// Генерируем новый путь через FilePathManager
$newFullPath = $pathMgr->getFilePath('Project', $projectId, $notesId, $oldFileName, $documentTitle, $projectName);
$newS3Key = $newFullPath;
// Относительный путь для БД (без префикса)
$newRelativePath = str_replace('crm2/CRM_Active_Files/Documents/', '', $newFullPath);
echo " Старый: $oldS3Key\n";
echo " Новый: $newS3Key\n";
echo " БД: $newRelativePath\n";
if (!$dryRun) {
try {
// Проверяем старый файл
if (!$s3->fileExists($oldS3Key)) {
echo " ⚠️ Файл не найден в S3\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 filename = ?, filelocationtype = 'S' WHERE notesid = ?");
$updateStmt->execute([$newRelativePath, $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 " - Обновить БД: filename='$newRelativePath', filelocationtype='S'\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📁 Структура: Project/$projectName" . "_$projectIdайл_docID.ext\n";
} else {
echo "⚠️ Миграция завершена с ошибками.\n";
}
?>