it-roy-ru.com

Как сбросить вывод после каждого вызова `echo`?

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

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

PS: немного грязно ставить флеш в конце вызова echo ...

Правка: ни Ответы не работали, PHP или Apache Fault? 

47
CuSS

Правка:

Я читал комментарии на странице руководства и наткнулся на ошибку , которая гласит, что 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);
32
amphetamachine

Я получил ту же проблему, и один из опубликованных примеров в руководстве работал. Набор символов должен быть указан в качестве одного из уже упомянутых постеров. 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 />';
56
Teno

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

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

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

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

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

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

10
nobody

что вам нужно, это flush method . пример:

echo "log to client";
 flush();
7
GSto

Для тех, кто приезжает в 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
Ari Waisberg

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

function fecho($string) {
 echo $string;
 ob_flush();
}
5
cam8001

У меня было нечто подобное. С помощью

// 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 () показывает свои настройки как "нет значения" при выключении, это нормальный? ,.

3
freedayum

Правильная функция для использования 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 байт.

2
Dennis G

Это прекрасно работает для меня (Apache 2.4/PHP 7.0):

@ob_end_clean();
echo "lorem ipsum...";
flush();
sleep(5);
echo "<br>dolor...";
flush();
sleep(5);
echo "<br>sit amet";
1
Radacina

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

1
marcovtwout

Это мой код: (работа для PHP7) 

private function closeConnection()
{
    @Apache_setenv('no-gzip', 1);
    @ini_set('zlib.output_compression', 0);
    @ini_set('implicit_flush', 1);

    ignore_user_abort(true);
    set_time_limit(0);

    ob_start();
    // do initial processing here
    echo json_encode(['ans' => true]);

    header('Connection: close');
    header('Content-Length: ' . ob_get_length());
    ob_end_flush();
    ob_flush();
    flush();
}
0
Dmitry Matrosov

Попробуй это:

while (@ob_end_flush());      
ob_implicit_flush(true);

echo "first line visible to the browser";
echo "<br />";

sleep(5);

echo "second line visible to the browser after 5 secs";

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

Важно то, что, отключив свой выходной буфер, как описано выше, вы больше не сможете перенаправлять ваш php-скрипт с помощью функции header(), потому что php может отправляться только один раз за каждый http-заголовок выполнения скрипта. Однако вы можете перенаправить, используя JavaScript. Просто дайте вашему php-скрипту повторить следующие строки:

        echo '<script type="text/javascript">';
        echo 'window.location.href="'.$url.'";';
        echo '</script>';
        echo '<noscript>';
        echo '<meta http-equiv="refresh" content="0;url='.$url.'" />';
        echo '</noscript>'; 
        exit;
0
Grigoreas P.

Одна вещь, которая не часто упоминается, это сжатие gzip, которое остается включенным из-за деталей в различных средах хостинга.

Вот современный подход, работающий с PHP-FPM как Fast CGI, для которого не требуется правило перезаписи .htaccess или переменная среды:

В php.ini или .user.ini:

output_buffering = 0
zlib.output_compression = 0
implicit_flush = true
output_handler = 

В PHP скрипте:

header('Content-Encoding: none'); // Disable gzip compression
ob_end_flush(); // Stop buffer
ob_implicit_flush(1); // Implicit flush at each output command

Смотрите этот комментарий на официальном PHP документе для ob_end_flush ().

0
ZalemCitizen

Обратите внимание, что если вы находитесь на определенных сайтах общего хостинга, таких как Dreamhost, вы не можете вообще отключить буферизацию вывода PHP, не пройдя разные маршруты:

Изменение кеша выходного буфера Если вы используете PHP FastCGI, PHP функции flush (), ob_flush () и ob_implicit_flush () не будут функционировать как ожидалось. По умолчанию вывод буферизуется на более высоком уровне чем PHP (в частности, модулем Apache mod_deflate, который похож по форме/функции на mod_gzip).

Если вам нужен небуферизованный вывод, вы должны либо использовать CGI (вместо FastCGI), либо обратиться в службу поддержки, чтобы запросить отключение mod_deflate для вашего сайта.

https://help.dreamhost.com/hc/en-us/articles/214202188-PHP-overview

0
Matthew Lock