# ADODB Session 2 Management Manual

V4.98 13 Feb 2008 (c) 2000-2008 John Lim (jlim#natsoft.com.my)

This software is dual licensed using BSD-Style and LGPL. This means you can use it in compiled proprietary and commercial products.

Useful ADOdb links: Download Other Docs

## Introduction

This document discusses the newer session handler adodb-session2.php. If you have used the older adodb-session.php, then be forewarned that you will need to alter your session table format. Otherwise everything is backward compatible. Here are the older docs for adodb-session.php.

## Why Session Variables in a Database?

We store state information specific to a user or web client in session variables. These session variables persist throughout a session, as the user moves from page to page.

To use session variables, call session_start() at the beginning of your web page, before your HTTP headers are sent. Then for every variable you want to keep alive for the duration of the session, call session_register($variable_name). By default, the session handler will keep track of the session by using a cookie. You can save objects or arrays in session variables also.

The default method of storing sessions is to store it in a file. However if you have special needs such as you:

- Have multiple web servers that need to share session info
- Need to do special processing of each session
- Require notification when a session expires

The ADOdb session handler provides you with the above additional capabilities by storing the session information as records in a database table that can be shared across multiple servers.

These records will be garbage collected based on the php.ini [session] timeout settings. You can register a notification function to notify you when the record has expired and is about to be freed by the garbage collector.

An alternative to using a database backed session handler is to use memcached. This is a distributed memory based caching system suitable for storing session information.

## The Improved Session Handler

In ADOdb 4.91, we added a new session handler, in adodb-session2.php. It features the following improvements:

- Fully supports server farms using a new database table format. The previous version used the web server time for timestamps, which can cause problems on a system with multiple web servers with possibly inconsistent times. The new version uses the database server time instead for all timestamps.
- The older database table format is obsolete. The database table must be modified to support storage of the database server time mentioned above. Also the field named DATA has been changed to SESSDATA. In some databases, DATA is a reserved word.
- The functions dataFieldName() and syncSeconds() is obsolete.

Usage is

    include_once("adodb/session/adodb-session2.php");
    ADOdb_Session::config($driver, $host, $user, $password, $database,$options=false);
    session_start();

    #
    # Test session vars, the following should increment on refresh
    #
    $_SESSION['AVAR'] += 1;
    print "<p>\$_SESSION['AVAR']={$_SESSION['AVAR']}</p>";

When the session is created in session_start( ), the global variable $ADODB_SESS_CONN holds the connection object.

The default name of the table is sessions2. If you want to override it:

    include_once("adodb/session/adodb-session2.php");
    $options['table'] = 'mytablename';
    ADOdb_Session::config($driver, $host, $user, $password, $database,$options);
    session_start();

### ADOdb Session Handler Features

- Ability to define a notification function that is called when a session expires. Typically used to detect session logout and release global resources.
- Optimization of database writes. We crc32 the session data and only perform an update to the session data if there is a data change.
- Support for large amounts of session data with CLOBs (see adodb-session-clob2.php). Useful for Oracle.
- Support for encrypted session data, see adodb-cryptsession2.php. Enabling encryption is simply a matter of including adodb-cryptsession2.php instead of adodb-session2.php.

### Session Handler Files

There are 3 session management files that you can use:

    adodb-session2.php        : The default
    adodb-cryptsession2.php   : Use this if you want to store encrypted session data in the database
    adodb-session-clob2.php   : Use this if you are storing DATA in clobs and you are NOT using oci8 driver

## Usage Examples

To force non-persistent connections, call Persist() first before session_start():

    include_once("adodb/session/adodb-session2.php");
    $driver = 'mysql'; $host = 'localhost'; $user = 'auser'; $pwd = 'secret'; $database = 'sessiondb';
    ADOdb_Session::config($driver, $host, $user, $password, $database,$options=false);
    ADOdb_session::Persist($connectMode=false);
    session_start();

The parameter to the Persist( ) method sets the connection mode. You can pass the following:

$connectMode | Connection Method
true | PConnect( )
false | Connect( )
'N' | NConnect( )
'P' | PConnect( )
'C' | Connect( )

To use a encrypted sessions, simply replace the file adodb-session2.php:

    include('adodb/session/adodb-cryptsession2.php');
    $driver = 'mysql'; $host = 'localhost'; $user = 'auser'; $pwd = 'secret'; $database = 'sessiondb';
    ADOdb_Session::config($driver, $host, $user, $password, $database,$options=false);
    adodb_sess_open(false,false,$connectMode=false);
    session_start();

And the same technique for adodb-session-clob2.php:

    include('adodb/session/adodb-session2-clob2.php');
    $driver = 'oci8'; $host = 'localhost'; $user = 'auser'; $pwd = 'secret'; $database = 'sessiondb';
    ADOdb_Session::config($driver, $host, $user, $password, $database,$options=false);
    adodb_sess_open(false,false,$connectMode=false);
    session_start();

## Installation

1. Create this table in your database. Here is the MySQL version:

    CREATE TABLE sessions2(
    	  sesskey VARCHAR( 64 ) NOT NULL DEFAULT '',
      	  expiry DATETIME NOT NULL ,
    	  expireref VARCHAR( 250 ) DEFAULT '',
    	  created DATETIME NOT NULL ,
    	  modified DATETIME NOT NULL ,
    	  sessdata LONGTEXT DEFAULT '',
    	  PRIMARY KEY ( sesskey ) ,
    	  INDEX sess2_expiry( expiry ),
    	  INDEX sess2_expireref( expireref )
    )

For PostgreSQL, use:

    CREATE TABLE sessions2(
     sesskey VARCHAR( 64 ) NOT NULL DEFAULT '',
     expiry TIMESTAMP NOT NULL ,
     expireref VARCHAR( 250 ) DEFAULT '',
     created TIMESTAMP NOT NULL ,
     modified TIMESTAMP NOT NULL ,
     sessdata TEXT DEFAULT '',
     PRIMARY KEY ( sesskey )
     );

    create INDEX sess2_expiry on sessions2( expiry );
    create INDEX sess2_expireref on sessions2 ( expireref );

Here is the Oracle definition, which uses a CLOB for the SESSDATA field:

      CREATE TABLE SESSIONS2
    (
       SESSKEY    VARCHAR2(48 BYTE)                  NOT NULL,
       EXPIRY     DATE                               NOT NULL,
       EXPIREREF  VARCHAR2(200 BYTE),
       CREATED    DATE                               NOT NULL,
       MODIFIED   DATE                               NOT NULL,
       SESSDATA   CLOB,
      PRIMARY KEY(SESSKEY)
    );

    CREATE INDEX SESS2_EXPIRY ON SESSIONS2(EXPIRY);
    CREATE INDEX SESS2_EXPIREREF ON SESSIONS2(EXPIREREF);

We need to use a CLOB here because for text greater than 4000 bytes long, Oracle requires you to use the CLOB data type. If you are using the oci8 driver, ADOdb will automatically enable CLOB handling. So you can use either adodb-session2.php or adodb-session-clob2.php - in this case it doesn't matter.

## Notifications

You can receive notification when your session is cleaned up by the session garbage collector or when you call session_destroy().

PHP's session extension will automatically run a special garbage collection function based on your php.ini session.cookie_lifetime and session.gc_probability settings. This will in turn call adodb's garbage collection function, which can be setup to do notification.

    	PHP Session --> ADOdb Session  --> Find all recs  --> Send          --> Delete queued
    	GC Function     GC Function        to be deleted      notification      records
    	executed at     called by                             for all recs
    	random time     Session Extension                     queued for deletion

When a session is created, we need to store a value in the session record (in the EXPIREREF field), typically the userid of the session. Later when the session has expired, just before the record is deleted, we reload the EXPIREREF field and call the notification function with the value of EXPIREREF, which is the userid of the person being logged off.

ADOdb uses a global variable $ADODB_SESSION_EXPIRE_NOTIFY that you must predefine before session start to store the notification configuration. $ADODB_SESSION_EXPIRE_NOTIFY is an array with 2 elements, the first being the name of the session variable you would like to store in the EXPIREREF field, and the 2nd is the notification function's name.

For example, suppose we want to be notified when a user's session has expired, based on the userid. When the user logs in, we store the id in the global session variable $USERID. The function name is 'NotifyFn'.

So we define (before session_start() is called):

    	$ADODB_SESSION_EXPIRE_NOTIFY = array('USERID','NotifyFn');

And when the NotifyFn is called (when the session expires), the $USERID is passed in as the first parameter, eg. NotifyFn($userid, $sesskey). The session key (which is the primary key of the record in the sessions table) is the 2nd parameter.

Here is an example of a Notification function that deletes some records in the database and temporary files:

    	function NotifyFn($expireref, $sesskey)
    	{
    		global $ADODB_SESS_CONN; # the session connection object
    		$user = $ADODB_SESS_CONN->qstr($expireref);

    		$ADODB_SESS_CONN->Execute("delete from shopping_cart where user=$user");
    		system("rm /work/tmpfiles/$expireref/*");
    	}

NOTE 1: If you have register_globals disabled in php.ini, then you will have to manually set the EXPIREREF. E.g.

    $GLOBALS['USERID'] = GetUserID();
    $ADODB_SESSION_EXPIRE_NOTIFY = array('USERID','NotifyFn');

NOTE 2: If you want to change the EXPIREREF after the session record has been created, you will need to modify any session variable to force a database record update.

### Synchronizing Page Frames

Sometimes you need to load multiple pages in a frameset and make sure that the session variables are synchronized. For example we have a page frame.php with an iframe child1.php:

       frame.php
           child1.php

Assume frame.php receives some $_GET variables and it updates the $_SESSION variables in memory. However the $_SESSION variables are only updated in the database when the page ends. So is possible that child1.php will still have the old $_SESSION variables.

- $_GET variables are posted to frame.php
- frame.php updates $_SESSION variables, but not the database
- child1.php is sent to browser, using old $_SESSION variables it loads from database
- frame.php completes it's processing and saves new $_SESSION variables into database -- too late!

We can fix this by using the php function session_commit:

    <?php
    session_start();
    .
    # do any required processing...

    session_commit();

    # now session variables have been saved to the database, and child1.php will get the latest $_SESSION variables.
    ?>
    <html>
    	<body>
    	<iframe src=child1.php>
    	</iframe>
    	</body>
    </html>

### Neat Notification Tricks

ExpireRef normally holds the user id of the current session.

1. You can then write a session monitor, scanning expireref to see who is currently logged on.

2. If you delete the sessions record for a specific user, eg.

    delete from sessions where expireref = '$USER'

then the user is logged out. Useful for ejecting someone from a site.

3. You can scan the sessions table to ensure no user can be logged in twice. Useful for security reasons.

## Compression/Encryption Schemes

Since ADOdb 4.05, thanks to Ross Smith, multiple encryption and compression schemes are supported. Currently, supported are:

      MD5Crypt (crypt.inc.php)
      MCrypt
      Secure (Horde's emulation of MCrypt, if MCrypt module is not available.)
      GZip
      BZip2

These are stackable. E.g.

    ADODB_Session::filter(new ADODB_Compress_Bzip2());
    ADODB_Session::filter(new ADODB_Encrypt_MD5());

will compress and then encrypt the record in the database.

## Session Cookie Regeneration: adodb_session_regenerate_id()

Dynamically change the current session id with a newly generated one and update database. Currently only works with cookies. Useful to improve security by reducing the risk of session-hijacking. See this article on Session Fixation for more info on the theory behind this feature. Usage:

    	include('path/to/adodb/session/adodb-session2.php');

    	session_start();
    	# Approximately every 10 page loads, reset cookie for safety.
    	# This is extremely simplistic example, better
    	# to regenerate only when the user logs in or changes
    	# user privilege levels.
    	if ((rand()%10) == 0) adodb_session_regenerate_id();

This function calls session_regenerate_id() internally or simulates it if the function does not exist.

## Vacuum/Optimize Database

During session garbage collection, if postgresql is detected, ADOdb can be set to run VACUUM. If mysql is detected, then optimize database could be called.You can turn this on or off using:

    $turnOn = true; # or false
    ADODB_Session::optimize($turnOn);

The default is optimization is disabled.

## Backwards Compatability

The older method of connecting to ADOdb using global variables is still supported:

     $ADODB_SESSION_DRIVER='mysql';
     $ADODB_SESSION_CONNECT='localhost';
     $ADODB_SESSION_USER ='root';
     $ADODB_SESSION_PWD ='abc';
     $ADODB_SESSION_DB ='phplens';

     include('path/to/adodb/session/adodb-session2.php');

In the above example, the only things you need to change in your code to upgrade is

- your session table format to the new one.
- the include file from adodb-session.php to adodb-session2.php.

## More Info

Also see the core ADOdb documentation. And if you are interested in the obsolete adodb-session.php, see old session documentation.