Обслуживание больших файлов с помощью PHP

Поэтому я пытаюсь обслуживать большие файлы с помощью PHP-скрипта, они не находятся в каталоге, доступном в Интернете, поэтому это лучший способ, с помощью которого я могу обеспечить доступ к ним.

Единственный способ, с помощью которого я мог бы думать о том, чтобы служить этому файлу, – загрузить его в память (fopen, fread, ect.), Установив данные заголовка в соответствующий тип MIME, а затем просто отразив все содержимое файла.

Проблема заключается в том, что я должен загрузить эти файлы размером ~ 700 МБ в память сразу и сохранить все до завершения загрузки. Было бы неплохо, если бы я мог передавать те части, которые мне нужны, когда они загружаются.

Есть идеи?

Вам не нужно читать все это – просто введите цикл, читающий его, скажем, 32Kb куски и отправляя его как вывод. Еще лучше, используйте fpassthru, который делает то же самое для вас ….

$name = 'mybigfile.zip'; $fp = fopen($name, 'rb'); // send the right headers header("Content-Type: application/zip"); header("Content-Length: " . filesize($name)); // dump the file and stop the script fpassthru($fp); exit; 

еще меньше строк, если вы используете readfile , который не нуждается в вызове fopen …

 $name = 'mybigfile.zip'; // send the right headers header("Content-Type: application/zip"); header("Content-Length: " . filesize($name)); // dump the file and stop the script readfile($name); exit; 

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

Лучший способ отправить большие файлы с php – это заголовок X-Sendfile . Это позволяет веб-серверу обслуживать файлы намного быстрее с помощью механизмов нулевой копии, таких как sendfile(2) . Он поддерживается lighttpd и apache с плагином .

Пример:

 $file = "/absolute/path/to/file"; // can be protected by .htaccess header('X-Sendfile: '.$file); header('Content-type: application/octet-stream'); header('Content-Disposition: attachment; filename="'.basename($file).'"'); // other headers ... exit; 

Сервер считывает заголовок X-Sendfile и отправляет файл.

Хотя fpassthru() был моим первым выбором в прошлом, руководство PHP фактически рекомендует * использовать readfile() вместо этого, если вы просто демпируете файл как есть для клиента.

* «Если вы просто хотите сбросить содержимое файла в выходной буфер, не изменяя его или не добиваясь определенного смещения, вы можете использовать readfile (), который сохранит вам вызов fopen ()». – Руководство по PHP

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

Вы можете сделать что-то подобное

 ln -s /home/files/big_files_folder /home/www/htdocs 

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

Посмотрите на fpassthru () . В более поздних версиях PHP это должно обслуживать файлы, не сохраняя их в памяти, как говорится в этом комментарии .

Странно, ни fpassthru (), ни readfile () не сделали это для меня, всегда имели ошибку памяти. Я прибегал к использованию passthru () без «f»:

 $name = 'mybigfile.zip'; // send the right headers header("Content-Type: application/zip"); header("Content-Length: " . filesize($name)); // dump the file and stop the script passthru('/bin/cat '.$filename); exit; 

эта команда exec 'cat' Unix и отправляет свой вывод в браузер.

комментарий для slim: причина, по которой вы просто не помещаете символическую ссылку, – это веб-пространство SECURITY.

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

И readfile () должен быть немного быстрее, что приводит к использованию механизма кэширования ОС, если это возможно (как, например, file_get_contents ()).

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

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