PHP-флеш, который работает… даже в Nginx
Возможно ли повторять каждый раз, когда выполняется цикл? Например:
foreach(range(1,9) as $n){
echo $n."\n";
sleep(1);
}
Вместо того, чтобы печатать все, когда цикл завершен, я бы хотел, чтобы он печатал каждый результат за раз.
8 answers
ОКОНЧАТЕЛЬНОЕ РЕШЕНИЕ
Итак, вот что я выяснил:
Flush не будет работать в режиме mod_gzip от Apache или gzip от Nginx, потому что, по логике, он выполняет сжатие содержимого, и для этого он должен буферизировать содержимое, чтобы сжать его. Любой вид gzipping веб-сервера повлиял бы на это. Короче говоря, на стороне сервера нам нужно отключить gzip и уменьшить размер буфера fastcgi. Итак:
-
В php.ini:
. output_buffering = Выключено
.zlib.вывод_компрессии= Выкл
-
В файле nginx.conf:
. gzip выключен;
. отключение proxy_buffering;
Также имейте под рукой эти строки, особенно если у вас нет доступа к php.ini:
@ ini_set('zlib.вывод_компрессии',0);
@ ini_set('неявный сброс',1);
@ ob_end_clean об_енд_клиналь();
Set_time_limit Установить время(0);
Последний, если он у вас есть, введите код ниже:
Ob_start('ob_gzhandler-об_старт');
Ob_flush-Промывка();
Тестовый код PHP:
ob_implicit_flush(1);
for($i=0; $i<10; $i++){
echo $i;
//this is for the buffer achieve the minimum size in order to flush data
echo str_repeat(' ',1024*64);
sleep(1);
}
Связанные:
Самый простой способ устранить буферизацию nginx - это создать заголовок:
header('X-Accel-Buffering: no');
Это исключает как proxy_buffering
, так и (если у вас есть nginx >= 1.5.6), fastcgi_buffering
. Бит fastcgi имеет решающее значение, если вы используете php-fpm. Заголовок также гораздо удобнее делать по мере необходимости.
Документы по буферизации X-Accel Документы по fastcgi_buffering
Простое решение на сервере nginx:
fastcgi_keep_conn on; # < solution
proxy_buffering off;
gzip off;
Я не хотел отключать gzip для всего сервера или всего каталога, только для нескольких сценариев, в нескольких конкретных случаях.
Все, что вам нужно, это перед тем, как что-либо будет повторено:
header('Content-Encoding: none;');
Затем выполните промывку как обычно:
ob_end_flush();
flush();
Nginx, похоже, улавливает, что кодировка была отключена, и не выполняет gzip.
Вам нужно очистить буфер php в браузере
foreach(range(1,9) as $n){
echo $n."\n";
flush();
sleep(1);
}
Вы можете сделать это, очистив выходной буфер в середине цикла.
Пример:
ob_start();
foreach(range(1,9) as $n){
echo $n."\n";
ob_flush();
flush();
sleep(1);
}
Обратите внимание, что ваши настройки php.ini могут повлиять на то, будет ли это работать или нет, если у вас включено сжатие zlib
Я обнаружил, что вы можете установить:
header("Content-Encoding:identity");
В вашем php-скрипте, чтобы отключить сжатие nginx без необходимости изменять nginx.conf
У меня была проблема с gzip, связанная с моим движком php-fpm. этот код является единственным, работающим для меня:
function myEchoFlush_init() {
ini_set('zlib.output_compression', 0);
ini_set('output_buffering', 'Off');
ini_set('output_handler', '');
ini_set('implicit_flush', 1);
ob_implicit_flush(1);
ob_end_clean();
header('Content-Encoding: none;');
}
function myEchoFlush($str) {
echo $str . str_repeat(' ', ini_get('output_buffering') * 4) . "<br>\n";
}
Это моя тестовая функция: она проверяет max_execution_time:
public function timeOut($time = 1, $max = 0) {
myEchoFlush_init();
if ($max) ini_set('max_execution_time', $max);
myEchoFlush("Starting infinite loop for $time seconds. It shouldn't exceed : " . (ini_get('max_execution_time')));
$start = microtime(true);
$lastTick = 1;
while (true) {
$tick = ceil(microtime(true) - $start);
if ($tick > $lastTick) {
myEchoFlush(microtime(true) - $start);
$lastTick = $tick;
}
if ($tick > $time) break;
}
echo "OK";
}