У меня есть php-скрипт, который только производит журналы для клиента.
Когда я что-то повторяю, я хочу, чтобы он был передан клиенту «на лету».
(Поскольку во время обработки скрипта страница пуста)
Я уже играл с ob_start()
и ob_flush()
, но они не работали.
Какое лучшее решение?
PS: немного грязно положить флеш в конце echo
звонка …
EDIT: Ни ответы не работали, ни PHP, ни Apache Fault?
Редактировать:
Я читал комманды на странице руководства и наткнулся на ошибку, в которой указано, что ob_implicit_flush
не работает, и ob_implicit_flush
является следующее:
ob_end_flush(); # CODE THAT NEEDS IMMEDIATE FLUSHING ob_start();
Что может даже произойти, так это то, что клиент не получает пакет с сервера, пока сервер не создаст достаточно символов для отправки того, что он считает отправкой пакета.
Старый ответ:
Вы можете использовать ob_implicit_flush
который будет ob_implicit_flush
буферизацию вывода, чтобы отключить буферизацию на некоторое время:
ob_implicit_flush(true); # CODE THAT NEEDS IMMEDIATE FLUSHING ob_implicit_flush(false);
Я получил ту же проблему, и один из опубликованных примеров в руководстве работал. Набор символов должен быть указан как один из плакатов, о которых уже упоминалось. 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 />';
Итак, вот что я узнал.
Флеш не работал бы с помощью apache mod_gzip или gzip от Nginx, потому что, по логике, это gzipping содержимое, и для этого он должен буферизовать контент, чтобы его gzip. Любой вид gzipping веб-сервера повлияет на это. Короче говоря, на стороне сервера нам нужно отключить 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); }
Попытка, по-видимому, не работающая, является побочным эффектом автоматического обнаружения набора символов.
Браузер ничего не отобразит, пока не узнает набор символов для его отображения, и если вы не укажете набор символов, ему нужно попытаться угадать его. Проблема заключается в том, что он не может сделать хорошее предположение без достаточного количества данных, поэтому браузеры, похоже, имеют этот 1024-байтовый (или подобный) буфер, который им нужно заполнить перед отображением чего-либо.
Поэтому решение состоит в том, чтобы убедиться, что браузеру не нужно угадывать набор символов.
Если вы отправляете текст, добавьте '; charset = utf-8 'для своего типа содержимого, а если это HTML, добавьте набор символов в соответствующий метатег.
то, что вы хотите, это метод флеша . пример:
echo "log to client"; flush();
Почему бы не сделать функцию для эха, например:
function fecho($string) { echo $string; ob_flush(); }
Правильная функция для использования – 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 байт.
У меня было похожее дело. С помощью
// 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 () показывает, что его значение «нет значения» при выключении, это нормально? ,
Попробуй это:
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;
Антивирусное программное обеспечение также может мешать промывке продукта. В моем случае Антивирус Касперского 2013 года хранил куски данных перед отправкой в браузер, хотя я использовал принятое решение.
Иногда проблема возникает из настроек Apache. Apache может быть настроен на gzip вывод. В файле .htaccess вы можете добавить, например:
SetEnv no-gzip 1
Обратите внимание, что если вы находитесь на определенных общедоступных сайтах хостинга, таких как 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
Я опаздываю на обсуждение, но я читал, что многие люди говорят, что добавляет flush (); в конце каждого кода выглядит грязным, и они правы.
Лучшее решение – отключить deblate, gzip и всю буферизацию от Apache, промежуточных обработчиков и PHP. Затем в вашем php.ini вы должны:
output_buffering = Off zlib.output_compression = Off implicit_flush = Off
Временное решение заключается в том, чтобы иметь это в php.ini, если вы можете решить свою проблему с помощью flush (); но вы думаете, что это грязно и уродливо, чтобы его повсюду.
implicit_flush = On
Если вы только указали это в своем php.ini, вам не нужно ставить flush (); в вашем коде больше.
Это мой код: (работа для 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(); }