200 lines
7.1 KiB
PHP
200 lines
7.1 KiB
PHP
|
|
<?php
|
|||
|
|
/**
|
|||
|
|
* Скрипт для восстановления файлов проекта 394091
|
|||
|
|
*/
|
|||
|
|
|
|||
|
|
error_reporting(E_ALL);
|
|||
|
|
ini_set('display_errors', 1);
|
|||
|
|
set_time_limit(0);
|
|||
|
|
|
|||
|
|
require_once '/var/www/fastuser/data/www/crm.clientright.ru/vendor/autoload.php';
|
|||
|
|
require_once '/var/www/fastuser/data/www/crm.clientright.ru/config.inc.php';
|
|||
|
|
|
|||
|
|
$config = require '/var/www/fastuser/data/www/crm.clientright.ru/crm_extensions/file_storage/config.php';
|
|||
|
|
$s3Bucket = $config['s3']['bucket'];
|
|||
|
|
|
|||
|
|
$projectId = 394091;
|
|||
|
|
|
|||
|
|
echo "=== ВОССТАНОВЛЕНИЕ ФАЙЛОВ ПРОЕКТА {$projectId} ===\n";
|
|||
|
|
echo str_repeat("=", 80) . "\n\n";
|
|||
|
|
|
|||
|
|
// Параметры
|
|||
|
|
$dryRun = isset($argv[1]) && $argv[1] === '--dry-run';
|
|||
|
|
|
|||
|
|
if ($dryRun) {
|
|||
|
|
echo "⚠️ РЕЖИМ ПРОВЕРКИ (dry-run) - файлы не будут восстановлены\n\n";
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
try {
|
|||
|
|
$s3Client = new \Aws\S3\S3Client([
|
|||
|
|
'version' => 'latest',
|
|||
|
|
'region' => $config['s3']['region'],
|
|||
|
|
'endpoint' => $config['s3']['endpoint'],
|
|||
|
|
'use_path_style_endpoint' => true,
|
|||
|
|
'credentials' => [
|
|||
|
|
'key' => $config['s3']['key'],
|
|||
|
|
'secret' => $config['s3']['secret'],
|
|||
|
|
],
|
|||
|
|
'suppress_php_deprecation_warning' => true
|
|||
|
|
]);
|
|||
|
|
|
|||
|
|
// Получаем документы проекта из БД
|
|||
|
|
echo "Подключение к БД...\n";
|
|||
|
|
$db = PearDatabase::getInstance();
|
|||
|
|
echo "✅ БД подключена\n";
|
|||
|
|
|
|||
|
|
echo "Выполнение запроса...\n";
|
|||
|
|
$result = $db->pquery("
|
|||
|
|
SELECT n.notesid, n.filename, n.filelocationtype, n.s3_bucket, n.s3_key, n.filesize
|
|||
|
|
FROM vtiger_notes n
|
|||
|
|
INNER JOIN vtiger_senotesrel sn ON sn.notesid = n.notesid
|
|||
|
|
WHERE sn.crmid = ?
|
|||
|
|
ORDER BY n.notesid
|
|||
|
|
", array($projectId));
|
|||
|
|
|
|||
|
|
echo "✅ Запрос выполнен\n";
|
|||
|
|
|
|||
|
|
$totalDocs = $db->num_rows($result);
|
|||
|
|
echo "Найдено документов в БД: {$totalDocs}\n\n";
|
|||
|
|
|
|||
|
|
if ($totalDocs == 0) {
|
|||
|
|
echo "Документы не найдены!\n";
|
|||
|
|
exit(0);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
$stats = [
|
|||
|
|
'total_docs' => $totalDocs,
|
|||
|
|
'existing' => 0,
|
|||
|
|
'deleted' => 0,
|
|||
|
|
'missing' => 0,
|
|||
|
|
'restored' => 0,
|
|||
|
|
'failed' => 0,
|
|||
|
|
'errors' => []
|
|||
|
|
];
|
|||
|
|
|
|||
|
|
// Проверяем каждый документ
|
|||
|
|
while ($row = $db->fetch_array($result)) {
|
|||
|
|
$s3Key = $row['s3_key'];
|
|||
|
|
$docId = $row['notesid'];
|
|||
|
|
$filename = $row['filename'];
|
|||
|
|
|
|||
|
|
echo "Документ ID: {$docId} | Файл: {$filename}\n";
|
|||
|
|
|
|||
|
|
if (empty($s3Key)) {
|
|||
|
|
echo " ⚠️ Нет S3 ключа\n\n";
|
|||
|
|
$stats['missing']++;
|
|||
|
|
continue;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
echo " S3 ключ: {$s3Key}\n";
|
|||
|
|
|
|||
|
|
// Проверяем существование файла
|
|||
|
|
$exists = $s3Client->doesObjectExist($s3Bucket, $s3Key);
|
|||
|
|
|
|||
|
|
if ($exists) {
|
|||
|
|
echo " ✅ Файл существует\n\n";
|
|||
|
|
$stats['existing']++;
|
|||
|
|
continue;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Проверяем версии и delete markers
|
|||
|
|
try {
|
|||
|
|
$versions = $s3Client->listObjectVersions([
|
|||
|
|
'Bucket' => $s3Bucket,
|
|||
|
|
'Prefix' => $s3Key,
|
|||
|
|
]);
|
|||
|
|
|
|||
|
|
$deleteMarker = null;
|
|||
|
|
$fileVersion = null;
|
|||
|
|
|
|||
|
|
foreach ($versions['Versions'] ?? [] as $version) {
|
|||
|
|
if (isset($version['IsDeleteMarker']) && $version['IsDeleteMarker']) {
|
|||
|
|
$deleteMarker = $version;
|
|||
|
|
} else {
|
|||
|
|
$fileVersion = $version;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if ($deleteMarker) {
|
|||
|
|
echo " ❌ Файл удален (delete marker от " . $deleteMarker['LastModified']->format('Y-m-d H:i:s') . ")\n";
|
|||
|
|
|
|||
|
|
if (!$dryRun) {
|
|||
|
|
// Удаляем delete marker
|
|||
|
|
try {
|
|||
|
|
$s3Client->deleteObject([
|
|||
|
|
'Bucket' => $s3Bucket,
|
|||
|
|
'Key' => $s3Key,
|
|||
|
|
'VersionId' => $deleteMarker['VersionId'],
|
|||
|
|
]);
|
|||
|
|
|
|||
|
|
// Если есть версия файла, копируем её
|
|||
|
|
if ($fileVersion) {
|
|||
|
|
$s3Client->copyObject([
|
|||
|
|
'Bucket' => $s3Bucket,
|
|||
|
|
'Key' => $s3Key,
|
|||
|
|
'CopySource' => "{$s3Bucket}/{$s3Key}?versionId={$fileVersion['VersionId']}",
|
|||
|
|
]);
|
|||
|
|
echo " ✅ Файл восстановлен из версии\n";
|
|||
|
|
} else {
|
|||
|
|
echo " ⚠️ Delete marker удален, но версия файла не найдена\n";
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
$stats['restored']++;
|
|||
|
|
sleep(1); // Пауза между запросами
|
|||
|
|
|
|||
|
|
} catch (Exception $e) {
|
|||
|
|
echo " ❌ Ошибка восстановления: " . $e->getMessage() . "\n";
|
|||
|
|
$stats['failed']++;
|
|||
|
|
$stats['errors'][] = "{$s3Key}: " . $e->getMessage();
|
|||
|
|
}
|
|||
|
|
} else {
|
|||
|
|
echo " ⏸️ Будет восстановлен (dry-run)\n";
|
|||
|
|
$stats['restored']++;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
$stats['deleted']++;
|
|||
|
|
|
|||
|
|
} else {
|
|||
|
|
echo " ⚠️ Файл отсутствует, но delete marker не найден\n";
|
|||
|
|
$stats['missing']++;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
} catch (Exception $e) {
|
|||
|
|
echo " ❌ Ошибка проверки версий: " . $e->getMessage() . "\n";
|
|||
|
|
$stats['failed']++;
|
|||
|
|
$stats['errors'][] = "{$s3Key}: " . $e->getMessage();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
echo "\n";
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Итоговая статистика
|
|||
|
|
echo str_repeat("=", 80) . "\n";
|
|||
|
|
echo "ИТОГОВАЯ СТАТИСТИКА:\n\n";
|
|||
|
|
echo "Всего документов: {$stats['total_docs']}\n";
|
|||
|
|
echo "Существующих файлов: {$stats['existing']}\n";
|
|||
|
|
echo "Удаленных файлов (delete marker): {$stats['deleted']}\n";
|
|||
|
|
echo "Отсутствующих файлов: {$stats['missing']}\n";
|
|||
|
|
|
|||
|
|
if (!$dryRun) {
|
|||
|
|
echo "Восстановлено: {$stats['restored']}\n";
|
|||
|
|
echo "Ошибок: {$stats['failed']}\n";
|
|||
|
|
} else {
|
|||
|
|
echo "Будет восстановлено: {$stats['restored']}\n";
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (!empty($stats['errors'])) {
|
|||
|
|
echo "\nОшибки:\n";
|
|||
|
|
foreach ($stats['errors'] as $error) {
|
|||
|
|
echo " - {$error}\n";
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
echo "\n=== ГОТОВО ===\n";
|
|||
|
|
|
|||
|
|
} catch (Exception $e) {
|
|||
|
|
echo "❌ Критическая ошибка: " . $e->getMessage() . "\n";
|
|||
|
|
echo "Stack trace:\n" . $e->getTraceAsString() . "\n";
|
|||
|
|
exit(1);
|
|||
|
|
}
|