Имена временных файлов PHP для загрузки файлов

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

Вот журнал, показывающий, как одно и то же имя файла tmp используется и перезаписывается при другой загрузке: http://pastebin.com/m65790440

Любая помощь очень ценится. Я пытался это исправить более 4 месяцев и со временем стало хуже. Спасибо.

РЕДАКТИРОВАТЬ: Имейте в виду, что это не проблема кода PHP, это происходит до того, как он достигнет любого кода PHP, файл, полученный через $_FILES['name']['tmp_name'], является неправильным, когда он получен и его отслеживают назад, что это перезаписывается с загрузкой кого-то еще, прежде чем это достигает сценария обработки загрузки

5 ответов

После погони за соответствующим кодом до _gettemp в реализации libc FreeBSD 7, я неясен относительно того, как содержимое файла tmp_name может быть недействительным. (Чтобы проследить это, вы можете скачать копию PHP 5.2.8 и прочитать в main/rfc1867.c - линия 1018 звонит в main/php_open_temporary_file.c функция, начинающаяся со строки 227, которая выполняет свою основную работу в функции, начинающейся со строки 97, которая, тем не менее, по сути является просто оболочкой для mkstemp в вашей системе, которая находится в реализации libc FreeBSD в строке 66 (связанный), который использует _gettemp (то же, что и выше) для создания случайного имени файла. Однако на странице man для mkstemp в разделе BUGS упоминается, что arc4random() функция не реентерабельна. Возможно, что два одновременных запроса входят в критическую секцию кода и возвращают один и тот же tmp_name - Я слишком мало знаю о том, как Apache работает с mod_php или php-cgi, чтобы комментировать там (хотя использование FastCGI/php-cgi может сработать - я не могу сейчас это прокомментировать).

Тем не менее, нацеливаясь на самое простое решение, если вы не совсем испытываете файл tmp_name сам по себе является недействительным, но вместо этого сталкивается с другими загруженными файлами (например, если использовать часть имени файла tmp_name в качестве единственного источника уникальности в сохраненном имени файла), вы можете столкнуться со столкновениями из-за парадокса дня рождения. В другом вопросе вы упомянули, что нужно переместить около 5 000 000 файлов, а в другом вопросе вы упомянули о получении 30-40 тыс. Загрузок в день. Это кажется мне главной ситуацией при столкновении с парадоксом дня рождения. В справочной странице mktemp упоминается, что (если используется шесть "X", как в PHP), существует 56 800 235 584 возможных имен файлов (62 ** 6 или 62 ** n, где n = количество "X" и т. Д.). Однако, учитывая, что у вас более 5 миллионов файлов, вероятность коллизии составляет приблизительно 100% (другая эвристика предполагает, что вы уже столкнулись с каким-то порядка 220 коллизий, если ((files*(files-1))/2)/(62**6) означает что угодно, где файлы = 5 000 000). Если это проблема, с которой вы столкнулись (вероятно, если не добавлять дополнительную энтропию к сгенерированному загруженному имени файла), вы можете попробовать что-то вроде move_uploaded_file($file['tmp_name'], UPLOADS.sha1(mt_rand().$file['tmp_name']).strrchr($file['name'], '.')) - идея состоит в том, чтобы добавить больше случайности к случайному имени файла, предотвращая столкновения. Альтернативой может быть добавление еще двух "X" к строке 134 main/php_open_temporary_file.c и перекомпилировать.

Похоже, что-то серьезно не так с вашей установкой PHP или с тем, какой системный вызов PHP использует для внутреннего генерирования случайных имен файлов (скорее всего, tempnam).

Для всех остальных: PHP обрабатывает загруженные файлы внутри до того, как пользовательский код когда-либо обрабатывается. Эти имена хранятся в $_FILES['file']['tmp_name'] (где 'file' - это (в кавычках) имя элемента ввода файла в форме).

PHP работает под Apache, как mod_php?

Вы можете попытаться создать временный каталог загрузки для каждого процесса, имя которого содержит ваш php getmypid(), затем ini_set ваш процесс PHP ' upload_tmp_dir в этот каталог. Это не будет работать, если новый php процесс создается для каждого запроса.

Переместите ваши файлы в каталог пользователя после того, как они были загружены. Эти временные файлы должны быть удалены.

Я бы рекомендовал использовать генератор GUID для имени файла, видя, что вы получаете так много.

Другие вопросы по тегам