237 lines
9.8 KiB
PHP
237 lines
9.8 KiB
PHP
|
|
<?php
|
|||
|
|
error_reporting(E_ALL);
|
|||
|
|
ini_set('display_errors', 1);
|
|||
|
|
|
|||
|
|
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'];
|
|||
|
|
|
|||
|
|
echo "Детальный анализ паттернов удалений\n";
|
|||
|
|
echo str_repeat("=", 80) . "\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 "1. Анализ удалений по времени суток...\n";
|
|||
|
|
$deletionsByHour = [];
|
|||
|
|
$deletionsByDay = [];
|
|||
|
|
$batchDeletions = []; // Массовые удаления (много файлов за короткое время)
|
|||
|
|
|
|||
|
|
$totalChecked = 0;
|
|||
|
|
$maxToCheck = 10000;
|
|||
|
|
|
|||
|
|
try {
|
|||
|
|
$isTruncated = true;
|
|||
|
|
$continuationToken = null;
|
|||
|
|
$pageCount = 0;
|
|||
|
|
$maxPages = 20;
|
|||
|
|
|
|||
|
|
$currentBatch = [];
|
|||
|
|
$lastDeleteTime = null;
|
|||
|
|
|
|||
|
|
while ($isTruncated && $pageCount < $maxPages && $totalChecked < $maxToCheck) {
|
|||
|
|
$params = [
|
|||
|
|
'Bucket' => $s3Bucket,
|
|||
|
|
'Prefix' => 'crm2/CRM_Active_Files/Documents/Project/',
|
|||
|
|
'MaxKeys' => 1000
|
|||
|
|
];
|
|||
|
|
|
|||
|
|
if ($continuationToken) {
|
|||
|
|
$params['ContinuationToken'] = $continuationToken;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
$versions = $s3Client->listObjectVersions($params);
|
|||
|
|
$pageCount++;
|
|||
|
|
|
|||
|
|
if (isset($versions['DeleteMarkers'])) {
|
|||
|
|
foreach ($versions['DeleteMarkers'] as $marker) {
|
|||
|
|
$totalChecked++;
|
|||
|
|
$deleteDate = isset($marker['LastModified']) ? $marker['LastModified'] : null;
|
|||
|
|
|
|||
|
|
if ($deleteDate) {
|
|||
|
|
$dateTime = new DateTime($deleteDate);
|
|||
|
|
$hour = $dateTime->format('H');
|
|||
|
|
$day = $dateTime->format('Y-m-d');
|
|||
|
|
|
|||
|
|
if (!isset($deletionsByHour[$hour])) {
|
|||
|
|
$deletionsByHour[$hour] = 0;
|
|||
|
|
}
|
|||
|
|
$deletionsByHour[$hour]++;
|
|||
|
|
|
|||
|
|
if (!isset($deletionsByDay[$day])) {
|
|||
|
|
$deletionsByDay[$day] = 0;
|
|||
|
|
}
|
|||
|
|
$deletionsByDay[$day]++;
|
|||
|
|
|
|||
|
|
// Определяем массовые удаления (более 10 файлов за минуту)
|
|||
|
|
$deleteTimestamp = strtotime($deleteDate);
|
|||
|
|
if ($lastDeleteTime && abs($deleteTimestamp - $lastDeleteTime) < 60) {
|
|||
|
|
$currentBatch[] = $marker;
|
|||
|
|
} else {
|
|||
|
|
if (count($currentBatch) > 10) {
|
|||
|
|
$batchDeletions[] = [
|
|||
|
|
'count' => count($currentBatch),
|
|||
|
|
'time' => date('Y-m-d H:i:s', $lastDeleteTime),
|
|||
|
|
'files' => array_slice($currentBatch, 0, 5) // Первые 5 для примера
|
|||
|
|
];
|
|||
|
|
}
|
|||
|
|
$currentBatch = [$marker];
|
|||
|
|
}
|
|||
|
|
$lastDeleteTime = $deleteTimestamp;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
$isTruncated = isset($versions['IsTruncated']) && $versions['IsTruncated'];
|
|||
|
|
$continuationToken = isset($versions['NextContinuationToken']) ? $versions['NextContinuationToken'] : null;
|
|||
|
|
|
|||
|
|
if (!$isTruncated) {
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Проверяем последний батч
|
|||
|
|
if (count($currentBatch) > 10) {
|
|||
|
|
$batchDeletions[] = [
|
|||
|
|
'count' => count($currentBatch),
|
|||
|
|
'time' => $lastDeleteTime ? date('Y-m-d H:i:s', $lastDeleteTime) : 'неизвестно',
|
|||
|
|
'files' => array_slice($currentBatch, 0, 5)
|
|||
|
|
];
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
echo " Проверено delete markers: $totalChecked\n\n";
|
|||
|
|
|
|||
|
|
echo " Удаления по часам суток:\n";
|
|||
|
|
ksort($deletionsByHour);
|
|||
|
|
foreach ($deletionsByHour as $hour => $count) {
|
|||
|
|
if ($count > 0) {
|
|||
|
|
echo " {$hour}:00 - " . ($hour + 1) . ":00: $count удалений\n";
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
echo "\n";
|
|||
|
|
|
|||
|
|
echo " Удаления по дням (топ 15):\n";
|
|||
|
|
arsort($deletionsByDay);
|
|||
|
|
$count = 0;
|
|||
|
|
foreach ($deletionsByDay as $day => $deleteCount) {
|
|||
|
|
echo " $day: $deleteCount удалений\n";
|
|||
|
|
if (++$count >= 15) break;
|
|||
|
|
}
|
|||
|
|
echo "\n";
|
|||
|
|
|
|||
|
|
if (!empty($batchDeletions)) {
|
|||
|
|
echo " Массовые удаления (более 10 файлов за минуту): " . count($batchDeletions) . "\n";
|
|||
|
|
foreach (array_slice($batchDeletions, 0, 5) as $batch) {
|
|||
|
|
echo " Время: {$batch['time']}, удалено файлов: {$batch['count']}\n";
|
|||
|
|
}
|
|||
|
|
echo "\n";
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
} catch (\Aws\Exception\AwsException $e) {
|
|||
|
|
echo " Ошибка: " . $e->getMessage() . "\n";
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Проверяем, может быть это связано с удалением документов в CRM
|
|||
|
|
echo "2. Проверка связи с удалением документов в CRM...\n";
|
|||
|
|
$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]
|
|||
|
|
);
|
|||
|
|
|
|||
|
|
// Проверяем, сколько документов было удалено в последние дни
|
|||
|
|
$stmt = $pdo->prepare('
|
|||
|
|
SELECT DATE(e.modifiedtime) as delete_date, COUNT(*) as count
|
|||
|
|
FROM vtiger_crmentity e
|
|||
|
|
INNER JOIN vtiger_notes n ON n.notesid = e.crmid
|
|||
|
|
WHERE e.deleted = 1
|
|||
|
|
AND n.filelocationtype = "E"
|
|||
|
|
AND e.modifiedtime >= DATE_SUB(NOW(), INTERVAL 60 DAY)
|
|||
|
|
GROUP BY DATE(e.modifiedtime)
|
|||
|
|
ORDER BY delete_date DESC
|
|||
|
|
LIMIT 20
|
|||
|
|
');
|
|||
|
|
$stmt->execute();
|
|||
|
|
$deletedDocs = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|||
|
|
|
|||
|
|
if (!empty($deletedDocs)) {
|
|||
|
|
echo " Удаленные документы в CRM (за последние 60 дней):\n";
|
|||
|
|
foreach ($deletedDocs as $doc) {
|
|||
|
|
echo " {$doc['delete_date']}: {$doc['count']} документов\n";
|
|||
|
|
}
|
|||
|
|
echo "\n";
|
|||
|
|
} else {
|
|||
|
|
echo " Удаленных документов не найдено\n\n";
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Сравниваем даты удалений в S3 и CRM
|
|||
|
|
echo "3. Сравнение дат удалений в S3 и CRM...\n";
|
|||
|
|
if (!empty($deletionsByDay) && !empty($deletedDocs)) {
|
|||
|
|
echo " Сравнение:\n";
|
|||
|
|
foreach ($deletedDocs as $doc) {
|
|||
|
|
$crmDate = $doc['delete_date'];
|
|||
|
|
$s3Count = $deletionsByDay[$crmDate] ?? 0;
|
|||
|
|
$crmCount = $doc['count'];
|
|||
|
|
|
|||
|
|
if ($s3Count > 0) {
|
|||
|
|
echo " $crmDate:\n";
|
|||
|
|
echo " Удалено в CRM: $crmCount документов\n";
|
|||
|
|
echo " Delete markers в S3: $s3Count\n";
|
|||
|
|
|
|||
|
|
if ($s3Count > $crmCount * 2) {
|
|||
|
|
echo " ⚠️ В S3 удалено значительно больше файлов!\n";
|
|||
|
|
} elseif (abs($s3Count - $crmCount) <= 10) {
|
|||
|
|
echo " ✅ Количество примерно совпадает\n";
|
|||
|
|
}
|
|||
|
|
echo "\n";
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
echo str_repeat("=", 80) . "\n";
|
|||
|
|
echo "ВЫВОДЫ:\n\n";
|
|||
|
|
|
|||
|
|
// Определяем наиболее вероятную причину
|
|||
|
|
$maxHour = array_search(max($deletionsByHour), $deletionsByHour);
|
|||
|
|
$maxDay = array_search(max($deletionsByDay), $deletionsByDay);
|
|||
|
|
$maxDayCount = max($deletionsByDay);
|
|||
|
|
|
|||
|
|
echo "1. Пик удалений:\n";
|
|||
|
|
echo " - Время: {$maxHour}:00\n";
|
|||
|
|
echo " - День: $maxDay ($maxDayCount удалений)\n\n";
|
|||
|
|
|
|||
|
|
if ($maxHour >= 6 && $maxHour <= 8) {
|
|||
|
|
echo "2. 💡 ВЕРОЯТНАЯ ПРИЧИНА: Автоматическая задача (cron job)\n";
|
|||
|
|
echo " Удаления происходят рано утром (6-8 утра) - типичное время для cron\n\n";
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (!empty($batchDeletions)) {
|
|||
|
|
echo "3. 💡 ВЕРОЯТНАЯ ПРИЧИНА: Массовое удаление (скрипт или автоматизация)\n";
|
|||
|
|
echo " Найдено " . count($batchDeletions) . " случаев массового удаления\n\n";
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
echo "4. 💡 РЕКОМЕНДАЦИЯ: Проверить:\n";
|
|||
|
|
echo " - DeleteOrphanedItems в Nextcloud (запускается ежедневно)\n";
|
|||
|
|
echo " - Cron задачи, которые могут удалять файлы\n";
|
|||
|
|
echo " - Логи Nextcloud на предмет массовых удалений\n";
|
|||
|
|
|
|||
|
|
} catch (Exception $e) {
|
|||
|
|
echo "ОШИБКА: " . $e->getMessage() . "\n";
|
|||
|
|
echo "Trace: " . $e->getTraceAsString() . "\n";
|
|||
|
|
}
|
|||
|
|
|