PHP Flush, который работает ... даже в Nginx - PullRequest
27 голосов
/ 02 февраля 2011

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

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

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

Ответы [ 8 ]

34 голосов
/ 19 апреля 2014

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

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

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

Документы по X-Accel-Buffering Документы по fastcgi_buffering

33 голосов
/ 16 февраля 2011

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

Итак, вот что я обнаружил:

Flush не будет работать под mod_gzip Apache или gzip Nginx, потому что, по логике, он загружает содержимое, и для этого он долженсодержимое буфера, чтобы сжать его.Любой вид взлома веб-сервера может повлиять на это.Короче говоря, на стороне сервера нам нужно отключить 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);
}

Похожие:

25 голосов
/ 30 ноября 2012

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

fastcgi_keep_conn on; # < solution

proxy_buffering off;
gzip off;
10 голосов
/ 27 июня 2013

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

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

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

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

ob_end_flush();
flush();

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

5 голосов
/ 02 февраля 2011

Вам нужно сбросить буфер php в браузер

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

См .: http://php.net/manual/en/function.flush.php

2 голосов
/ 07 марта 2014

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

header("Content-Encoding:identity");

в вашем php-скрипте, чтобы отключить ggin-файл nginx без изменения nginx.conf

2 голосов
/ 02 февраля 2011

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

Пример:

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

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

1 голос
/ 04 мая 2017

У меня возникла проблема с 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";
}
...