The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

NAME

Apache::Session - Maintain session state across HTTP requests

SYNOPSIS

  use Apache::Session::Win32; # use a global hash on Win32 systems
  use Apache::Session::DBI;   # use a database for real storage
  use Apache::Session::File;  # or maybe an NFS filesystem
  use Apache::Session::IPC;   # or an IPC shared memory block
  
  # setup the session options
  $opts = { autocommit => 0,
            lifetime   => 60
          };
          
  # Create a new unique session.
  $session = Apache::Session::Win32->new( $opts );

  # fetch the session ID
  $id      = $session->{ '_ID' };
 
  # open an old session, or undef if not defined
  $session = Apache::Session::Win32->open( $id, $opts );

  # store data into the session (can be a simple
  # scalar, or something more complex).
  
  $session->{ 'foo' } = 'Hi!';
  $session->{ 'bar' } = { complex => [ qw(list of settings) ] };
  
  $session->store();  # write to storage

DESCRIPTION

This module provides the Apache/mod_perl user a mechanism for storing persistent user data in a global hash, which is independent of its real storage mechanism. Apache::Session provides an abstract baseclass from which storage classes can be derived. Existing classes include:

    Apache::Session::DBI
    Apache::Session::Win32
    Apache::Session::File
    Apache::Session::IPC

CHOOSING A SUBCLASS

Before you begin you will need to know what subclass you are going to use. Here are my recommendations:

Apache::Sessions::DBI is the fastest and most reliable of all the storage classes. If you have a database available, I would recommend using the DBI module. DBI sessions can be shared between different servers, running different plaforms, and they survive server shutdowns.

For Win32, Apache::Session::Win32 is a good choice if you don't need the sessions to survive a server restart. Win32 does frequent garbage collection to keep the httpd process from growing out of control. Win32 also provides run-time monitoring via Apache::Status, and is also very fast.

Apache::Session::File is useful for low-traffic servers. Unfortunately, as traffic increases performance worsens. The culprit is -e filename, which can be extremely slow in a directory with hundreds of thousands of files. Apache::Session::File does not currently do aggressive garbage collection, but this is planned. File could be used on a server farm where DBI isn't available.

Apache::Session::IPC looked promising at first, but now I don't recommend it. Maybe it is my platform (Linux 2.0.34), but IPC on my test machine is ridiculously slow. Also, IPC::Shareable will sometimes fall over under heavy load. Try to use one of the other classes if you can.

INSTALLATION

You will need to build, test, and install the MD5 module, plus one or more of FreezeThaw, Storable, DBI, and IPC::Shareable, depending on the storage subclass you intend to use. See the subclass documentation for more details.

 perl Makefile.PL
 make
 make install

ENVIRONMENT

Apache::Session will respect the environment variables SESSION_SECRET, SESSION_LIFETIME, SESSION_ID_LENGTH, and SESSION_MAX_ATTEMPTS. Derived subclasses may define their own environment variables.

SESSION_SECRET

SESSION_SECRET is fed to MD5->hexhash to generate session IDs. This is not used for security, but you should change it to reduce the possibility of someone predicting your ID sequence. The default value is "not very secret".

SESSION_LIFETIME

SESSION_LIFETIME is the default lifetime of a session object in seconds. This value can be overridden by the calling program during session creation/retrieval. If the environment variable is not set, 3600 seconds (1 hour) is used.

SESSION_ID_LENGTH

SESSION_ID_LENGTH is the number of characters in the session ID. The default is 16. Since the session IDs are hexadecimal strings, this allows for 18,446,744,079 billion concurrent sessions.

SESSION_MAX_ATTEMPTS

SESSION_MAX_ATTEMPTS is the number of times that the package will attempt to create a new session. The package will choose a new random session ID for each attempt. The default value is 5.

The relevant sections of my httpd.conf look like:

 PerlSetEnv SESSION_SECRET a%A^Djhcx6:
 PerlSetEnv SESSION_ID_LENGTH 16
 PerlSetEnv SESSION_LIFETIME 10

USAGE

Creating a new session object

 $opts = { 'subclass-specific' => 'option overrides' };
  
 $session = Apache::Session->new();  
 $session = Apache::Session->new( $opts );  
 $session = Apache::Session->new( { autocommit => 1 } );

Note that you must consult $session->{ '_ID' } to learn the session ID for persisting it with the client. The new ID number is generated afresh, you are not allowed to specify it for a new object.

