Запретить буферизацию вывода с помощью PHP и Apache

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

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

3 ответа

Решение

Единственное решение, которое сработало для меня, это установить output_buffering директива в php.ini "Выкл." Я не хотел делать это для всего сервера, только для этого конкретного ресурса. Обычно вы можете использовать ini_set из сценария PHP, но по какой-либо причине php не позволяет output_buffering быть установленным таким образом (см. руководство php).

Что ж, получается, что если вы используете Apache, вы можете установить некоторые директивы php ini (включая output_buffering) из конфигурации вашего сервера, включая файл.htaccess. Поэтому я использовал следующее в файле.htaccess для отключения output_buffering только для этого одного файла:

<Files "q.php">
    php_value output_buffering Off
</Files>

И тогда в моей статической конфигурации сервера мне просто нужно AllowOverride Options=php_value (или больший молот, как AllowOverride All) для того, чтобы это было разрешено в файле.htaccess.

Вы не упоминаете, какой веб-сервер вы используете, но я собираюсь выйти на конечность и предположить Apache2. Я ударил почти то же самое, что вы описываете. Я пытался заставить свой скрипт cgi передавать информацию, как она была готова, вместо того, чтобы буферизовать все это. Работал в кайф и т.д., но буферизовался в браузере (почти в любом браузере), что, по крайней мере, сводило с ума. Я прошел точные шаги, которые вы описываете. Решение в моем случае было изменить sites-enabled/terrifico.com файл конфигурации в Apache2 (рассматриваемая строка начинается с

SetEnvIfNoCase

(Вы можете игнорировать материал выше и ниже этой строки, я просто показываю это для справки о том, где я его разместил.)

<VirtualHost *:80>
ServerAdmin webmaster@localhost
ServerName test.terrifico.com
ServerAlias test.terrifico.com

SetEnvIfNoCase Request_URI \.cgi$ no-gzip dont-vary

DocumentRoot /var/www/test.terrifico.com

Из-за того, что я смотрел на сетевой трафик, идущий взад и вперед, я, наконец, понял, что браузер рекламирует, что он принимает дефляцию для чего-либо (это был текст). В этом была разница между браузером и curl, например. Существенный бит был

Accept-Encoding: GZIP, выкачать, SDCH

Там было немного о chunking, но это не повлияло на эту конкретную проблему. Итак, браузер запрашивал mod_deflate пнуть, что побеждало мои тщательно извергаемые байты, как я получил их в моем сценарии cgi. Вы можете изменить его в браузере, но было бы разумнее изменить его на сервере один раз для работы.

Возможно, это помогает.

Отключить буферизацию вывода во время выполнения в PHP без изменения php.ini или имея .htaccess файл, просто используйте ob_end_flush() или же ob_end_clean() в начале сценария. Например:

Это должно вывести без буферизации:

<?php
ob_end_clean();

for ($i = 0; $i < 5; $i++)
{
    echo "$i\n";
    flush();
    usleep(0.5e6);
}

Это выводит с буферизацией (все за один раз), если output_buffering включен независимо от flush() вызов:

<?php

for ($i = 0; $i < 5; $i++)
{
    echo "$i\n";
    flush();
    usleep(0.5e6);
}

Несмотря на свое название, ob_implicit_flush звонки flush()не ob_flush(), неявно после каждого вывода. Это может быть удобно в этом случае после закрытия буфера вывода в начале:

<?php
ob_end_clean(); // disable output buffer
ob_implicit_flush(); // call flush() automatically after every output

for ($i = 0; $i < 5; $i++)
{
    echo "$i\n";
    usleep(0.5e6);
}

Это исправляет сторону PHP. Там может быть что-то еще происходит с mod_deflate или похожий (см. ответ Теда Коллинза), и я заметил, что Firefox требуется по крайней мере 1024 байта, прежде чем он вообще начнет что-либо выводить.

Другие вопросы по тегам