3

I have a few conceptual questions (all related, I think) regarding the following script, at the comments. The script works fine.

<?PHP
ob_start();

// Create string to overflow browser buffer ...?
$buffer = str_repeat(" ", 4096);

// Indicate new header / html content ...?
$buffer .= "\r\n<span></span>\r\n";

for ($i=0; $i<5; $i++) {
  echo $buffer.$i;
  ob_flush();
  flush();
  sleep(1);
}

ob_end_flush();
?>

First, why do I need to send the \r\n<tag>\r\n to the browser? I assume it has something to do with headers.

Second, why do I need some HTML in the middle?

Third, there are many examples that use 256 bytes instead of 4096. However, the script doesn't work if I use 256. Are these examples outdated, and will this number change again in the future?

//EDIT REGARDING SOURCE LINKS

This code was gathered mainly from the commentary in php.net sleep() function and the solution to this SO question. Neither mentions why to include \r\n.

//EDIT REGARDING HEADERS

If I don't add \r\n, an HTML tag, and a second set of \r\n, the script will not execute properly in Chrome or Safari (it just dumps all the values at once).

Additionally, if this is called before a session_start(), it throws an error: "Cannot send session cache limiter - headers already sent".

Community
  • 1
  • 1
Ben
  • 54,723
  • 49
  • 178
  • 224
  • It would help to know what is the script's purpose/expected result. – netcoder Nov 16 '10 at 05:04
  • 3
    4096 bytes is the default `php.ini` output buffering setting. `\r\n` is just a typical Windows environment newline. – Phil Nov 16 '10 at 05:06
  • where did you get this code from? what is it supposed to do? – cambraca Nov 16 '10 at 05:10
  • @netcoder, @cambraca - If you actually ran the script you would see it echoes 0, 1, 2, 3, 4 with one second intervals. It is taken from various sources, primarily the php.net reference documentation. – Ben Nov 16 '10 at 05:12
  • @Phil - Why do I need to send that for this to work? – Ben Nov 16 '10 at 05:12
  • does it not work when you just echo the `$i` variable? – cambraca Nov 16 '10 at 05:15
  • @Steve: You may want to put your comment (i.e.: expected result) in the post itself, for better answers. :) – netcoder Nov 16 '10 at 05:15
  • @Steve also, if you got the code from somewhere, maybe include the url from where you got it. It probably has clues about whether it actually needs the \r\n and empty span – cambraca Nov 16 '10 at 05:17
  • @Steve The only reason I can think of sending 4096 bytes before any content is to beat any configured output buffering. The code uses output buffering functions though which makes the the above redundant – Phil Nov 16 '10 at 05:20
  • 3
    +1 this is a valid question. don't mark it invalid if it's not within your competence level to answer it – bcosca Nov 16 '10 at 05:20
  • 2
    @cambraca Google Fu! http://www.php.net/manual/en/function.sleep.php#95164 – Phil Nov 16 '10 at 05:23
  • @Steven I'd say the example simply wanted their HTML source to render nice in notepad.exe, hence the `\r\n` – Phil Nov 16 '10 at 05:25

3 Answers3

2

First, why do I need to send the \r\n<tag>\r\n to the browser? I assume it has something to do with headers.

Second, why do I need some HTML in the middle?

Normally browser have to wait until they have fetched the whole response until it can be rendered (just think of XML that can be valid until the last character). But since that would make a bad user experience, most browsers start to parse and render the contents as early as possible.

And here this HTML fragment could be the initiator for the browser to actually build the DOM and start rendering.

Third, there are many examples that use 256 bytes instead of 4096. However, the script doesn't work if I use 256. Are these examples outdated, and will this number change again in the future?

As the manual hints that there might be some further buffering incorporated in the web server, this might be the attempt to overflow those buffers that they are also flushed in order to have the expected effect.

Gumbo
  • 643,351
  • 109
  • 780
  • 844
  • That makes sense too. However, the script fails if I send `\r\n sometext \r\n`. It only works with a tag in the middle. Wouldn't plaintext trigger the DOM also, just with a text node? – Ben Nov 16 '10 at 07:00
  • @Steve: No, obviously not. Although normally the *Content-Type* header field specifies the, well, content type, there are situations where that information is missing. So there are no hints what’s actually being sent and at that moment [MIME type sniffing](http://tools.ietf.org/html/draft-abarth-mime-sniff) takes place in most browsers. – Gumbo Nov 16 '10 at 07:54
1

The reason for using \r\n would be make the output render nicely when viewed using a Windows source viewer like notepad.exe.

Nothing to do with headers here.

Seeing as the code uses the output buffering functions, I have no idea why they feel the need to try and overflow a 4kb buffer (the default in a standard php.ini though more professionals would opt for no default output buffering).

Phil
  • 157,677
  • 23
  • 242
  • 245
  • I think it tries to overflow the buffer in the browser, since in theory flush() should, well, flush the php buffer, no? – cambraca Nov 16 '10 at 05:39
  • 1
    @cambraca Quite a few hints in the `flush()` manual page - http://php.net/manual/en/function.flush.php – Phil Nov 16 '10 at 05:42
  • the solution to the SO question I linked to in my first edit has a comment in which the author states "Although I need to send \r\n's along with the content before I flush it out for it to work". – Ben Nov 16 '10 at 05:54
  • Any suggestions on how to handle this without the 4kb overflow issue? – Ben Nov 16 '10 at 06:44
-1
<?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();
?>
LarsTech
  • 80,625
  • 14
  • 153
  • 225
Saeed.r
  • 1
  • 1