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

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

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

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

Любые идеи?

Ответ 1

Вам не нужно читать все это - просто введите цикл, читающий его, скажем, 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, которые просто запрашивают фрагменты файла, который он должен отображать на текущей странице. Это немного связано, но см. Это для примера.

Ответ 2

Лучший способ отправить большие файлы с 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 и отправляет файл.

Ответ 3

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

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

Ответ 4

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

Вы можете сделать что-то вроде этого

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

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

Ответ 5

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

Ответ 6

Странно, ни 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: причина, по которой вы просто не помещаете символическую ссылку, - это webspace - SECURITY.

Ответ 7

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

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

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

Ответ 8

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