An Object-based Approach to HTTP Compression in PHP

Welcome to the second tutorial of the series “Using HTTP compression in PHP.” In three parts, this series demonstrates how to apply HTTP compression to parsed PHP pages, in order to reduce their overall download times, which results in faster delivery of dynamic content.

Introduction

Over the first tutorial of this series, I developed some hands-on examples, aimed at illustrating how “Gzip” encoding can be used within PHP scripts to compress the output generated by dynamic PHP pages. After transferring the encoded data to the client, contents are uncompressed and finally displayed on the browser.

As you probably recall, the data encoding/decoding process that I just described  was performed by a combination of the PHP built-in “gzencode()” function and some output buffering functions. These became extremely handy for storing temporarily the dynamic output of parsed PHP files and applying “Gzip” encoding on the respective data. Indeed, output buffering control can be used as a simple mechanism for implementing different kinds of post-processing on parsed data, such as caching (X)HTML output, or compressing dynamic pages, to name a few popular applications.

Now that the data compression methods shown in the previous article are hopefully familiar concepts to you, it’s time to move toward the implementation of HTTP compression within object-oriented PHP applications, particularly, for obvious reasons, on those whose output include some sort of (X)HTML rendering process.

By the end of this article, you should have the appropriate knowledge for building a simple data compressor class, in addition to using HTTP compression for reducing the download time of object-generated web pages. I’m sure the subject is quite interesting to you, so let’s dive into the topic together.

{mospagebreak title=Object-based “Gzip” compression: creating a data compressor PHP class}

Before I make a data compressor class that internally uses “Gzip” encoding for compressing the data passed as input argument, first let me list the “getCompressedContent()” function that I wrote in the previous tutorial, to refresh your memory of how this function looked. Here is its signature:

function getCompressedContent($data){
    // check if browser supports gzip encoding
    if(strstr($_SERVER[‘HTTP_ACCEPT_ENCODING’],’gzip’)){
        // start output buffer
        ob_start();
        // check to see if $data is a file
        if(file_exists($data)){
            // include file into output buffer
            include($data);
        }
        else{
            // echo string to output buffer
            echo $data;
        }
        // crunch content & compress data with gzip
        $data=gzencode(preg_replace(“/
(rn|n)/”,””,ob_get_contents()),9);
        echo ‘Hello’;
        // clean up output buffer
        ob_end_clean();
        // send http header
        header(‘Content-Encoding: gzip’);
    }
    // return data
    return $data;
}

Now, I hope the above function is pretty familiar to you, because I’m going to use it as the foundation for building the data compressor class that I mentioned before. Particularly, I’ll define this class for use in PHP 5, but you can easily adapt its source code to include it within your PHP 4 scripts. Here’s how the “DataCompressor” class looks:

// define ‘DataCompressor’ class
class DataCompressor{
    private $data;
    public function __construct($data){
        if(!file_exists($data)||!is_string($data)){
            throw new Exception(‘Invalid input data’);
        }
        $this->data=$data;
    }
    public function fetchCompressedData(){
        // check if browser supports gzip encoding
        if(strstr($_SERVER[‘HTTP_ACCEPT_ENCODING’],’gzip’)){
            // start output buffer
            ob_start();
            // check to see if $data is a file
            if(file_exists($this->data)){
                // include file into output buffer
                include($this->data);
            }
            else{
                // echo string to output buffer
                echo $this->data;
            }
            // crunch content & compress data with gzip
            $this->data=gzencode(preg_replace(“/
(rn|n)/”,”,ob_get_contents()),9);
            // clean up output buffer
            ob_end_clean();
            // return data
            return $this->data;
        }
        return false;
    }
    public function sendEncodingHeader(){
        header(‘Content-Encoding: gzip’);
    }
}

As I said earlier, I wrote the above class inspired by the source code of the previous “getCompressedContent()” function, something that should be quite obvious. As you can see, the workhorse of the class is the “fetchCompressedData()” method, which is very similar to its procedural counterpart. In this case, this method opens up an output buffer, then includes the contents of the $this->data property, and finally returns the “gzip-encoded” data, after cleaning up the respective buffer.

Additionally, the class constructor accepts the mentioned $data incoming argument, which is properly checked inside this method to make sure it’s either a file or a simple string. Any other type of data passed on to the constructor will throw an exception, which eventually will be caught by client code.

Finally, I decided to define separately the “sendEncodingHeader()” method, providing the class with the ability to send this HTTP header when the method is specifically called. Definitely, breaking down the class code into different specific methods helps keep the whole class as a much more flexible programming structure.

Right, now that I’ve shown you the signature of the “DataCompressor” class, you’ll probably want to see how it can be used within a basic sample PHP script. For this reason, jump into the next section, so you can learn how this class is utilized as part of a pretty useful hands-on example.

{mospagebreak title=Setting up a concrete example: putting the “DataCompressor” class to work}

In order to demonstrate in a friendly way how the “DataCompressor” class can be used within an object-oriented development environment, I’ll use the same “sample_file.php” file that you saw in my previous tutorial. As you’ll recall, it displayed some rows from a “users” database table. In addition, I’ll list the two MySQL processing classes used by this sample file. The example begins by showing both MySQL-related classes:

