search for in the  
<session_set_cookie_paramssession_start>
Last updated: Thu, 19 May 2005

session_set_save_handler

(PHP 4, PHP 5)

session_set_save_handler --  Sets user-level session storage functions

Description

bool session_set_save_handler ( string open, string close, string read, string write, string destroy, string gc )

session_set_save_handler() sets the user-level session storage functions which are used for storing and retrieving data associated with a session. This is most useful when a storage method other than those supplied by PHP sessions is preferred. i.e. Storing the session data in a local database. Returns TRUE on success or FALSE on failure.

Note: The "write" handler is not executed until after the output stream is closed. Thus, output from debugging statements in the "write" handler will never be seen in the browser. If debugging output is necessary, it is suggested that the debug output be written to a file instead.

The following example provides file based session storage similar to the PHP sessions default save handler files. This example could easily be extended to cover database storage using your favorite PHP supported database engine.

Read function must return string value always to make save handler work as expected. Return empty string if there is no data to read. Return values from other handlers are converted to boolean expression. TRUE for success, FALSE for failure.

Example 1. session_set_save_handler() example

<?php
function open($save_path, $session_name)
{
  global
$sess_save_path, $sess_session_name;
      
 
$sess_save_path = $save_path;
 
$sess_session_name = $session_name;
  return(
true);
}

function
close()
{
  return(
true);
}

function
read($id)
{
  global
$sess_save_path, $sess_session_name;

 
$sess_file = "$sess_save_path/sess_$id";
  if (
$fp = @fopen($sess_file, "r")) {
  
$sess_data = fread($fp, filesize($sess_file));
   return(
$sess_data);
  } else {
   return(
""); // Must return "" here.
 
}

}

function
write($id, $sess_data)
{
  global
$sess_save_path, $sess_session_name;

 
$sess_file = "$sess_save_path/sess_$id";
  if (
$fp = @fopen($sess_file, "w")) {
   return(
fwrite($fp, $sess_data));
  } else {
   return(
false);
  }

}

function
destroy($id)
{
  global
$sess_save_path, $sess_session_name;
      
 
$sess_file = "$sess_save_path/sess_$id";
  return(@
unlink($sess_file));
}

/*********************************************
 * WARNING - You will need to implement some *
 * sort of garbage collection routine here.  *
 *********************************************/
function gc($maxlifetime)
{
  return
true;
}

session_set_save_handler("open", "close", "read", "write", "destroy", "gc");

session_start();

// proceed to use sessions normally

?>

See also the session.save_handler configuration directive.



User Contributed Notes
session_set_save_handler
Robert Chapin
06-May-2005 04:09
Session authentication is not meant to be part of the session handlers.

These handlers only read and write the session data itself, and will not allow you to call the vital function session_regenerate_id().

To add extra authentication routines, call them after session_start returns control.  DO NOT put them in your 'open' or 'read' handlers.

Enjoy,
-- Miqro
markus at fischer dot name
16-Mar-2005 03:07
Note that there's a bug with custom session handlers and when you want to start a session again after you have called session_destroy.

session_destroy disables the custom session_handler and this a call to session_start after it will fail with "Failed to initialize storage module".

See http://bugs.php.net/32330 for more information and a workaround.
oliver at teqneers dot de
03-Feb-2005 05:44
For some people it might be important to know, that if the standard session handler has been overwritten with session_set_save_handler, no locking is working anymore (between session_read and session_write). The following might happen:

script "A" start        .
read session data        .
.                        script "B" start
.                        read session data
running (30secs)        add session data
.                        write sesion data
.                        script "B" stop
write session data      .
script "A" stop          .

If a script "A" runs for a long time (say 30secs) the same user might start another script "B", which also uses a session. Script "B" will start and read session data, even though script "A" is still running. Because script "B" is much faster it will finish its work and write back its session data before script "A" has ended. Now script "A" ends and overwrites all of script "B"'s session data. If you DON'T use session_set_save_handler, this cannot happend, because in this case, PHP will not start script "B" until script "A" ends.
Selcuk
15-Nov-2004 10:05
I have found a good library that enables MySQL sessions:

