Files
crm.clientright.ru/crm_extensions/file_storage/migrate_single_project.php
Fedor 269c7ea216 feat: OnlyOffice Standalone integration with S3 direct URLs
 ЧТО СДЕЛАНО:
- Поднят новый standalone OnlyOffice Document Server (порт 8083)
- Настроен Nginx для доступа через office.clientright.ru:9443
- Создан open_file_v3_standalone.php для работы с новым OnlyOffice
- Реализована поддержка прямых S3 URL (bucket публичный)
- Добавлен s3_proxy.php с поддержкой Range requests
- Создан onlyoffice_callback.php для сохранения (базовая версия)
- Файлы успешно открываются и загружаются!

⚠️ TODO (на завтра):
- Доработать onlyoffice_callback.php для сохранения обратно в ОРИГИНАЛЬНЫЙ путь в S3
- Добавить Redis маппинг documentKey → S3 path
- Обновить CRM JS для использования open_file_v3_standalone.php
- Протестировать сохранение файлов
- Удалить тестовые файлы

📊 РЕЗУЛЬТАТ:
- OnlyOffice Standalone РАБОТАЕТ! 
- Файлы открываются напрямую из S3 
- Редактор загружается БЫСТРО 
- Автосохранение настроено  (но нужна доработка callback)
2025-11-01 01:02:03 +03:00

