Articles

The month of PHP functions : home made serialisation

  • Ecrit par Damien Seguy
  • lundi 23 avril 2007
Image pour le titre du contenu

Ce document est aussi disponible en français fr 


It is well known that session hates resources. If ever you put one resource, such as a MySQL connection, you'll get back a string, and a nasty one. With PHP 5, you'll get a fatal error, more consistent with PHP unability to restaure the actual value.
The problem start with the fact tha t sessions will store data as files, or text in general, and they must turn the internal representation of all data into a string. For numbers, arrays or objects, this is easy enough. For ressources, it is much more difficult, like with PDF objects, or even just impossible, like a MySQL connexion.

However, all hope is not lost. Indeed, if it is always impossible to serialize a ressource, we always have the possibility to fake it. And this is where the two magical PHP methods __sleep() et __wakeup() become so handy.

__sleep() will be called automagically when PHP serialize the object. It will give a hook to tidy the resource and ready it for storing. On the other hand, __wakeup() will be called upon loading, and will be the place to restore all information as needed.

Let's take an example. The followin object handle a MySQL connection : the class was stripped down ot its bare minimum.

<?php
 
class myDB  {
    function __construct() {
        $this->res = mysqli_connect('localhost','user','pass','base');
    }
    
    function __sleep() {
        mysqli_close($this->res);
        return array();
    }
 
    function __wakeup() {
        $this->__construct();
    }
}
 
$myBase = new myDB();
 
$x = serialize($maBase);
 
$y = unserialize($x);
 
>


Here, take two notes : we have presented those two magic methods as linked to sessions. In fact, they are linked to the functions serialize() and unserialize(), which are called by sessions. It is actually possible to use them outside any session scope.

Besides that, __sleep() must return an array, with the list of object members which will be saved. All other members will be omitted. If__sleep() return NULL, the whole object will not be saved.

What to do with  __sleep() and __wake() ?
  The example above showed how to keep a MySQL connection open between two scripts. Now, you may store any MySQL connexion in a session, and never think about opening it ever again : sessions will do it for you. Here are some other usage of those functions.

Protéger les données de sessions en les chiffrant
<?php
 
class myClass  {
    function __construct() {
        $this->clear = 'php';
    } 
    
    function __sleep() {
        $this->crypted = str_rot13($this->clear);
        return array('crypted');
    }
 
    function __wakeup() {
        $this->clear = str_rot13($this->crypted);
        unset($this->crypted);
    }
}
 
$myClass = new myClass();
 
print $x = serialize($myClass);
 
$y = unserialize($x);
 
>

Note : please, use a more robust algorithm than ROT13, and a stealthier name than 'crypted'.

Signing session values

<?php
 
class myClass  {
    function __construct() {
        $this->a = 'b';
        $this->c = 'd';
    } 
    
    function __sleep() {
        $membres = get_object_vars($this);
        $this->signature = md5('S4lT'.join('|', array_values($membres)));
        $sauve = array_keys($membres);
        $sauve[] = 'signature';
        return $sauve;
    }
 
    function __wakeup() {
        $membres = get_object_vars($this);
        $signature = $membres['signature'];
        unset($membres['signature']);
 
        $test = md5('S3l'.join('|', array_values($membres)));
        if ($test != $signature) {
            print "Beware : those data have been modified";
        }
    }
}
 
 
$myClass = new myClass();
 
 
 
print $x = serialize($myClass);
 
 
 
$y = unserialize($x);
 
 
 
?>


Reducing data size
Use the native PHP functions, such as gzip, bzip2 or zip, to reduce the size of data when storing them on the disque. Less data to the disk, means more performance.

<?php
 
class myClass  {
    function __construct() {
        $this->a = str_repeat('abc', 1000);
        $this->primes = array(2,3,5,7,11,13,17,19);
    } 
    
    function __sleep() {
        $membres = get_object_vars($this);
        $this->compresse = bzcompress(serialize($membres));
        return array('compresse');
    }
 
    function __wakeup() {
        $membres = unserialize(bzdecompress($this->compresse));
        unset($this->compresse);
        foreach($membres as $nom => $valeur) {
            $this->$nom = $valeur;
        }
        $this->primes = array(2,3,5,7,11,13,17,19);
    }
}
 
$myClass = new myClass();
 
$x = serialize($myClass);
$y = unserialize($x);
>

You may also compress data by simply reprocessing data. In the above example, there is no need to store the primes array, as we have other means to reinitialize it again. No data is the best compression ever.

Keep in mind

  • All methods starting with __ are magical methods. There are quite a load of new one in PHP 5, but _sleep() and __wakeup() were already here in PHP 4.
  • __sleep() and __wakeup() are mainly here to clean up the data and get ready for storage. If you're clean too thourouhgly, you're probably hurting your system.
  • Those functions are separae from the custom session handler, but theyr work hand in hand with it.
  • Don't use serialize() with data that will go out of the server, and transit via the browser
< Précédent   Suivant >

Commentaires

Vous pouvez ajouter votre commentaire!


Vous devez vous connecter pour commenter