Имена временных файлов 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 для имени файла, видя, что вы получаете так много.