Как сбросить вывод после каждого вызова `echo`? - PullRequest
51 голосов
/ 28 июня 2010

У меня есть сценарий php, который создает журналы только для клиента.
Когда я что-то передаю, я хочу, чтобы это было передано клиенту на лету.
(Поскольку во время обработки сценариястраница пуста)
Я уже играл с ob_start() и ob_flush(), но они не сработали.

Какое лучшее решение?

PS: этонемного грязно, чтобы добавить очистку в конце вызова echo ...

РЕДАКТИРОВАТЬ: не работает ни Ответы, PHP или ошибка Apache?

Ответы [ 17 ]

57 голосов
/ 05 октября 2012

У меня возникла та же проблема, и сработал один из опубликованных примеров в руководстве. Набор символов должен быть указан в качестве одного из уже упомянутых постеров. http://www.php.net/manual/en/function.ob-flush.php#109314

header( 'Content-type: text/html; charset=utf-8' );
echo 'Begin ...<br />';
for( $i = 0 ; $i < 10 ; $i++ )
{
    echo $i . '<br />';
    flush();
    ob_flush();
    sleep(1);
}
echo 'End ...<br />';
33 голосов
/ 12 февраля 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 to make the buffer achieve the minimum size in order to flush data
    echo str_repeat(' ',1024*64);

    sleep(1);
}
32 голосов
/ 28 июня 2010

Изменить:

Я читал комментарии на странице руководства и наткнулся на ошибку , которая гласит, что ob_implicit_flush не работает , и вот обходной путь для него:

ob_end_flush();

# CODE THAT NEEDS IMMEDIATE FLUSHING

ob_start();

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


Старый ответ:

Вы можете использовать ob_implicit_flush, который скажет буферизации вывода отключить буферирование на некоторое время:

ob_implicit_flush(true);

# CODE THAT NEEDS IMMEDIATE FLUSHING

ob_implicit_flush(false);
11 голосов
/ 25 апреля 2012

Промывка, которая, по-видимому, не работает, является побочным эффектом автоматического определения набора символов.

Браузер не отобразит ничего, пока не узнает набор символов для его отображения, и если вы не укажете набор символов, ему нужно попытаться угадать его. Проблема в том, что он не может сделать правильное предположение без достаточного количества данных, поэтому браузеры, похоже, имеют этот 1024-байтовый (или аналогичный) буфер, который им нужно заполнить перед отображением чего-либо.

Поэтому решение состоит в том, чтобы браузер не угадывал набор символов.

Если вы отправляете текст, добавьте '; charset = utf-8 'к его типу контента, и, если это HTML, добавьте набор символов в соответствующий метатег.

10 голосов
/ 21 февраля 2018

Для тех, кто приезжает в 2018 году:

ЕДИНСТВЕННОЕ решение сработало для меня:

<?php

    if (ob_get_level() == 0) ob_start();
    for ($i = 0; $i<10; $i++){

        echo "<br> Line to show.";
        echo str_pad('',4096)."\n";    

        ob_flush();
        flush();
        sleep(2);
    }

    echo "Done.";

    ob_end_flush();
?>

и очень важно сохранить часть "4096", потому что кажется, что она "заполняет" буфер ...

7 голосов
/ 28 июня 2010

вы хотите использовать метод flush .пример:

echo "log to client";
 flush();
5 голосов
/ 28 июня 2010

Почему бы не сделать функцию эхом, как это:

function fecho($string) {
 echo $string;
 ob_flush();
}
3 голосов
/ 28 июня 2010

Правильная функция для использования flush().

<html>
<body>
<p>
Hello! I am waiting for the next message...<br />
<?php flush(); sleep(5); ?>
I am the next message!<br />
<?php flush(); sleep(5); ?>
And I am the last message. Good bye.
</p>
</body>
</html>

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

3 голосов
/ 21 января 2011

У меня было нечто подобное. Использование

// ini_set("output_buffering", 0);  // off 
ini_set("zlib.output_compression", 0);  // off
ini_set("implicit_flush", 1);  // on   

в моем случае частая промывка выходного сигнала.

Но я должен был сбросить вывод прямо в определенной точке (в цикле, который я запускаю), поэтому использовал оба

ob_flush();
flush();

вместе работали на меня.

Я не смог выключите "output_buffering" с помощью ini_set (...), должен был повернуть это непосредственно в php.ini phpinfo () показывает свои настройки как "нет значения" при выключении, это то, что нормальный? .

1 голос
/ 19 мая 2015

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

...