ASPit - Totally ASP JSit - Totally JavaScript
Search PHPit

Use this textbox to search for articles on PHPit. Seperate keywords with a space.

Advertisements

Messing with the output buffer

I love messing with the output buffer, doing weird things (and a lot is possible). Let's look at this really simple example first to see what I mean:


function mycallback ($buffer) {
        $buffer = 'BOOYAAH!';

        return $buffer;
}

ob_start('mycallback');

echo 'This will never appear';

?>

What the above code does is enable output buffering, with our own custom buffer handler, which replaces the buffer with a new string. A neat application of this would be post replacing. Imagine you could let your script output a lot of html, and later wanted to delete that html again. Without output buffering this wouldn't be possible at all, but even with output buffering you can't discard parts of the buffer, and you can only discard the whole buffer. What if we only want to replace part of the buffer?

With a custom buffer handler that's possible, and it's actually something I use in one of my scripts to combat a buffering bug in PHP. Consider the following code:

class Buffer {
        var $replacements = array();

        function replace ($replace, $with) {
                // Add to replacements array
                array_push ($this->replacements, array($replace, $with));
                return true;
        }

        function do_replace ($buffer) {
                // Do all replacements on the buffer
                foreach ($this->replacements as $r) {
                        $buffer = str_replace ($r['0'], $r['1'], $buffer);
                }

                return $buffer;
        }
}

$buffer = New Buffer;
ob_start(array(&$buffer, 'do_replace'));

echo 'My name is Henry';

// Do some other logic here
// and come to the conclusion that
// my name isn't Henry, but Dennis

$buffer->replace ('Henry', 'Dennis');

?>

Great isn't it, and in some cases it really makes it easier to do certain things. The above code is probably very "filthy", and should be cleaned up, but it's about the principle behind it. It's even possible to add new content before old content, e.g.

class Buffer {
        var $replacements = array();
        var $addbefore = array();

        function replace ($replace, $with) {
                // Add to replacements array
                array_push ($this->replacements, array($replace, $with));
                return true;
        }

        function add_before ($str) {
                array_push ($this->addbefore, $str);
                return true;
        }

        function do_replace ($buffer) {
                // Do all replacements on the buffer
                foreach ($this->replacements as $r) {
                        $buffer = str_replace ($r['0'], $r['1'], $buffer);
                }

                // Add new stuff before
                foreach ($this->addbefore as $a) {
                        $buffer = $a . $buffer;
                }

                return $buffer;
        }
}

$buffer = New Buffer;
ob_start(array(&$buffer, 'do_replace'));

echo 'My name is Henry';

// Do some other logic here
// and come to the conclusion that
// my name isn't Henry, but Dennis

$buffer->replace ('Henry', 'Dennis');

$buffer->add_before ('

The page now starts with this!

'
);

?>

And these are just simple examples of all the stuff that's possible. Messing with the output buffer is really a great thing, and I love doing it, just because you can do so much funky things with it. There are a few caveats though, and the biggest one is that it contains a few bugs here there (e.g. the one I linked above). Also, output buffering can make your website appear to be downloading slower. You should also watch out when using a custom output handler and ob_gzhandler together as it gives problems (I'll talk more about that in a future entry).

For now, start messing with that output buffer, and come up with creative applications. If you find anything good, don't forget to e-mail me, because I'm always interested!

Leave a Reply