Google Chrome and Streaming HTTP connections? - php

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.

Related

Progress bar not working flush

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.

Using PHP Output Bufferering to Issue JavaScript During Processing

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.

PHP Flush() not working in Chrome

I stumbled upon this function which promised to work across IE, FF & Chrome. But it does not work in Chrome. Is there a work around?
function buffer_flush(){
echo str_pad('', 512);
echo '<!-- -->';
if(ob_get_length()){
#ob_flush();
#flush();
#ob_end_flush();
}
#ob_start();
}
Here's how I got flush() working in a while loop in Chrome 12.0.742.122 with PHP 5.3.6:
echo("<html><body>");
while(1) {
echo(str_pad($my_string_var,2048," "));
#ob_flush();
flush();
}
Using a lesser str_pad value worked too, but it would take a bit longer for the first output to appear. If any of the other lines were missing, nothing would appear.
The "#" isn't strictly necessary, but it prevents the log from filling up with "nothing in the buffer" notices.
And of course if you have a pre-existing page, just make sure the <html> and <body> tags are in there; I was writing a page from scratch.
With flush()/ob_flush() you only send the output to the browser, but its still up to the browser, when it displays it. I assume, that chrome just waits, until it has enough data received to display a "useful" page, instead of some fragments.
Some suggestions anyway:
Avoid using # (especially if you don't know exactly, what it does)
If you don't call ob_end_*(), you don't need to call ob_start() again. Its inefficient
function buffer_flush(){
echo '<!-- -->'; // ?
ob_flush();
flush();
}
Some browsers (IE6 at the very least, and possibly chrome) require a certain amount of "useful" characters (i.e. not spaces) before outputting anything. In the case of IE6, it even is the compressed data's size that needs to be pushed.
function force_flush() {
echo "\n\n<!-- Deal with browser-related buffering by sending some incompressible strings -->\n\n";
for ( $i = 0; $i < 5; $i++ )
echo "<!-- abcdefghijklmnopqrstuvwxyz1234567890aabbccddeeffgghhiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz11223344556677889900abacbcbdcdcededfefegfgfhghgihihjijikjkjlklkmlmlnmnmononpopoqpqprqrqsrsrtstsubcbcdcdedefefgfabcadefbghicjkldmnoepqrfstugvwxhyz1i234j567k890laabmbccnddeoeffpgghqhiirjjksklltmmnunoovppqwqrrxsstytuuzvvw0wxx1yyz2z113223434455666777889890091abc2def3ghi4jkl5mno6pqr7stu8vwx9yz11aab2bcc3dd4ee5ff6gg7hh8ii9j0jk1kl2lmm3nnoo4p5pq6qrr7ss8tt9uuvv0wwx1x2yyzz13aba4cbcb5dcdc6dedfef8egf9gfh0ghg1ihi2hji3jik4jkj5lkl6kml7mln8mnm9ono -->\n\n";
while ( ob_get_level() )
ob_end_flush();
#ob_flush();
#flush();
} # force_flush()
There are several components that can have impact on this issue.
Read carefully through the documentation of this function:
http://www.php.net/manual/en/function.flush.php
One solution I had was using Apache2 with mod-php (not as fcgi but as native apache-module) and Chromium. The result came immediately and the script was still running and sending more results.
After typing the following two code-lines every echo-command will immediately push the text to the whatever-PHP-backend:
ob_implicit_flush(1);
#ob_end_flush(); // set an end to the php-output-buffer!
But this php backend can have its own buffer. For example I run nginx as webserver and php is used by the fast-cgi module. Nginx itself has its own buffer ... and so on.
The Browser also can buffer the request. But as I experience Chromium (or Google Chrome) has a verry small or no buffer.
Please read the documentation of every function I mentioned to understand what they really do - but specially the documentation of flush().
Personal hint: Do not put extra characters into the output-buffer but read and understand the configuration of your server.
EDIT:
If you have gzip enabled the whole response from the server will be buffered.
I found that a content type header really makes it work in chrome after few trial and errors.
But i don't know why chrome does not flush otherwise.
after searching for more answers i read that chrome flushes as you expect only when a valid content type is set. fine.
Here is the code i experimented.
<?php
header('Content-Type: text/html; charset=UTF-8');
echo 'starting...';
flush();
echo 'to sleep...';
flush();
sleep(5);
echo 'awake';
if i do not include the content type header i get like the following in one shot after 5 seconds. so what we expect did not work.
starting...to sleep...awake is displayed and the script terminates.
where as when i gave the content type like the above with the subtype(charset) then
starting...to sleep... is displayed immediately and then after 5 seconds awake is displayed.
i am just blindly assuming that with respect to the content type header chrome shows the output.
Besides when i gave 'Content-Type: text/plain' or 'Content-Type: text/html' it did not work. it worked only with the subtype 'charset=[sometexthere]'.
were as application/json worked. and i did not experiment with more mimes.
The reason i am here is
i wanted to use readystate 3 in ajax response. it works fine except chrome and safari. since chrome is using webkit it is the same in both i think.
in other browsers including IE the flushing is working as expected and also the readystate=3 but in chrome and safari i just used the above workaround.
here is the screenshot of the readystate - responsetext from the above php script
in the image there a two sets of response the first one with readystate 3 and responsetext as empty when content type is not used.
in the second response you can see ready state 3 has responsetext with the expected output. this is when content type is used.
so... Chrome only knows.
when used str_pad
When you use string padding you can get more expected result. i tried with 1024 as the above answers suggested but only with content type set.
if padding is used and no content type is set then it did not work.
and
i had raised a question similar to this and i am going to add my own answer by linking this answer to that and back to back... so that it will be easy for users to get more details. hhmmm.

How to echo in PHP while the script is still executing?

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.

PHP: Output data before and after sleep()?

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.

Categories