How do echo out progress on MAMP using flush() - php

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

Related

PHP Header Redirect Working Despite Previous Earlier HTML and echo Output?

Does anyone know why this script succeeds for me on each server I've tried? I am successfully redirected to Google despite earlier output before the header call.
According to the PHP documentation, it is stated that adding headers after output fails and returns a warning. However, I am seeing inconsistent behavior on my web servers. I've been using similar approaches to accomplish some things, and it has worked just fine except for one case where it randomly stopped working.
<?php
echo "lol";
?>
<html>
<?php
header("Location: http://www.google.com");
exit();
?>
So, what's the deal? Do recent versions of PHP now allow this?
My php version is PHP 5.5.9-1ubuntu4.14 on Ubuntu 14.04 x64
Output_buffering was enabled on my server which allows for some of this as explained by the setting:
; 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.
; Possible Values:
; On = Enabled and buffer is unlimited. (Use with caution)
; Off = Disabled
; Integer = Enables the buffer and sets its maximum size in bytes.
; Note: This directive is hardcoded to Off for the CLI SAPI
; Default Value: Off
; Development Value: 4096
; Production Value: 4096
; http://php.net/output-buffering
output_buffering = 4096
Ugh, php.

What are the "serious performance implications" of implicit_flush?

My site's admin section has a bunch of very slow report-generating scripts that echo output line by line as it is generated. To have this output flushed immediately to the browser, instead of the user having to wait for minutes before they see any response, we have output_buffering disabled and we call ob_implicit_flush at the beginning of such scripts.
For convenience, I was considering just turning on the implicit_flush setting in php.ini instead of adding ob_implicit_flush() calls to every script that would benefit from it.
However, the documentation contains the following scary but unexplained remark:
implicit_flush
...
When using PHP within an web environment, turning this option on has serious performance implications and is generally recommended for debugging purposes only.
What are these "serious performance implications", and do they justify the manual's recommendation?
It may or may not be what the manual is hinting at, but one context in which either turning on implicit_flush or calling ob_implicit_flush() has serious performance implications is when using PHP with Apache through mod_php with mod_deflate enabled.
In this context, flush() calls are able to push output all the way through mod_deflate to the browser. If you have any scripts that echo large amounts of data in small chunks, flushing every chunk will cripple mod_deflate's ability to compress your output, quite possibly resulting in a 'compressed' form that is larger than the original content.
As an extreme example, consider this simple script which echoes out a million random numbers:
<?php
header('Content-Type: text/plain');
for ($i=0; $i < 1000000; $i++) {
echo rand();
echo "\n";
}
?>
With output_buffering off and implicit_flush also off (for now), let's hit this in Chrome with the dev tools open:
Note the Size/Content column; the decompressed output is 10.0MB in size, but thanks to mod_deflate's gzip compression, the entire response was compressed down to 4.8MB, roughly halving it in size.
Now hitting exactly the same script with implicit_flush set to On:
Once again, the 'decompressed' output is 10.0MB in size. This time, though, the size of the HTTP response was 28.6MB - mod_deflate's 'compression' has actually trebled the size of the response.
This, for me, is more than enough reason to heed the PHP manual's advice of leaving the implicit_flush config option off, and only using ob_implicit_flush() (or manual flush() calls) in contexts where doing so actually serves a purpose.

PHP flush the output to browser

I work on a PHP project and I use flush().
I did a lot of search and found that PHP sends long outputs of scripts to the browser in chunk parts and does not send all the huge data when the script terminates.
I want to know the size of this data, I mean how many bytes the output must be for PHP to send them to browser.
It's not only PHP that chunks the data; it's actually the job of Apache (or Tomcat etc) to do this. That's why the default is to turn off the "chunking" in PHP and leave it to Apache. Even if you force a flush from PHP, it still can get trapped by Apache. From the manual:
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. It also doesn't affect PHP's userspace output buffering
mechanism. This means you will have to call both ob_flush() and
flush() to flush the ob output buffers if you are using those.
There's a Wikipedia article on transfer encoding / chunking: http://en.wikipedia.org/wiki/Chunked_transfer_encoding
Apache gets more complicated with GZIP or deflate encoding; you'll need to hit an apache server as to how you chan configure it.
i think you are wrong
see this code
echo str_repeat(' ',1024);
for($i=0;$i<10;$i++){
echo $i;
flush();
sleep(1);
if you run it see that every 1 byte sent to browser and print
//the str_repeat is for browser buffer for showing data and nothing else

How to correctly show output at every echo on all browsers?

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

PHP flushing output as soon as you call echo

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...

Categories