Skip to content

Instantly share code, notes, and snippets.

@gadhra
Created April 14, 2011 20:35
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save gadhra/920462 to your computer and use it in GitHub Desktop.
Save gadhra/920462 to your computer and use it in GitHub Desktop.
A PHP5 Session handler
<?php
/***
* @note session handler::PHP5::session-class-php
* @author Stefan Antonowicz
* @link http://us2.php.net/manual/en/function.session-set-save-handler.php
*
* Database session handler
*
* This class overwrites the default session save functions for PHP, so we
* can write to the database rather than the filesystem
*
*
*
* This dbSession handler writes to a mysql table:
* CREATE TABLE `sessions` (
* `sessionID` varchar(32) NOT NULL,
* `session_data` longtext,
* `session_time` int(11) NOT NULL DEFAULT '0',
* `session_ip` varchar(32) DEFAULT NULL,
* `session_status` enum('active','passive') DEFAULT NULL,
* PRIMARY KEY (`sessionID`)
*) ENGINE=InnoDB DEFAULT CHARSET=latin1;
*
* This file should also include the MySQL class, either through
* autoloader or directly in controller
*/
class dbSession {
/**
* @access private
* @var int
*
* Base lifetime of session
*/
private static $lifetime = 0;
/**
* @access private
* @var string
*
* User defined Data Source Name (DSN) for mysql connection.
*/
private static $dsn = 'mysql://<username>:<password>@<host>/<dbname>';
/**
* @access private
* @var string
*
* User defined domain for any cookies to be set. Set to .foo.com to
* allow cookies to be used across multiple servers and/or multiple
* subdomains
*/
private static $cookie_domain = '';
/**
* Constructor
*
* The constructor uses the session_set_save_handler to overload the user-level session storage functions in PHP
* Additionally, it calls session_start() after the session has been registered.
* All session_start( ) callouts sitewide MUST be in
* the form of "new dbSession()" and NOT just "session_start()"
*
* @access public
*/
public function __construct( ) {
if( dbSession::$lifetime ) {
$this->lifetime = dbSession::$lifetime;
} else {
$this->lifetime = ini_get( 'session.gc_maxlifetime' );
}
session_set_save_handler(
array( &$this, 'open' ),
array( &$this, 'close' ),
array( &$this, 'read' ),
array( &$this, 'write' ),
array( &$this, 'destroy' ),
array( &$this, 'gc' )
);
register_shutdown_function( 'session_write_close' );
$this->my = new MySQL( dbSession::$dsn );
session_start( );
}
/**
* open
*
* As of PHP 5.0.5 the write and close handlers are called after object destruction and
* therefore cannot use objects or throw exceptions. Not useful for current implementation
*
* @access public
* @return bool Always returns true (See Notes)
*/
public function open( $path, $name ) {
return( TRUE );
}
/**
* close
*
* As of PHP 5.0.5 the write and close handlers are called after object destruction and
* therefore cannot use objects or throw exceptions. Not useful for current implementation
*
* @access public
* @return bool Always returns true (See Notes)
*/
public function close( ) {
return( TRUE );
}
/**
* read
*
* @access public
* @return array unserialized $_SESSION array stored in database
*
*/
public function read( $sid ) {
$this->my->sql = "SELECT session_data FROM sessions WHERE sessionID = '$sid' AND session_time > " . time();
$this->my->query( );
$fields = mysql_fetch_assoc( $this->my->result );
return( $fields['session_data'] );
}
/**
* write
*
* Stores unserialied array from $_SESSION as serialized string in database. Serialization takes
* place automagically by PHP session handlers. Additionally, creates new record if no record
* currently exists
*
* @access public
* @param $sid the php_session_id
* @param $data the data to store
*/
public function write( $sid, $data ) {
/**
* quick clean of ip so no one can poison the db via GLOBAL overload
*/
preg_match( '/[\d]{1,3}\.[\d]{1,3}\.[\d]{1,3}\.[\d]{1,3}/', $_SERVER['REMOTE_ADDR'], $match );
$ip = sizeof( $match ) ? $_SERVER['REMOTE_ADDR'] : '0.0.0.0';
$expiry = time( ) + $this->lifetime;
$data = mysql_real_escape_string( $data );
$sql = "INSERT INTO sessions (sessionID, session_data, session_time, session_ip)
VALUES ('$sid', '$data', $expiry, '$ip')
ON DUPLICATE KEY UPDATE session_data='$data', session_time = '$expiry'";
$this->my->query( $sql );;
}
/**
* destroy
*
* Deletes session from database. For now, also kills $_COOKIE containing session_name
*
* @access public
*/
public function destroy( $sid ) {
$sql = "DELETE FROM sessions WHERE sessionID = '$sid'";
$this->my->query( $sql );
if( isset( $_COOKIE[session_name()] ) ) {
setcookie( session_name( ), '', time()-42000, '/' );
}
}
/**
* gc
*
* Perform garbage collection, dependent on lifetime, gc_probability,
* and gc_divisor established in php.ini
*
* @access public
* @return int
*/
public function gc( ) {
$time = time( ) - $this->lifetime;
$sql = "DELETE FROM sessions WHERE session_time < $time";
$res = $this->my->query( $sql );
return;
}
/**
* saveMessage
*
* Saves a message as an array - useful for passing messages
* from one page to the other
*
* @access public
* @param $msg array of messages
*/
public static function saveMessage( $msg ) {
if(! session_id( ) ) {
return( FALSE );
}
$_SESSION['message'] = $msg;
}
/**
* getMessageFromSession
*
* returns an array of messages set by saveMessage, and unsets
* the variable
*
* @access public
* @see saveMessage
*/
public static function getMessageFromSession( ) {
if(! session_id( ) ) {
return( FALSE );
}
if(! $_SESSION['message'] ) {
return( FALSE );
}
$msg = $_SESSION['message'];
unset( $_SESSION['message'] );
return( $msg );
}
/**
* makeCookie
*
* wrapper to set a cookie
* @access public
* @param $name the cookie name
* @param $value the cookie value
* @param $expiry when the cookie should expire. Leave as "0" for the cookie to expire on browser close
* @param $path the path on the server that the cookie is valid. Leave as "/" to allow the cookie to be
* accessed at all directory levels
* @param $domain the domain that the cookie is set on.
*/
public static function makeCookie( $name, $value, $expiry=0, $path="/", $domain='' ) {
if(! $domain ) {
$domain = dbSession::$cookie_domain;
}
setcookie( $name, $value, $expiry, $path, $domain );
}
/**
* getCookie
*
* wrapper to retrieve a cookie
* @access public
* @param $name the cookie name
* @param $serialized whether the cookie contains a serialized string, like a serialized array
*/
public static function getCookie( $name, $serialized=FALSE ) {
if(! $_COOKIE[$name] ) {
return;
}
$c = $_COOKIE[$name];
if( $serialized ) {
$c = unserialize( stripslashes( $c ) );
}
return( $c );
}
/**
* killCookie
*
* wrapper to destroy a cookie
* @access public
* @param $name the cookie name
* @param $path the path on the server that the cookie is valid. Leave as "/" to allow the cookie to be
* accessed at all directory levels
* @param $domain the domain that the cookie is set on.
*/
public static function killCookie( $name, $path="/", $domain='' ) {
if(! $domain ) {
$domain = dbSession::$cookie_domain;
}
dbSession::makeCookie( $name, '', time()-3600, $path, $domain );
}
}
?>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment