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