I developed a facebook application in PHP. The problem is that it takes 2 minutes to display the result. This might confuse the user, who sees a blank canvas and leaves.
I just want to echo a statement that it is still processing.
I tried flush(); and ob_flush(); and ob_start(); but it is of no use.
Is there any other simpler alternative to address my specific problem?
I tried this, but it did not work as well.
ob_implicit_flush(true);
ob_end_flush();
for ($i=0; $i<5; $i++) {
echo $i.'<br>';
sleep(1);
}
EDIT:
The above code works perfectly fine with IE and other Browsers.
Only Chrome has this issue.
Convert it to an AJAX request, where you load a quick page which can have anything you want, and then loads in data from the slower page in the background.
flush() won't do what you want because it will return only part of the output and the client will tend to wait for the complete page.
Call flush(); as often as required.
Unfortunately, this might or might not make the browser feel happy to display your stuff. Even on IE, the result isn't predictable.
Related
I got big problem, becouse i tested everything to make it works, but`s not - yet :)
i got simple for loop and there is a star, end, flush inside, but still my browser load all output at the and of loop, and i took for this question simple example:
<?php
if (ob_get_level() == 0) ob_start();
for ($i = 0; $i<10; $i++){
echo "<br> Line to show.";
echo str_pad('',4096)."\n";
ob_flush();
flush();
sleep(2);
}
echo "Done.";
ob_end_flush();
?>
a i`vd setup all about outpuuting_bufforing, zlib, gzib, and other alls. Exacly in htacces, script, file, even in php.ini, apache. I got dedicaded server so can configure what i need. Can some1 tell me what more can i try?
Ofc there is no error in any log file.
Thanks for advice !
The comments in the official PHP documentation for ob_flush() mention, that most browsers have an all-or-nothing approach to loading content. Therefore the browser will not show anything until the whole page is loaded.
See http://php.net/manual/de/function.ob-flush.php#109699
This means that flushing output to the browser will not work for you.
The alternative would be to start the initial request via AJAX and then use a second request to provide information about the current progess.
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.
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.
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
Google chrome doesn't behave the same as other browsers when encountering this nugget:
<?php
while (true) {
echo "<script type='text/javascript'>\n";
echo "alert('hello');\n";
echo "</script>";
flush();
sleep(5);
}
?>
It seems that it's waiting for the connection to terminate before doing anything.
Other than polling how can I do a similar thing in Google Chrome?
I had a similar issue to this, and solved it by adding an HTML tag (in my case <br />) before each flush.
My guess would be that Chrome waits for an element which is being displayed to close before triggering a re-render. That's only a guess though.
It didn't seem to require 1024 bytes - I think I would have had just under 512 bytes when it worked.
Some browsers require a certain number of bytes to be downloaded before rendering available data. I remember the last time I tried to do what you're doing I ended up having to dump something like 300 spaces to be sure the browser would bother with it.
I wish I had access to Chrome at the moment to test out some ideas. Have you tried adding some HTML after </script> and seeing if it renders incrementally? I imagine it would, and if so that'd be proof that Chrome doesn't want to run javascript in <script> elements while the page is loading. Of course, rendering the markup might trigger your scripts to run. If not, you could try including the javascript as external files and see if that affects execution time.
I think browsers generally have some leeway according to the spec in when they begin executing javascript, especially as the page loads. It might not be possible to do this in a fully cross-browser way without polling.
Did you talk with Chrome developers? Did you open a bug about that? IMHO the best solution is make Chrome behave like other browsers do, rather than having a workaround for it.
Okay, actually you probably will need a short-term workaround. But imagine a world in which each browser behaves differently in each aspect, say HTTP, HTML, CSS handling... it would not be a pleasant place!
Stream is working. The answer from eyelidlessness is the solution.
print "2048 points[BR>\n";
The [ = <
BTW look at the user-agent. Safari needs much bytes too. I think 1024. Firefox needs not so much bytes.
<?php
$i = 0;
while (true) {
if($i == 0) {
echo "<html><body>";
}
echo "<script type='text/javascript'>\n";
echo "alert('hello');\n";
echo "</script>";
if($i == 0 ) {
$padstr = str_pad("",2048," ");
echo $padstr;
echo "</body></html>";
}
flush();
sleep(5);
$i = $i + 1;
}
?>
For fist time send at least 2048 bytes of data. then it will work fine. And make sure to keep script tag in a body tag. The strange thing is , in my case if I add 1024 bytes it worked. Hope this helps you
The above program is working fine in google chrome.