// define ‘MySQL’ class
class MySQL{
    private $host;
    private $user;
    private $password;
    private $database;
    private $connId;
    // constructor
    function __construct($options=array()){
        if(!is_array($options)){
            throw new Exception(‘Connection options must be an
array’);
        }
        foreach($options as $option=>$value){
            if(empty($option)){
                throw new Exception(‘Connection parameter cannot
be empty’);
            }
            $this->{$option}=$value;
        }
        $this->connectDb();
    }
    // private ‘connectDb()’ method
    private function connectDb(){
        if(!$this->connId=mysql_connect($this->host,$this-
>user,$this->password))
{
            throw new Exception(‘Error connecting to MySQL’);
        }
        if(!mysql_select_db($this->database,$this->connId)){
            throw new Exception(‘Error selecting database’);
        }
    }
    // public ‘query()’ method
    public function query($sql){
        if(!$result=mysql_query($sql)){
            throw new Exception(‘Error running query ‘.$sql.’
‘.mysql_error());
        }
        return new Result($this,$result);
    }
}
// define ‘Result’ class
class Result{
    private $mysql;
    private $result;
    // constructor
    public function __construct($mysql,$result){
        $this->mysql=$mysql;
        $this->result=$result;
    }
    // public ‘fetch()’ method
    public function fetch(){
        return mysql_fetch_array($this->result,MYSQL_ASSOC);
    }
    // public ‘count()’ method
    public function count(){
        if(!$rows=mysql_num_rows($this->result)){
            throw new Exception(‘Error counting rows’);
        }
        return $rows;
    }
    // public ‘get_insertId()’ method
    public function getInsertId(){
        if(!$insId=mysql_insert_id($this->mysql->connId)){
            throw new Exception(‘Error getting insert ID’);
        }
        return $insId;
    }
    // public ‘seek()’ method
    public function seek($row){
        if(!int($row)&&$row<0){
            throw new Exception(‘Invalid row parameter’);
        }
        if(!$row=mysql_data_seek($this->mysql->connId,$row)){
            throw new Exception(‘Error seeking row’);
        }
        return $row;
    }
    // public ‘getAffectedRows()’ method
    public function getAffectedRows(){
        if(!$rows=mysql_affected_rows($this->mysql->connId)){
            throw new Exception(‘Error counting affected rows’);
        }
        return $rows;
    }
    // public ‘getQueryResource()’ method
    public function getQueryResource(){
        return $this->result;
    }
}

Now that you’ve hopefully recalled how the above MySQL processing classes looked, it’s time to list the corresponding “sample_file.php” file. Here’s the respective definition for this file:

try{
    // include class files
    require_once ‘mysqlclass.php’;
    require_once ‘resultclass.php’;
    // connect to MySQL
    $db=new MySQL(array
(‘host’=>’host’,’user’=>’user’,’password’=>’password’,
‘database’=>’database’));
    // run SQL query
    $result=$db->query(‘SELECT * FROM users’);
    // display results
    while($row=$result->fetch()){
        echo $row[‘id’].$row[‘name’].$row[’email’].'<br />’;
    }
}
catch(Exception $e){
    echo $e->getMessage();
    exit();
}

As the above example clearly shows, the “sample_file.php” file first includes the corresponding MySQL processing classes, in order to connect to the MySQL server, and then performs a simple SELECT statement to fetch a few rows from a sample “users” database table. Once the database rows have been returned by the query, they’re simply displayed on the browser, as one expects when proceeding with a regular MySQL result set.

Of course, since I’m currently using PHP 5 as my testing platform, the whole code is wrapped by a single “try-catch” block, in order to trap all the potential exceptions that could eventually be triggered by the different sections of the script. As you can see, all the tasks performed by the “sample_file.php” file are very understandable.

Now that you clearly understand how the previous sample file works, take a look at the following piece of code, which demonstrates a practical implementation for the “DataCompressor” class:

try{
    // instantiate a new ‘DataCompressor’ object
    // pass the ‘sample_file.php’ file in order to compressing
its dynamic output
    $dataComp=new DataCompressor(‘sample_file.php’);
    // send Gzip http header
    $dataComp->sendEncodingHeader();
    // uncompress & display data
    echo $dataComp->fetchCompressedData();
}
// catch all possible exceptions
catch(Exception $e){
    echo $e->getMessage();
    exit();
}

If you study the example shown above, then you’ll definitely agree with me that using the “DataCompressor” class is really a simple and straightforward process.

{mospagebreak title=Explaining the example}

First, the script instantiates a new “DataCompressor” object, and secondly passes the sample PHP file that you just saw to the constructor. Since the source code of the “fetchCompressedData()” method will include this file after opening an output buffer, its whole dynamic output will be first “crunched” (that is, all new line characters will be removed) and finally compressed by the “Gzip” encoding algorithm.

Before the data is actually encoded, the script calls the “sendEncodingHeader()” method, in this way indicating to the browser that contents will be transmitted compressed over the network. At the end of the script execution, the data is transparently decoded by the browser, and finally displayed to the user.

As you can see, the whole data compression/decompression process is handled by the “DataCompressor” class in combination with the corresponding user agent, which means that using HTTP compression to make dynamic PHP pages load faster is quite easy to implement in several PHP scripts.

To wrap up

Unfortunately, that’s all for the moment. Throughout this second part of the series, I demonstrated how to use HTTP compression in object-based development environments, by creating a data compressor class in PHP 5. As you learned in the article, this class utilizes a few simple methods for fetching incoming data, and then returns the contents properly compressed. Additionally, it allows you to send the corresponding HTTP header using a separate method, which makes the class even more flexible. Thus, if you feel inclined to extend its functionality, go ahead and develop a full-featured HTTP compression system.

In the last article of the series, I’ll explain how to take advantage of HTTP compression within a PHP web page generator system, which uses objects to create dynamic web documents. Curious about how this will be achieved? You’ll have to wait till the next part!

[gp-comments width="770" linklove="off" ]

chat sex hikayeleri Ensest hikaye