PHP buffer: output_buffering and ob_start

  perfgeeks        2013-06-20 22:54:15       19,010        1    

buffer is one piece of memory section, it is usually 4Kb in Linux. It is mainly used between different devices with different speed or different priorities. With buffer, the waiting time between different processes will be reduced. Here is one simple example, when you type something in a text editor, every time when you type a character, the operating system will not write it to the disk directly, instead it will write it to buffer first When the buffer is full, the data in the buffer will be written to disk. But when you call flush(), the data in the buffer will be written to the disk immediately.

php.output_buffering

By default php buffer is enabled, and the default size of the buffer is 4096, i.e 4Kb. You can find the output_buffering in php.ini file. When echo,print user data, the output data will be written to output buffer. When the output buffer is full, it will send the data to browser through TCP. You can also use ob_start() manually activate php.output_buffering. Even the data size is over 4Kb, the data will not be sent to browser using TCP since ob_start() has extended the PHP buffer. Only when the script completes execution or ob_end_flush() is called, the data will be sent to the browser.

1. When output_buffering=4096, and the data size is small

<?php
for ($i = 0; $i < 10; $i++) {
    echo $i . '<br/>';
    sleep($i + 1);  //
}
?>

The data will be sent to browser and displayed only when the response ends instead of sending data every few seconds. Before waiting for the server to complete its processing, the browser will remain blank. This is because the data size is too small, so the output buffer is not filled up. The order of data write is : echo->php buffer->tcp buffer->browser.

2. When output_buffering=0, and data size is small

<?php
//ini_set('output_buffering', 0) not working
//Should edit /etc/php.ini,set output_buffering=0 to disable output buffering
//ini_set('output_buffering', 0);   //disable output buffering
for ($i = 0; $i < 10; $i++) {
    echo $i . '<br/>';
    flush();  //Ask OS to output data to browser
    sleep($i + 1);  //
}
?>

After disabling output buffer, the data will be sent to browser consistently, it no needs to wait for the completion of this script. This is because the data will not stay at the output buffer, the order of data write is : echo->tcp buffer->browser

3. When output_buffering=4096, the data size is relatively large. Without calling ob_start()

<?php
for ($i = 0; $i < 10; $i++) {
    echo file_get_contents('./f4096') . $i . '<br/>';
    sleep($i +1);
}
?>

The response is not over, data will be sent to the browser consistently and the browser display will not remain blank. Even though php.output_buffering is enabled, data will still be sent consistently instead of all at once. This is because output buffer is too small, and when it's filled up, the data will be sent to the browser right away.

4. When output_buffering=4096, the data size is relatively large. Calling ob_start()

<?php
ob_start(); //Enable php buffer
for ($i = 0; $i < 10; $i++) {
    echo file_get_contents('./f4096') . $i . '<br/>';
    sleep($i + 1);
}
ob_end_flush();
?>

Data will be sent to the browser only after the script completes execution. Before output, the browser will remain blank and wait for server response.

tcpdump

Here we can monitor tcp packets using tcpdump. We can observe the difference between using ob_start() and not using ob_start().

1. Without using ob_start()

12:30:21.499528 IP 192.168.0.8.webcache > 192.168.0.28.cymtec-port: . ack 485 win 6432
12:30:21.500127 IP 192.168.0.8.webcache > 192.168.0.28.cymtec-port: . 1:2921(2920) ack 485 win 6432
12:30:21.501000 IP 192.168.0.8.webcache > 192.168.0.28.cymtec-port: . 2921:7301(4380) ack 485 win 6432
12:30:21.501868 IP 192.168.0.8.webcache > 192.168.0.28.cymtec-port: P 7301:8412(1111) ack 485 win 643
12:30:24.502340 IP 192.168.0.8.webcache > 192.168.0.28.cymtec-port: . 8412:14252(5840) ack 485 win 6432
12:30:24.503214 IP 192.168.0.8.webcache > 192.168.0.28.cymtec-port: . 14252:15712(1460) ack 485 win 6432
12:30:24.503217 IP 192.168.0.8.webcache > 192.168.0.28.cymtec-port: P 15712:16624(912) ack 485 win 6432

