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


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

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

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

Author: hakre, 2011-02-02

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

Связанные:

 32
Author: Roger, 2017-05-23 12:26:12

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

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

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

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

 30
Author: Andy Fowler, 2014-04-19 14:39:17

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

fastcgi_keep_conn on; # < solution

proxy_buffering off;
gzip off;
 24
Author: Ondrej Prochazka, 2012-11-30 12:08:26

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

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

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

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

ob_end_flush();
flush();

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

 10
Author: Redzarf, 2013-06-27 10:10:29

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

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

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

 5
Author: Petah, 2011-02-02 04:13:57

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

Пример:

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

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

 2
Author: Andy Baird, 2011-02-02 04:18:23

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

header("Content-Encoding:identity");

В вашем php-скрипте, чтобы отключить сжатие nginx без необходимости изменять nginx.conf

 2
Author: ttk, 2014-03-06 21:05:33

У меня была проблема с 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
Author: Nicolas Thery, 2017-05-04 10:38:44