Saturday, April 21, 2007

PHP output buffering

The output buffering functions of php aren't well known (yet), but are
nevertheless extremely useful. These functions give you more control
over the output generated by your scripts than you would normally
have, and in some cases, this control is essential. Not only do you
have control over when, where, and why your output is displayed, but
you can also control how the output is handled. In this tutorial I
hope to cover the general idea behind output buffering, as well as a
few common uses.

Lets begin with a common problem, and an easy way to fix it. Some of
you may notice this common mistake, because a lot of the people new to
php have made it:

PHP Example: (!)

echo "You will now be directed to google.com...\n";
header("Location: http://sanjeev-naroliya.blogspot.com/");
?>

Those of you who know your way around php a bit will know that you
cannot use the header() function after there is any output. Output in
this script begins with "". The script above would result in an error
of "cannot add header information, headers already sent". Here is how
to use the output buffering functions to get around this problem:

PHP Example: (!)

//start output buffering
ob_start();
?>
echo "You will now be directed to google.com...\n";
header("Location: http://sanjeev-naroliya.blogspot.com/");
?>

//send the contents of the buffer to the browser
ob_end_flush();
?>


Please do not take this example literally as a way to get around the
error, it'd be much easier to just move the header() function to the
top, or use a meta refresh, but it's the principle that I would like
you to grasp. Lets break this down into small peices.
ob_start();
This function opens up a new buffer. All output of the script will be
put into this buffer, so that you may act upon it later. Think of this
like a giant string in which all of the output of your script will be
appended to. In the previous example, the output would be "You will
now be directed to google.com...".

at the end you see the ob_end_flush() function. This function is used
to 'flush' (send) data to the browser, and to close the buffer.

As you have noticed, you cannot do much with these two functions
alone. Now comes the fun part. The Output Buffering API in php comes
with some nice functions to give you a lot of control over the way you
handle your scripts, Read on if you want to check these out in
detail.

I think the best way to teach more about output buffering would be to
show you examples and explain them later. Many people will be able to
identify what the code is supposed to do before even reading the
explanations, output buffering is just that easy. Lets begin:

PHP Example: (!)

//start output buffering
ob_start();
//call the get_database_content function
get_database_content();
//call the page_end function
page_end();

function get_database_content() {
mysql_connect('some host','user','pass');
$query = mysql_query("SELECT * FROM users WHERE userid='12'");
while( $thingy = $mysql_fetch_array($query) ) {
echo $thingy;
}
}

function page_end() {
if(mysql_error() > 0) {
ob_end_clean();
echo "ERROR: ".mysql_error();
} else {
ob_end_flush();
}
}

?>


In this example a buffer is opened with ob_start, and then functions
are called to control the output. get_database_content will connect to
a database and echo some data, and then page_end will check to see if
all went well. If there was an error while using the database, the
buffer is cleared, and an error message is displayed. If all went
well, the buffer is sent to the browser with ob_end_flush().

PHP Example: (!)

ob_end_clean();


The ob_end_clean function empties (hence 'clean') and then closes the
buffer without sending the content to the browser.

Here is another example, introducing two new functions.

PHP Example: (!)

//start output buffering
ob_start();
//call the get_database_content function
get_database_content();
//call the page_end function
page_end();

function get_database_content() {
mysql_connect('some host','user','pass');
$query = mysql_query("SELECT * FROM users WHERE userid='12'");
while( $thingy = $mysql_fetch_array($query) ) {
echo $thingy;
}
}

function page_end() {
if(mysql_error > 0){
ob_clean();
echo "ERROR: ".mysql_error();
ob_flush();
} else {
ob_flush();
}
}
ob_end_clean();
?>


This example is basically same as the last, except it uses ob_flush
and ob_clean. ob_flush will send the contents of the buffer to the
browser and empty the buffer, but will not close the buffer. ob_clean
will empty the contents of the buffer without sending the output to
the browser. It also does not close the buffer. At the end the buffer
is closed with ob_end_clean.

Another function which you will use often while using output buffering
is ob_get_contents. Let's take a look at some example code:

PHP Example: (!)

//start output buffering
ob_start();
echo "wwooooo";
echo "hoo!";
ob_flush();
//call the get_database_contents function
get_database_contents();
//call the page_end function
page_end();

function get_database_content() {
mysql_connect('some host','user','pass');
$query = mysql_query("SELECT * FROM users WHERE userid='12'");
while( $thingy = $mysql_fetch_array($query) ) {
echo $thingy;
}
}

function page_end(){
$stuff = ob_get_contents();
$file = fopen("data.txt","w");
fwrite($file, $stuff);
fclose($file);
}
ob_end_clean();
?>


As you can see, ob_get_contents returns the content of the buffer. If
there is no buffer open, ob_get_contents will return false. There are
a few more functions that I won't go into detail over, which I will
list below, with a brief explanation.

flush
This function will try to put all output in the buffer to the browser.
ob_implicit_flush
This function turns explicit flushing on or off, if no flag is given
as a parameter it will default as on. With ob_implicit_flush the
buffer will be flushed after each call to output, and explicitly
calling flush() is no longer needed.
ob_get_length
This will return the length of the output buffer, or false if there is
no active buffer.
ob_get_level
This function returns the nesting level of the output buffering
mechanism. meaning, it will return the level of nested output
buffering, if you have more than one open buffer.
ob_get_status
This function returns an array of either the status of currenly open
buffers or FALSE.
NOTE: this function is EXPERIMENTAL. The name and functionality can be
changed in future versions of php, or it could be dropped altogether.

There is really only one more area of interest I would like to hit on
output buffering, and that is ob_gzhandler. You can read about it on
the next page. Ob_gzhandler is (in my opinion) the best part of output
buffering. Read on.

Ob_gzhandler can be used to automatically compress data before it is
sent to the browser, decreasing loading time, on browsers which
support it (the function will determine which type of compression your
browser can handle: gzip, deflate, or none at all). This is an
extremely useful function for any website which uses large amounts of
dynamic data. A quick example:

PHP Example: (!)

//start output buffering with the ob_gzhandler callback
ob_start("ob_gzhandler");
echo "this data is compressed.";
ob_end_flush();
?>


A small warning: although your server will have less bandwidth being
used, the CPU load will be drastically increased।

2 comments:

  1. Hello there people, I just registered on this wonderful online community and wanted to say howdy! Have a impressive day!

    ReplyDelete
  2. AnonymousMay 23, 2010

    Hello

    It is my first time here. I just wanted to say hi!

    ReplyDelete