I'm developing a long running php script that compiles scraped information from multiple sources, organizes them, and caches them in a database.
As this script has a very high runtime, I'd like to print out runtime status reports in order to track the progress.
for ($i = 1; $i<= 10; $i++) {
echo "Starting iteration #$i\n";
set_time_limit(40);
echo "Time Limit set, starting 10 second sleep.\n";
sleep(10);
echo "Finishing iteration #$i\n\n";
}
echo "Iterations Finished.";
would output:
Starting iteration #1
Time Limit set, starting 10 second sleep
then wait 10 seconds and output:
Finishing iteration #1
Starting iteration #2
Time Limit set, starting 10 second sleep
then right before the php finishes parsing, it will output:
Iterations Finished.
What is the best way to achieve this?
If you are running PHP from the CLI you can output directly to stdout, without having to wait for the script
to end, using :
$handle = fopen('php://stdout', 'r');
fwrite($handle, $output);
If run from CGI, which would be really bad for a script like this, you would have to change how the buffer acts with flush();
Try writing the runtime status reports to a file, then viewing live updates of the file using ajax, per this question: Live feed of an updating file
Related
I am creating simple script to test that I can echo inside my while loop before it gets 60 seconds,but the problem is it will not echo inside my loop.I don't know if it is really executed inside my while loop. Then my browser will crashed.
$timelimit = 60; //seconds
set_time_limit($timelimit);
$start_time = time(); //set startup time;
while(((time() - $start_time) < $timelimit) || !$timelimit){
echo "executing..<br/>";
}
Thank you in advance.
This is a very tight loop. It will run very fast and will create a very large output, which will eventually kill the browser (it will have hundreds of thousands of lines). You may add some delay to your loop:
while(((time() - $start_time) < $timelimit) || !$timelimit){
sleep(1); // pause for 1 second
echo "executing..<br/>";
}
In this case the output will be only 60 lines, and the browser should render it after a minute of waiting.
CPU execution is very first (approximately 10^-9s per execution). Your looping time is 60 seconds. So consider how many (may be 300915626 executions) executions will occur. During this time if you want to print something your browser will be killed.
If you're expecting to see the output as the script generates it, then you'll want to add a flush(); after your echo. However, if I recall correctly, php will still wait to send the output until it has a certain number of bytes (1024 maybe?)
I am using php, I see while() loop in php. I want to ask something can we use
while() loop as mysql_unbuffered_query().
This code make good understanding.
<?php
echo 'While Loop is going to start';
$i = 0;
while($i <= 1000){
echo 'Now number is '.$i;
$i++;
}
echo 'Continue to running script';
?>
What happens when we run this code first of all this code read while loop is going to start
then read the while loop and create the statement to run Now number is 0.....1000
then read Continue to running script And when the code is finished it print out whole data.But I did not want this.
What I want.
First script read the while Loop is going to start and print out then read while loop and
print out Now number is 0 then go Continue to running script and print out But the
back end of script while loop still working, My mean both while loop and continue script working at once.
This give you more understanding.
OUTPUT(First time when script running is start)
1 - While Loop is going to start
2 - Now number is 0
3 - Continue to running script
OUTPUT(Script running is continue)
1 - While Loop is going to start
2 - Now number is 0
3 - Now number is 1
. - ...............
1000 - Now number is 1000
1001 - Continue to running script
Might be this is impossible.If yes how I can do that.
But maybe this is possible like mysql_unbuffered_query().
Like when while loop complete one cycle it print out the number and then other one and so on to complete.
OUTPUT(First time when while loop complete one cycle)
1 - While Loop is going to start
2 - Now number is 0
OUTPUT(while loop complete second cycle)
1 - While Loop is going to start
2 - Now number is 0
3 - Now number is 1
If this is possible, Please guide me how can I do that.
Thanks..............
If you are running this script from the command line, output buffering is always off, and implicit flush is always on (according to http://us3.php.net/manual/en/outcontrol.configuration.php ). Because of this, I suspect you are running this PHP within a web server.
There are several PHP INI values which affect buffering, so you may wish to turn off these features:
<?php
ini_set('zlib.output_compression', 'off');
ini_set('implicit_flush', 'on');
ini_set('output_buffering', 'off');
echo "While Loop is going to start.\n";
$i = 0;
while($i <= 10){
echo "Now number is ".$i."\n<br>\n";
$i++;
sleep(1);
}
echo "\n<br>Finished running script\n\n";
?>
Even after all that, it's possible that PHP is behaving exactly as you want, but your web server is buffering the output. This thread may be of interest: php flush not working
If you are using apache, you can add a line to an .htaccess file to turn off gzip compression (which automatically buffers until there's enough data to compress and send)
I found this page (http://www.bluehostforum.com/showthread.php?18996-Turning-off-Gzip) which describes the process, but it basically says to add
SetEnv no-gzip dont-vary
to your .htaccess file.
Can you confirm that the script I posted above works as you'd expect in your command line environment or not?
Also, if you are working within a web server, please post which web server you're using (IIS/apache/etc)
You need threads or processes. This is a good thread: Does PHP have threading?
My favorite answer there is https://stackoverflow.com/a/14201579/650405
Forcing output to the browser works with the following calls in this order
ob_flush();
flush();
It, however, will not background any processing going on.
I just want to print a counting from 1 to 10 at an interval of 10 sec between each integer.
eg.
$i=10; //Time delay
for($j=1;$j<11;$j++)
{
echo $j;
//do something to delay the execution by $i seconds
}
I have tried everything including flush(), ob_flush(), ob_implicit_flush() but all i get is a frozen screen untill the whole time is executed.
http://php.net/manual/en/function.sleep.php
The sleep function will interrupt execution of your script.
But have you considered using Javascript for something like this? Your script may reach maximum execution time, and will be hogging resources on the server. Use the client's resources instead!
What you want is much more javascript-related than PHP. Because PHP is serverside it is not designed to do these kind of operations. You COULD get it to work, but it would not be very pretty.
In my logic; counting from 1 to 10 should not involve the server at all. You can do this directly in the browser, hence use javascript.
you want to print the countdown while your php script is running?
if yes, then try that non-recommended fragment:
ob_start();
for($i=0;$i<10;$i++) {
echo str_repeat(" ",10000);
echo 'printing...<br />';
ob_flush();
flush();
sleep(1);
}
you see, the strange line:
echo str_repeat(" ",10000);
it seems that browsers needs some "data" before deciding to really flush your data.
Use javascript for real time counters.
Use jQuery. On $(document).ready add a delay of 10 seconds to show a specific div which would contain the info to appear after 10 seconds.
For ready - http://api.jquery.com/ready/
For delay - http://api.jquery.com/delay/
Yes, use Javascript as it's not possible to accomplish this task with PHP using HTTP because of output buffering.
I need a fix for this.here is just part of my code
<?php
$number = 30;
while($number > 0) {
$number--;
sleep(30);
print "$number . Posted<br>";
}
?>
The loop process in the loop is actually much bigger, i just put the important stuff.
Anyways as you can see it should print
30 posted
(wait 30 seconds)
29 Posted
(wait 30 seconds)
28 Posted
(wait 30 seconds)
But instead it waits till the loop is over, then just prints it all at once. Is there a fix for this? I was thinking an ajax method, but I dont know of any.
Nice that everyone explained why.
This is because by default PHP will process everything before it 'flushed' anything out to the browser. By just printing each line, it's storing that information in the buffer which will all be printed simultaneously once PHP is finished executing.
If you want PHP to flush that content to the browser immediately after the line, you need to call flush() after each one, then it will output the text one line at a time after each one is called.
Call flush() after printing.
You need to use flush()
An example of a loop with flush() is
<?php
ob_start();
for ($i = 0; $i < 10; $i++)
{
echo "<div>" . time() . ": Iteration $i</div>";
sleep(1);
ob_flush();
flush();
}
ob_end_flush();
?>
You should not flush often because you force php to process messages and this will increase the time of execution.
You might put \n in echo or print to flush the buffer.
I want to read everything from a textfile and echo it. But there might be more lines written to the text-file while I'm reading so I don't want the script to exit when it has reached the end of the file, instead I wan't it to wait forever for more lines. Is this possible in php?
this is just a guess, but try to pass through (passthru) a "tail -f" output.
but you will need to find a way to flush() your buffer.
IMHO a much nicer solution would be to build a ajax site.
read the contents of the file in to an array. store the number of lines in the session. print the content of the file.
start an ajax request every x seconds to a script which checks the file, if the line count is greater then the session count append the result to the page.
you could use popen() inststed:
$f = popen("tail -f /where/ever/your/file/is 2>&1", 'r');
while(!feof($f)) {
$buffer = fgets($f);
echo "$buffer\n";
flush();
sleep(1);
}
pclose($f)
the sleep is important, without it you will have 100% CPU time.
In fact, when you "echo" it, it goes to the buffer. So what you want is "appending" the new content if it's added while the browser is still receiving output. And this is not possible (but there are some approaches to this).
I solved it.
The trick was to use fopen and when eof is reached move the cursor to the previous position and continue reading from there.
<?php
$handle = fopen('text.txt', 'r');
$lastpos = 0;
while(true){
if (!feof($handle)){
echo fread($handle,8192);
flush();
$lastpos = ftell($handle);
}else{
fseek($handle,$lastpos);
}
}
?>
Still consumes pretty much cpu though, don't know how to solve that.
You may also use filemtime: you get latest modification timestamp, send the output and at the end compare again the stored filemtime with the current one.
Anyway, if you want the script go at the same time that the browser (or client), you should send the output using chunks (fread, flush), then check any changes at the end. If there are any changes, re-open the file and read from the latest position (you can get the position outside of the loop of while(!feof())).