How do i output to the browser before the script finishes executing?
For example, the code below will output all 100 "hi" at once, how do I make it so it will output as soon as that section of code is read/processed? For example: PHPBB3 forum shows installing process step by step.
<?php
for ($i = 0; $i <= 100; $i++) {
echo "hi";
echo "<br>";
}
?>
Call ob_implicit_flush() before your loop.
Note that this is not a guarantee (web server buffers, proxy buffers and web browsers who refuse to rerender are your enemy). It MAY help to echo some linefeeds (\n) as I seem to remember that there are browsers who will not rerender until they received a complete line.
This will not work at all if you use output buffering (e.g. for compression using gzip (if the gzip modul you use uses buffering which is not uncommon) or other reasons).
Related
I'm trying to run a loop every second for 25 seconds basically.
for($i = 0; $i <= 25; $i += 1){
echo $i;
sleep(1)
}
The thing is it doesn't output until it's fully done, so after the loop continues 25 times. Is there a way to do this so it will output before each sleep? and not wait until the full loop is complete?
Thanks!
I just hashed through this same problem from a beginner perspective and came up with this bare-bones script which will do what you want.
<?PHP
ob_start();
$buffer = str_repeat(" ", 4096)."\r\n<span></span>\r\n";
for ($i=0; $i<25; $i++) {
echo $buffer.$i;
ob_flush();
flush();
sleep(1);
}
ob_end_flush();
?>
Questions that you may ask could be here (about \r\n) and here (about ob_flush()). Hope that helps you out.
What you're trying to achieve is incremental output to the browser from PHP.
Whether this is achievable can depend on your server and how you're invoking PHP.
PHP under FastCGI
You're probably a bit more likely to run into this kind of problem when PHP is running under FastCGI rather than as an Apache module, because the coupling between the server and the PHP processes is not as tightly coupled. FastCGI communication uses output buffering once the data has left the PHP processes, with the output sent to the browser only once the request is fully complete, or this buffer has filled up. On top of this, the PHP processes tend to be terminated after a certain amount of time, to avoid letting any one run for too long.
That said, a combination of ob_end_flush() (or ob_flush()) and flush() should still cause PHP to request that the downstream buffers are cleared, so this may still work. You may need to also investigate whether you need to length the time limit for PHP scripts.
PHP under mod_php
If you're using mod_php, you can write incrementally out to the browser. Use the flush() command to ensure that the PHP module will flush it instantly. If you don't have output buffering, or some Apache module such as mod_gzip, then it should go out instantly to the user's browser. What's more, you can keep your PHP script running as long as you like (with set_time_limit() in PHP), under the default configurations, though of course it will consume some memory.
You may run into trouble with some browsers which don't start rendering the page until a certain amount of a page is downloaded. Some versions of IE may wait for 1KB. I've found that Chrome can wait for more. A lot of people get around this by adding padding, such as a long comment 1 or 2 KB long at the top of the document.
Call flush will force PHP to push all of the output buffer to the client before proceeding.
for($i = 0; $i <= 25; $i += 1){
echo $i;
flush();
sleep(1);
}
EDIT:
After testing this on my lighttpd server I noticed that it buffered my outputs in blocks of 4096 characters, and I assume other browser might have similar buffering schemes. Also GZIP can prevent flush completely. Unfortunately there is no way to test that it's working due to the nature of HTTP.
Also another issue with this strategy is that it leaves that PHP proc blocked to other requests. This can cause requests to pile up.
I' am using XMLHttpRequest 2 to get chunked response through it's onprogress event and displaying it in browser. Everything seems to work fine but I have a little confusion. Consider the following code:
<?php
echo "I' am sending ";
ob_flush();
flush();
echo "content to client.";
ob_flush();
flush();
This is pretty standard PHP way of sending chunked response to client. However I was expecting to get output as two different chunks, one containing first echo's result and other containing second's. But I' am getting a single combined chunk of both echo statements. When I put sleep(1) after first flush() then everything seems to work fine.
My question is that is there some deliberate wait on webserver side to wait for some other content before sending already received chunk or is there some thread scheduling mechanism that is forcing network layer of Apache to wait for it's turn.
Edit
I forgot to mention that I have disabled webserver's output buffering which means if I flush something from PHP it will get sent to browser.
Any help is highly appreciated.
Thanks.
See: http://www.icemelon.com/tutorials/20/Output_While_Script_Still_Running.htm
You may be seeing browser output buffering here. Try adding:
for($k = 0; $k < 40000; $k++)
echo ' ';
Right before you flush in order to fill up the browser's buffer and make it spit out your output.
Wonder if there's a way for a PHP script returns and print immediately on the browser (via a web page) the result of various functions without waiting for the completion of the next.
Sample PHP code:
<? php
for ($i = 0; $i < 100; $i++) {
echo $i. ":". my_function(); / / takes a long time to run
}
?>
release:
0: value ... (the function of the cycle $i = 1 is still running)
1: value ... (the function of the cycle $i = 2 is still running)
and so on ...
you may use the flush() function to attempt to flush data back to the browser.
description from php.net:
Flushes the write buffers of PHP and whatever backend PHP is using
(CGI, a web server, etc). This attempts to push current output all the
way to the browser with a few caveats.
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.
sample code below, tested on chrome 31.0.1650.57 (linux), Safari (6.0.4) (osx):
note: whether or not to show the flushed output is up to the browser (usually depending on the amount of data in the response). for example Safari (6.0.4) wants 512 bytes of data before outputting data to the browser. You can get around this by doing something like padding 512 characters to beginning of the output.
<?php
header( 'Content-type: text/html; charset=utf-8' );
echo str_repeat(" ",512); //pad the buffer with data (in case browser needs it)
while (true){
//write go to the browser every 2 seconds.. forever
echo "go...<br/>";
ob_flush();
flush();
sleep(2);
}
?>
more info here http://us1.php.net/manual/en/function.flush.php
I have a script that runs for like 1 hour.
I have 2 webhosts, in one of them, I can see the output in realtime, (it loops a million times and echoes stuff) while on the other webhost, I have to wait until the script is finished running before I see any output at all.
How can I change the settings to show the output in realtime? I guess this is a php.ini thing.
Adding code: This code will output while executing in the first server, but not in the second server. Additional info, if i put the value of 1015 lower, the first server waits with outputting. So it seems that my first server is flushing every 1015 characters, while the second does not.
while ($a++ < 5) {
$b = 0;
while ($b++ < 1015) {
echo "H";
}
echo "<br><br>\n";
sleep(1);
}
On my second server, output buffering is off, and i tried turning on implicit_flush to no avail.
This is related to output buffering. If output buffering is turned on, the output is not sent to the client immediately but will wait until a certain amount of data buffered. This usually increases performance but will cause problem like yours.
The simple solution doesn't require changing any php.ini settings, but simply put this at the beginning of your script:
<?php
while (#ob_end_flush());
?>
This will flush and disable all output buffering at once.
(Source: http://www.php.net/manual/en/function.ob-end-flush.php#example-460)
You may also want to read the PHP manual on Output Control. The related php.ini settings are listed here.
If you want to make sure things are being sent (i.e. before a time-consuming task), call flush() at the appropriate times.
Edit:
In fact browsers may have their own buffers, especially when Content-Type is not explicitly set (the browser need to sniff the MIME-type of the file). If this is the case, you cannot control the browser's behaviour.
One way that might solve it is to explicitly set the Content-Type:
header("Content-Type: text/plain"); // if you don't need HTML
// OR
header("Content-Type: text/html");
But this is not guaranteed to work. It works on my Firefox but not Chrome.
Anyway, your final code should look like:
header("Content-Type: text/html"); // Set Content-Type
while (#ob_end_flush()); // Flush and disable output buffers
while ($a++ < 5) {
$b = 0;
while ($b++ < 1015) {
echo "H";
//flush(); // In fact because there is no significant delay, you should not flush here.
}
echo "<br><br>\n";
flush(); // Flush output
sleep(1);
}
Try calling flush periodically. If you are using output buffering, you may want to turn that off with a sequence of ob_end_flush or use ob_flush as well.
I have a php script that uses cURL and takes about 10-15 minutes to execute. What it does, it parses about 1000 pages looking for specific matches and throughout the script I have diagnostic messages echo'ed out, like "Going to the next page", "Found a match", "Error loading page" ... The way it works now (and the way that it's normal) is it executes for like 10 minutes and only then spits out all my custom messages.
I would like to be able to display those messages as they happen, not when the script is done executing. I was thinking something like AJAX would do it, but am not sure how it would work. Any tips are greatly appreciated. Thanks.
So, this is a old post but I found a solution for this. As I also have to make the same thing, output when the script is still running. Not any answer from here helped.
First of all, I am using Win32 server(production) and XAMPP as local for tests. This example is just a proof of concept and can be modified as you please.
<?php
ob_implicit_flush(true);
for($i=1; $i<=10; $i++){
echo "$i ...<br>";
for($k = 0; $k < 40000; $k++) echo ' ';
sleep(1);
}
?>
So, we open output buffer as implicit. Then we make a demo loop to count from 1 to 10 and display the values as they are been processed. Second loop will fill in the browsers buffer. And finally to check if everything is working well we make a sleep for 1 second. Otherwise the script will run too fast and we could not know if we achieved the goal.
Hope this helps !
You could create a staging table.
The PHP script could, instead of echo'ing the message, store them into a database table (possibly memory table for performance).
You could then periodically poll a seperate PHP script using ajax, which would query the table, and return any new messages to the client.
Use flush to immediately send output to the browser, by flushing the output buffer.
echo "foo";
flush();
echo "bar";
flush();
Actually you're looking for something like flush and ob_flush, however bear in mind that there are a lot of factors that can prevent your output from being flush'd as it happens.
From the flush documentation you'll get:
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.
I'm using the #ob_flush() after every echo. In this example PHP_EOL creates a new line after $string
function output($string){
echo $string.PHP_EOL;
#ob_flush();
}
Basically, have your script write HTML output to a temporary log file. Then use ajax to periodically update the end-user's browser with the temporary log file. jQuery will make quick work of this.
Ajax is the only guaranteed way to get it to work on all browsers. Here is a quote from PHP's flush page.
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.
Sounds to be like you have output buffering turned on.
Calling ob_end_flush() will print what's currently in the buffer, and turn off the buffer for the rest of the script execution.
You can use the flush() function to send all the content of the buffer to the client. http://php.net/manual/fr/function.flush.php
You could use both flush and ob_flush, reminding to set the content type header:
<?php
header( 'Content-type: text/html; charset=utf-8' );
for( $i = 0 ; $i < 10 ; $i++ ){
echo $i . '<br>';
flush();
ob_flush();
sleep(1);
}
Source: dermeister note in php.net ob_flush page.
Tested on Firefox 42.0 and Chrome 46.0