I have foreach functions that print students names
$names = array("Alex","Brad","Tom");
foreach($names as $name) {
echo "$name <br />";
sleep(3);
}
How can i print each name, each 3 seconds?
After "echo $name" i need some timer to stop the loop and wait for 3 seconds.
sleep() functions doesn't work here. What else i can do?
You can not do this server side (reliably). This is because there is just too much possibility of your traffic being held or buffered on the way: by the webserver, by proxies along the way, by your browser, etc. It would however probably work on CLI.
So I would definitely do it client-side, without sacrificing security (if needed).
If this is only for "cosmetic" purposes, you can create an AJAX method which will return the array of names, and then have Javascript output them with its timers.
Or, you could have AJAX call the PHP script using timers, and PHP will return only one name. It can save the current timestamp in the DB or in a Session variable, and don't return a new name until some time has passed.
try using flush function
ob_start();
$names = array("Alex","Brad","Tom");
foreach($names as $name) {
echo "$name <br />";
ob_flush();
flush();
sleep(10);
}
If you need to do this in a web page you need to flush the output or disable output buffering to get that work. Some references:
http://php.net/manual/en/book.outcontrol.php
http://php.net/manual/en/function.flush.php
In php CLI that code will work.
You can do this with javascript, ajax
or with flush() function
<?php
$names = array("Alex","Brad","Tom");
foreach($names as $name) {
echo "$name <br />";
flush();
sleep(3);
}
working demo
You can write flush(); after echo
Related
Considering a simple script
<?php
echo "hi";
foreach ($_GET['arr'] as $a)
{
echo $a ."<br>";
}
echo "<p>Masel tov</p>";
foreach ($_GET['arr2'] as $a)
{
echo $a ."<br>";
}
i expect the script to echo continuously. Instead the script does echo all-at-once when finished. Even the first "hi" gets echoed after 1 minute when the script finishes.
Is there a setting to prevent this from happen or why is that so?
Depending on your config, output is cached until completion. You can force a flush with either ob_flush() or flush(). Sadly many modern browser also dont update until page load is complete, no matter how often you flush.
flush http://php.net/manual/en/function.flush.php
ob_flush http://php.net/manual/en/function.ob-flush.php
Configuration Settings for PHP's output buffering.
http://www.php.net/manual/en/outcontrol.configuration.php
There is a function ob_implicit_flush that can be used to enable/disable automatic flushing after each output call. But have a look at the comments on the PHP manual before using it.
Check with this
if (ob_get_level() == 0)
{
ob_start();
}
for ($i = 1; $i<=10; $i++){
echo "<br> Task {$i} processing ";
ob_flush();
flush();
sleep(1);
}
echo "<br /> All tasks finished";
ob_end_flush();
If you want displaying the items one by one and keep clean code that works with every server setup, you might consider using ajax. I don't like flushing the buffer unless there are no other options to accomplish the task.
If your project isn't a webproject you might consider running your code in the php console (command line) to receive immediate output.
PHP sends, as you noticed, all data at once (the moment the script has finished) - you search for something like this http://de1.php.net/manual/de/function.ob-get-contents.php :
<?php
ob_start();
echo "Hello ";
$out1 = ob_get_contents();
echo "World";
$out2 = ob_get_contents();
ob_end_clean();
var_dump($out1, $out2);
?>
I have a simple php page, that is doing some operations for an mysql result set:
$i = $d = $n = 0;
$sql="SELECT record, field1,field2,field3 from table where condition='xxxx'" ;
result=$db->send_sql($sql);
while($row=mysql_fetch_array($result, MYSQL_ASSOC))
{
//about 500 results
//now performing some actions on these results via function call
$i++;
if($row['field1'] == 'xxx')
{
$d++;
echo $row['record'].": ";
echo do_something(field1,field2); //function will echo some text
echo "<br>";
}
else
{
$n++;
echo $row['record'].": nothing to do <br>";
}
}
echo "<hr>Total: ".$i." - Updates: ".$d." - Nothing done: ".$n;
All works, as it should but the Output/echos are only shown, once all operations have been done and the while statement has been worked through.
It might be a silly question, but is there a way to show the "echos/output" "on the fly" - so the user get's the "something is happening" experience?
echo sends the output toward the user immediately, but that output might be held up by a couple of layers in between. If you want the feel you describe, use AJAX. Otherwise, you can try some of these approaches:
Turn output buffering off
flush() immediately after sending your HTML head element
then flush() periodically, with some str_repeat() to kickstart/prevent timeouts
See also this and this conversation on performance/best practices and this conversation on output buffering.
PHP is run on the server and displays output to the client when it is finished. I think you will need Javascript to do this, but I could be wrong.
You can try to use flush() function to send data to browser after each loop execution.
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 script that checks the status of a few hundred webpages. However, the script takes about 2 minutes to load, and the screen is blank until the script has finished running. Then all the data is outputted at once.
I want to output data while the script is still running. Here's part of my script:
foreach ($urls as $url){
$headers = get_headers($url,true);
$status = $headers[0];
list($protocol, $code, $message) = explode(' ',$status,3);
echo '<br>'.$url.'<br>'.$code.'<br>';
}
http://php.net/manual/en/function.flush.php contains the answer you seek.
Be aware this may negatively hit your performance, but it sounds like you're more interested in seeing it's progress. :-)
This is a common function which I use throughout a lot of my scripts to see progress.
function flush_buffers() {
ob_end_flush();
ob_flush();
flush();
ob_start();
}
I can't remember the original source of this function, probably from php.net somewhere!
Hope it helps!
One thing I have noticed with php, is that nothing is output to the screen until the script has stopped working. For the project I am working on I feed in a list of over 100 items and it performs a HTTP request for each item and when finished, shows a page with the status of each item, success failure etc.
What I want to know is if there is a way to output the results of each 'foreach' loop as they happen? So the user watching the screen sees the magic happening one line at a time or after say 5 lines.
I have only ever seen this done with Ajax type requests, is that what I should be looking to do instead maybe? Can anyone point me to a php function that does this or is it not possible?
It may be better to store all script output in a buffer then flush the buffer when required.
For example:
<?php
if (ob_get_level() == 0) ob_start();
$test = Array('one','two','three','four');
foreach ($test as $key=>$val)
{
echo $test;
ob_flush();
flush();
}
ob_end_flush();
?>
Make sure you have mod_gzip disabled!
flush() should do it, or you can look at all the output buffering functions
Use the flush() command
I use
flush(); #ob_flush();
after the output.