Intereting Posts
Предупреждение: array_key_exists () ожидает, что параметр 2 будет массивом, boolean given Создание отличительных комбинаций PHP Передача PHP-сгенерированного JSON через семантическую разметку Как получить значение hash (#) в строке запроса Функции повторного использования Symfony2 в контроллерах Нужна помощь в вычислении MySQL-запроса для подсчета, если определенное число Являются ли скалярные и строгие типы в PHP7 функцией повышения производительности? Удалить дубликаты определенных символов из строки Как безопасно выполнять пользовательский код PHP Получение статуса отслеживания заказов USPS с помощью PHP Строка с комой для плавания с точкой Функция base_url () не будет работать на страницах ошибок. Даже после автозагрузки Создать отчет с просмотрами страниц и уникальными посетителями, используя GAPI Загрузить изображение на сервер с iOS не работает Являются ли методы магии лучшей практикой в ​​PHP?

Проверка того, что два файла идентичны с использованием чистого PHP?

TL; DR: У меня есть система CMS, в которой хранятся вложения (непрозрачные файлы) с использованием SHA-1 содержимого файла в качестве имени файла. Как проверить, действительно ли загруженный файл соответствует одному в хранилище, учитывая, что я уже знаю, что хеш SHA-1 соответствует для обоих файлов? Я бы хотел иметь высокую производительность.

Длинная версия:

Когда пользователь загружает новый файл в систему, я вычисляю хэш SHA-1 содержимого загруженного файла, а затем проверяю, существует ли файл с идентичным хешем уже на сервере хранения. PHP ставит загруженный файл в /tmp до того, как мой код будет запущен, а затем я запустил sha1sum против загруженного файла, чтобы получить хэш SHA-1 содержимого файла. Затем я вычисляю разветвление из вычисленного хэша SHA-1 и определяю папку хранения в иерархической иерархии каталогов NFS. (Например, если хеш SHA-1 для содержимого файла равен 37aefc1e145992f2cc16fabadcfe23eede5fb094 постоянным именем файла является /nfs/data/files/37/ae/fc1e145992f2cc16fabadcfe23eede5fb094 .) Помимо сохранения фактического содержимого файла, я INSERT новую строку в базу данных SQL для предоставленных пользователем метаданных (например, Content-Type , original filename, datestamp и т. д.).

В данном случае я делаю вывод, что новый загруженный файл имеет хэш SHA-1, который соответствует существующему хешу на сервере хранения. Я знаю, что изменения для этого происходят случайно, астрономически низки, но я хотел бы быть уверен. (Для специального случая см. Https://shattered.io/ )

Учитывая два имени файла $file_a и $file_b , как быстро проверить, имеют ли оба файла одинаковое содержимое? Предположим, что файлы слишком большие для загрузки в память. С Python я бы использовал filecmp.cmp() но PHP, похоже, не имеет ничего подобного. Я знаю, что это можно сделать с помощью fread() и прервать, если найден несоответствующий байт, но я бы предпочел не писать этот код.

Если у вас уже есть одна сумма SHA1, вы можете просто сделать:

 if ($known_sha1 == sha1_file($new_file)) 

в противном случае

 if (filesize($file_a) == filesize($file_b) && md5_file($file_a) == md5_file($file_b) ) 

Также проверьте размер файла, чтобы несколько предотвратить хеш-коллизию (что уже очень маловероятно). Также используется MD5, потому что он значительно быстрее, чем алгоритмы SHA (но немного менее уникальные).


Обновить:

Это то, как точно сравнивать два файла друг с другом.

 function compareFiles($file_a, $file_b) { if (filesize($file_a) == filesize($file_b)) { $fp_a = fopen($file_a, 'rb'); $fp_b = fopen($file_b, 'rb'); while (($b = fread($fp_a, 4096)) !== false) { $b_b = fread($fp_b, 4096); if ($b !== $b_b) { fclose($fp_a); fclose($fp_b); return false; } } fclose($fp_a); fclose($fp_b); return true; } return false; } 

Обновить

Если вы хотите удостовериться, что файлы равны, вы должны сначала проверить размеры файлов, и если они совпадают, просто сравните содержимое файла. Это намного быстрее, чем использование хэш-функции и, безусловно, даст правильный результат.


Не требуется загружать весь файл в память, если вы hash содержимое с помощью md5_file() или sha1_file() или другой hash_function. Вот пример использования md5 :

 $hash = md5_file('big.file'); // big.file is 1GB in my test var_dump(memory_get_peak_usage()); 

Вывод:

 int(330540) 

В вашем примере это будет:

 if(md5_file('FILEA') === md5_file('FILEB')) { echo 'files are equal'; } 

Обратите внимание, что когда вы используете хеш-функцию, у вас всегда будет ситуация, когда вам нужно решить сложность, с одной стороны, и вероятность столкновений (что означает, что два разных сообщения создают один и тот же хеш) с другой стороны.

Используйте хеш Sha1, как и вы. Если они равны, сравните их хэш-файлы md5 и файлы. Если вы ТОГДА встретите файл, который соответствует всем трем проверкам, но НЕ равен – вы только что нашли святой Грааль: D

Когда ваши файлы большие и двоичные, вы можете просто проверить несколько байтов из нескольких смещений. Он должен быть намного быстрее, чем любая функция хеширования, особенно, что функция возвращает результат первым другим символом.

Однако этот метод не будет работать для файлов, содержащих только несколько разных символов. Это лучшее для больших архивов, видео и так далее.

 function areFilesEqual($filename1, $filename2, $accuracy) { $filesize1 = filesize($filename1); $filesize2 = filesize($filename2); if ($filesize1===$filesize2) { $file1 = fopen($filename1, 'r'); $file2 = fopen($filename2, 'r'); for ($i=0; $i<$filesize1 && $i<$filesize2; $i+=$accuracy) { fseek($file1, $i); fseek($file2, $i); if (fgetc($file1)!==fgetc($file2)) return false; } fclose($file1); fclose($file2); return true; } return false; } 

Следующий фрагмент кода поможет вам проверить, идентичны ли файлы или нет.

 /***check equality of files*/ $file1="pics/star.jpg"; $file2="pics/dupe.jpg"; if(sha1_file($file1)==sha1_file($file2)) echo "Identical"; else echo "Not Identical";