http://www.code.dearneighbor.com/db_esession.html

From the site:

The DB_eSession PHP class facilitates having sessions stored in a MySQL database. You can gain more secure and stable PHP sessions by using a database, and utilizing this class in your PHP scripts.
Balu
19-Sep-2004 05:26
If a session is closed the save-handlers seem to be resetted (in PHP 4.1.2 they are), so you need to run session_set_save_handler() again after e.g. running session_write_close() and restarting the session with session_start();
Ido <ido+code at cs dot uchicago dot edu>
08-Jul-2004 10:51
Encrypted Sessions:  For those who are either sending their session data in the clear (i.e.: MySQL connections without SSL), or who have sensitive data stored in sessions (such as credit card information!) and wish to protect their users.

I have placed a link to a very crude example of session data encryption for MySQL-based session handling below:

http://www.cs.uchicago.edu/~ido/session_include_php.txt

I apologize if the code is a bit sloppy.  I might release some of my better code for this kind of thing if I have time to delete any site-specific references from that code.

Donate to my college education:)
http://www.cs.uchicago.edu/~ido/donate.php 

Motivation: While most online merchants do not store personal or credit card information in plaintext, most use standard sessions provided by PHP or other database session handlers which store session data in the clear.  Most shopping cart solutions store very sensitive data in session variables.

I hope I can convince more of my fellow web developers to make the minimal effort to protect privacy and confidentiality of user data by encrypting session data prior to storage. All sites developed (even in part) by me feature session data encryption, most of which feature automatic monthly regeneration of random encryption keys (and flawless auto-rollover to the new keys).

In practice, you would probably want to store the symmetric key in a safer location, such as in your Apache config file as a PHP global variable.  Regardless, encryption should be a minimal precaution when sensitive data (session data, for example) is sent across a network -- such as when your database and web servers are on different hosts, or when your database server is on a machine which you cannot ensure is secure.
dolan at unt dot edu
09-Jun-2004 03:23
This is an LDAP implementation that I wrote which works just fine for me.  This assumes you've got some global variables with your host and other info.  It also uses a custom error function which I have not defined here.  Also, it assumes your LDAP server is set up with correct permissions, objectclass, and all that.  I used an octet string in LDAP to hold the session data.  I had to manually wrap some of this so be careful with cutting and pasting.

$sessconn=null;
//Custom session handling stored in local LDAP
function ldap_sess_open($save_path,$session_name) {
   global $infohost,$infoport,$infodn,$infopw,$sessconn;
   $sessconn=@ldap_connect($infohost,$infoport);
   if(!@ldap_bind($sessconn,$infodn,$infopw)) {
   setError("Failed to open session.");
   return false;
   }
   return true;
}

function ldap_sess_close() {
   global $sessconn;
   @ldap_close($sessconn);
   return true;
}

function ldap_sess_read($id) {
   global $sessconn;
   $sr=@ldap_search($sessconn,'ou=sessions,o=Company',
"(cn=$id)");
   $info=@ldap_get_entries($sessconn,$sr);
   if($info['count']>0)
   return $info[0]['session'][0];
   else
   return "";
}

function ldap_sess_write($id,$sess_data) {
   global $sessconn;
   $update=array();
   $update['objectClass']=array('phpsession','top');
   $update['session']=$sess_data;
   $dn="cn=$id,ou=sessions,o=Company";
   @ldap_delete($sessconn,$dn);
   @ldap_add($sessconn,$dn,$update);
   return true;
}

function ldap_sess_destroy($id) {
   global $sessconn;
   $dn="cn=$id,ou=sessions,o=Company";
   @ldap_delete($sessconn,$dn);
   return true;
}

