Обслуживание большого файла через Zend Framework - PullRequest
2 голосов
/ 18 ноября 2009

В нашем приложении аутентификация выполняется с помощью набора плагинов контроллера, которые проверяют пользователя и т. Д.

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

Как я могу отключить буферизацию только для этого одного контроллера?

РЕДАКТИРОВАТЬ: Спасибо за все полезные советы по очистке любой существующей буферизации вывода - я думаю, что я специально искал способ сделать это в рамках?

Ответы [ 6 ]

4 голосов
/ 18 ноября 2009

Интересная проблема ... Вы можете попробовать:

// ...
public function largeFileAction()
{
    // this clears all active output buffers
    while (ob_get_level()) {
        ob_end_clean();
    }
    readfile('path/to/large/file');
    exit(); // to prevent further request handling
}
//  ...
2 голосов
/ 18 ноября 2009

Как писал Тайсон, ваш лучший выбор (если вы имеете полный контроль над сервером) - проверять учетные данные пользователя и перенаправлять его (временное перенаправление 302) на URL-адрес, по которому он может загрузить файл.

Для предотвращения повторного использования этих URL-адресов мы используем Lighttpd и его mod_secdownload , который позволяет генерировать хэш, действительный в течение указанного периода времени.

nginx имеет X-Accel-Redirect , а Apache имеет mod_xsendfile .

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

Если вы решите пойти по этому пути, вам придется либо добавить другой IP-адрес на сервер и привязать Apache только к одному IP-адресу, а другой сервер (lighty of nginx) - к другому, поскольку они являются веб-серверами. оба слушают порт 80. И смена порта для одного из серверов не очень хорошая идея, потому что многие люди не имеют доступа к портам более высокого уровня.

Если добавление другого IP-адреса невозможно, вы можете установить nginx на порт 80 и использовать его в качестве обратного прокси-сервера для передачи динамических запросов в Apache, который может прослушивать другой порт и обслуживать все статические файлы.

2 голосов
/ 18 ноября 2009

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

Может ли что-то подобное достичь того, что вы хотите сделать?

class DownloadController
{
    public function downloadAction()
    {
        $this->_helper->layout()->disableLayout();
        $this->_helper->viewRenderer->setNoRender(true);
        // authenticate user if not done elsewhere already
        header( /* ... the usual stuff ... */);
        filepassthru(/* some path outside webroot */);
        exit;
    }
}
0 голосов
/ 18 ноября 2009
$handle = fopen('/path/to/file', 'r');
$chunk_size = 8192;

while ($chunk = fread($handle, $chunk_size)) {
    echo $chunk;
    ob_flush();
}

Это, вероятно, потребует некоторой настройки, такой как добавление правильных заголовков и чтение в двоичном режиме, если необходимо, но основная идея - это звук. Я успешно использовал этот метод для отправки файлов размером более 50 МБ с пределом памяти PHP 16 МБ.

0 голосов
/ 18 ноября 2009

Учитывая возможность использования внешнего скрипта для вывода файла и его потоковой передачи в браузер с помощью функции PHP passthru.

Если в системе на основе Linux, вы можете попробовать что-то вроде passthru("cat video_file.flv");

Однако лучше избегать этой потоковой передачи (изнутри PHP) и выдавать клиенту перенаправление HTTP 301 на URL-адрес реального статического ресурса, чтобы веб-сервер мог обрабатывать потоковую передачу напрямую.

0 голосов
/ 18 ноября 2009

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

вы можете увеличить предел памяти, используя ini_set()

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...