- Исправлен N8N_CODE_PROCESS_UPLOADED_FILES_FIXED.js: использовать uploads_field_labels[0] вместо [grp] - Создан SQL_CLAIMSAVE_FIXED_NEW_FLOW_DEDUP.sql с дедупликацией documents_meta - Создан SQL_CLEANUP_DOCUMENTS_META_DUPLICATES.sql для очистки существующих дубликатов - Создан полный уникальный индекс idx_document_texts_hash_unique на document_texts(file_hash) - Добавлен SESSION_LOG_2025-11-28_documents_dedup.md с описанием всех изменений Fixes: - field_label теперь корректно отображает 'Переписка' вместо 'group-2' - documents_meta не накапливает дубликаты при повторных сохранениях - ON CONFLICT (file_hash) теперь работает для document_texts
204 lines
8.1 KiB
PHP
204 lines
8.1 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 "Анализ удалений файлов из S3\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";
|
||
|
||
$deletionsByDate = [];
|
||
$deletionsByProject = [];
|
||
$totalChecked = 0;
|
||
$maxToCheck = 5000; // Ограничиваем для скорости
|
||
|
||
try {
|
||
$isTruncated = true;
|
||
$continuationToken = null;
|
||
$pageCount = 0;
|
||
$maxPages = 10;
|
||
|
||
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++;
|
||
$key = $marker['Key'];
|
||
$deleteDate = isset($marker['LastModified']) ? $marker['LastModified'] : null;
|
||
|
||
if ($deleteDate) {
|
||
$dateKey = substr($deleteDate, 0, 10); // YYYY-MM-DD
|
||
if (!isset($deletionsByDate[$dateKey])) {
|
||
$deletionsByDate[$dateKey] = 0;
|
||
}
|
||
$deletionsByDate[$dateKey]++;
|
||
}
|
||
|
||
// Извлекаем ID проекта из пути
|
||
if (preg_match('/Project\/([^\/]+)_(\d+)\//', $key, $matches)) {
|
||
$projectId = $matches[2];
|
||
if (!isset($deletionsByProject[$projectId])) {
|
||
$deletionsByProject[$projectId] = 0;
|
||
}
|
||
$deletionsByProject[$projectId]++;
|
||
}
|
||
}
|
||
}
|
||
|
||
$isTruncated = isset($versions['IsTruncated']) && $versions['IsTruncated'];
|
||
$continuationToken = isset($versions['NextContinuationToken']) ? $versions['NextContinuationToken'] : null;
|
||
|
||
if (!$isTruncated) {
|
||
break;
|
||
}
|
||
}
|
||
|
||
echo " Проверено delete markers: $totalChecked\n\n";
|
||
|
||
// Сортируем по датам
|
||
krsort($deletionsByDate);
|
||
|
||
echo " Удаления по датам (топ 20):\n";
|
||
$count = 0;
|
||
foreach ($deletionsByDate as $date => $count) {
|
||
if ($count > 0) {
|
||
echo " $date: $count удалений\n";
|
||
if (++$count >= 20) break;
|
||
}
|
||
}
|
||
echo "\n";
|
||
|
||
// Сортируем проекты по количеству удалений
|
||
arsort($deletionsByProject);
|
||
|
||
echo " Проекты с наибольшим количеством удалений (топ 10):\n";
|
||
$count = 0;
|
||
foreach ($deletionsByProject as $projectId => $deleteCount) {
|
||
echo " Проект $projectId: $deleteCount удалений\n";
|
||
if (++$count >= 10) break;
|
||
}
|
||
echo "\n";
|
||
|
||
} catch (\Aws\Exception\AwsException $e) {
|
||
echo " Ошибка: " . $e->getMessage() . "\n";
|
||
}
|
||
|
||
// Проверяем логи системы
|
||
echo "2. Проверка логов на наличие записей об удалениях...\n";
|
||
$logFiles = [
|
||
'/var/log/nginx/error.log',
|
||
'/var/log/apache2/error.log',
|
||
'/var/www/fastuser/data/www/crm.clientright.ru/logs/debug.log',
|
||
'/var/www/fastuser/data/www/crm.clientright.ru/logs/s3_debug.log',
|
||
];
|
||
|
||
foreach ($logFiles as $logFile) {
|
||
if (file_exists($logFile)) {
|
||
echo " Проверка: $logFile\n";
|
||
$lines = file($logFile);
|
||
if ($lines) {
|
||
$deleteLines = array_filter($lines, function($line) {
|
||
return stripos($line, 'delete') !== false &&
|
||
(stripos($line, 's3') !== false || stripos($line, 'file') !== false);
|
||
});
|
||
|
||
if (!empty($deleteLines)) {
|
||
echo " Найдено строк с упоминанием удалений: " . count($deleteLines) . "\n";
|
||
echo " Последние 5 записей:\n";
|
||
foreach (array_slice($deleteLines, -5) as $line) {
|
||
echo " " . substr(trim($line), 0, 150) . "\n";
|
||
}
|
||
} else {
|
||
echo " Записей об удалениях не найдено\n";
|
||
}
|
||
}
|
||
echo "\n";
|
||
}
|
||
}
|
||
|
||
// Проверяем, есть ли скрипты крона, которые могут удалять файлы
|
||
echo "3. Поиск скриптов, которые могут удалять файлы...\n";
|
||
$cronFiles = [
|
||
'/var/spool/cron/crontabs/root',
|
||
'/etc/cron.d/',
|
||
'/var/www/fastuser/data/www/crm.clientright.ru/cron/',
|
||
];
|
||
|
||
foreach ($cronFiles as $cronPath) {
|
||
if (file_exists($cronPath)) {
|
||
echo " Проверка: $cronPath\n";
|
||
if (is_dir($cronPath)) {
|
||
$files = glob($cronPath . '*');
|
||
foreach ($files as $file) {
|
||
if (is_file($file)) {
|
||
$content = file_get_contents($file);
|
||
if (stripos($content, 'delete') !== false || stripos($content, 'remove') !== false) {
|
||
echo " Найден файл: $file\n";
|
||
echo " Содержит упоминания удаления\n";
|
||
}
|
||
}
|
||
}
|
||
} else {
|
||
$content = file_get_contents($cronPath);
|
||
if (stripos($content, 'delete') !== false || stripos($content, 'remove') !== false) {
|
||
echo " Файл содержит упоминания удаления\n";
|
||
}
|
||
}
|
||
}
|
||
}
|
||
echo "\n";
|
||
|
||
// Проверяем, может быть это связано с синхронизацией Nextcloud
|
||
echo "4. Проверка связи с Nextcloud синхронизацией...\n";
|
||
$nextcloudFiles = glob('/var/www/fastuser/data/www/crm.clientright.ru/crm_extensions/file_storage/*sync*.php');
|
||
if (!empty($nextcloudFiles)) {
|
||
echo " Найдено файлов синхронизации: " . count($nextcloudFiles) . "\n";
|
||
foreach ($nextcloudFiles as $file) {
|
||
$content = file_get_contents($file);
|
||
if (stripos($content, 'delete') !== false) {
|
||
echo " $file содержит код удаления\n";
|
||
}
|
||
}
|
||
} else {
|
||
echo " Файлы синхронизации не найдены\n";
|
||
}
|
||
echo "\n";
|
||
|
||
} catch (Exception $e) {
|
||
echo "ОШИБКА: " . $e->getMessage() . "\n";
|
||
echo "Trace: " . $e->getTraceAsString() . "\n";
|
||
}
|
||
|