12:30:31.505934 IP 192.168.0.8.webcache > 192.168.0.28.cymtec-port: . 16624:23924(7300) ack 485 win 6432
12:30:31.506839 IP 192.168.0.8.webcache > 192.168.0.28.cymtec-port: P 23924:24836(912) ack 485 win 6432
12:30:42.508871 IP 192.168.0.8.webcache > 192.168.0.28.cymtec-port: . 24836:32136(7300) ack 485 win 6432
12:30:42.509744 IP 192.168.0.8.webcache > 192.168.0.28.cymtec-port: P 32136:33048(912) ack 485 win 6432
12:30:57.512137 IP 192.168.0.8.webcache > 192.168.0.28.cymtec-port: . 33048:40348(7300) ack 485 win 6432
12:30:57.513016 IP 192.168.0.8.webcache > 192.168.0.28.cymtec-port: P 40348:41260(912) ack 485 win 6432
12:31:06.513912 IP 192.168.0.8.webcache > 192.168.0.28.cymtec-port: P 41260:41265(5) ack 485 win 6432
12:31:06.514012 IP 192.168.0.8.webcache > 192.168.0.28.cymtec-port: F 41265:41265(0) ack 485 win 6432
12:31:06.514361 IP 192.168.0.8.webcache > 192.168.0.28.cymtec-port: . ack 486 win 6432

2. Using ob_start()

12:36:06.542244 IP 192.168.0.8.webcache > 192.168.0.28.noagent: . ack 485 win 6432
12:36:51.559128 IP 192.168.0.8.webcache > 192.168.0.28.noagent: . 1:2921(2920) ack 485 win 6432
12:36:51.559996 IP 192.168.0.8.webcache > 192.168.0.28.noagent: . 2921:7301(4380) ack 485 win 6432
12:36:51.560866 IP 192.168.0.8.webcache > 192.168.0.28.noagent: . 7301:11681(4380) ack 485 win 6432
12:36:51.561612 IP 192.168.0.8.webcache > 192.168.0.28.noagent: . 11681:16061(4380) ack 485 win 6432
12:36:51.561852 IP 192.168.0.8.webcache > 192.168.0.28.noagent: . 16061:20441(4380) ack 485 win 6432
12:36:51.562479 IP 192.168.0.8.webcache > 192.168.0.28.noagent: . 20441:24821(4380) ack 485 win 6432
12:36:51.562743 IP 192.168.0.8.webcache > 192.168.0.28.noagent: . 24821:29201(4380) ack 485 win 6432
12:36:51.562996 IP 192.168.0.8.webcache > 192.168.0.28.noagent: . 29201:33581(4380) ack 485 win 6432
12:36:51.563344 IP 192.168.0.8.webcache > 192.168.0.28.noagent: P 33581:35041(1460) ack 485 win 6432
12:36:51.563514 IP 192.168.0.8.webcache > 192.168.0.28.noagent: . 35041:36501(1460) ack 485 win 6432
12:36:51.563518 IP 192.168.0.8.webcache > 192.168.0.28.noagent: . 36501:37961(1460) ack 485 win 6432
12:36:51.563523 IP 192.168.0.8.webcache > 192.168.0.28.noagent: . 37961:39421(1460) ack 485 win 6432
12:36:51.563526 IP 192.168.0.8.webcache > 192.168.0.28.noagent: . 39421:40881(1460) ack 485 win 6432
12:36:51.563529 IP 192.168.0.8.webcache > 192.168.0.28.noagent: FP 40881:41233(352) ack 485 win 6432
12:36:51.570364 IP 192.168.0.8.webcache > 192.168.0.28.noagent: . ack 486 win 6432

With above comparism, the time interval is different between these two. Without using ob_start(), the waiting interval is relatively large, the data in tcp buffer is sent out after waiting for 4 seconds. Data doesn't remain in the php buffer for a long time. This is because php buffer is filled up and the data has to be sent out. With ob_start(), data is sent to the browser all at once.

We often can see use of ob_start() in some template engines. In some famous open source projects such as wordpress,drupal and smarty, we can see the use of it. For example, in drupal application:

//@file:user-profile.tpl.php
  • username: name; ?>
  • picture:picture; ?>
 
//@file:template-render.php

 
//@file:profile.php
 $user);
print theme_render_template('user-profile.tpl.php', $variables);
?>

Source : http://www.perfgeeks.com/?p=344

PHP BUFFER  OUTPUT_BUFFERING  OB_START 

       

  RELATED


  1 COMMENT


Shauna [Reply]@ 2015-01-13 00:13:02
You can definitely see your enthusiasm within the work you write. The world hopes for more passionate writers like you who are not afraid to say how they believe. Always go after your heart.


  RANDOM FUN

How a hacker works