ONLamp.com    
 Published on ONLamp.com (http://www.onlamp.com/)
 See this if you're having trouble printing code examples


Session Tracking: Part 2

by W.J. Gilmore
05/10/2001

As you learned in the last article, session tracking can add a whole new dimension to your web site. This week, I'll build upon what we learned, and show you how to create custom functions to store user session data. However, before delving further into how these functions are created, let's take a moment to ask why we would want to do this in the first place.

Why would it be necessary to create custom functions instead of using the default file method offered by PHP? Among other things, it facilitates the use of a database for storing session data. Database storage of session data is useful not only for reasons of efficiency, but also because it allows session information to be easily retrieved across different networks and domains.

Configuration

If you remember from the last article, session information is stored by default within separate files -- one file for each session identification (SID) number. There are also two other methods in which session information can be stored: shared memory and via creation of the custom storage functions. I'll discuss configuration of the latter method in this section.

Open your php.ini file and locate the directive:

session.save_handler = files ; handler used to store/retrieve data

To make use of the custom storage functions that I'll create later on in this article, session.save_handler should be set as follows:

session.save_handler = user ; handler used to store/retrieve data

This tells the PHP engine that you intend to define your own session storage functions. We'll get to exactly how this is accomplished later.

The functions

Regardless of what storage media you intend to use, there are six functions that must be defined. These six functions perform the operations required by the PHP engine to carry out its session-handling functionality. I'll define each function's purpose and parameters here:

session_open($session_save_path, $session_name)
The function session_open() simply initializes any elements that may be used throughout the sessions process. The two input parameters $session_save_path and $session_name refer to the configuration directives found in the php.ini. We'll use PHP's get_cfg_var() function to retrieve these configuration values in later examples.

session_close()
The function session_close() operates much like a typical handler function does, closing any open resources initialized by session_open(). As you can see, there are no input parameters for this function. Keep in mind that this does not destroy the session. That is the job of session_destroy(), introduced later in this section.

session_read($sessionID)
This function reads the session data from the storage media. The input parameter $sessionID refers to the session ID that will be used to identify the data stored for this particular client.

session_write($sessionID, $value)
This function writes the session data to the storage media. The input parameter $sessionID is the variable name, and the input parameter $value is the session data.

session_destroy($SID)
This function is likely the last function you'll call in your script. It will destroy the session and all relevant session variables. The input parameter $SID refers to the session ID in the currently open session.

session_garbage_collect($lifetime)
This function effectively deletes all sessions that have expired. The input parameter $lifetime refers to the session configuration directive session.gc_maxlifetime, found in the php.ini file.

Once these functions are defined, you then need to tie them into the PHP session-handling logic. This is accomplished by passing their names into PHP's predefined session_set_save_handler() function. For example, assuming that the custom function names are those shown above, you would define them as custom storage handlers as seen below:

session_set_save_handler("session_open", "session_close", 
                         "session_read", "session_write", 
            "session_destroy", "session_garbage_collect");

Keep in mind that you can choose function names to be whatever you wish. What's important is that:

MySQL session-storage functionality

Thus far, I've defined the requirements as specified by PHP's user-defined session functionality. This information can then be applied to the media in which you would like to handle session data. In this section, I'll show you how this is accomplished with the popular MySQL database server.

Before creating the functions, the database table should be created. Listing 1 displays the table as I've created it. Depending on the level of activity you expect regarding the sessions table, you may also wish to create a database specifically for the sessions table. However, I'll leave that detail to you.


Listing 1: A MySQL session storage table

mysql>CREATE TABLE SessionsTable (
    ->SID char(32) NOT NULL,
    ->expiration INT NOT NULL,
    ->value TEXT NOT NULL,
    ->PRIMARY KEY(SID) );

Listing 2 shows the MySQL handler functions. I've defined these functions in the same order in which they were introduced in the previous section. Please take some time to study the function syntax and accompanying comments.


Listing 2: The MySQL session-storage library

(<code>mysql_sessions.inc</code>)</p>

<?

// Session Table

$sess_table = "SessionsTable";

// Retrieve the session maximum lifetime (found in php.ini)

$lifetime = get_cfg_var("session.gc_maxlifetime");

//=============
// function: mysql_session_open()
// purpose: Opens a persistent server connection and selects the
//    database.
//=============

mysql_session_open($session_path, $session_name) {

  mysql_pconnect("localhost", "myusername", "mysecretpassword")
         or die("Can't connect to MySQL server! ");

  mysql_select_db("sessions_database")
         or die("Can't select MySQL sessions database");

} // end mysql_session_open()

//=============
// function: mysql_session_close()
// purpose: Doesn't actually do anything since the server connection is
//    persistent. Keep in mind that although this function
//    doesn't do anything in my particular implementation, I
//    still must define it.
//=============

mysql_session_close() {

  return 1;

} // end mysql_session_close()

//=============
// function: mysql_session_select()
// purpose: Reads the session data from the database
//=============

mysql_session_select($SID) {

  GLOBAL $sess_db;
  GLOBAL $sess_table;

  $query = "SELECT value FROM $sess_table
      WHERE SID = '$SID' AND
      expiration > ". time();

  $result = mysql_query($query);

} // end mysql_session_select()

//=============
// function: mysql_session_write()
// purpose: This function writes the session data to the database. If that SID // already exists, then the existing data will be updated.
//=============

mysql_session_write($SID, $value) {

  GLOBAL $sess_db;
  GLOBAL $sess_table;
  GLOBAL $lifetime;

  $expiration = time() + $lifetime;

  $query = "INSERT INTO $sess_table
      VALUES('$SID', '$expiration', '$value')";

  $result = mysql_query($query, $sess_db);

  if (! $result) :

   $query = "UPDATE $sess_table SET
       expiration = '$expiration',
       value = '$value' WHERE
       SID = '$SID' AND expiration >". time();

   $result = mysql_query($query, $sess_db);

  endif;

} // end mysql_session_write()

//=============
// function: mysql_session_destroy()
// purpose: deletes all session information having input SID (only one row)
//=============

mysql_session_destroy($sessionID) {

  GLOBAL $sess_table;

  $query = "DELETE FROM $sess_table
      WHERE SID = '$sessionID'";
  $result = mysql_query($query);

} // end mysql_session_destroy()

//=============
// function: mysql_session_garbage_collect()
// purpose: deletes all sessions that have expired.
//=============

mysql_session_garbage_collect($lifetime) {

  GLOBAL $sess_table;

  $query = "DELETE FROM $sess_table
      WHERE sess_expiration < ".time() - $lifetime;
  $result = mysql_query($query);

  return mysql_affected_rows($result);

} // end mysql_session_garbage_collect()

?>


Once I've defined these functions, I can then include the library within another script and call the session_set_save_handler() function, which acts to tie the MySQL functions into PHP's session-handling functionality. Listing 3 is a script showing you how this function is used to integrate the MySQL functions.


Listing 3: Using session_set_save_handler() to integrate the MySQL functions

<?
INCLUDE("mysql_sessions.inc");

session_set_save_handler("mysql_session_open", "mysql_session_close",
  "mysql_session_select", "mysql_session_write",
  "mysql_session_destroy",
  "mysql_session_garbage_collect");

session_start();

// At this point, sessions can be used just as they were in the
// previous article!

?>


Conclusion

This wraps up this week's article, and also the conclusion of the two-part series on session tracking. The first article demonstrated how sessions can provide an invaluable addition to your Internet application, allowing for data to transparently follow a user. This article built upon what was learned in the first article, showing how it's possible to quickly create your own interface to the session functionality, making it possible to handle data via any PHP-supported media.

Next week, I turn my attention toward PHP's encryption capabilities, showing you how PHP's vast functionality can be used in collaboration with several of the most advanced encryption algorithms in the world.

W.J. Gilmore has been developing PHP applications since 1997, and is frequently published on the subject within some of the Web's most popular development sites. He is the author of 'A Programmer's Introduction to PHP 4.0' (January 2001, Apress), and is the Assistant Editorial Director of Web and Open Source Technologies at Apress.


Return to the PHP DevCenter.

Copyright © 2009 O'Reilly Media, Inc.