function ldap_sess_gc($maxlifetime) {
   global $sessconn;
   $sr=@ldap_search($sessconn,'ou=sessions,o=Company',
'(objectClass=phpsession)',array('+','cn'));
   $info=@ldap_get_entries($sessconn,$sr);
   if($info['count']>0) {
   for($i=0;$i<$info['count'];$i++) {
       $id=$info[$i]['cn'][0];
       $dn="cn=$id,ou=sessions,o=Company";
       $modified=stamp2local($info[$i]['modifytimestamp'][0]);
       if((time()-$modified)>=$maxlifetime)
       @ldap_delete($sessconn,$dn);
   }
   }
   return true;
}

//converts my LDAP timestamps over to Unix timestamps
function stamp2local($ldapstamp) {
   $year=substr($ldapstamp,0,4);
   $month=substr($ldapstamp,4,2);
   $day=substr($ldapstamp,6,2);
   $hour=substr($ldapstamp,8,2);
   $minute=substr($ldapstamp,10,2);
   $stamp=gmmktime($hour,$minute,0,$month,$day,$year);
   return $stamp;
}

//Use this so that if your LDAP server goes down people can still
//retain sessions the normal way
$checkds=@ldap_connect($infohost,$infoport);
if(@ldap_bind($checkds,$infodn,$infopw)) {
   session_set_save_handler("ldap_sess_open","ldap_sess_close",
"ldap_sess_read","ldap_sess_write","ldap_sess_destroy",
"ldap_sess_gc");
}
@ldap_close($checkds);
Monty
07-Apr-2004 05:03
It's really important to apply addslashes() to the serialized values passed to your custom session Write handler if you are using MySQL for storing sessions, even if you have magic_quotes turned on. Otherwise, values stored in $_SESSION will not be saved with the actual session in MySQL, or will be truncated.

<?
function sessWrite($key, $val) {

  
$val = addslashes($val);

  
// Now do your database insert here.

  
return TRUE;
}
?>

Without addslashes(), the above handler would simply not work, and you will get no error back from PHP about it either.
turan yilmaz
04-Apr-2004 10:04
I found a very good written custom session handling code from:http://www.zend.com/zend/spotlight/code-gallery-wade8.php
16-Mar-2004 06:41
@andrew at netrux dot com

never forget: always add escaping when building sql strings.
mysql_escape_string() / pg_escape_string() or whatever is your friend.
tonanbarbarian at hotmail dot com
04-Dec-2003 12:30
I found the need to have a garbage collection function run with my sessions so I had to write my own session handler.

I took the example code above but found that it had a problem, it does not open the session file exclusively.
This means that if you have a frameset where 2 pages are accessing the session at the same time and both modify the session only the last page to finish processing will have its session data saved. The first page will have all of its session data overwritten.

So here is a modified version of a file session handler in PHP that has file locking. (Not supported on FAT or NFS apparently)

$sess_save_path = $sess_session_name = $fp=null;
function open ($save_path, $session_name) {
  global $sess_save_path, $sess_session_name;
      
  $sess_save_path = $save_path;
  $sess_session_name = $session_name;
  return(true);
}

function close() {
  global $fp;
  flock($fp, LOCK_UN);
  fclose($fp);
  $fp=null;
  return(true);
}

function read ($id) {
  global $sess_save_path, $sess_session_name, $fp;

  $sess_file = "$sess_save_path/sess_$id";
  if ($fp = @fopen($sess_file, "r+")) {
   flock($fp, LOCK_EX);
   $sess_data = fread($fp, filesize($sess_file));
   return($sess_data);
  } else {
   return(""); // Must return "" here.
  }

}

function write ($id, $sess_data) {
  global $sess_save_path, $sess_session_name, $fp;

  $sess_file = "$sess_save_path/sess_$id";
  if (!empty($fp)) {
   fseek($fp,0);
   return(fwrite($fp, $sess_data));
  } elseif ($fp = @fopen($sess_file, "w")) {
   flock($fp, LOCK_EX);
   return(fwrite($fp, $sess_data));
  } else {
   return(false);
  }
}

function destroy ($id) {
  global $sess_save_path, $sess_session_name;
      
  $sess_file = "$sess_save_path/sess_$id";
  return(@unlink($sess_file));
}

