Controlling outputs in PHP

May 21, 2007 on 7:42 pm | In PHP |

PHP has provided developers with many ways to control outputs, but not many scripts put them into use. Output buffering and flushing are great ways to enhance the usability of your web applications.

In a normal request sent to the web server from the browser, the web server typically responds with the header information and the actual content requested. The header contains numerous things, including the name of the server software, the last modified date and content-type of the document, and others. After the header comes the content. For an HTML page (or any scripts that produce HTML output), that would be the HTML source code of the page.

Buffering the output of this content

PHP provides a number of functions that let you buffer your script’s output. Normally, whatever you output is directly sent to the client immediately to be displayed on their web browser (or, rather, waiting until a fixed number of bytes to be ready before sending it out). You can change this behavior by buffering your outputs.

If you are familiar with C programming, this idea is similar to intercepting the output to STDOUT (imagine using pipes in the UNIX command-line to take all outputs from a program and feed it to another program). There is a list of functions in PHP, with the prefix of “ob_”, that lets you do just this — intercepting output to the client. The “ob” stands for Output Buffering.

Taking feedback from the comments on the last post, I don’t want to make this seem like a beginner tutorial — rather, I want to simply inform you of its capabilities and reasons to use it, and let you do more research on how to use it if you are interested.

The php.net documentation has a list of output buffering functions available to you. Most of them involve around getting the contents of the buffer, cleaning the buffer (discards the content), and flushing the buffer (sends the content out and clean the buffer), or a combination of them; and of course the start and end functions. The end function must be done together with either a flush or a clean.

Why buffer output?

There are many reasons this could come in handy. Imagine you are printing a page containing a table of data that comes from several MySQL queries. Of course, all your queries should have error handling. Sometimes, one query in the middle of the page might fail, and you get a page with half of the data table printed, and a MySQL warning/error follows (and usually, the page stops loading). To avoid such a case, you could start output buffering and flush only at the end when everything successfully runs. When an error is encountered, simply end and clean the buffer and print an error page. Here is a quick and brief pseudo-code for a situation like that.

<?php

ob_start();

?>
Your data is below:
<?

$err = 0;
for (...) {
   // complicated loop involving many things!
   mysql_query(...);
   // somehow, you run a query in each iteration.
   // this is a bad design, but just for demonstration here...
   if (error) // some error checking
   {
      $err = 1;
      break;
   }
}
if ($err)
{
   echo "..."; // print an error page here
   ob_end_clean(); // forget what was printed before
}
else
{
   ob_end_flush(); // print out data normally
}

?>

If you intend to do this for all your scripts, there is even a setting in the php.ini configuration that let you turn on output buffering by default, saving you to do ob_start() and ob_end_*() at the beginning and end of all your scripts.

output_buffering = On

By default, it is set to a number like 4096. In that case, it always waits until 4kb of data is ready before sending it out. By switching it to On, you are saving all output buffer until explicitly told to flush.

What if I want to do the opposite?

In some cases, it becomes necessary for a developer to do the exactly opposite of that. For example, in one script, there may be a query (and the manipulation of its results) that take very long to finish. However, you want whatever that was ready to be sent to the client and printed first. (for example, even a message of “Please wait while the page loads” would be nice to see!)

As seen above, if PHP is configured to wait for all 4kb of data to be ready before printing, you could get “stuck” and see an empty page before this happens. Fortunately, PHP provides us a flush() function [documentation] that lets you do just this. However, you should be aware that there is still a possibility that the output gets “stuck”, due to a number of other reasons, quoting from the php.net documentation:

  • flush() has no effect on the buffering scheme of your web server or the browser on the client side. Thus you need to call both ob_flush() and flush() to flush the output buffers.
  • Several servers, especially on Win32, will still buffer the output from your script until it terminates before transmitting the results to the browser.
  • Server modules for Apache like mod_gzip may do buffering of their own that will cause flush() to not result in data being sent immediately to the client.
  • Even the browser may buffer its input before displaying it. Netscape, for example, buffers text until it receives an end-of-line or the beginning of a tag, and it won’t render tables until the </table> tag of the outermost table is seen.
  • Some versions of Microsoft Internet Explorer will only start to display the page after they have received 256 bytes of output, so you may need to send extra whitespace before flushing to get those browsers to display the page.

Conclusion

Far too often, we come across interactive web sites where they encounter a database error, and the page stops in the middle with half the data printed. Other times, you are trying to access a page with tons of data waiting to be loaded, only to be treated a blank page without knowing if your internet died, or if the server is working on your page, or if your computer/browser froze.

With the power of the above functions, a developer should be able to have much better control on the outputs of his/her web applications. Remember, the design of software should be user-oriented. Keep confusions and annoyances to a minimum!

No Comments yet »

RSS feed for comments on this post. TrackBack URI

Leave a comment

You must be logged in to post a comment.

Powered by WordPress with Pool theme design by Borja Fernandez. Entries and comments feeds. Valid XHTML and CSS. ^Top^