picture of Ying Zhang
This document describes how to customize the session handlers in PHP4. We will provide examples of how to write a fully functional session handler that works with DBM files and one that works with a MySQL database.

New to PHP4 was a set of native session handling functions which was badly missing from PHP3. By default, each session is stored as a separate file in your temporary directory (eg. /tmp in Unix). This may or may not be appropriate depending on your requirements. For example, if you have a bunch of web/PHP servers on different machines, you can't easily share sessions between them (well you could save the sessions on an NFS share but that would be slow). Another problem is that you potentially have thousands or even millions of session files cluttering up your file system (you run a big site right <grin>).

Fortunately for us, the developers of PHP4 were forward thinking enough (thanks!) to provide the ability for users like you and me to extend the session handling routines.
This document is written to explain these session handlers a bit and to provide two working examples of how you can extend the session handlers. Our first example will be to make the session handlers save session data into DBM files. Our second example will have our sessions save into a MySQL database.
Before you proceed, download the attachment and extract it into your web document directory.

Session Handler Functions

Any custom session handler we write will have to provide 6 basic functions, they get called by the PHP4 session handler so you do not need to worry about calling them yourself. The nice thing about all this is that your custom session handler functions are completely transparent, so you can change them without affec
The functions are are:
  1. sess_open($sess_path, $session_name);
    This function is called by the session handler to initialize things. The two parameters passed to it are $sess_path, which corresponds to the session.save_path setting in your php.ini file, and $session_name which corresponds to the session.name setting in your php.ini file. More on the duties of this function when we go into specific examples.

  2. sess_close();
    This function is called when to when the page is finished executing and the session handler needs to close things off. (Note, do not confuse this with sess_destroy(), which is called to kill the session).

  3. sess_read($key);
    This function is called by the session handler to read the data associated with a given session key ($key). This function must retrieve and return the session data for the session identified by $key. (Note: you do not have to worry about serializing and unserializing data, if you do not know what this means, then don't worry about it).

  4. sess_write($key, $val);
    This function is called when the session handler has session data to save, which usually happens at the end of your script. It is responsible for saving the session data in such a way that it can be retrieved later on by sess_read($key).

  5. sess_destroy($key);
    This function is called when a session is destroyed. It is responsible for deleting the session and cleaning things up.

  6. sess_gc($maxlifetime);
    This function is responsible for garbage collection. In the case of session handling, it is responsible for deleting old, stale sessions that are hanging around. The session handler will call this every now and then.

So now we know what functions we have to provide, they don't necessarily have to be given those names but they have to accept those parameters (whether you need them or not).

A DBM Session Handler

Our first example is to write a customized session handler to save session data into a DBM file. (This is the session_dbm.php file from ying20000602.zip.) There are many reasons why you might want to do this, for example, if you were on a shared server from your ISP and you did not want your sessions mixing with those from their other client's scripts.
IMPORTANT NOTE:
You must have DBM support in your PHP4 before you try this. If you do not things can get ugly, real ugly!
The approach we are going to take is to have one DBM file that stores all the session data (in case you don't know, a DBM file is like a very simple database that only holds key/value pairs). To fit this into the 6 functions:
  1. sess_open($sess_path, $session_name);
    We will open the DBM file in read/write mode by calling dbmopen(). The name of our DBM file will be /tmp/PHPSESSID unless you've modified the session path and name settinsg in your php.ini file.

  2. sess_close();
    In this function, we are simply going to close the DBM file properly by calling dbmclose().

  3. sess_read($key);
    Here we just call dbmfetch() to load up the session data associated with the session key. When loading up a session, it is necessary to make sure I'm not reading something that's been expired, so we will attach a timestamp to the session.

  4. Why? So that incase it has expired, but hasn't been removed out for whatever reason, we don't accidentally read in expired data. This would be a big no-no!
    We know that DBM only stores key/value pairs, so we have to glue the timestamp onto the value when writing the session data, and extract it when reading in the session data. Any session who's timestamp has been expired will be ignored. See the source code, it will make more sense there.

  5. sess_write($key, $val);
    To write a session, we will use the dbmreplace() function. Note from above that we want to save an expiry timestamp on the session, so we will attach it to the value.

  6. sess_destroy($key);
    Destroying a session is easy, we just call dbmdelete() to remove it from the session file.

  7. sess_gc($maxlifetime);
    Garbage collection is a bit nasty and intensive here, what we must do is loop through all the sessions that we've saved in our DBM file and delete the ones that have expired. This can be slow because we must loop through all the sessions stored in the file.

So now we've got a DBM session handler, cool! Now let's get these sessions stored in a MySQL database.

A MySQL Session Handler

Our next example is to write a customized session handler to save session data into a MySQL database. (This is the session_mysql.php file from ying20000602.zip.) You would want sessions stored in a database when you have lots of web/PHP servers and you need to share session between them (eg. if you are serving so many users that you need load balancing). You have a bunch of machines doing web/PHP stuff, a machine serving your normal database needs, and another machine running a MySQL database to handle sessions. But that might be overkill for most people :)
IMPORTANT NOTE:
You must have MySQL support in your PHP4 before you try this. If you do not things can get ugly, real ugly!
First let's create a session database in MySQL, and then the table to create the session table. Fire up your MySQL client and issue these commands:
mysql> CREATE DATABASE sessions;

mysql> GRANT select, insert, update, delete ON sessions.* TO phpsession@localhost
    -> IDENTIFIED BY \'phpsession\';

mysql> CREATE TABLE sessions (
    ->     sesskey char(32) not null,
    ->     expiry int(11) unsigned not null,
    ->     value text not null,
    ->     PRIMARY KEY (sesskey)
    -> );
	
Next, modify the $SESS_DB* variables in the session_mysql.php file to match your database setup. Make sure it all looks okay before you continue.
Our 6 functions will now work against a MySQL database:
  1. sess_open($sess_path, $session_name);
    We need to connect to the MySQL database here using mysql_pconnect(), and then selecting the session database using mysql_select_db(). The $sess_path and $session_name parameters are irrelevant but we have to keep them.

  2. sess_close();
    We are opening a persistent connection to MySQL so we don't do anything in this function.

  3. sess_read($key);
    A simple SELECT statement will do the trick, we want to read the session data for the given key, and we can specify that the expiry timestamp must be in the future.

  4. sess_write($key, $val);
    Writing a session is a little bit trickier. We first try to save the session into the database using an INSERT statement. If that fails (from a Primary Key constraint) then that means the key already exists, so then we have to write an UPDATE statement instead.

  5. sess_destroy($key);
    Destroying a session is easy, we just delete the session key from the database.

  6. sess_gc($maxlifetime);
    Garbage collection is easy as well, we just have to delete all the expired sessions (where the expiry timestamp is in the past) from the database.

Now we've got a MySQL session handler, pretty easy wasn't it?

Conclusion

This concludes this little tutorial, hopefully you have a good feel for how to extend the session handling functions in PHP4. The examples here are just simple ones to demonstrate how you would do it, extend them to accomodate your needs and if you find any bugs, please let me know :)