function gc ($maxlifetime) {
   global $sess_save_path, $sess_session_name;
      
  $sess_file = "$sess_save_path/sess_$id";
  return true;
}

session_set_save_handler ("open", "close", "read", "write", "destroy", "gc");

enjoy
coco at digitalco2 dot com
23-Nov-2003 05:59
When using mySQL for your session handling functions, don't forget to call mysql_select_db() to change the database if you are using a separate database for your session data. Call mysql_select_db() INSIDE every handler function that accesses the database, since if you write session data after accessing another database, it will not change the database to your session database, and therefore, not write the session data.
andrew at netrux dot com
22-Oct-2003 08:15
For those interested in a postgresql version.  Seems to work but dont come crying to me when it eats your pistachio nuts!

<?

Derived from php file version on website
, changes copyright andrew@netrux.com.

/*

create table sessions(
sessionid    char(255) primary key not null,
lastupdated  timestamp not null,
datavalue    text);

*/

function open ($save_path, $session_name) {
 
$sess_conn=pg_connect("host=localhost dbname= user=postgres")
   or die (
"PostgreSQL error: --> " . pg_last_error($sess_conn));
  return(
true);
}

function
close() {
  return(
true);
}

function
read ($id) {
 
$result=pg_query("select * from sessions where sessionid = '$id'")
   or die (
"PostgreSQL error: --> " . pg_last_error($sess_conn));
  if (
pg_num_rows($result)==1) {
  
$row=pg_fetch_array($result);
   return(
$row[2]);
  } else {
   return(
"");
  }
}

function
write ($id, $sess_data) {
  
pg_query("delete from sessions where sessionid = '$id'")
     or die (
"PostgreSQL error: --> " . pg_last_error($sess_conn));
  
pg_query("insert into sessions(sessionid,lastupdated,datavalue) values('$id','now'::timestamp,'$sess_data')")
     or die (
"PostgreSQL error: --> " . pg_last_error($sess_conn));
   return(
true);
}

function
destroy ($id) {
 
pg_query("delete from sessions where sessionid = '$id'")
   or die (
"PostgreSQL error: --> " . pg_last_error($sess_conn));
 
pg_close($sess_conn);
  return(
true);
}

/*********************************************
 * WARNING - You will need to implement some *
 * sort of garbage collection routine here.  *
 *********************************************/
function gc ($maxlifetime) {
  return
true;
}

session_set_save_handler ("open", "close", "read", "write", "destroy", "gc");

?>
rafael dot tz at uol dot com dot br
25-Jul-2003 01:38
Hi people! I was wondering about a MySQL Sessions control... Here is some of my work, a little mod on some cods that I've found this far:

if(!mysql_table_exists("sessions",$DB))
{
       $query = 'CREATE TABLE sessions
                 (
                 SessionID    char(255)  not null,
                 LastUpdated  datetime    not null,
                 DataValue    text,
                 PRIMARY KEY ( SessionID ),
                 INDEX ( LastUpdated )
                 )';
       mysql_query($query);
}
                            

function sessao_open($aSavaPath, $aSessionName)
{
       global $aTime;

       sessao_gc( $aTime );
       return True;
}

function sessao_close()
{
       return True;
}

function sessao_read( $aKey )
{
       $query = "SELECT DataValue FROM sessions WHERE SessionID='$aKey'";
       $busca = mysql_query($query);
       if(mysql_num_rows($busca) == 1)
       {
             $r = mysql_fetch_array($busca);
             return $r['DataValue'];
       } ELSE {
             $query = "INSERT INTO sessions (SessionID, LastUpdated, DataValue)
                       VALUES ('$aKey', NOW(), '')";
             mysql_query($query);
             return "";
       }
}

function sessao_write( $aKey, $aVal )
{
       $aVal = addslashes( $aVal );
       $query = "UPDATE sessions SET DataValue = '$aVal', LastUpdated = NOW() WHERE SessionID = '$aKey'";
       mysql_query($query);
       return True;
}

function sessao_destroy( $aKey )
{
       $query = "DELETE FROM sessions WHERE SessionID = '$aKey'";
       mysql_query($query);
       return True;
}

