<?php
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
/**
* a session class without use of any session functions of the php language
*
*
* @license GNU/GPL http://www.gnu.org/licenses/gpl.html
* @author stijn1989 <stijnleenknegt@gmail.com>
* @version Versie 1.0
* @package Session
*/
/**
* The session class
*
* @package Session
* @author stijn1989
*/
class Session
{
/**
* constantes of the session class
*/
const ERROR_SESSION_WRITE_FILE = 'Could not write the session data to the session file!';
const ERROR_SESSION_OPEN_FILE = 'Could not open the session file!';
const ERROR_SESSION_CLOSE_FILE = 'Could not close the session file!';
const ERROR_SESSION_OPEN_DIR = 'Could not open the dir!';
const ERROR_SESSION_READ_DIR = 'Could not read the dir!';
const ERROR_SESSION_CLOSE_DIR = 'Could not close the dir!';
const ERROR_SESSION_READ_FILE = 'Could not read the contents of the session file!';
const ERROR_SESSION_DELETE_FILE = 'Could not delete the session file.';
const ERROR_SESSION_TOUCH_FILE = 'Could not toch the file.';
/**
* the session
*
* @access private
* @name $_session
*/
/**
* length of the session ID
*
* @access private
* @name $_sidl
*/
/**
* path to store the session files
*
* @access public
* @name $session_path
*/
static public $session_path = './session/';
/**
* strong error handling?
*
* @access public
* @name $session_error_force
*/
static public $session_error_force = true;
/**
* construct - start the session
* $timeoutforce = true -- it will check all session files on the server
* servers with lot's of traffice/visitors should put this to false
* if you don't won't long loadtimes and site-errors.
*
* @access public
* @param integer $timeout
* @param boolean $timeout_force
* @return boolean
*/
public function __construct( $timeout = 0 , $timeoutforce = false )
{
//check if the session isn't already running - update the history of the session
if( $this->session_check_alive() === true ) {
//check the timeout
if( $timeout != 0 && $timeoutforce === false ) {
$this->session_check_timeout();
} elseif( $timeout != 0 && $timeoutforce === true ) {
$this->session_check_timeout_force();
}
//update when it isn't timeout
if( $this->session_check_alive() === true ) {
$this->session_update_data_history( time() , $_SERVER['REQUEST_URI'] ); } else {
return false;
}
return true;
}
//session setup
self::$_session = array( 'id' => $this->create_session_id() , 'ip' => $_SERVER['REMOTE_ADDR'] , 'start' => time() );
$session = array( 'session_ip' => self::$_session['ip'] , 'session_id' => self::$_session['id'] ,
'session_start' => self::$_session['start'] ,
'session_timeout' => $timeout ,
'session_host' => $_SERVER['HTTP_HOST'] ,
'session_data' => array( 'session_history' => array( time() => $_SERVER['REQUEST_URI'] ) , 'session_vars' => array( ) )
);
//create the new session
try {
if( touch( $this->session_file_name() , time() , time() ) === false ) { throw new Exception( self::ERROR_SESSION_TOUCH_FILE );
}
if( ($fp = fopen( $this->session_file_name() , 'w' )) === false ) { throw new Exception( self::ERROR_SESSION_OPEN_FILE );
}
if( fwrite( $fp , $this->session_data( $session ) ) === false ) { throw new Exception( self::ERROR_SESSION_WRITE_FILE );
}
if( fclose( $fp ) === false ) { throw new Exception( self::ERROR_SESSION_CLOSE_FILE );
} else {
return true;
}
}
catch ( Exception $e )
{
die( $this->session_error() ); }
}
/**
* create the name for the session file
*
* @access private
* @return string
*/
private function session_file_name( )
{
return self::$session_path . str_replace('.' , '_' , $_SERVER['REMOTE_ADDR']) . '.session'; }
/**
* create a session id
*
* @access private
* @return integer
*/
private function create_session_id( )
{
for( $i = 0 ; $i < self::$_sidl ; $i++ ) {
}
return (strlen($id) != self::$_sidl) ?
0 : $id;
}
/**
* make the session data
* $mode = 0 (serialize) or 1 (unserialize)
*
* @param $data
* @param $mode
* @access private
* @return string
*/
private function session_data( $data , $mode = 0 )
{
switch( $mode ) {
default:
case 0:
case 1:
}
}
/**
* returns an error of the Exception class
*
* @access private
* @param object $obj
* @return string
*/
private function session_error( Exception $obj )
{
$str = 'Error <b>' . $obj->getCode() . '</b>: ';
$str .= $obj->getMessage();
$str .= ' In <b>' . $obj->getFile() . '</b> ';
$str .= 'at line <b>' . $obj->getLine() . '</b>';
return $str;
}
/**
* check if the session is running
*
* @access private
* @return true
*/
private function session_check_alive( )
{
return ( file_exists( $this->session_file_name() ) === true ) ?
true : false;
}
/**
* update the history data. only when call to new session start
*
* @param integer $time
* @param string $page
* @access private
* @return boolean
*/
private function session_update_data_history( $time , $page )
{
if( $this->session_check_alive() === false ) {
return false;
}
//let's get the data of the file
$data = $this->session_get_data( $this->session_file_name() );
//$data is an array now (3D) we need to update the session_data (key) his value
$data['session_data']['session_history'][$time] = $page;
//update the session file
return ( $this->session_update_data( $this->session_file_name() , $data , true ) === false ) ? false : true;
}
/**
* get the data of the session file
*
* @access private
* @param string $file
* @param boolean $unserialize
* @return string
*/
private function session_get_data( $file , $unserialize = true )
{
try {
throw new Exception( self::ERROR_SESSION_TOUCH_FILE );
}
if( ($fp = fopen( $file , 'r' )) === false ) { throw new Exception( self::ERROR_SESSION_OPEN_FILE );
}
$data = fgets($fp , 4096); }
if( fclose( $fp ) === false ) { throw new Exception( self::ERROR_SESSION_CLOSE_FILE );
}
}
catch ( Exception $e )
{
die( $this->session_error($e) ); }
return ( $unserialize === true ) ? $this->session_data($data , 1) : $data;
}
/**
* update the new session data by inserting it in the session file
*
* @access private
* @param string file
* @param string $data
* @param boolean $serialize
* @return boolean
*/
private function session_update_data( $file , $data , $serialze = false )
{
if( $serialze === true ) {
$data = $this->session_data( $data , 0 );
}
try {
throw new Exception( self::ERROR_SESSION_TOUCH_FILE );
}
if( unlink($file) === false ) { throw new Exception( self::ERROR_SESSION_DELETE_FILE );
}
throw new Exception( self::ERROR_SESSION_TOUCH_FILE );
}
if( ($fp = fopen( $file , 'w' )) === false ) { throw new Exception( self::ERROR_SESSION_OPEN_FILE );
}
if( fwrite( $fp , $data ) === false ) { throw new Exception( self::ERROR_SESSION_WRITE_FILE );
}
if( fclose( $fp ) === false ) { throw new Exception( self::ERROR_SESSION_CLOSE_FILE );
}
}
catch( Exception $e )
{
die( $this->session_error($e) ); }
return true;
}
/**
* check if the session var has the correct pattern. no starting with a numbre and special chars or spaces
*
* @access private
* @param string $var
* @return boolean
*/
private function session_check_var_name( $var )
{
$pattern = '#^[a-zA-Z][a-zA-Z0-9\_]+#si';
return ( preg_match($pattern , $var) ) ?
true : false;
}
/**
* register a session var like $_SESSION['varName'] = varValue; (check clone OOP @php.net)
*
* @access public
* @param string $name
* @param mixed $value;
* @return boolean
*/
public function register_var( $name , $value )
{
if( $this->session_check_alive() === false ) {
return false;
}
//check the var
if( $this->session_check_var_name($name) === false ) {
self::$session_return_last[] = false;
}
//register the var by getting and updating the session file.
//almost an clone of the session_update_data_history function
$data = $this->session_get_data( $this->session_file_name() );
$data['session_data']['session_vars'][$name] = $value;
return ( $this->session_update_data( $this->session_file_name() , $data , true ) === false ) ? false : true;
}
/**
* check if the $name session var exists
*
* @param string $name
* @return boolean
*/
public function exists( $name )
{
if( $this->session_check_alive() === false ) {
return false;
}
//recursie
foreach ($name as $value) {
$this->delete_var($value);
}
} else {
//check if the var exists
$data = $this->session_get_data( $this->session_file_name() );
return ( array_key_exists( $name , $data['session_data']['session_vars'] ) === true ) ?
true : false;
}
}
/**
* change the value of an session var that exists
* $force is when the key($name) doesn't exists it creates the value
* $replace: 1 = vervangt de waarde met $value
* 2 = voegt de waarde toe aan de rechterkant
* 3 = voor floats/integers bijtellen met opgeven $value
* 4 = voor floats/integers aftrekken met opgeven $value
* 5 = voor floats/integers vermenigvuldigen met opgeven $value
* 6 = voor floats/integers delen met opgeven $value
* 7 = voor floats/integers modules met opgeven $value
*
* @access public
* @param string $name
* @param mixed $value;
* @param integer $replace
* @param boolean $force
* @return boolean
*/
public function update_var( $name , $value , $replace = 1 , $force = false )
{
if( $this->session_check_alive() === false ) {
self::$session_return_last[] = false;
}
//check the var
if( $this->session_check_var_name($name) === false ) {
return false;
}
//register the var by getting and updating the session file.
$data = $this->session_get_data( $this->session_file_name() );
if( $force === true && $this->exists( $name ) === false ) {
$data['session_data']['session_vars'][$name] = $value;
} elseif( $this->exists( $name ) === true ) {
switch($replace) {
default: $data['session_data']['session_vars'][$name] = $value;
break;
case 1: $data['session_data']['session_vars'][$name] = $value;
break;
case 2: $data['session_data']['session_vars'][$name] .= $value;
break;
case 3: $data['session_data']['session_vars'][$name] += $value;
break;
case 4: $data['session_data']['session_vars'][$name] -= $value;
break;
case 5: $data['session_data']['session_vars'][$name] *= $value;
break;
case 6: $data['session_data']['session_vars'][$name] /= $value;
break;
case 7: $data['session_data']['session_vars'][$name] %= $value;
break;
}
} else {
return false;
}
return ( $this->session_update_data( $this->session_file_name() , $data , true ) === false ) ? false : true;
}
/**
* delete a session var
*
* @access public
* @param string $name
* @return boolean
*/
public function delete_var( $name )
{
if( $this->session_check_alive() === false ) {
self::$session_return_last[] = false;
}
//check the var
if( $this->session_check_var_name($name) === false ) {
return false;
}
//register the var by getting and updating the session file.
$data = $this->session_get_data( $this->session_file_name() );
unset( $data['session_data']['session_vars'][$name] );
return ( $this->session_update_data( $this->session_file_name() , $data , true ) === false ) ? false : true;
}
/**
* get the value of a session var
*
* @access public
* @param string $name
* @return mixed
*/
public function get_var( $name )
{
if( $this->session_check_alive() === false ) {
return false;
}
//check the var
if( $this->session_check_var_name($name) === false ) {
return false;
}
//register the var by getting and updating the session file.
$data = $this->session_get_data( $this->session_file_name() );
return $data['session_data']['session_vars'][$name];
}
/**
* get the value of a session var
* the return is an array (if check_alive is true) -> [array] [key : time] _-_ [value : url]
*
* @access public
* @return mixed
*/
public function get_history( )
{
if( $this->session_check_alive() === false ) {
return false;
}
//get the history
$data = $this->session_get_data( $this->session_file_name() );
return $data['session_data']['session_history'];
}
/**
* set the values of the session vars to empty - reset
*
* @access public
* @param boolean $reset_history
* @return boolean
*/
public function reset( $reset_history = false ) {
if( $this->session_check_alive() === false ) {
return false;
}
//reset all variables
$data = $this->session_get_data( $this->session_file_name() );
foreach( $data['session_data']['session_vars'] as $key => $value ) {
$data['session_data']['session_vars'][$key] = '';
}
//history?
if( $reset_history === true ) {
foreach( $data['session_data']['session_history'] as $key => $value ) {
unset( $data['session_data']['session_history'] ); }
}
return ( $this->session_update_data( $this->session_file_name() , $data , true ) === false ) ? false : true;
}
/**
* checks the session timeout. if it's timeout it destroy the session and creates new one
*
* @access private
* @return mixed
*/
private function session_check_timeout( )
{
if( $this->session_check_alive() === false ) {
return false;
}
//get the latest key of the session_history
$data = $this->session_get_data( $this->session_file_name() );
$keys = array_keys( $data['session_data']['session_history'] );
if( $dif > $data['session_timeout'] ) {
$this->destroy();
}
}
/**
* checks the session timeout with great force. means he looks to every session file
*
* @access private
* @return mixed
*/
private function session_check_timeout_force( )
{
if( $this->session_check_alive() === false ) {
return false;
}
//force that session
$dir = opendir( self::$session_path );
while( ($file = readdir( $dir )) !== false) { if( $file != '.' && $file != '..' ) {
$data = $this->session_get_data( self::$session_path . $file );
$keys = array_keys( $data['session_data']['session_history'] );
if( $dif > $data['session_timeout'] && $data['session_timeout'] != 0 ) {
$this->destroy();
}
}
}
}
/**
* destroy the session
*
* @access public
* @return boolean
*/
public function destroy( )
{
if( $this->session_check_alive() === false ) {
return false;
}
//destroy
try {
if( touch( $this->session_file_name() , time() , time() ) === false ) { throw new Exception( self::ERROR_SESSION_TOUCH_FILE );
}
if( unlink( $this->session_file_name() ) === false ) { throw new Exception( self::ERROR_SESSION_DELETE_FILE );
}
}
catch ( Exception $e )
{
die( $this->session_error($e) ); }
return true;
}
}
?>