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.
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 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
I have some PHP code that is receiving and processing large images. I'd like to echo out some JavaScript at certain points while the image is being processed to update the DOM with jQuery. Here is some sample code, but it isn't working. It just waits the entire 5 seconds and then makes the alerts happen back to back. I want it to do the first alert immediately and then next alert after 5 seconds.
ob_start();
echo '<script type="text/javascript">alert(\'1...\');</script>';
ob_flush();
sleep(5);
ob_start();
echo '<script type="text/javascript">alert(\'2...\');</script>';
ob_flush();
Can anyone help?
Most browsers buffer content until a certain size is reached. Try making your script blocks longer by padding them with something.
Also: You should call flush, not just ob_flush, and make sure zlib compression is turned off.
I have some PHP code that is receiving and processing large images. I'd like to echo out some JavaScript at certain points while the image is being processed to update the DOM with jQuery.
This may be out-of-scope for what you have to get done, but I'd use AJAX for this. You can certainly get what you want to occur, but the approach isn't good in the long term.
Instead of submitting the whole page and waiting for it to come back at a crawl, use an AJAX request to upload the image and get the result. Then a timer on the client can issue separate AJAX "how far done are you?" requests. The two PHP instances would communicate via setting a "done" flag on the job entry in a database, etc.
While it makes the client-side stuff a bit more complex, it is much easier to handle user interaction (such as allowing the user to cancel a long-running job) and makes your PHP code a lot more tightly-focused.
Adding this to the top of the script will work:
for ($i = 0; $i < ob_get_level(); $i++) { ob_end_flush(); }
ob_implicit_flush(1);
As far as I know, ob_implicit_flush(1) forces a flush on every output statement. So the other ob_start() and ob_flush() calls wouldn't be necessary. I don't know if that works for you.
<?php
for ($i = 0; $i < ob_get_level(); $i++) { ob_end_flush(); }
ob_implicit_flush(1);
echo '<script type="text/javascript">alert(\'1...\');</script>';
sleep(5);
echo '<script type="text/javascript">alert(\'2...\');</script>';
?>
Following is working in FF4:
<?php
echo '<script type="text/javascript">alert("1");</script>';
flush();
sleep(5);
echo '<script type="text/javascript">alert("2");</script>';
?>
I implemented a chat "server" with something like that long ago. It was working.
This ob_* stuff isn't helpful for this.
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.
I've written a script to geocode some points which has a structure basically like this:
//get an unupdated record
$arr_record;
while(count($arr_record) > 0)
{
//strings are derived from $arr_record
geocode($string1);
geocode($string2);
geocode($string3);
array_pop($arr_record);
}
function geocode($string) {
//if successful
update($coords)
}
function update($coords) {
//update the database
header('Location:http://localhost/thisfile.php')
}
The trouble is that even when the geocode is successful and the database is updated, and teh header resent, the script still goes back into the while loop without reloading the page and starting again on a new record.
Is this normal behaviour for PHP? How do I avoid it behaving like this?
After header() use die(); to terminate the script and output.
How do I avoid it behaving like this?
Put exit() after header().
another effective way is not to send headers directly in a loop. which is not proper (i couldn't find in php.net manual but i remember it was discussed before in phpusenet).
it may act unexpected in different php versions. & different apache ver. installations.
php as cgi will make problems too.
you can assign it to return as string then you can send header later...
function update($coords) {
//update the database
if(statement to understand update is ok){
return 'Location:http://localhost/thisfile.php';
} else {
return false;
}
}
if($updateresult=update($cords)!=false){ header($updateresult); }
but if i were you... i would try to work ob_start() ob_get_contents() ob_end()
because those are the excellent way to control what will be sent to browser. normal mimetypes or headers... whatever. it's better way while working with headers & html output at the same time.
ob_start(); /* output will be captured now */
echo time(); /* echo test */
?>
print something more...
<?php /* tag test */
/* do some stuff here that makes output. */
$content=ob_get_contents();
ob_end_clean();
/* now everything as output with echo, print or phptags.
are now stored into $content variable
then you can echo it to browser later
*/
echo "This text will be printed before the previous code";
echo $content;