function sessao_gc( $aMaxLifeTime )
{
       $query = "DELETE FROM sessions WHERE UNIX_TIMESTAMP(NOW()) - UNIX_TIMESTAMP(LastUpdated) > $aMaxLifeTime";
       mysql_query($query);
       return True;
}

session_set_save_handler("sessao_open", "sessao_close", "sessao_read", "sessao_write", "sessao_destroy", "sessao_gc");
15-Jun-2003 02:22
One day while googling around - I found this session handler class on the net: http://www.cheetah-soft.com/csh/ - seems to work really well.

LT
Joe Wheeler
30-Jan-2003 07:04
If you happen to want to build a session manager object you can set the handlers from inside the class. This helps to keep the class encapsulated which helps make it nice and reusable.

class Session_manager {
...
   session_set_save_handler(
       array(& $this, 'session_open_method'),
       array(& $this, 'session_close_method'),
       array(& $this, 'session_read_method'),
       array(& $this, 'session_write_method'),
       array(& $this, 'session_destroy_method'),
       array(& $this, 'session_gc_method')
   );
...
}

Each handler is identified by an array containing a self-reference to the instance (note the &) and a string identifying a method in the session manager class.

Remember that the new operator passes back a copy of the object. This is important if you want to call session_set_save_handler() from inside the class constructor. You must remember to use another reference when you create the instance...

$my_session_manager = & new Session_manager;

Otherwise the session handlers will be assigned to an instance which is created by the new operator and NOT to the copy which is stored in the variable $my_session_manager.
ivo at magstudio dot net
25-Nov-2002 09:08
Just a few words to explain some troubles while using session_set_save_handler(). It appears that internally PHP calls session management functions in this order: open(), read(), write(), close(). Close() function is called even if you does not make a call to sesison_start(), perhaps for some reasons like cleaning.
   If you try to redefine these functions and call sessions_set_save_handler() but something doesn't work, (in my case the ssion data hasn't been written) it's a good idea to debug them in the order they are called. They doesn't produce error output to browser but you can use print or echo.
   Shortly, if your write() function doesn't work as expected take a look for errors in previous functions - open() and read().
   I hope that this will help to save someone few hours debugging.
steve at saturn5 dot com
10-Jun-2002 10:39
if you want to call session_start again after session_destroy, you have to call session_set_save_handler a second time. otherwise the session module doesn't know about all the nice functions you defined earlier because it has been destroyed.

example:

# session handlers functions are defined
# somewhere else

session_set_save_handler ("sess_open", "sess_close", "sess_read", "sess_write", "sess_destroy", "sess_gc");

session_start();

# do some stuff ...

session_destroy();

# call this again, because session_destroy
# destroys more than just the session.

session_set_save_handler ("sess_open", "sess_close", "sess_read", "sess_write", "sess_destroy", "sess_gc");

session_start();

...

we need to call session_start() twice in our login script to prevent multiple logins. i tore my hair out over this one. hope this helps someone else. :)
spam at skurrilo dot de
08-May-2002 06:16
You can't use the session autostart feature with

session.save_handler = user

set in your php.ini. Use instead the auto_prepend_file directive in the php.ini and point it to your save_handler with an session_start() at the end.
jpm at phpbrasil dot com
17-Apr-2002 12:51
You may also use static class methods as the 'function names' for session_set_save_handler(), as in:

<?php
session_set_save_handler
(
  array(
"SessionHandler", "open"),
  array(
"SessionHandler", "close"),
  array(
"SessionHandler", "read"),
  array(
"SessionHandler", "write"),
  array(
"SessionHandler", "destroy"),
  array(
"SessionHandler", "gc")
);
?>

Anyway, just a little note that this is also possible.

<session_set_cookie_paramssession_start>
 Last updated: Thu, 19 May 2005
Copyright © 2001-2005 The PHP Group
All rights reserved.
This unofficial mirror is operated at: The Server Pages
Last updated: Thu May 19 17:35:34 2005 CDT