Приглашаем посетить
Чернышевский (chernyshevskiy.lit-info.ru)

Output Buffering

Previous
Table of Contents
Next

Output Buffering

Throughout this book, we have had to avoid sending output before particular PHP functions, most notably the setcookie and header functions. If there is a blank line in any of our script files before a call is made, a warning pops up about headers already being sent and functions not working correctly.

To alleviate this problem, PHP includes a feature called output buffering, or output control. This is a group of functions that gather all of our output in a buffer before sending it to the client machine. This has the advantage of waiting for all setcookie and header function calls to execute properly before sending the output. Some users have even seen performance improvements when using this extension.

How it Works

Output buffering works by not sending the output headers and content as they are emitted within the script (either through the print and echo functions, or through non-code blocks in the script files being processed). Instead, it holds these in a buffer (a memory data) and only sends them (and any necessary headers) to the client when instructed.

There are functions to turn on buffering, get the current contents of the buffer, submit the current contents for output (also called flushing the buffers), discard the buffer, and close the output buffer. This functionality is built into PHP and requires no extra effort to compile or enable it at runtime.

Configuration of this feature area is limited to three options in php.ini:

  • output_buffering (default value of "0") If this is set to 'On,' then output buffering is enabled for all pages processed by the PHP engine. Instead of 'On,' you can also specify a numeric value that sets the maximum size of the output buffer.

  • output_handler (defaults to NULL) This controls which function the buffered output is redirected through before it is sent to the client. By default, it is simply sent to the client when script execution ends or the buffers are flushed. We will see more on custom handlers in the "Writing Your Own Handler."

  • implicit_flush (defaults to "0") This controls whether the output buffers are flushed each time the user calls print or echo. This has serious negative performance implications, so it should be used only for debugging purposes.

Using Output Buffering

It is remarkably easy to use output buffering in your pages. You begin output buffering in your script by calling the ob_start function:

<?php
  ob_start();   // no output before me !!

  require_once('filea.inc');
  require_once('fileb.inc');

  etc. ...

At the end of your script, you call the ob_end_flush function to end buffered output and cause the current buffered content to be sent to the client (along with any headers) when you are done with your output:

<?php
  ob_start();

  ...
  ..
  .

  echo "Thank you for visiting<br/>\n";

  ob_end_flush();
?>

Another way to end output buffering is to call the ob_end_clean function. This not only ends output buffering but also deletes the contents of the output buffers. This is typically used in error situations when you want to redirect the user to another page, as follows:

<?php
  ob_start();

  // includes/requires here ...

  echo "Listing users from database:";

  $conn = @new mysqli('host', 'user', 'pwd', 'dbname');
  if (mysqli_connect_errno() != 0)
  {
    ob_end_clean();
    header("Location: showerror.php?err=" . $conn->errno);
    exit;
  }

  // otherwise, proceed as normal.

  ob_end_flush();
?>

Output buffering is so easy to use! Apart from these functions, there are a few others that we might use:

  • ob_flush This causes any current output in the buffers to be flushed (sent) to the client.

  • ob_clean This erases (cleans) the current contents of the output buffers. However, output buffering remains enabled.

  • ob_get_length This returns the current size of the output buffer in bytes.

  • ob_get_content This function allows us to fetch the current contents of the output buffer if we wish to do additional processing on it before we send it to the client.

Writing Your Own Handler

Output buffering is a powerful system into which we can insert our functions to process the data before we submit them to the client. One way we might choose to use this functionality is to compress the data before we send it to the client. This reduces the network traffic between the client and the server (compression can be extremely effective in some situations) and makes the data more difficult to read as it is transmitted.

Most modern browsers accept content compressed with the gzip algorithm if you send it the Content-Encoding: gzip header. (The browsers will tell you if they accept this through the Accept-Content-Encoding: header sent with the request.) PHP happens to have built-in functions for encoding (and decoding) data that uses the gzip algorithm.

You can add your own handler function by passing its name as a parameter to the ob_start function or by specifying its name as the value of the output_handler configuration option in php.ini. With the buffered output as its parameter, this function is called when output is ready for transmission to the client. It should then compress this output and return it as the data to be sent, as follows:

<?php

function compress_handler($in_output)
{
  // this is a built-in function in PHP! 
  return gzencode($in_output);
}

// make sure the client browser actually accepts gzip output
if (strpos($_SERVER['HTTP_ACCEPTS_ENCODING'], 'gzip') 
    !== FALSE)
{
  // indicate we want to compress, and tell client browser
  ob_start('compress_handler');
  header('Content-Encoding: gzip');
}
else
{
  // just use regular output buffering
  ob_start();
}

?>

The preceding code snippet is a perfect example of something to put into a separate file and include as the first thing in each of your script files.

PHP provides most of this functionality for us in an output handler called ob_gzhandler (which can be passed to ob_start). However, some users have had problems with this handler. It is probably safer to use your own.


Previous
Table of Contents
Next