$opts, if provided, must be a hash reference. See the next section for defined options.

Fetching a session object

 $session = Apache::Session->open( $id );
 $session = Apache::Session->open( $id, 
             { autocommit => 1 , lifetime => 600 } );

where $id is a session handle returned by a previous call to new(). You are free to use cookies, header munging, or extra-sensory perception to determine the session id to fetch.

The hashref of runtime options allows you to override the options that were used during the object creation. The standard options are "autocommit" and "lifetime", but your storage mechanism may define others.

Autocommit defines whether your session is update in real storage every time it is modified, or only when you call store(). If you set autocommit to 0 but do not call $session->store(), your changes will be lost. Setting autocommit to 1 may adversely effect performance.

Lifetime changes the current lifetime of the object, in seconds.

Deleting a session object

 $session->destroy();

Deletes the session from physical storage.

Storing and autocommit

 $session->store();

If you set autocommit to 0 during open() or new(), you must call $session->store() to save your changes. You can also call store() when autocommit is 1, so it might be a good idea to always call store() regardless of autocommit.

Data

 $session->{ 'varname' } = $complex_data_structure;
 $complex_data_structure = $session->{ 'varname' };
 delete $session{ 'varname' };

Hash access is the only method for storing session data. Treat the session object like a normal hash, and it will take care of the rest. Don't clobber any of the metadata (see below).

Metadata

Metadata, such as the session ID, access time, lifetime, and expiration time are all stored in the session object. Therefore, the following hash keys are reserved and should not be assigned to:

 _ID
 _EXPIRES
 _LIFETIME
 _ACCESSED
 _AUTOCOMMIT
 _LOCK

You can safely do this:

 my $id = $session->{ '_ID' };

But please don't do this:

 $session->{ '_ID' } = "Foo"; #wrong!

Other Methods

 print $session->dump_to_html();

Dumps your session hash to an HTML table.

 $session->rewrite();

Rewrite() returns a fully-qualified URL with the session ID embedded as path info. A good use for this might be:

 print "<a href=".$session->rewrite().">Click Here</a>"

SUBCLASSING

The Apache::Session module allows you to use the included implementations, but also makes it easy to subclass. Just ensure that your subclass includes each of the following functions:

$class->fetch( $id )

Performs the very basic physical fetch operation. This is used by open(). Fetch should return a hash reference, or undef on failure.

$class->create( $id )

Creates a session, with the given id, in the physical storage. Create() should do some garbage collections, also. If a request is made to create an object with an ID which is already taken, create() should check to see whether the existing object is expired, and do the right thing. Create() should return a hashref, or undef on failure.

$class->options()

Returns a hashref of options for your physical session storage, which the superclass will merge with the global defaults and runtime overrides. This method should return a hashref with each option as a key. If you wish, you may implement this like so:

 sub options {
   { autocommit => 0,
     lifetime   => $ENV{'SESSION_LIFETIME'},
     other      => options
   };
 }  

...and Apache::Session will do the work for you.

Apache::Session defines a single default setting, autocommit => 1, which may suit your needs fine. In this case, you don't have to override this method.

$class->commit( $hashref );

The commit method should write the given hash into the physical storage. How you do that is up to you as long as you can get the hash back out again. This method may be critical for performance, especially if autocommit is true.

$object->destroy()

Removes the session from the physical storage. This should remove all traces of the session, including any associated locks.

$object->DESTROY()

This method will get called when the session object goes out-of-scope. You might want to use this method to clean up any locks that are associated with the object.

locking

Depending on the nature of your storage system, you may need to implement a locking structure to serialize/atomize read and write operations. This locking structure should be transparent to the end user.

BUGS

Apache::Session::IPC is known break under heavy loads on Linux. Apache::Session::File slowly degrades over time unless you periodically clean out the session file directory.

TODO

Apache::Session::Daemon

AUTHORS

Jeffrey Baker <jeff@godzilla.tamu.edu>, author and maintainer.

Randy Harmon <rjharmon@uptimecomputers.com> created storage independence through subclassing, with useful comments, suggestions, and source code from:

  Bavo De Ridder <bavo@ace.ulyssis.student.kuleuven.ac.be>
  Jules Bean <jmlb2@hermes.cam.ac.uk>
  Lincoln Stein <lstein@cshl.org>

Redistribute under the Perl Artistic License.