Вопрос проверяет знание подходов к определению, что файл уже загружался, и способов борьбы с дубликатами.
Для обнаружения повторной загрузки файла обычно используют хэши содержимого (MD5/SHA-256), комбинацию имени файла и размера, метаданные (дата, источник), а также бизнес-ключи из содержимого (например, идентификаторы записей). При загрузке считают хэш файла или его части, сверяют с ранее сохранёнными значениями и решают, считать ли файл дублем. Также можно использовать дедупликацию на уровне строк: уникальные ключи в БД, индексы, таблицы "processed hash". Комбинация хэшей и бизнес-ограничений позволяет надёжно отсекать повторные загрузки.
Нужно решить две задачи:
Понять, загружался ли такой файл ранее.
Не допустить дублирования данных внутри системы (даже если файл другой, но записи совпадают).
Определение: Хэш файла — результат криптографической функции (MD5, SHA-1, SHA-256) над всем содержимым файла.
Алгоритм:
при загрузке файла — считаем хэш
ищем этот хэш в таблице uploaded_files
если найден — файл уже загружался
Структура таблицы:
id
file_hash
original_name
size
created_at
user_id
php
$hash = hash_file('sha256', $uploadedFilePath);
$exists = $db->fetchOne(
'SELECT id FROM uploaded_files WHERE file_hash = :hash',
['hash' => $hash]
);
if ($exists) {
// дубликат файла
}
очень надёжно (если использовать сильный алгоритм)
не завязано на имя файла
легко реализуется
нужно прочитать файл целиком для хэширования
для 300 МБ это ощутимая операция (но делается один раз)
Если полный хэш считать дорого:
можно взять первые N МБ + последние N МБ
или несколько "срезов" по файлу
хэш рассчитывается по их конкатенации
Вероятность коллизии чуть выше, но для бизнес-задач обычно достаточно.
Быстрый фильтр:
если size и original_name не совпадают → точно не тот же файл
если совпадают → возможный дубликат, можно дополнительно проверить хэш
Это уменьшает количество полных хэширований.
Файл может отличаться (дата выгрузки, количество строк), но содержать уже импортированные записи.
Подходы:
На уровне таблиц:
уникальный индекс по бизнес-ключу: например (external_id), (user_id, period), (contract_number)
Если запись уже была:
вставка падает с ошибкой unique constraint
вы решаете: игнорировать, обновлять, логировать
Для каждой строки можно считать хэш её "смысла":
php
$hash = hash('sha256', $userId . '|' . $date . '|' . $amount);
И хранить его в таблице:
row_hash — unique
при повторной попытке вставить такой же — срабатывает уникальность
Полезно хранить:
хэш файла
количество строк
диапазон дат или ключей
источник (поставщик)
Тогда:
мы знаем, что файл "Поставщик А, данные за январь" уже загружен
можно запретить повторную загрузку или предупредить пользователя
или предложить режим "пере-заливки" с заменой
Можно добавлять:
idempotency-key в запросы импортов
временные блокировки на импорт одного и того же файла
логику "если последний импорт для этого типа ещё не завершён — запрещать новый"
Если несколько воркеров обрабатывают один и тот же файл или разные файлы с пересечением:
уникальные индексы в БД не дадут записать дубль
можно использовать INSERT ... ON CONFLICT DO NOTHING (Postgres)
или INSERT IGNORE / REPLACE (MySQL, но аккуратно)
На практике лучше использовать комбинацию:
Быстрая проверка по размеру и имени (эвристика).
Надёжная проверка по хэшу файла.
Защита на уровне данных: уникальные ключи и хэш строк.
Бизнес-ограничения: нельзя загружать один и тот же период дважды без явного подтверждения.
Дубликаты файлов и данных лучше ловить на нескольких уровнях:
хэш файла (или его части) — чтобы понять, что файл уже загружался
уникальные ключи и хэш строк — чтобы не допустить повторный импорт тех же записей
бизнес-ограничения и idempotency — чтобы избежать логических дублей на уровне сценариев
Это делает систему устойчивой к повторным загрузкам и ошибкам пользователей.