I thought flush(); would work, at least from what Google/Stackoverflow tell me, but on my Windows WAMP (Windows, Apache, MySQL, PHP) system it doesn't work.
Is there some PHP setting I have to set to make flush() work?
Here's my code:
<?php
echo "Fun";
flush();
sleep(5);
echo "<br>Mo";
?>
The code just outputs all together when the script is done executing (after 5 seconds).. I don't want this, I want 'Fun' to show up right away, and then after 5 seconds 'Mo'.
I've tried other combinations of flush like ob_end_flush(); or ob_implicit_flush(true); but nothing is working. Any ideas?
So that'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 this lines at hand, specially if you don't have acces 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, coment 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 for the buffer achieve the minimum size in order to flush data
echo str_repeat(' ',1024*64);
sleep(1);
}
The script works fine from CLI, displaying "Fun", waiting 5 secs before displaying "<br>Mo".
For a browser the results might be a bit different because:
The browser wont start rendering right away. Getting 3 bytes of data for HTML document isn't enough to do anything, so it'll most likely wait for a few more.
Implicit IO buffering on the lib level will most likely be active until a newline is received.
To work around 1) use text/plain content type for your test; 2) needs newlines, so do an echo "Fun\n"; and echo "<br>Mo\n"; Of course you wont be using text/plain for real HTML data.
If you're using CGI/FastCGI, forget it! These don't implement flush. The Webserver might have it's own buffer.
You can disable all output buffering in PHP with following command:
ob_implicit_flush();
If the problem persists, although you explicitly set
implicit_flush = yes
in your php.ini, you might also want to set
output_buffering = off
which did the trick in my case (after pulling my hair for 4+hrs)
Check your php.ini for output_buffering.
Maybe the problem is Apache here, which also may have buffers...
Related
I'm trying to run a simple PHP script on MAMP. I'm using PHP 5.2.17 and I have compression turned off. Im trying to execute this simple script
<?php
ob_flush();
foreach(range(1,9) as $n){
echo $n."\n";
flush();
sleep(1);
}
For sme reason this is not doing what it is supposed to. Rather than sequentially echoing out the numbers, it's simply echoing them out when the loop is done. Am I missing something? is there another way to do this?
Output buffering is a mechanism for controlling how much output data
(excluding headers and cookies) PHP should keep internally before
pushing that data to the client. If your application's output exceeds
this setting, PHP will send that data in chunks of roughly the size
you specify. Turning on this setting and managing its maximum buffer
size can yield some interesting side-effects depending on your
application and web server. You may be able to send headers and
cookies after you've already sent output through print or echo. You
also may see performance benefits if your server is emitting less
packets due to buffered output versus PHP streaming the output as it
gets it. On production servers, 4096 bytes is a good setting for
performance reasons.
Note: Output buffering can also be controlled via Output Buffering Control
functions.
php.ini Possible Values:
On = Enabled and buffer is unlimited. (Use with caution)
Off = Disabled
Integer = Enables the buffer and sets its maximum size in bytes.
eg: output_buffering = Off
Note: This directive is hardcoded to Off for the CLI SAPI
http://php.net/output-buffering
A Working example if output_buffering is set to 4096
<?php
ob_start();
// Output string to overflow browser php.ini output_buffering setting.
echo str_repeat(PHP_EOL, 4097);
for ($i=0; $i<5; $i++) {
echo PHP_EOL.$i;
ob_flush();
flush();
sleep(1);
}
ob_end_flush();
?>
Indeed, it is the buffer size
PHP buffer why \r\n
This example worked for me
I have an object for tasks and on __deconstruct(), it's meant to run some of the lengthier cleanup tasks after the rest of the page has already loaded. Unfortunately, it buffers the output and won't send it until after the tasks are finished (nothing is printed in the tasks).
I've read through http://www.php.net/flush and tried all the suggestions there. Obviously I've tried disabling output_buffering in php.ini. I've disabled deflate_module, zlib compression is off, don't have mod_gzip. Calling flush() or ob_flush() has no effect, nor does enabling implicit_flush.
I'm just running XAMPP (currently apache 2.2.17, php 5.3.4) under Windows Server 2008 R2. PHP is being run as a module.
And yes, I could set up some little AJAX hack to run the task manager or even set up a scheduled task to run this specific task, but output buffering has been an issue elsewhere, too. Would just like it to be gone sometimes.
From a similar thread, someone suggested seeing what the following would do:
<?php
while (TRUE)
{
echo 'x';
flush();
sleep(1);
}
?>
As expected, the page displays nothing until the maximum execution time is reached, at which point it flushes the buffer.
This has become extremely frustrating. Anyone have any ideas what could still be causing it to buffer?
You're only sending a small amount of data. Browsers have their own buffer, which can be based on a number of bytes, by which elements have been received, or by something else.
In short, there is nothing you can do about this. The buffering is happening client-side, not server-side. You could try sending more data before your xs.
You can prove this by packet sniffing the connection between the server and the browser, with Wireshark or similar.
hmmm, interesting grabbed a snip of code I have used else where and it works as expected...
https://stackoverflow.com/a/9728519/632951
<?php
echo str_repeat('fillerbytes',20*1024/strlen('fillerbytes'));
echo '<body style="font-size:6px;font-family:arial;">';
echo str_repeat('<br>',2);
for($i=1; $i<=5000; $i++){
echo $i . ' ';
ob_flush();
flush();
usleep(2000); // 2 ms each = 10s total
}
?>
Watch my server count to 5000 http://atwebresults.com/texttest/new.php
(Doesn't work on some free hosts like freehostingeu.com.)
My flush mechanism stopped working, i'm not sure why.
I'm trying to run a simple flush example now, with no luck:
echo "before sleep";
flush();
sleep(5);
echo "after sleep";
after doing some reading, and understanding ngin x was was installed on my server lately, I requested it to be disabled for my domain. (the server admin said he disabled it for this specific domain)
also, i tried disabling gzip, added these lines to .htaccess
SetOutputFilter DEFLATE
SetEnv no-gzip dont-vary
also, tried adding these to my php file
ini_set('output_buffering','on');
ini_set('zlib.output_compression', 0);
nothing helps. its sleeping 5 seconds and then displaying all the content together.
I've been using it before, and have been using also through the output buffer (ob_start, ob_flush etc., now just trying to make the simplest example work)
"Stopped working" is a pretty high level. You should actually take a look what works or not to find out more.
This can be done by monitoring the network traffic. You will see how much of the response is already done and in which encoding it's send.
If the response is getting compressed, most compression functions need a certain number of bytes before they can compress them. So even you do a flush() to signal PHP to flush the output buffer, there still can be a place either within PHP output filtering or the server waiting for more to do the compression. So next to compression done by apache, check if your PHP configuration does compression as well and disable it.
If you don't want to monitor your network traffic, the curl command-line utility is doing a pretty well job to display what's going on as well and it might be easier to use it instead of network monitoring.
curl -Ni --raw URL
Make sure you use the -N switch which will disable buffering by curl so you see your scripts/servers output directly.
Please see the section Inspecting HTTP Compression Problems with Curl in a previous answer of mine that shows some curl commands to look into the output of a request while it's done with compression as well.
curl is able to show you eventually compressed data uncompressed and you can disable compression per request, so regardless of the server or PHP output compression settings, you can test more differentiated.
<?php
ini_set('zlib.output_handler', '');
ini_set('zlib.output_compression', 0);
ini_set('output_handler', '');
ini_set('output_buffering', false);
ini_set('implicit_flush', true);
apache_setenv( 'no-gzip', '1' );
for($i = 0; $i < 5; $i++){
echo str_repeat(chr(0), 4096); #flood apache some null bytes so it feels the packet is big enough to be sent...
echo "$i<br/>";
flush();
sleep(1);
}
?>
I wasn't sure how to title this thread, sorry.
I have a script that processes some logs and I echo a lot of debug information as the process goes. Since moving to the new server, it seems that the script hangs for 30 odd seconds, then spits out all the logging, then hangs again for 30 odd seconds and the process continues.
This is really odd behavior and I don't know where to start. Its like it isn't processing the file line by line but in blocks ...
PHP version is 5.1.6 on a CentOS running plesk. (My old CP was CPanel)
Any ideas?
EDIT: Simple example of my issue - Running this code:
for ($i=0; $i<100; $i++) {
echo "test $i";
sleep(1);
}
the script will hang for 100 seconds, then print out all the "test 1" ect. Sleep is required in my main script and on the other server just echoed the values in turn.
EDIT2: Have tried setting output_buffering = 0 and implicit_flush = On and didn't help.
You may have output_buffering On. Try to disable it first.
You can do it either in the php.ini file, in a .htaccess file if your server allows it, or use the following code at the beginning of your PHP script:
while (ob_get_level()) ob_end_clean();
Also, use flush() after each echo or print, and it should be all right!
Update:
You might also encounter other buffers that you cannot control from within PHP (web server, browser, ...), which is why you're still not seing anything. A workaround is to send some blank bytes after each print:
while (ob_get_level()) ob_end_clean();
for ($i=0; $i<100; $i++) {
echo "test $i";
echo str_repeat(' ', 256);
flush();
sleep(1);
}
However, while this example works for me on IE & Firefox, it does not work on Chrome!
I moved my files to a new server and I had a script that instantly showed output on every echo to the browser, but this isn't working on the new server. Here is my test code:
#ini_set('output_buffering', 0); #ini_set('implicit_flush', 1);
for ($i = 0; $i < ob_get_level(); $i++) ob_end_flush();
ob_implicit_flush(1);
ignore_user_abort(true); set_time_limit(0);
$max_wait_time = 30;
$begin_time = microtime(true);
$elapsed_time = 0;
while(!connection_aborted()) {
echo $i++.str_repeat(' ', 1020).'<br/>';
flush(); ob_flush();
usleep(1000000);
if($elapsed_time > $max_wait_time){ break; }
$elapsed_time++;
}
I've tried a few things which has become the above. But turning output buffering on and flushing hasn't worked for me. I have tested this on Chrome and Firefox, they both just output everything at the end.
Any ideas?
Excerpt from the flush documentation:
flush() may not be able to override
the buffering scheme of your web
server and it has no effect on any
client-side buffering in the browser.
[...]
Several servers, especially on Win32,
will still buffer the output from your
script until it terminates before
transmitting the results to the
browser.
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.
Chances are high that you changed to a different web server (or web server configuration), which buffers the output of the whole script before outputting it.
The setting you're looking for is in your PHP.ini and it's called output_buffering:
; output_buffering
; Default Value: Off
; Development Value: 4096
; Production Value: 4096
Set it to off manually and restart your webserver to make flush() actually flush something when you want it, not after 4kb of data :)
Note that ini_set doesn't always necessarily has to work for this. If you want full control, disable it in php.ini itself, or as a .htacces php_value flag
Browsers decide for themselves when to output content. So if you don't meet that threshold, they'll just wait until it is met and only then show more content to the user.
Try to add to .htaccess
php_value output_buffering Off