it-swarm.com.ru

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

Можно ли повторять каждый раз при выполнении цикла? Например:

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

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

25
Roger

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

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

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

Связанные с:

33
Roger

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

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

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

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

32
Andy Fowler

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

fastcgi_keep_conn on; # < solution

proxy_buffering off;
gzip off;
24
Ondrej Prochazka

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

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

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

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

ob_end_flush();
flush();

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

10
Redzarf

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

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

Смотрите: http://php.net/manual/en/function.flush.php

5
Petah

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

header("Content-Encoding:identity");

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

2
ttk

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

Пример:

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

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

2
Andy Baird

У меня была проблема с 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";
}
1
Nicolas Thery