可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I have a php script that only produces logs to the client.
When I echo something, I want it to be transferred to client on-the-fly.
(Because while the script is processing, the page is blank)
I had already played around with ob_start()
and ob_flush()
, but they didn\'t work.
What\'s the best solution?
PS: it is a little dirty to put a flush at the end of the echo
call...
EDIT: Neither the Answers worked, PHP or Apache Fault?
回答1:
Edit:
I was reading the commends on the manual page and came across a bug that states that ob_implicit_flush
does not work and the following is a workaround for it:
ob_end_flush();
# CODE THAT NEEDS IMMEDIATE FLUSHING
ob_start();
What may even be happening is that the client does not receive the packet from the server until the server has built up enough characters to send what it considers a packet worth sending.
Old Answer:
You could use ob_implicit_flush
which will tell output buffering to turn off buffering for a while:
ob_implicit_flush(true);
# CODE THAT NEEDS IMMEDIATE FLUSHING
ob_implicit_flush(false);
回答2:
I\'ve gotten the same issue and one of the posted example in the manual worked. A character set must be specified as one of the posters here already mentioned. 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 />\';
回答3:
So here\'s what I found out.
Flush would not work under Apache\'s mod_gzip or Nginx\'s gzip because, logically, it is gzipping the content, and to do that it must buffer content to gzip it. Any sort of web server gzipping would affect this. In short, at the server side we need to disable gzip and decrease the fastcgi buffer size. So:
Also have these lines at hand, especially if you don\'t have access to php.ini:
@ini_set(\'zlib.output_compression\',0);
@ini_set(\'implicit_flush\',1);
@ob_end_clean();
set_time_limit(0);
Last, if you have it, comment the code bellow:
ob_start(\'ob_gzhandler\');
ob_flush();
PHP test code:
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);
}
回答4:
Flushing seemingly failing to work is a side effect of automatic character set detection.
The browser will not display anything until it knows the character set to display it in, and if you don\'t specify the character set, it need tries to guess it. The problem being that it can\'t make a good guess without enough data, which is why browsers seem to have this 1024 byte (or similar) buffer they need filled before displaying anything.
The solution is therefore to make sure the browser doesn\'t have to guess the character set.
If you\'re sending text, add a \'; charset=utf-8\' to its content type, and if it\'s HTML, add the character set to the appropriate meta tag.
回答5:
what you want is the flush method.
example:
echo \"log to client\";
flush();
回答6:
For those coming in 2018:
The ONLY Solution worked for me:
<?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();
?>
and its very important to keep de \"4096\" part because it seems that \"fills\" the buffer...
回答7:
Why not make a function to echo, like this:
function fecho($string) {
echo $string;
ob_flush();
}
回答8:
I had a similar thing to do. Using
// ini_set(\"output_buffering\", 0); // off
ini_set(\"zlib.output_compression\", 0); // off
ini_set(\"implicit_flush\", 1); // on
did make the output flushing frequent in my case.
But I had to flush the output right at a particular point(in a loop that I run), so using both
ob_flush();
flush();
together worked for me.
I wasn\'t able to
turn off \"output_buffering\" with
ini_set(...), had to turn it directly
in php.ini, phpinfo() shows its setting
as \"no value\" when turned off, is that
normal? .
回答9:
The correct function to use is 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>
Please note that there is a \"problem\" with IE, which only outputs the flushed content when it is at least 256 byte, so your first part of the page needs to be at least 256 byte.
回答10:
Anti-virus software may also be interfering with output flushing. In my case, Kaspersky Anti-Virus 2013 was holding data chunks before sending it to the browser, even though I was using an accepted solution.
回答11:
Try this:
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\";
Just notice that this way you\'re actually disabling the output buffer for your current script. I guess you can reenable it with ob_start() (i\'m not sure).
Important thing is that by disabling your output buffer like above, you will not be able to redirect your php script anymore using the header()
function, because php can sent only once per script execution http headers.
You can however redirect using javascript. Just let your php script echo following lines when it comes to that:
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;
回答12:
Note if you are on certain shared hosting sites like Dreamhost you can\'t disable PHP output buffering at all without going through different routes:
Changing the output buffer cache If you are using PHP FastCGI, the PHP
functions flush(), ob_flush(), and ob_implicit_flush() will not
function as expected. By default, output is buffered at a higher level
than PHP (specifically, by the Apache module mod_deflate which is
similar in form/function to mod_gzip).
If you need unbuffered output, you must either use CGI (instead of
FastCGI) or contact support to request that mod_deflate is disabled
for your site.
https://help.dreamhost.com/hc/en-us/articles/214202188-PHP-overview
回答13:
This is my code: (work for 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();
}
回答14:
This works fine for me (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\";
回答15:
Sometimes, the problem come from Apache settings. Apache can be set to gzip the output.
In the file .htaccess you can add for instance :
SetEnv no-gzip 1
回答16:
I\'m late to the discussion but I read that many people are saying appending flush(); at the end of each code looks dirty, and they are right.
Best solution is to disable deflate, gzip and all buffering from Apache, intermediate handlers and PHP. Then in your php.ini you should have:
output_buffering = Off
zlib.output_compression = Off
implicit_flush = Off
Temporary solution is to have this in your php.ini IF you can solve your problem with flush(); but you think it is dirty and ugly to put it everywhere.
implicit_flush = On
If you only put it above in your php.ini, you don\'t need to put flush(); in your code anymore.