php, загрузка файла - PullRequest
       42

php, загрузка файла

16 голосов
/ 08 апреля 2011

Я использую простой скрипт загрузки файлов:

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 МБ.

Я все проверил, написал собственный код (используя obf-функции и fread вместо readfile), но не могу загрузить большие файлы.

Спасибо за ваши ответы.

  • Я использую Apache 2.2, PHP 5.3
  • Все настройки PHP для работы с большими файлами в порядке. (время выполнения, ограничения памяти, ...

Ответы [ 5 ]

19 голосов
/ 08 апреля 2011

Одна проблема, с которой я столкнулся в следующем коде, заключается в том, что вы не можете контролировать поток вывода, ваш PHP разрешает обрабатывать его, не зная точно, что происходит в фоновом режиме:

Что вам нужно сделать, это настроитьсистема вывода, которой вы можете управлять и реплицировать серверы acros.

Например:

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: допустимая память исчерпана

3 голосов
/ 01 декабря 2012

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

Это можно сделать как минимум двумя способами: либо PHP-скрипт копирует файл в «зону загрузки», которую, например, можно регулярно очищать от «старых» файловкаким-либо другим фоновым сценарием / сценарием обслуживания или вы предоставляете клиентам реальное постоянное местоположение.

Конечно, есть недостатки, как и в случае с каждым решением.Во-первых, в зависимости от того, какие клиенты (curl, wget, GUI-браузер) запрашивают файл, они могут не поддерживать перенаправление, которое вы делаете, а во-вторых, файлы очень подвержены внешнему миру и могут быть всегда прочитаны безуправление (доступом) PHP-скрипта.

3 голосов
/ 08 апреля 2011

Кажется, у readfile могут быть проблемы с длинными файлами. Как спросил @Khez, сценарий может работать слишком долго. Быстрый поиск в Google привел к паре примеров разбивки файла.

http://teddy.fr/blog/how-serve-big-files-through-php http://www.php.net/manual/en/function.readfile.php#99406

0 голосов
/ 08 апреля 2011

Реальное решение состоит в том, чтобы не использовать PHP-скрипт для простой отправки файла клиенту, это излишне, и ваш веб-сервер лучше подходит для этой задачи.

Предположительно, у вас есть причина для отправки файлов черезPHP, возможно, пользователи должны сначала пройти аутентификацию?В этом случае вам следует использовать X-Accel-Redirect (если вы используете nginx) или X-Sendfile (ранее X-LIGHTTPD-send-file) на lighttpd.

Если вы используете Apache, я нашел несколько ссылок на mod_xsendfile , но я никогда не использовал его лично, и я сомневаюсь, что он установлен для вас, если вы управляли хостингом.

Если эти решения несостоятельны, я прошу прощения, но мне действительно нужно больше информации о фактической проблеме: почему вы отправляете эти файлы через PHP в первую очередь?

0 голосов
/ 08 апреля 2011

Вы убедились, что ваш скрипт может работать долго достаточно и достаточно памяти?

Вам действительно нужна буферизация вывода?

...