<?
/*
  BZCompressor:
  
  Demonstrates how to compress a chunked stream of output data on the fly and then send compressed
  chunks out as they are ready.
  
  This can be used with ob_start to catch all output of the script. When combined with a chunk_size
  parameter, you can have PHP output data as its buffer fills.
  
  For this to work in your installation, you must apply the patch to PHP's bzip2.compress-Filter
  I posted here <http://bugs.php.net/bug.php?id=42117> because the default implementation at least
  until PHP-5.2.3 had a bug in handling the ending of the bz2-stream.
  
  This junk of code is (c) 2007 by Philip Hofstetter <phofstetter@sensational.ch> and licensed
  under the new BSD license without advertising clause.
  
  Not the useage of a temporary file. I would loved to have done it without, but it seems
  like there's no way to get bzip2.compress to write a bz2-stream end to the stream it's 
  attached to but to use fclose(), so I need the file to get the last chunk of data.
*/

class BZCompressor{
    private 
$_name;
    private 
$_handle_write;
    private 
$_handle_read;
    private 
$pos 0;
    
    public function 
startOutput(){
        
$this->_name tempnam(sys_get_temp_dir(), 'bzcomp');
        
$this->_handle fopen($this->_name'w+');
        
stream_filter_append($this->_handle'bzip2.compress'STREAM_FILTER_WRITE, array('blocks' => 9'work' => 0));
        
$this->pos 0;        
    }
    

    public function 
outputHandler($data$state){
        if ( (
$state PHP_OUTPUT_HANDLER_START) == PHP_OUTPUT_HANDLER_START$this->startOutput();
        
fputs($this->_handle$data);
        if ( (
$state PHP_OUTPUT_HANDLER_END) == PHP_OUTPUT_HANDLER_END){
             
fclose($this->_handle);        
             
$this->_handle fopen($this->_name'r');
         }
        
$data "";
        
fseek($this->_handle$this->posSEEK_SET);
        while(!
feof($this->_handle)){
            
$t fread($this->_handle4096);
            
$this->pos += strlen($t);
            
$data .= $t;
        }
        if ( (
$state PHP_OUTPUT_HANDLER_END) == PHP_OUTPUT_HANDLER_END){
            
fclose($this->_handle);
            
unlink($this->_name);
        }
        return 
$data;        
    }
}

/* Usage-Sample: */

$str "BEGIN (%d)\nLorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\nEND (%d)\n";

$c = new BZCompressor();
/* 
Please note that the small chunk_size of 16384 bytes is not recommended
but for demonstration purposes. Using such a small buffer causes some
considerable loss of performance.

Personally, I would go with something around 50K
*/
ob_start(array($c'outputHandler'), 16384);
for(
$x 0$x 10000$x++)
    
printf($str$x$x);
ob_end_flush();

/* 
If you want to work WITHOUT the temporary file and are ready to live
with changes to all your output code and relay on something I'd
probably call a hack, you can use the sample code below for 
instant-gratification :-)

This also has the advantage of buffering that works better for the
bzip library because you don't have to manually specify a buffer size.
This makes me think that the overall compression rate and performance
of this solution both are better, but it relies on the idea to
fopen() the already open PHP-output-stream which I don't actually know
if it's a legal thing to do.

Note that this, too, requires the bug in bzip2.compress to be
fixed in your PHP installation because the bug causes the internal
bzlib buffer not to be flushed out on fclose()

------
$fh = fopen('php://output', 'w');
stream_filter_append($fh, 'bzip2.compress', STREAM_FILTER_WRITE, $param);
for($x = 0; $x < 10000; $x++)
    fprintf($fh, $str, $x, $x);
fclose($fh);

------

*/
?>