2008-12-15 08:56:18 +00:00
< ? php defined ( 'SYSPATH' ) OR die ( 'No direct access allowed.' );
/**
* Session library .
*
2010-01-06 11:35:01 -08:00
* $Id : Session . php 4729 2009 - 12 - 29 20 : 35 : 19 Z isaiah $
2008-12-15 08:56:18 +00:00
*
2010-01-06 11:35:01 -08:00
* @ package Kohana
2008-12-15 08:56:18 +00:00
* @ author Kohana Team
2009-11-24 19:20:36 -08:00
* @ copyright ( c ) 2007 - 2009 Kohana Team
* @ license http :// kohanaphp . com / license
2008-12-15 08:56:18 +00:00
*/
class Session_Core {
// Session singleton
2009-03-17 18:56:01 +00:00
protected static $instance ;
2008-12-15 08:56:18 +00:00
// Protected key names (cannot be set by the user)
protected static $protect = array ( 'session_id' , 'user_agent' , 'last_activity' , 'ip_address' , 'total_hits' , '_kf_flash_' );
// Configuration and driver
protected static $config ;
protected static $driver ;
// Flash variables
protected static $flash ;
// Input library
protected $input ;
2009-06-30 20:48:16 -07:00
// Automatically save the session by default
public static $should_save = true ;
2008-12-15 08:56:18 +00:00
/**
* Singleton instance of Session .
2009-11-24 19:20:36 -08:00
*
* @ param string Force a specific session_id
2008-12-15 08:56:18 +00:00
*/
2009-11-24 19:20:36 -08:00
public static function instance ( $session_id = NULL )
2008-12-15 08:56:18 +00:00
{
2009-03-17 18:56:01 +00:00
if ( Session :: $instance == NULL )
2008-12-15 08:56:18 +00:00
{
// Create a new instance
2009-11-24 19:20:36 -08:00
new Session ( $session_id );
}
elseif ( ! is_null ( $session_id ) AND $session_id != session_id () )
{
throw new Kohana_Exception ( 'A session (SID: :session:) is already open, cannot open the specified session (SID: :new_session:).' , array ( ':session:' => session_id (), ':new_session:' => $session_id ));
2008-12-15 08:56:18 +00:00
}
2009-03-17 18:56:01 +00:00
return Session :: $instance ;
2008-12-15 08:56:18 +00:00
}
2009-11-24 19:20:36 -08:00
2009-09-04 20:15:21 -07:00
/**
* Be sure to block the use of __clone .
*/
private function __clone (){}
2008-12-15 08:56:18 +00:00
/**
* On first session instance creation , sets up the driver and creates session .
2009-11-24 19:20:36 -08:00
*
* @ param string Force a specific session_id
2008-12-15 08:56:18 +00:00
*/
2009-11-24 19:20:36 -08:00
protected function __construct ( $session_id = NULL )
2008-12-15 08:56:18 +00:00
{
$this -> input = Input :: instance ();
// This part only needs to be run once
2009-03-17 18:56:01 +00:00
if ( Session :: $instance === NULL )
2008-12-15 08:56:18 +00:00
{
// Load config
2009-03-17 18:56:01 +00:00
Session :: $config = Kohana :: config ( 'session' );
2008-12-15 08:56:18 +00:00
// Makes a mirrored array, eg: foo=foo
2009-03-17 18:56:01 +00:00
Session :: $protect = array_combine ( Session :: $protect , Session :: $protect );
2008-12-15 08:56:18 +00:00
// Configure garbage collection
2009-03-17 18:56:01 +00:00
ini_set ( 'session.gc_probability' , ( int ) Session :: $config [ 'gc_probability' ]);
2008-12-15 08:56:18 +00:00
ini_set ( 'session.gc_divisor' , 100 );
2009-03-17 18:56:01 +00:00
ini_set ( 'session.gc_maxlifetime' , ( Session :: $config [ 'expiration' ] == 0 ) ? 86400 : Session :: $config [ 'expiration' ]);
2008-12-15 08:56:18 +00:00
// Create a new session
2009-11-24 19:20:36 -08:00
$this -> create ( NULL , $session_id );
2008-12-15 08:56:18 +00:00
2009-03-17 18:56:01 +00:00
if ( Session :: $config [ 'regenerate' ] > 0 AND ( $_SESSION [ 'total_hits' ] % Session :: $config [ 'regenerate' ]) === 0 )
2008-12-15 08:56:18 +00:00
{
// Regenerate session id and update session cookie
$this -> regenerate ();
}
else
{
// Always update session cookie to keep the session alive
2009-03-17 18:56:01 +00:00
cookie :: set ( Session :: $config [ 'name' ], $_SESSION [ 'session_id' ], Session :: $config [ 'expiration' ]);
2008-12-15 08:56:18 +00:00
}
2009-11-24 19:20:36 -08:00
// Close the session on system shutdown (run before sending the headers), so that
2008-12-15 08:56:18 +00:00
// the session cookie(s) can be written.
2009-11-24 19:20:36 -08:00
Event :: add ( 'system.shutdown' , array ( $this , 'write_close' ));
2008-12-15 08:56:18 +00:00
// Singleton instance
2009-03-17 18:56:01 +00:00
Session :: $instance = $this ;
2008-12-15 08:56:18 +00:00
}
2009-11-24 19:20:36 -08:00
Kohana_Log :: add ( 'debug' , 'Session Library initialized' );
2008-12-15 08:56:18 +00:00
}
/**
* Get the session id .
*
* @ return string
*/
public function id ()
{
return $_SESSION [ 'session_id' ];
}
/**
* Create a new session .
*
* @ param array variables to set after creation
2009-11-24 19:20:36 -08:00
* @ param string Force a specific session_id
2008-12-15 08:56:18 +00:00
* @ return void
*/
2009-11-24 19:20:36 -08:00
public function create ( $vars = NULL , $session_id = NULL )
2008-12-15 08:56:18 +00:00
{
// Destroy any current sessions
$this -> destroy ();
2009-03-17 18:56:01 +00:00
if ( Session :: $config [ 'driver' ] !== 'native' )
2008-12-15 08:56:18 +00:00
{
// Set driver name
2009-03-17 18:56:01 +00:00
$driver = 'Session_' . ucfirst ( Session :: $config [ 'driver' ]) . '_Driver' ;
2008-12-15 08:56:18 +00:00
// Load the driver
if ( ! Kohana :: auto_load ( $driver ))
2009-11-24 19:20:36 -08:00
throw new Kohana_Exception ( 'The :driver: driver for the :library: library could not be found' ,
array ( ':driver:' => Session :: $config [ 'driver' ], ':library:' => get_class ( $this )));
2008-12-15 08:56:18 +00:00
// Initialize the driver
2009-03-17 18:56:01 +00:00
Session :: $driver = new $driver ();
2008-12-15 08:56:18 +00:00
// Validate the driver
2009-03-17 18:56:01 +00:00
if ( ! ( Session :: $driver instanceof Session_Driver ))
2009-11-24 19:20:36 -08:00
throw new Kohana_Exception ( 'The :driver: driver for the :library: library must implement the :interface: interface' ,
array ( ':driver:' => Session :: $config [ 'driver' ], ':library:' => get_class ( $this ), ':interface:' => 'Session_Driver' ));
2008-12-15 08:56:18 +00:00
// Register non-native driver as the session handler
session_set_save_handler
(
2009-03-17 18:56:01 +00:00
array ( Session :: $driver , 'open' ),
array ( Session :: $driver , 'close' ),
array ( Session :: $driver , 'read' ),
array ( Session :: $driver , 'write' ),
array ( Session :: $driver , 'destroy' ),
array ( Session :: $driver , 'gc' )
2008-12-15 08:56:18 +00:00
);
}
// Validate the session name
2009-03-17 18:56:01 +00:00
if ( ! preg_match ( '~^(?=.*[a-z])[a-z0-9_]++$~iD' , Session :: $config [ 'name' ]))
2009-11-24 19:20:36 -08:00
throw new Kohana_Exception ( 'The session_name, :session:, is invalid. It must contain only alphanumeric characters and underscores. Also at least one letter must be present.' , array ( ':session:' => Session :: $config [ 'name' ]));
2008-12-15 08:56:18 +00:00
// Name the session, this will also be the name of the cookie
2009-03-17 18:56:01 +00:00
session_name ( Session :: $config [ 'name' ]);
2008-12-15 08:56:18 +00:00
// Set the session cookie parameters
session_set_cookie_params
(
2009-03-17 18:56:01 +00:00
Session :: $config [ 'expiration' ],
2008-12-15 08:56:18 +00:00
Kohana :: config ( 'cookie.path' ),
Kohana :: config ( 'cookie.domain' ),
Kohana :: config ( 'cookie.secure' ),
Kohana :: config ( 'cookie.httponly' )
);
2009-11-24 19:20:36 -08:00
$cookie = cookie :: get ( Session :: $config [ 'name' ]);
if ( $session_id === NULL )
{
// Reopen session from signed cookie value.
$session_id = $cookie ;
}
// Reopen an existing session if supplied
if ( ! is_null ( $session_id ))
{
session_id ( $session_id );
}
2008-12-15 08:56:18 +00:00
// Start the session!
session_start ();
// Put session_id in the session variable
$_SESSION [ 'session_id' ] = session_id ();
// Set defaults
if ( ! isset ( $_SESSION [ '_kf_flash_' ]))
{
$_SESSION [ 'total_hits' ] = 0 ;
$_SESSION [ '_kf_flash_' ] = array ();
2009-11-24 19:20:36 -08:00
$_SESSION [ 'user_agent' ] = request :: user_agent ();
2008-12-15 08:56:18 +00:00
$_SESSION [ 'ip_address' ] = $this -> input -> ip_address ();
}
// Set up flash variables
2009-03-17 18:56:01 +00:00
Session :: $flash =& $_SESSION [ '_kf_flash_' ];
2008-12-15 08:56:18 +00:00
// Increase total hits
$_SESSION [ 'total_hits' ] += 1 ;
// Validate data only on hits after one
if ( $_SESSION [ 'total_hits' ] > 1 )
{
// Validate the session
2009-03-17 18:56:01 +00:00
foreach ( Session :: $config [ 'validate' ] as $valid )
2008-12-15 08:56:18 +00:00
{
switch ( $valid )
{
// Check user agent for consistency
case 'user_agent' :
2009-11-24 19:20:36 -08:00
if ( $_SESSION [ $valid ] !== request :: user_agent ())
2008-12-15 08:56:18 +00:00
return $this -> create ();
break ;
// Check ip address for consistency
case 'ip_address' :
if ( $_SESSION [ $valid ] !== $this -> input -> $valid ())
return $this -> create ();
break ;
// Check expiration time to prevent users from manually modifying it
case 'expiration' :
if ( time () - $_SESSION [ 'last_activity' ] > ini_get ( 'session.gc_maxlifetime' ))
return $this -> create ();
break ;
}
}
}
// Expire flash keys
$this -> expire_flash ();
// Update last activity
$_SESSION [ 'last_activity' ] = time ();
// Set the new data
2009-03-17 18:56:01 +00:00
Session :: set ( $vars );
2008-12-15 08:56:18 +00:00
}
/**
* Regenerates the global session id .
2009-03-17 18:56:01 +00:00
*
2008-12-15 08:56:18 +00:00
* @ return void
*/
public function regenerate ()
{
2009-03-17 18:56:01 +00:00
if ( Session :: $config [ 'driver' ] === 'native' )
2008-12-15 08:56:18 +00:00
{
// Generate a new session id
// Note: also sets a new session cookie with the updated id
session_regenerate_id ( TRUE );
// Update session with new id
$_SESSION [ 'session_id' ] = session_id ();
}
else
{
// Pass the regenerating off to the driver in case it wants to do anything special
2009-03-17 18:56:01 +00:00
$_SESSION [ 'session_id' ] = Session :: $driver -> regenerate ();
2008-12-15 08:56:18 +00:00
}
// Get the session name
$name = session_name ();
if ( isset ( $_COOKIE [ $name ]))
{
// Change the cookie value to match the new session id to prevent "lag"
2009-11-24 19:20:36 -08:00
cookie :: set ( $name , $_SESSION [ 'session_id' ]);
2008-12-15 08:56:18 +00:00
}
}
/**
* Destroys the current session .
*
* @ return void
*/
public function destroy ()
{
if ( session_id () !== '' )
{
// Get the session name
$name = session_name ();
// Destroy the session
session_destroy ();
// Re-initialize the array
$_SESSION = array ();
// Delete the session cookie
cookie :: delete ( $name );
}
}
/**
* Runs the system . session_write event , then calls session_write_close .
*
* @ return void
*/
public function write_close ()
{
static $run ;
if ( $run === NULL )
{
$run = TRUE ;
// Run the events that depend on the session being open
Event :: run ( 'system.session_write' );
// Expire flash keys
$this -> expire_flash ();
// Close the session
session_write_close ();
}
}
/**
* Set a session variable .
*
* @ param string | array key , or array of values
* @ param mixed value ( if keys is not an array )
* @ return void
*/
public function set ( $keys , $val = FALSE )
{
if ( empty ( $keys ))
return FALSE ;
if ( ! is_array ( $keys ))
{
$keys = array ( $keys => $val );
}
foreach ( $keys as $key => $val )
{
2009-03-17 18:56:01 +00:00
if ( isset ( Session :: $protect [ $key ]))
2008-12-15 08:56:18 +00:00
continue ;
// Set the key
$_SESSION [ $key ] = $val ;
}
}
/**
* Set a flash variable .
*
* @ param string | array key , or array of values
* @ param mixed value ( if keys is not an array )
* @ return void
*/
public function set_flash ( $keys , $val = FALSE )
{
if ( empty ( $keys ))
return FALSE ;
if ( ! is_array ( $keys ))
{
$keys = array ( $keys => $val );
}
foreach ( $keys as $key => $val )
{
if ( $key == FALSE )
continue ;
2009-03-17 18:56:01 +00:00
Session :: $flash [ $key ] = 'new' ;
Session :: set ( $key , $val );
2008-12-15 08:56:18 +00:00
}
}
/**
* Freshen one , multiple or all flash variables .
*
* @ param string variable key ( s )
* @ return void
*/
public function keep_flash ( $keys = NULL )
{
2009-03-17 18:56:01 +00:00
$keys = ( $keys === NULL ) ? array_keys ( Session :: $flash ) : func_get_args ();
2008-12-15 08:56:18 +00:00
foreach ( $keys as $key )
{
2009-03-17 18:56:01 +00:00
if ( isset ( Session :: $flash [ $key ]))
2008-12-15 08:56:18 +00:00
{
2009-03-17 18:56:01 +00:00
Session :: $flash [ $key ] = 'new' ;
2008-12-15 08:56:18 +00:00
}
}
}
/**
* Expires old flash data and removes it from the session .
*
* @ return void
*/
public function expire_flash ()
{
static $run ;
// Method can only be run once
if ( $run === TRUE )
return ;
2009-03-17 18:56:01 +00:00
if ( ! empty ( Session :: $flash ))
2008-12-15 08:56:18 +00:00
{
2009-03-17 18:56:01 +00:00
foreach ( Session :: $flash as $key => $state )
2008-12-15 08:56:18 +00:00
{
if ( $state === 'old' )
{
// Flash has expired
2009-03-17 18:56:01 +00:00
unset ( Session :: $flash [ $key ], $_SESSION [ $key ]);
2008-12-15 08:56:18 +00:00
}
else
{
// Flash will expire
2009-03-17 18:56:01 +00:00
Session :: $flash [ $key ] = 'old' ;
2008-12-15 08:56:18 +00:00
}
}
}
// Method has been run
$run = TRUE ;
}
/**
* Get a variable . Access to sub - arrays is supported with key . subkey .
*
* @ param string variable key
* @ param mixed default value returned if variable does not exist
* @ return mixed Variable data if key specified , otherwise array containing all session data .
*/
public function get ( $key = FALSE , $default = FALSE )
{
if ( empty ( $key ))
return $_SESSION ;
$result = isset ( $_SESSION [ $key ]) ? $_SESSION [ $key ] : Kohana :: key_string ( $_SESSION , $key );
return ( $result === NULL ) ? $default : $result ;
}
/**
* Get a variable , and delete it .
*
* @ param string variable key
* @ param mixed default value returned if variable does not exist
* @ return mixed
*/
public function get_once ( $key , $default = FALSE )
{
2009-03-17 18:56:01 +00:00
$return = Session :: get ( $key , $default );
Session :: delete ( $key );
2008-12-15 08:56:18 +00:00
return $return ;
}
/**
* Delete one or more variables .
*
* @ param string variable key ( s )
* @ return void
*/
public function delete ( $keys )
{
$args = func_get_args ();
foreach ( $args as $key )
{
2009-03-17 18:56:01 +00:00
if ( isset ( Session :: $protect [ $key ]))
2008-12-15 08:56:18 +00:00
continue ;
// Unset the key
unset ( $_SESSION [ $key ]);
}
}
2009-06-30 20:48:16 -07:00
/**
* Do not save this session .
* This is a performance feature only , if using the native
* session " driver " the save will NOT be aborted .
2009-11-24 19:20:36 -08:00
*
2009-06-30 20:48:16 -07:00
* @ return void
*/
public function abort_save ()
{
Session :: $should_save = FALSE ;
}
2008-12-15 08:56:18 +00:00
} // End Session Class