This is purely for learning more about output buffering and nothing more. What I wish to do is echo a string to the browser, sleep 10 seconds, and then echo something else. Normally the browser would wait the full 10 seconds and then post the whole result, how I would I stop that? An example:
ob_start();
echo "one";
sleep(10);
echo "two";
faileN's answer is correct in theory. Without the ob_flush() the data would stay in PHP's buffer and not arrive at the browser until the buffer is implicitly flushed at the end of the request.
The reason why it still doesn't work is because the browsers also contain buffers. The data is now sent out correctly, but the browser waits after getting "one" before it actually kicks off rendering. Otherwise, with slow connections, page rendering would be really, really slow.
The workaround (to illustrate that it's working correctly) is, of course, to send a lot of data at once (maybe some huge html comment or something) or to use a tool like curl on the command line.
If you want to use this sending/sleeping cycle for some status update UI on the client, you'd have to find another way (like long-polling and AJAX)
ob_start();
echo "one";
ob_flush();
sleep(10);
ob_start();
echo "two";
Is that what you mean?
If I understand correctly, you are trying to print part of the response on screen, wait 10 seconds and output the rest, all this when the page is loading. This would require some client side scripting for that as PHP will output the entire response at the end.
I think a combination of ob_flush and flush might work, but buffering is not handled the same on every browser (such as IE).
I use the JavaScript's setTimeOut() function for this. It works fine.
Additionally, you can use the <noscript> tag for browsers where JavaScript is disabled.
$txt = setPageHeader(); // a PHP function that returns a new DOCTYPE
// plus <html><head>(...)</head>,
// plus an opening <body> tag
echo 'All things were completed. You should be redirected in about 3 seconds';
$txt .= '<script type="text/javascript">';
$txt = $txt.'function Rediriger() {document.location.replace(\'http://yoursite.com/yourpage.php?anticaching='.rand().'\');}';
$txt .= 'setTimeout (\'Rediriger()\', \'3000\')';
$txt .= '</script>';
$txt .= '<noscript>Javascript is disabled in your browser. Click here for being redirected.</noscript>';
$txt .= '</body></html>';
echo ($txt);
With ob_flush() - but that will clear the buffer contents. You can't inject a delay into a buffer, it just doesn't work like that.
You either output the entire buffer at once, or hold on to the entire buffer for later use.
Can't because browser waiting for full version of document because what browser engine parsing half of XHTML page and after this (how to render half of XML?) reading other part.
You must think about send header before to inform browser as binary data was sanded then browser get you data after recv and propably get out this data on screen immediate.
I miss understand this question because i never think about inject to string buffer 10s sleep.
Related
I understand how sleep works, But it works before something happens. Say for example I have a few echos and mail and some other things. Then have a sleep, then a redirect. Well, it looks like the sleep goes first, then everything just spam at once and cause server cpu increase. Is there something that is similar to sleep, that will not act after things have not been executed?
for example
echo 'Hey';
sleep(3);
echo 'My next text after 3 seconds is up';
well, with this, This does not work, and it does the same thing using C#.
When this happens, the page will not respond for 3 seconds, then both messages "Hey" & "My next text after 3 seconds is up" will show all at once. Is im using this for the wrong thing? Is there something else I should use?
Since I have never used sleep, and I seen alot of people use this for the same thing and it works, but in my case, it does not really works the way I thought it would.
PHP not C#
You can do it via flushing the output at points. You can also use ob_implicit_flush for this purpose which would ensure that output will be flushed at each output call without explicit calls for flush.
header( 'Content-type: text/html; charset=utf-8' );
echo 'Hey';
for($i=0;$i<60;$i++){
echo "<br />My next text after $i seconds is up";
ob_flush();
flush();
sleep(1);
}
Note that php docs for ob_flush suggests that you should try putting content-type header when things are not working. But above code worked without that also.
It runs exactly as it was programmed, the thing is, the output is being buffered. You have to disable buffering, and force a flush() to make sure its sent before the sleep().
while (# ob_end_flush()); // closes all existing buffers if any
echo 'Hey';
flush(); // make sure it was flushed to the client
sleep(3);
...
And still it might not work in all cases, because theres another buffer, and this one you cannot control: the browser. Some browsers will not render any HTML unless it has received a certain minimum amount of data.
Good day!
I am having some issues with getting the echo statement to output before the execution of the exec()
<?
if (isset($_POST['ipaddress'])) {
$escaped_command = escapeshellcmd($_POST['ipaddress']);
if(filter_var($escaped_command, FILTER_VALIDATE_IP)) {
echo "Gleaning ARP information, please wait..";
$command = exec('sudo /sbin/getarp.exp');
The echo statement is being outputted after the execution of the $command. The execution time can be anywhere from 15-30 seconds depending on how large the ARP table on the remote router is. Is there an order of operations that I am not aware of? It appears that all the statements within the if statement are executed in parallel and not by line by line as I had assumed.
I would rather not a solution be provided, but some documentational links that would lead me to finding a solution. I have searched what I could, but was not able to find a viable solution.
Any help would be appreciated.
Thanks.
This is happening because the script will run in its entirety before any result/output is sent to the browser.
In PHP there is a concept of "output buffering".
Whenever you output something (e.g. using echo, print, etc.) the text is thrown into a buffer. This buffer is only sent at certain times (at the end of the request, for instance, or when the buffer is full).
In order to empty the buffer (to "flush" it) you need to do it manually. The flush() function will do this. Sometimes you also need to call ob_flush() (this is if you have opened custom output buffers yourself). It is generally a good idea to just call both functions and be done with it:
echo 'Wait a few seconds...';
flush(); ob_flush();
sleep(3);
echo ' aaand we are done!';
See Output Buffering Control for more information on output buffering in PHP.
This is probably an issue with the output buffer. PHP buffers output and writes it to the browser in chunks. Try adding a call to ob_flush() between the echo and the exec(); this will force PHP to write the current contents of the buffer to the browser.
By default, php does not send any of the output until the php script is done running completely. There is a solution. However, I hear it is a little browser dependent. I would test it on different systems and browsers to see if it is working:
ob_implicit_flush (true)
Put that before any of your echo/print commands and that should allow anything printed to show right up on the browser.
A more universal approach would be to integrate your page with asynchronous javascript. A process commonly referred to as "AJAX". It is a little more difficult because it requires the use of many interacting scripts, some client-side and some server-side. However, AJAX is the defacto way to do thing like this on the web.
I'm trying to figure out why this loop doesn't return anything to the browser:
while(1) {
echo "hello";
flush();
sleep(1);
}
I'm expecting it to return "hello" to the browser every second... am I wrong? Right now the page just seems to hang.
PHP only outputs after execution has finished. so all you are doing where is generating a new hello every milisecond, and since you never exit the loop, you never see the output.
To correct my answer and make you to understand better, and for the AJAX lovers...
you need and extra flush there.. the 'ob_' one:
<?php
while( 1 ):
echo "hello";
ob_flush( ); flush();
sleep( 1 );
endwhile;
This is the 'trick' for everyone who need to know ;)
The browser won't display anything until the entire page is received. PHP is not capable of what you're trying to accomplish.
In Javascript, this is pretty simple.
<script>
window.setInterval(function(){document.innerHTML += "<br> Hello"}, 1000)
</script>
You should realise that PHP is a scripting language in the sense that it returns the output only after completing the script. EDIT: Or after output buffers are filled, thanks #Marc B.
Regardless I would say it is wiser to use JS for this or if you really need your server, use AJAX requests.
Perhaps you should consider using Javascript? That will allow you to add content every second (do keep in mind that JS is run at the clientside though, so you might not want to make your operations all that expansive then.)
Alternatively you could consider using AJAX requests through for instance JQuery, but that might be outside the scope of this question...
Maybe is not to late to answer but if you want to flush every second here I give you a sample:
<?php
echo "Flushing every second ...\n";
flush( );
$seconds = array (0,1,2,3,4,5,6,7,8,9);
foreach ($seconds as $second):
echo $second . "\n";
sleep( 1 );
#ob_flush( ); flush( );
endforeach;
echo 'I flashed 10 second :P';
Valentin gave you the right answer (upvote him/accept his answer!), but didn't explain why. Here's the explanation:
Output buffering
PHP doesn't output to the browser immediately, it waits to have some amount of content to send to the browser (probably it sends in chunks of 1024, 2048 or 4096 bytes), or when the execution ends. Calling flush() makes PHP send the data, but there is more than one layer of buffering. One is the internal buffering (what I've just commented), but you can add more layers of buffering. Suppose this code:
<?php
echo "hi";
setcookie('mycookie', 'somevalue');
?>
The setcookie() function sends an http header to the browser, but it can't do it because in HTTP, the server (or the client, it is the same both ways) must send first all headers, a blank line, and then the contents. As you see, you are outputting some content (hi) before the header, so it fails (because the internal buffering follows the same order of execution).
You can add another layer of output buffering, using the php functions ob_*(). With ob buffering it only buffers content output, not HTTP headers. And you can use them to get the output of functions that directly output to the browser, like var_dump(). Also, you can nest layers of ob:
<?php
// start first level of output buffering
ob_start();
echo "nesting at level ", ob_get_level(), "<br />\n"; // prints level 1
echo "hi<br />";
ob_start();
echo "nesting at level ", ob_get_level(), "<br />\n"; // prints level 2
var_dump($_POST);
$post_dump = ob_get_clean();
// this will print level 1, because ob_get_clean has finished one level.
echo "nesting at level ", ob_get_level(), "<br />\n";
echo "The output of var_dump(\$_POST) is $post_dump<br />\n";
// in spite of being inside a layer of output_buffering, this will work
setcookie('mycookie', 'somevalue');
// flush the current buffer and delete it (will be done automatically at the
// end of the script if not called explicitly)
ob_end_flush();
Probably your PHP server has output_buffering enabled by default. See the configuration variables to turn it off/on by default.
Ok, Carlos criticize me because I didn't explained my answer but also his answer is to vague... with cookies, layers.. POST, ob_levels... :OO to much info with no real point about the real question of the user but I will tell you why your code is not working. Because you have set in the php.ini the output buffering something like:
output_buffering = On
or
output_buffering = 4096 (default setting on most distributions)
Thats why you need the extra 'ob_flush( )', to get rid of any garbage output..
so... To make your code work you have 2 options:
1). set output_buffering = 0 or Off (if you have access to the php.ini)
2). ob_flush many times as layers of buffering you have
If you don't know how many layers you have you can do something like:
while (#ob_end_clean( ));
and clean every garbage you can have, and then your code will work just fine..
Complete snipp:
<?php
while (#ob_end_clean( ));
while(1) {
echo "hello";
flush();
sleep(1);
}
Cya..
Adding to all the other answers,
To do asynchronous Server push to clients you'll need to use WebSockets. It's a vast subject and not fully standardized, but there are certainly ways of doing it. If you are interested search for PHP Websockets.
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
Do I need to pass back any HTTP headers to tell the browser that my server won't be immediately closing the connection and to display as the HTML is received? Is there anything necessary to get the HTML to incrementally display like flush()?
This technique used to be used for things like chat, but I'm thinking about using it for a COMET type application.
Long polling is a common technique to do something like this; to briefly summarise, it works as follows:
The client sends an XHR to the server.
If there is data ready, the server returns this immediately.
If not, the server keeps the connection open until data does become available, then it returns this.
If the request times-out, go back to 1).
The page running on the client receives this data, and does what it does with it.
Go back to 1)
This is how Facebook implements its chat feature.
This article also clears up some of the misconceptions of long-polling, and details some of the benefits of doing so.
The client will close the connection when it does not receive any data for a certain time. This timeout cannot be influenced by HTTP headers. It is client-specific and usually set to 120 seconds IIRC.
So all you have to do is send small amounts of data regularly to avoid hitting the timeout.
I think a more robust solution is a page with a Javascript timer that polls the server for new data. Keeping the response open is not something the HTTP protocol was designed for.
I would just echo / print the HTML as I went. There are a few different ways you can have the script pause before sending the next bit. You shouldn't need to do anything with headers or any special code to tell the browser to wait. As long as your script is still running it will render the HTML it receives from the script.
echo "<HTML><HEAD.../HEAD><BODY>";
while (running)
{
echo "printing html... </br>";
}
echo "</BODY></HTML>"; //all done
Try forever frame (like in gmail)
All of these technics are just hacks, http isn't designed to do this.
at the end of your script, use something like this (assuming you had output buffering on by putting ob_start() at the top of your page
<?php
set_time_limit(0); // Stop PHP from closing script after 30 seconds
ob_start();
echo str_pad('', 1024 * 1024, 'x'); // Dummy 1 megabyte string
$buffer = ob_get_clean();
while (isset($buffer[0])) {
$send = substr($buffer, 0, 1024 * 30); // Get 30kbs bytes from buffer :D
$buffer = substr($buffer, 1024 * 30); // Shorten buffer
echo $send; // Send buffer
echo '<br />'; // forces browser to reload contents some how :P
ob_flush(); // Flush output to browser
flush();
sleep(1); // Sleep for 1 second
}
?>
That script basically outputs 1 megabyte of text at 30kbs (simulated) no matter how fast the user and server connection is.
Depending on what you are doing, you could just echo as your script proceeds, this will then send the html to the browser as it is echoed.
I would suggest you investigate implementing such functionality using Ajax, rather than plain old HTML. This allows you much more flexibility in terms of architectural design and user interface