167 lines
5.6 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
/**
* Простая миграция одного проекта в новую структуру
* Использование: php migrate_single_project.php PROJECT_ID
*/
require_once(__DIR__ . '/../../config.inc.php');
require_once(__DIR__ . '/../../include/database/PearDatabase.php');
$adb = PearDatabase::getInstance();
// Получаем ID проекта
$projectId = isset($argv[1]) ? (int)$argv[1] : null;
if (!$projectId) {
echo "❌ Укажите ID проекта!\n";
echo "Использование: php migrate_single_project.php PROJECT_ID\n";
exit(1);
}
echo "🔄 МИГРАЦИЯ ПРОЕКТА $projectId\n";
echo "==========================================\n\n";
// Получаем информацию о проекте
$result = $adb->pquery("SELECT p.projectname FROM vtiger_project p WHERE p.projectid = ?", [$projectId]);
if ($adb->num_rows($result) == 0) {
echo "❌ Проект не найден!\n";
exit(1);
}
$projectName = $adb->query_result($result, 0, 'projectname');
echo "📁 Проект: $projectName\n\n";
// Функция очистки имени файла
function sanitizeName($name) {
// Транслитерация
$translitMap = [
'А' => 'A', 'Б' => 'B', 'В' => 'V', 'Г' => 'G', 'Д' => 'D',
'Е' => 'E', 'Ё' => 'E', 'Ж' => 'Zh', 'З' => 'Z', 'И' => 'I',
'Й' => 'Y', 'К' => 'K', 'Л' => 'L', 'М' => 'M', 'Н' => 'N',
'О' => 'O', 'П' => 'P', 'Р' => 'R', 'С' => 'S', 'Т' => 'T',
'У' => 'U', 'Ф' => 'F', 'Х' => 'H', 'Ц' => 'Ts', 'Ч' => 'Ch',
'Ш' => 'Sh', 'Щ' => 'Sch', 'Ъ' => '', 'Ы' => 'Y', 'Ь' => '',
'Э' => 'E', 'Ю' => 'Yu', 'Я' => 'Ya',
'а' => 'a', 'б' => 'b', 'в' => 'v', 'г' => 'g', 'д' => 'd',
'е' => 'e', 'ё' => 'e', 'ж' => 'zh', 'з' => 'z', 'и' => 'i',
'й' => 'y', 'к' => 'k', 'л' => 'l', 'м' => 'm', 'н' => 'n',
'о' => 'o', 'п' => 'p', 'р' => 'r', 'с' => 's', 'т' => 't',
'у' => 'u', 'ф' => 'f', 'х' => 'h', 'ц' => 'ts', 'ч' => 'ch',
'ш' => 'sh', 'щ' => 'sch', 'ъ' => '', 'ы' => 'y', 'ь' => '',
'э' => 'e', 'ю' => 'yu', 'я' => 'ya'
];
$name = strtr($name, $translitMap);
$name = preg_replace('/[^a-zA-Z0-9_\-]/', '_', $name);
$name = preg_replace('/_+/', '_', $name);
$name = trim($name, '_');
if (strlen($name) > 100) {
$name = substr($name, 0, 100);
}
return $name;
}
$sanitizedName = sanitizeName($projectName);
$newFolder = "Documents/Project/{$sanitizedName}_{$projectId}";
echo "📁 Новая папка: $newFolder\n\n";
// Получаем все документы проекта
$result = $adb->pquery(
"SELECT n.notesid, n.title, n.filename, n.s3_key, n.filelocationtype
FROM vtiger_notes n
JOIN vtiger_senotesrel snr ON snr.notesid = n.notesid
JOIN vtiger_crmentity e ON e.crmid = n.notesid
WHERE snr.crmid = ? AND e.deleted = 0 AND n.filelocationtype = 'E'
ORDER BY n.notesid",
[$projectId]
);
$total = $adb->num_rows($result);
echo "📊 Найдено документов: $total\n\n";
if ($total == 0) {
echo "✅ Нет документов для миграции\n";
exit(0);
}
$migrated = 0;
$errors = 0;
while ($doc = $adb->fetch_array($result)) {
$notesid = $doc['notesid'];
$title = $doc['title'];
$oldS3Key = $doc['s3_key'];
echo "[$migrated/$total] Документ: $title (ID: $notesid)\n";
echo " Старый s3_key: $oldS3Key\n";
// Извлекаем имя файла и расширение
$oldFilename = basename($oldS3Key);
$pathInfo = pathinfo($oldFilename);
$extension = isset($pathInfo['extension']) ? '.' . $pathInfo['extension'] : '';
// Новое имя файла: file_docID_название.ext
$newFilename = "file_{$notesid}_{$pathInfo['filename']}{$extension}";
// Новый путь в S3
$newS3Key = "{$newFolder}/{$newFilename}";
$newNcPath = "/crm/crm2/CRM_Active_Files/{$newFolder}/{$newFilename}";
// Новый URL
$bucket = 'f9825c87-4e3558f6-f9b6-405c-ad3d-d1535c49b61c';
$newUrl = "https://s3.twcstorage.ru/{$bucket}/crm2/CRM_Active_Files/{$newS3Key}";
echo " Новый s3_key: $newS3Key\n";
echo " Новый nc_path: $newNcPath\n";
// Копируем файл в S3 (используем aws s3 cp)
$oldKey = "crm2/CRM_Active_Files/" . $oldS3Key;
$newKey = "crm2/CRM_Active_Files/" . $newS3Key;
$copyCmd = "aws s3 cp " .
"s3://{$bucket}/{$oldKey} " .
"s3://{$bucket}/{$newKey} " .
"--endpoint-url https://s3.twcstorage.ru " .
"--region ru-1 2>&1";
echo " Копирование в S3...\n";
exec($copyCmd, $output, $returnCode);
if ($returnCode !== 0) {
echo " ❌ ОШИБКА копирования: " . implode("\n", $output) . "\n";
$errors++;
continue;
}
echo " ✅ Скопировано в S3\n";
// Обновляем БД
$updateResult = $adb->pquery(
"UPDATE vtiger_notes
SET s3_key = ?, nc_path = ?, filename = ?
WHERE notesid = ?",
[$newS3Key, $newNcPath, $newUrl, $notesid]
);
if ($updateResult) {
echo " ✅ БД обновлена\n";
$migrated++;
} else {
echo " ❌ ОШИБКА обновления БД\n";
$errors++;
}
echo "\n";
}
echo "==========================================\n";
echo "✅ МИГРАЦИЯ ЗАВЕРШЕНА!\n";
echo "Обработано: $total\n";
echo "Мигрировано: $migrated\n";
echo "Ошибок: $errors\n";