Files
crm.clientright.ru/search_by_doc_id.php
Fedor 840acca51a feat(documents): дедупликация documents_meta и исправление field_label
- Исправлен 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
2025-11-28 18:16:53 +03:00

356 lines
15 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
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';
$docId = 386869;
$s3Bucket = $config['s3']['bucket'];
echo "ПОЛНЫЙ поиск всех файлов, связанных с документом $docId\n";
echo str_repeat("=", 80) . "\n\n";
try {
// Получаем информацию о документе из БД
$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 notesid, title, s3_key, filename, filelocationtype FROM vtiger_notes WHERE notesid = ?');
$stmt->execute([$docId]);
$doc = $stmt->fetch(PDO::FETCH_ASSOC);
if (!$doc) {
die("Документ $docId не найден в БД\n");
}
echo "Информация о документе:\n";
echo " ID: {$doc['notesid']}\n";
echo " Название: {$doc['title']}\n";
echo " S3 Key (ожидаемый): " . ($doc['s3_key'] ?: 'не указан') . "\n";
echo " Filename: " . substr($doc['filename'], 0, 150) . "\n";
echo " Тип хранения: " . ($doc['filelocationtype'] ?: 'не указан') . "\n\n";
// Инициализация S3 клиента
$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
]);
$foundFiles = [];
// 1. Проверяем ожидаемый путь
echo "1. Проверка ожидаемого пути в S3...\n";
if (!empty($doc['s3_key'])) {
try {
$result = $s3Client->headObject([
'Bucket' => $s3Bucket,
'Key' => $doc['s3_key']
]);
echo " ✅ Файл найден по ожидаемому пути!\n";
echo " Путь: {$doc['s3_key']}\n";
echo " Размер: " . number_format($result['ContentLength'] / 1024, 2) . " KB\n";
$foundFiles[] = [
'key' => $doc['s3_key'],
'size' => $result['ContentLength'],
'source' => 'ожидаемый путь'
];
} catch (\Aws\Exception\AwsException $e) {
echo " ❌ Файл не найден по ожидаемому пути: " . $e->getAwsErrorCode() . "\n";
}
}
echo "\n";
// 2. Поиск по точному ID документа
echo "2. Поиск файлов с точным ID $docId...\n";
$searchPatterns = [
(string)$docId,
(string)($docId - 1),
(string)($docId + 1),
(string)($docId - 2),
(string)($docId + 2),
];
$totalChecked = 0;
$maxFilesToCheck = 50000;
foreach ($searchPatterns as $pattern) {
echo " Поиск по паттерну: $pattern\n";
try {
$isTruncated = true;
$continuationToken = null;
$pageCount = 0;
$maxPages = 50;
while ($isTruncated && $pageCount < $maxPages && $totalChecked < $maxFilesToCheck) {
$params = [
'Bucket' => $s3Bucket,
'MaxKeys' => 1000
];
if ($continuationToken) {
$params['ContinuationToken'] = $continuationToken;
}
$objects = $s3Client->listObjectsV2($params);
$pageCount++;
$totalChecked += isset($objects['Contents']) ? count($objects['Contents']) : 0;
if (isset($objects['Contents'])) {
foreach ($objects['Contents'] as $object) {
$key = $object['Key'];
// Ищем файлы, содержащие паттерн
if (strpos($key, $pattern) !== false) {
// Проверяем, не добавили ли уже этот файл
$alreadyAdded = false;
foreach ($foundFiles as $found) {
if ($found['key'] === $key) {
$alreadyAdded = true;
break;
}
}
if (!$alreadyAdded) {
try {
$headResult = $s3Client->headObject([
'Bucket' => $s3Bucket,
'Key' => $key
]);
echo " ✅ НАЙДЕН: $key\n";
echo " Размер: " . number_format($headResult['ContentLength'] / 1024, 2) . " KB\n";
echo " Дата: " . ($headResult['LastModified'] ?? 'не указана') . "\n";
$foundFiles[] = [
'key' => $key,
'size' => $headResult['ContentLength'],
'source' => "поиск по ID $pattern",
'date' => $headResult['LastModified'] ?? null
];
} catch (\Aws\Exception\AwsException $e) {
// Пропускаем недоступные файлы
}
}
}
}
}
$isTruncated = isset($objects['IsTruncated']) && $objects['IsTruncated'];
$continuationToken = isset($objects['NextContinuationToken']) ? $objects['NextContinuationToken'] : null;
if (!$isTruncated) {
break;
}
}
} catch (\Aws\Exception\AwsException $e) {
echo " Ошибка при поиске: " . $e->getMessage() . "\n";
}
}
echo " Проверено файлов: $totalChecked\n\n";
// 3. Поиск по ключевым словам из названия документа
echo "3. Поиск по ключевым словам из названия...\n";
$title = mb_strtolower($doc['title']);
$keywords = [];
// Извлекаем ключевые слова
if (strpos($title, 'исковое') !== false) $keywords[] = 'iskovoe';
if (strpos($title, 'заявление') !== false) $keywords[] = 'zayavlenie';
if (strpos($title, 'марсель') !== false) $keywords[] = 'marse';
if (strpos($title, 'гафиев') !== false) $keywords[] = 'gafiev';
if (strpos($title, 'gafiev') !== false) $keywords[] = 'gafiev';
echo " Ключевые слова: " . implode(', ', $keywords) . "\n";
if (!empty($keywords)) {
// Ищем в temp/ папках
try {
$objects = $s3Client->listObjectsV2([
'Bucket' => $s3Bucket,
'Prefix' => 'temp/',
'MaxKeys' => 10000
]);
if (isset($objects['Contents'])) {
foreach ($objects['Contents'] as $object) {
$key = $object['Key'];
$keyLower = mb_strtolower($key);
// Проверяем совпадение по ключевым словам
$matches = 0;
foreach ($keywords as $keyword) {
if (strpos($keyLower, $keyword) !== false) {
$matches++;
}
}
// Если совпало хотя бы 2 ключевых слова
if ($matches >= 2) {
$alreadyAdded = false;
foreach ($foundFiles as $found) {
if ($found['key'] === $key) {
$alreadyAdded = true;
break;
}
}
if (!$alreadyAdded) {
try {
$headResult = $s3Client->headObject([
'Bucket' => $s3Bucket,
'Key' => $key
]);
echo " ✅ НАЙДЕН по ключевым словам: $key\n";
echo " Размер: " . number_format($headResult['ContentLength'] / 1024, 2) . " KB\n";
$foundFiles[] = [
'key' => $key,
'size' => $headResult['ContentLength'],
'source' => 'поиск по ключевым словам',
'date' => $headResult['LastModified'] ?? null
];
} catch (\Aws\Exception\AwsException $e) {
// Пропускаем
}
}
}
}
}
} catch (\Aws\Exception\AwsException $e) {
echo " Ошибка при поиске: " . $e->getMessage() . "\n";
}
}
echo "\n";
// 4. Поиск в папке проекта (если известен projectId)
echo "4. Поиск в папке проекта...\n";
$stmt = $pdo->prepare('SELECT crmid FROM vtiger_senotesrel WHERE notesid = ? LIMIT 1');
$stmt->execute([$docId]);
$projectRel = $stmt->fetch(PDO::FETCH_ASSOC);
if ($projectRel) {
$projectId = $projectRel['crmid'];
echo " Проект ID: $projectId\n";
$projectPrefixes = [
"crm2/CRM_Active_Files/Documents/Project/",
"temp/$projectId/",
];
foreach ($projectPrefixes as $prefix) {
try {
$objects = $s3Client->listObjectsV2([
'Bucket' => $s3Bucket,
'Prefix' => $prefix,
'MaxKeys' => 1000
]);
if (isset($objects['Contents'])) {
foreach ($objects['Contents'] as $object) {
$key = $object['Key'];
// Ищем файлы с ID документа
if (strpos($key, (string)$docId) !== false ||
strpos($key, (string)($docId - 1)) !== false ||
strpos($key, (string)($docId + 1)) !== false) {
$alreadyAdded = false;
foreach ($foundFiles as $found) {
if ($found['key'] === $key) {
$alreadyAdded = true;
break;
}
}
if (!$alreadyAdded) {
try {
$headResult = $s3Client->headObject([
'Bucket' => $s3Bucket,
'Key' => $key
]);
echo " ✅ НАЙДЕН в папке проекта: $key\n";
echo " Размер: " . number_format($headResult['ContentLength'] / 1024, 2) . " KB\n";
$foundFiles[] = [
'key' => $key,
'size' => $headResult['ContentLength'],
'source' => "папка проекта $projectId",
'date' => $headResult['LastModified'] ?? null
];
} catch (\Aws\Exception\AwsException $e) {
// Пропускаем
}
}
}
}
}
} catch (\Aws\Exception\AwsException $e) {
// Пропускаем ошибки
}
}
}
echo "\n";
// Итоги
echo str_repeat("=", 80) . "\n";
echo "ИТОГОВЫЕ РЕЗУЛЬТАТЫ:\n";
echo " Всего найдено файлов: " . count($foundFiles) . "\n\n";
if (!empty($foundFiles)) {
echo "НАЙДЕННЫЕ ФАЙЛЫ:\n";
foreach ($foundFiles as $i => $file) {
echo " " . ($i + 1) . ". {$file['key']}\n";
echo " Размер: " . number_format($file['size'] / 1024, 2) . " KB\n";
echo " Источник: {$file['source']}\n";
if ($file['date']) {
echo " Дата: {$file['date']}\n";
}
echo "\n";
}
// Определяем наиболее вероятный файл
echo "💡 РЕКОМЕНДАЦИЯ:\n";
$bestMatch = null;
foreach ($foundFiles as $file) {
if ($file['source'] === 'ожидаемый путь') {
$bestMatch = $file;
break;
}
}
if (!$bestMatch && !empty($foundFiles)) {
// Берем первый найденный файл
$bestMatch = $foundFiles[0];
}
if ($bestMatch) {
echo " Наиболее вероятный файл: {$bestMatch['key']}\n";
echo " Этот файл можно использовать для обновления s3_key в БД\n";
}
} else {
echo " ❌ Файлы не найдены в S3\n";
echo " Возможно, файл находится в Nextcloud или локальном хранилище\n";
}
} catch (Exception $e) {
echo "ОШИБКА: " . $e->getMessage() . "\n";
echo "Trace: " . $e->getTraceAsString() . "\n";
}