PHP-флеш, который работает... даже в Nginx

Можно ли эхо каждый раз, когда цикл выполняется? Например:

foreach(range(1,9) as $n){
    echo $n."\n";
    sleep(1);
}

Вместо того, чтобы печатать все, когда цикл закончен, я бы хотел, чтобы он печатал каждый результат за раз.

Ответ 1

ЗАКЛЮЧИТЕЛЬНОЕ РЕШЕНИЕ

Итак, что я узнал:

Флеш не будет работать под Apache mod_gzip или Nginx gzip, потому что он логически является gzipping содержимым, и для этого он должен буферизовать содержимое для его gzip. Любой вид gzipping веб-сервера повлияет на это. Короче говоря, на стороне сервера нам нужно отключить gzip и уменьшить размер буфера fastcgi. Итак:

  • В php.ini:

    . output_buffering = Off

    . zlib.output_compression = Off

  • В nginx.conf:

    . gzip off;

    . proxy_buffering off;

Также есть эти строки под рукой, особенно если у вас нет доступа к php.ini:

  • @ini_set ( 'zlib.output_compression', 0);

  • @ini_set ( 'implicit_flush', 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);
}

по теме:

Ответ 2

Самый простой способ устранить буферизацию nginx - это исправить заголовок:

header('X-Accel-Buffering: no');

Это устраняет как proxy_buffering, так и (если у вас есть nginx >= 1.5.6), fastcgi_buffering. Бит fastcgi имеет решающее значение, если вы используете php-fpm. Заголовок также гораздо удобнее делать по мере необходимости.

Документы по буферизации X-Accel Документы на fastcgi_buffering

Ответ 3

Простое решение на сервере nginx:

fastcgi_keep_conn on; # < solution

proxy_buffering off;
gzip off;

Ответ 4

Мне не нужно было отключать gzip для всего сервера или целого каталога, всего лишь для нескольких скриптов, в нескольких конкретных случаях.

Все, что вам нужно, это прежде, чем что-то будет эхо-сообщение:

header('Content-Encoding: none;');

Затем выполните флеш как обычно:

ob_end_flush();
flush();

Nginx, похоже, забирает кодировку, отключенную и не gzip.

Ответ 6

Вы можете выполнить это, сбросив выходной буфер в середине цикла.

Пример:

ob_start();
foreach(range(1,9) as $n){
    echo $n."\n";
    ob_flush();
    flush();
    sleep(1);
}

Обратите внимание, что ваши настройки php.ini могут повлиять на то, будет ли это работать или нет, если вы включили сжатие zlib

Ответ 7

Я обнаружил, что вы можете установить:

header("Content-Encoding:identity");

в вашем php script для отключения nginx gzipping без изменения nginx.conf

Ответ 8

У меня была проблема с gzip, исходящая от моего php-fpm engine. этот код работает только для меня:

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";
}