I'm wondering if this is a PHP.ini config issue. I find that, with large data sets, I can't echo incremented values.
<?php
ob_start();
*SQL query*
$count++;
$search_results = ob_get_clean();
echo $count;
echo $search_results;
?>
The code itself works, but with large data sets it doesn't appear at all. I'm wondering if this is a cacheing issue?
This was not a memory issue, it was related to php.ini settings. In particular, the max_execute time was not high enough. I changed it to;
max_execution_time = 600
Solved the issue.
I have a PHP code as below. When I run this on Apache (Apache/2.2.17 ), the result is that it prints 'Program started....' and then waits for 5 seconds and then print 'Script complete.' when I run this on a browser.
<?php
header( 'Content-type: text/html; charset=utf-8' );
set_time_limit(0);
ob_implicit_flush(TRUE);
echo 'Program started....';
ob_flush();
sleep(5);//making the script to wait for 5 seconds
echo 'Script complete.';
?>
When I run the same above code on IIS (IIS 8), I program waits for 5 seconds and then prints 'Program started....Script complete.' at the end of execution.
How can I make the code to behave the same on IIS as i does on Apache.
The comments in the PHP documentation for flush note several items in apache to check that may prevent flush() working properly:
Server modules for Apache like mod_gzip may do buffering of their own
that will cause flush() to not result in data being sent immediately
to the client.
See http://php.net/manual/en/function.flush.php and do a find for "apache" for items to try disabling. Example from commenter mandor at mandor dot net:
This is what I use to turn off pretty much anything that could cause
unwanted output buffering and turn on implicit flush:
#apache_setenv('no-gzip', 1);
#ini_set('zlib.output_compression', 0);
#ini_set('implicit_flush', 1);
for ($i = 0; $i < ob_get_level(); $i++) { ob_end_flush(); }
ob_implicit_flush(1);
?>
I am doing a lot of processing at my PHP page and I want to display progress information to the user, for instance, finished 10% 20% and so. What is happening now is that all the data is displayed at once after processing is done, how can I display it right away!
I tried to set comment out output buffer in php.ini and I tried to use flush() after echo statements, not working, any suggestions?
Here is my code:
ob_start();
while ($line = read_file_line("c:/1.txt")) {
$read_lines_count++;
if($read_lines_count % 100 == 0) {
echo "parsed $read_lines_count <br />";
ob_flush();
}
}
First you need to call ob_start() before any code is printed.
Then echo whatever you want
call ob_flush() when you want to show the buffer on screen.
and at the end, a call to ob_end_flush() to end buffering and show output.
Make sure your php.ini has this line uncommented:
output_buffering = On
More Info : http://www.php.net/manual/en/book.outcontrol.php
I've read many articles and did research online, but I cannot figure out why those commands are not working on my machine. Code get executed but it echoes when whole script is executed. I am testing it with simple code, I will easily implement it later for everything else. Here is the code:
ob_start();
echo "Start ...<br />\n";
for( $i = 0 ; $i < 5 ; $i++ )
{
echo $i."<br />\n";
ob_flush();
flush();
sleep(1);
}
echo "End ...<br />\n";
I tried using ob_end_flush(), nothing worked for me. I've checked php.ini for configuration it says:
output_buffering = 4096
zlib.output_compression = Off
implicit_flush = Off
I don't know what is wrong, I've also read on php.net "As of August 2012, all browsers seem to show an all-or-nothing approach to buffering. In other words, while php is operating, no content can be shown."
Is my code wrong? Server settings? Browsers? Is there a workaround?
Did you try?
ob_implicit_flush(true);
While I don't know the real answer, you can do it like this:
<?php
ob_start();
ob_implicit_flush(false);
echo str_repeat(' ', 1024);
# rest of code here
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?
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 />';
ob_flush();
flush();
sleep(1);
}
echo 'End ...<br />';
Edit:
I was reading the comments 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();
If this does not work then 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);
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:
In php.ini:
output_buffering = Off
zlib.output_compression = Off
In nginx.conf:
gzip off;
proxy_buffering off;
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);
}
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...
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.
what you want is the flush method.
example:
echo "log to client";
flush();
Why not make a function to echo, like this:
function fecho($string) {
echo $string;
ob_flush();
}
One thing that is not often mentionned is gzip compression that keeps turned ON because of details in various hosting environments.
Here is a modern approach, working with PHP-FPM as Fast CGI, which does not need .htaccess rewrite rule or environment variable :
In php.ini or .user.ini :
output_buffering = 0
zlib.output_compression = 0
implicit_flush = true
output_handler =
In PHP script :
header('Content-Encoding: none'); // Disable gzip compression
ob_end_flush(); // Stop buffer
ob_implicit_flush(1); // Implicit flush at each output command
See this comment on official PHP doc for ob_end_flush() need.
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? .
header( 'X-Accel-Buffering: no' );
header( 'Content-Type: text/html; charset=utf-8' );
echo 'text to display';
echo '<span style="display: none;">' . str_repeat ( ' ', 4096 ) . '</span>';
flush();
usleep( 10 );
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.
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";
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.
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
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;
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
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.
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();
}