У меня есть PHP-скрипт, который отправляет большое количество записей, и я хочу очистить каждую запись, как только она будет доступна: клиент может обрабатывать каждую запись по мере ее поступления, ей не нужно ждать весь ответ. Я понимаю, что для всего переноса требуется немного больше, потому что его нужно отправлять по нескольким пакетам, но он все же позволяет клиенту начать работу раньше.
Я пробовал все функции flush()
и ob_flush()
но ничто не помогает получить данные, фактически отправленные по строке до завершения страницы. Я подтвердил, что это не веб-браузер, потому что я тестировал его с помощью telnet.
Единственное решение, которое сработало для меня, – установить директиву output_buffering
в php.ini на «Off». Я не хотел делать это для всего сервера, только для этого конкретного ресурса. Обычно вы можете использовать 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
От взгляда на сетевой трафик, идущий туда и обратно, мне наконец-то стало ясно, что браузер рекламирует, что он принял дефляцию ни за что (это был текст). Например, это разница между браузером и завитком. Основной бит был
Accept-Encoding: GZIP, выкачать, SDCH
Было немного о chunking
, но это не повлияло на эту конкретную проблему. Таким образом, браузер запрашивал mod_deflate
чтобы 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 байта, прежде чем он начнет выводить что-нибудь вообще.