Я использую простой скрипт загрузки файлов:
if (file_exists($file)) { header('Content-Description: File Transfer'); header('Content-Type: application/octet-stream'); header('Content-Disposition: attachment; filename='.basename($file)); header('Content-Transfer-Encoding: binary'); header('Expires: 0'); header('Cache-Control: must-revalidate, post-check=0, pre-check=0'); header('Pragma: public'); header('Content-Length: ' . filesize($file)); ob_clean(); flush(); readfile($file); exit; }
Он работает на моем локальном сервере до 200 мб.
Когда я пытаюсь использовать этот код на своем веб-сайте, он загружает 173 КБ вместо 200 МБ-файла.
Я проверил все, написал какой-то пользовательский код (используя функции ob и fread вместо readfile), но не могу загрузить большие файлы.
Спасибо за ответ.
Одна из проблем, которые у меня есть со следующим кодом, заключается в том, что у вас нет контроля над потоком вывода, позволяя PHP обрабатывать его, не зная точно, что происходит в фоновом режиме:
Что вам нужно сделать, так это настроить систему вывода, в которой вы можете управлять и реплицировать серверы accros.
Например:
if (file_exists($file)) { if (FALSE!== ($handler = fopen($file, 'r'))) { header('Content-Description: File Transfer'); header('Content-Type: application/octet-stream'); header('Content-Disposition: attachment; filename='.basename($file)); header('Content-Transfer-Encoding: chunked'); //changed to chunked header('Expires: 0'); header('Cache-Control: must-revalidate, post-check=0, pre-check=0'); header('Pragma: public'); //header('Content-Length: ' . filesize($file)); //Remove //Send the content in chunks while(false !== ($chunk = fread($handler,4096))) { echo $chunk; } } exit; } echo "<h1>Content error</h1><p>The file does not exist!</p>";
Это только базовая задача, но приготовьтесь!
Также прочитайте мой ответ здесь: file_get_contents => PHP Неустранимая ошибка: Допустимая память исчерпана
Кажется, что readfile может иметь проблемы с длинными файлами. Как сказал @Khez, возможно, скрипт работает слишком долго. В результате быстрого Googling появилось несколько примеров разбивки файла.
http://teddy.fr/blog/how-serve-big-files-through-php http://www.php.net/manual/en/function.readfile.php#99406
Одним из решений некоторых сценариев является то, что вы можете использовать PHP-скрипт для разумного решения, какой файл загружать, но вместо отправки файла непосредственно с PHP вы можете вернуть перенаправление клиенту, который затем содержит прямую ссылку, которая обрабатывается только веб-сервером.
Это можно сделать, по крайней мере, двумя способами: либо PHP-скрипт копирует файл в «зону загрузки», которая, например, может быть очищена из «старых» файлов регулярно каким-либо другим фоновым / служебным скриптом, либо вы обнаружите реальное постоянное место для клиентов.
Конечно, есть недостатки, как в случае с каждым решением. В этом заключается то, что в зависимости от клиентов (завиток, wget, GUI-браузера), запрашивающих файл, они могут не поддерживать перенаправление, которое вы делаете, а в другом – файлы очень подвержены внешнему миру и могут быть прочитаны всегда без (доступ) для скрипта PHP.
Вы уверены, что ваш скрипт может работать достаточно долго и иметь достаточно памяти?
Вам действительно нужна буферизация вывода?
Реальное решение состоит в том, чтобы избежать использования PHP-скрипта для просто отправки файла клиенту, это слишком много, и ваш веб-сервер лучше подходит для задачи.
Предположительно, у вас есть причина для отправки файлов через PHP, возможно, сначала пользователи должны пройти аутентификацию? Если это так, вы должны использовать X-Accel-Redirect (если вы используете nginx) или X-Sendfile (ранее X-LIGHTTPD-send-file) на lighttpd.
Если вы используете Apache, я нашел несколько ссылок на mod_xsendfile, но я никогда не использовал его лично, и я сомневаюсь, что он установлен для вас, если вы управляете хостингом.
Если эти решения несостоятельны, я приношу свои извинения, но мне действительно нужна дополнительная информация о реальной проблеме: почему вы отправляете эти файлы через PHP в первую очередь?