Files
crm.clientright.ru/move_files_from_temp.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

214 lines
8.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
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';
$projectId = 384256;
$s3Bucket = $config['s3']['bucket'];
echo "Перемещение файлов проекта $projectId из temp/ в правильную структуру\n";
echo str_repeat("=", 80) . "\n\n";
try {
// Инициализация 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
]);
// Подключение к БД
$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]
);
// Получаем все файлы из temp/384256/
echo "1. Поиск файлов в temp/$projectId/...\n";
$tempFiles = [];
$objects = $s3Client->listObjectsV2([
'Bucket' => $s3Bucket,
'Prefix' => "temp/$projectId/",
'MaxKeys' => 1000
]);
if (isset($objects['Contents'])) {
foreach ($objects['Contents'] as $object) {
$key = $object['Key'];
// Пропускаем папки
if (substr($key, -1) !== '/') {
$tempFiles[] = $key;
}
}
}
echo " Найдено файлов в temp/: " . count($tempFiles) . "\n\n";
if (empty($tempFiles)) {
die("Файлы не найдены в temp/$projectId/\n");
}
// Получаем документы проекта из БД
echo "2. Получение документов проекта из БД...\n";
$stmt = $pdo->prepare('
SELECT n.notesid, n.title, n.s3_key, n.filename
FROM vtiger_notes n
INNER JOIN vtiger_crmentity e ON e.crmid = n.notesid
INNER JOIN vtiger_senotesrel snr ON snr.notesid = n.notesid
WHERE snr.crmid = ? AND e.deleted = 0 AND n.filelocationtype = "E"
ORDER BY n.notesid ASC
');
$stmt->execute([$projectId]);
$dbDocs = $stmt->fetchAll(PDO::FETCH_ASSOC);
echo " Найдено документов в БД: " . count($dbDocs) . "\n\n";
// Сопоставляем файлы из temp/ с документами в БД
echo "3. Сопоставление файлов...\n";
$mappings = [];
foreach ($tempFiles as $tempFile) {
$basename = basename($tempFile);
// Извлекаем ID из имени файла (например, 384260 из 384260_8_Dogovor...)
if (preg_match('/^(\d+)_/', $basename, $matches)) {
$fileDocId = $matches[1];
// Ищем соответствующий документ в БД
// Обычно файл с ID 384260 соответствует документу 384259 (ID файла = ID документа + 1)
// Но лучше искать по ближайшему ID
$matchedDoc = null;
foreach ($dbDocs as $doc) {
// Проверяем разные варианты соответствия
if ($doc['notesid'] == $fileDocId - 1 ||
$doc['notesid'] == $fileDocId ||
abs($doc['notesid'] - $fileDocId) <= 2) {
// Дополнительная проверка по названию
$docTitleLower = mb_strtolower($doc['title']);
$fileNameLower = mb_strtolower($basename);
// Проверяем совпадение по ключевым словам
$keywords = ['dogovor', 'podtverzhdenie', 'skrin', 'zayavlenie', '8', '9', '10', '7'];
$foundKeyword = false;
foreach ($keywords as $keyword) {
if (strpos($docTitleLower, $keyword) !== false && strpos($fileNameLower, $keyword) !== false) {
$foundKeyword = true;
break;
}
}
if ($foundKeyword || abs($doc['notesid'] - $fileDocId) <= 1) {
$matchedDoc = $doc;
break;
}
}
}
if ($matchedDoc) {
$mappings[] = [
'temp_file' => $tempFile,
'doc_id' => $matchedDoc['notesid'],
'doc_title' => $matchedDoc['title'],
'target_s3_key' => $matchedDoc['s3_key'],
'current_s3_key' => $matchedDoc['s3_key']
];
echo "{$basename} -> Документ {$matchedDoc['notesid']}: {$matchedDoc['title']}\n";
} else {
echo " ⚠️ {$basename} -> Не найден соответствующий документ (ID файла: $fileDocId)\n";
}
}
}
echo "\n Всего сопоставлено: " . count($mappings) . " файлов\n\n";
if (empty($mappings)) {
die("Не удалось сопоставить файлы с документами\n");
}
// Перемещаем файлы
echo "4. Перемещение файлов в S3...\n";
$moved = 0;
$errors = 0;
foreach ($mappings as $mapping) {
$sourceKey = $mapping['temp_file'];
$targetKey = $mapping['target_s3_key'];
$docId = $mapping['doc_id'];
echo " Перемещение: " . basename($sourceKey) . "\n";
echo " Из: $sourceKey\n";
echo " В: $targetKey\n";
try {
// Проверяем, существует ли целевой путь (если да, пропускаем)
try {
$s3Client->headObject([
'Bucket' => $s3Bucket,
'Key' => $targetKey
]);
echo " ⚠️ Целевой файл уже существует, пропускаем\n\n";
continue;
} catch (\Aws\Exception\AwsException $e) {
if ($e->getAwsErrorCode() != 'NotFound') {
throw $e;
}
}
// Копируем файл в новое место
$s3Client->copyObject([
'Bucket' => $s3Bucket,
'CopySource' => $s3Bucket . '/' . $sourceKey,
'Key' => $targetKey,
'MetadataDirective' => 'COPY'
]);
echo " ✅ Файл скопирован\n";
// Удаляем исходный файл из temp/
$s3Client->deleteObject([
'Bucket' => $s3Bucket,
'Key' => $sourceKey
]);
echo " ✅ Исходный файл удален из temp/\n";
// Обновляем filename в БД (если нужно)
$newFilename = "https://s3.twcstorage.ru/{$s3Bucket}/" . rawurlencode($targetKey);
$updateStmt = $pdo->prepare('UPDATE vtiger_notes SET filename = ? WHERE notesid = ?');
$updateStmt->execute([$newFilename, $docId]);
echo " ✅ Путь в БД обновлен\n";
$moved++;
} catch (\Aws\Exception\AwsException $e) {
echo " ❌ Ошибка: " . $e->getMessage() . " (Code: " . $e->getAwsErrorCode() . ")\n";
$errors++;
} catch (Exception $e) {
echo " ❌ Ошибка: " . $e->getMessage() . "\n";
$errors++;
}
echo "\n";
}
echo str_repeat("=", 80) . "\n";
echo "РЕЗУЛЬТАТЫ:\n";
echo " Перемещено файлов: $moved\n";
echo " Ошибок: $errors\n";
} catch (Exception $e) {
echo "КРИТИЧЕСКАЯ ОШИБКА: " . $e->getMessage() . "\n";
echo "Trace: " . $e->getTraceAsString() . "\n";
}