Please read original post before continuing.
<?php
/** *************************************************/
/** Copyright (c) 2009 Hamid Sarfraz
/**
/** @author : praisedpk@gmail.com
/** @version : 1.0
/** @web : http://phpleaks.blogspot.com/2009/05/relatively-secure-php-sessions.html
/**
/** *************************************************/
/** *************************************************/
/**
/** You can use $_SESSION just like you do under ordinary circumstances
/** Only different you have to do is use
/** $session = new session();
/** you can skip this by setting 'SESSION_AUTO_START' to true
/** to initialize new session (as an alternative of session_start() function)
/** must use
/** $session->close();
/** at the end of script to write the $_SESSION data to session file.
/**
/** *************************************************/
/** Functions ***************************************/
/** __construct() for initializing session
/** validate_id() for validating existing id
/** close() for writing the existing $_SESSION data to session file
/** destroy() for destroying session data from session file. No Change to $_SESSION
/** must be used after close() ( or do not use close() after call to destroy() )
/** or everything will be restored. (close() copies $_SESSION data to session file
/** so call to close() after a call to destroy() will make no sense.
/**
/** clear() for setting $_SESSSION to an emtry array
/** logger() for logging the errors occured in session handling. use print_r($session->error)
/** automatically echos errors except when error_reporting() is set to DISABLED
/** generate_id() for generating random session id (16 digit hexadecimal)
/** gc() collect garbage feature just like php's default
/** regenerate_id() regenerates session id, renames the session file, sends new session cookie and returns new session id.
/**
/** *************************************************/
$path = str_replace('\','/',dirname(__FILE__)).'/';
#str_replace() is to make this path linux like (if you are on windows.
/** *************************************************/
/** SESSION_SECURITY_SALT ==> Use at least 40 digit string for extreme security.*/
define('SESSION_SECURITY_SALT' , 'CAUTION: Change this text inside single quotes to something less meaningful');
/** *************************************************/
/** *************************************************/
/** SESSION_NAME ==> Script Default 'as', php's default 'PHPSESSID'. Must be alphanumeric.*/
define('SESSION_NAME' , 'as' );
/** *************************************************/
/** *************************************************/
/** SESSION_SCRIPT_PATH ==> Current File's path. Keep this file out of webroot. Dont change the below setting. Just move file and the settings will automatically adjust.*/
define('SESSION_SCRIPT_PATH' , $path );
/** *************************************************/
/** *************************************************/
/** SESSION_SAVE_PATH ==> Path to temporary directory where to keep session files. directory must be writable and must already exist.*/
define('SESSION_SAVE_PATH' , $path.'tmp/' );#don't forget the / at the end.
/** *************************************************/
/** *************************************************/
/** SESSION_LIFE ==> Minimum time (in seconds) to keep session data in session file. 1440 is php's default, so i used it as default. Change it if you want.*/
define('SESSION_LIFE' , 1440 );
/** *************************************************/
/** *************************************************/
/** SESSION_FILE_PREFIX ==> Used as prefix of session file name. For example as_134abcdef5234213.*/
define('SESSION_FILE_PREFIX' , 'as_' );
/** *************************************************/
/** *************************************************/
/** SESSION_AUTO_START ==> Starts session automatically. Just like php's autostart feature. True=autostart | false=donot autostart*/
define('SESSION_AUTO_START' , true );
/** *************************************************/
/** *************************************************/
/** SESSION_COOKIE_PATH ==> the path on your domain, for which to keep session valid and accessible. '/' means full domain.*/
define('SESSION_COOKIE_PATH' , '/' );
/** *************************************************/
/** *************************************************/
/** SESSION_COOKIE_LIFE_TIME ==> Session Cookie life time. Default is '0' (string) which means delete cookie on browser close.*/
define('SESSION_COOKIE_LIFE_TIME' , '0' );
/** *************************************************/
/** *************************************************/
/** SESSION_COOKIE_DOMAIN ==> Domain for which to make it work. default is '.example.com'. Notice the '.' in the beginning, it makes the cookie accessible along all subdomains.*/
define('SESSION_COOKIE_DOMAIN' , '.example.com' );
/** *************************************************/
/** *************************************************/
/** SESSION_COOKIE_SECURE ==> Send Session Cookie on only Secure Connection? True = yes | False = no.*/
define('SESSION_COOKIE_SECURE' , false );
/** *************************************************/
/** *************************************************/
/** SESSION_COOKIE_HTTP_ONLY ==> Disallow javascript access to cookie? True = yes | False = no.*/
define('SESSION_COOKIE_HTTP_ONLY' , true );
/** *************************************************/
/** *************************************************/
/** SESSION_GC_PROBABILITY ==> See 'session.gc_probability' in php manual. Dont change this value if you are unsure.*/
define('SESSION_GC_PROBABILITY' , 1 );
/** *************************************************/
/** *************************************************/
/** SESSION_GC_DIVISOR ==> See 'session.gc_divisor' in php manual. Dont change this value if you are unsure.*/
define('SESSION_GC_DIVISOR' , 100 );
/** *************************************************/
/** *************************************************/
/**
/**
/**
/**
/**
/**
/** DO NOT CHANGE ANYTHING BELOW
/**
/**
/**
/**
/**
/** *************************************************/
$_SESSION = array();
class session
{
var $path = SESSION_SCRIPT_PATH;
var $name = SESSION_NAME;
var $save_path = SESSION_SAVE_PATH;
var $life = SESSION_LIFE;
var $file_prefix = SESSION_FILE_PREFIX;
var $cookie_path = SESSION_COOKIE_PATH;
var $cookie_life = SESSION_COOKIE_LIFE_TIME;
var $cookie_domain = SESSION_COOKIE_DOMAIN;
var $cookie_secure = SESSION_COOKIE_SECURE;
var $http_only = SESSION_COOKIE_HTTP_ONLY;
var $gc_probability = SESSION_GC_PROBABILITY;
var $gc_divisor = SESSION_GC_DIVISOR;
var $salt = SESSION_SECURITY_SALT;
var $id;
var $errors = array();
function __construct()
{
if( isset($_COOKIE[$this->name]) )
{
$this->id = $_COOKIE[$this->name];
if( $this->validate_id($this->id) === true )
{
if( file_exists( $this->save_path . $this->file_prefix . $this->id ) )
{
if( $session_data = file_get_contents( $this->save_path . $this->file_prefix . $this->id ) )
{
$_SESSION = unserialize($session_data);
$this->id = $this->regenrate_id();
return true;
}
$this->logger('Failed to fetch session data from session file.');
}
}
}
$this->id = $this->generate_id();
setcookie( $this->name , $this->id , $this->cookie_life , $this->cookie_path , $this->cookie_domain , $this->cookie_secure , $this->http_only );
}
function validate_id( $id = '')
{
if( ctype_xdigit($id) and strlen($id) == '32' )
{
if( substr($id , 0 , 12) === substr( md5( $this->salt . ( isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : '' ) . substr($id , -20 ) ) , 7 , 12 ) )
{
return true;
}
}
return false;
}
function close() #session_write_close()
{
$data = serialize($_SESSION);
if (is_writable($this->save_path ))
{
if(!$handle = fopen($this->save_path . $this->file_prefix . $this->id , 'w+'))
{
$this->logger('Failed to open session file on '. __FILE__ .' line '. ( __LINE__ -2 ).'.');
return false;
}
if (fwrite($handle, $data) === FALSE)
{
$this->logger('Failed to write session data to session file on '. __FILE__ .' line '. ( __LINE__ -2 ).'.');
return false;
}
}
else
{
$this->logger('Session file is not writable. Unable to write session data on '. __FILE__ .'.');
return false;
}
if(is_resource($handle))
{
fclose($handle);
unset($handle);
}
$gc = floor(( $this->gc_probability / $this->gc_divisor ) * rand ( 0 , $this->gc_divisor ));
if($gc)
{
$this->gc();
}
return true;
}
function destroy()#session_destroy() reset session file but no change to $_SESSION. use it for logout
{
if(is_writable($this->save_path . $this->file_prefix . $this->id ))
{
if(!$handle = fopen($this->save_path . $this->file_prefix . $this->id , 'w+'))
{
$this->logger('Failed to open session file for destroy.');
return false;
}
if (fwrite( $handle, 'a:0:{}' ) === FALSE)
{
$this->logger('Failed to destroy session data.');
return false;
}
}
else
{
$this->logger('Session file is not writable. Unable to destroy session data.');
return false;
}
if(is_resource($handle))
{
fclose($handle);
unset($handle);
}
return true;
}
function clear()
{
$_SESSION = array();
return true;
}
function logger($error)
{
$this->errors[] = $error;
if( error_reporting() !== 0 )
{
echo $error;
}
return true;
}
function generate_id()
{
$idpart[2] = substr( md5(uniqid().mt_rand('9999999' , '99999999')) , -20 ) ;
$idpart[1] = substr( md5( $this->salt . ( isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : '' ) . $idpart[2]) , 7 , 12 ) ;
return $idpart[1].$idpart[2];
}
function gc($id = '')
{
#you can always call this function to force collect garbage.
if($id !== '')
{
if( !file_exists( $this->save_path . $this->file_prefix . $id ))
{
$this->logger('Provided wrong session id for deletion of session file');
return false;
}
if( !unlink( $this->save_path . $this->file_prefix . $id ) )
{
$this->logger('Failed to delete session file for id '.$id );
return false;
}
return true;
}
$dir = opendir($this->save_path);
while ($sess_file = readdir($dir))
{
if (($sess_file != ".") && ($sess_file != ".."))
{
if( fileatime($this->save_path . $sess_file ) < ( time() - $this->life ) )
{
if(!unlink( $this->save_path . $sess_file ))
{
$this->logger('Failed to delete session file '.$sess_file );
}
}
}
}
closedir($dir);
return true;
}
function regenrate_id()
{
if( !headers_sent() )
{
$newid = $this->generate_id();
if( !rename( $this->save_path . $this->file_prefix . $this->id , $this->save_path . $this->file_prefix . $newid ) )
{
$this->logger('Failed to regenrate session id.');
return false;
}
$this->id = $newid;
setcookie( $this->name , $this->id , $this->cookie_life , $this->cookie_path , $this->cookie_domain , $this->cookie_secure , $this->http_only );
}
return $this->id;
}
}
if( defined('SESSION_AUTO_START') AND SESSION_AUTO_START === true )
{
$session = new session();
}
?>