506 lines
9.6 KiB
PHP
506 lines
9.6 KiB
PHP
|
<?php defined('SYSPATH') OR die('No direct script access.');
|
||
|
/**
|
||
|
* Base session class.
|
||
|
*
|
||
|
* @package Kohana
|
||
|
* @category Session
|
||
|
* @author Kohana Team
|
||
|
* @copyright (c) 2008-2012 Kohana Team
|
||
|
* @license http://kohanaframework.org/license
|
||
|
*/
|
||
|
abstract class Kohana_Session {
|
||
|
|
||
|
/**
|
||
|
* @var string default session adapter
|
||
|
*/
|
||
|
public static $default = 'native';
|
||
|
|
||
|
/**
|
||
|
* @var array session instances
|
||
|
*/
|
||
|
public static $instances = array();
|
||
|
|
||
|
/**
|
||
|
* Creates a singleton session of the given type. Some session types
|
||
|
* (native, database) also support restarting a session by passing a
|
||
|
* session id as the second parameter.
|
||
|
*
|
||
|
* $session = Session::instance();
|
||
|
*
|
||
|
* [!!] [Session::write] will automatically be called when the request ends.
|
||
|
*
|
||
|
* @param string $type type of session (native, cookie, etc)
|
||
|
* @param string $id session identifier
|
||
|
* @return Session
|
||
|
* @uses Kohana::$config
|
||
|
*/
|
||
|
public static function instance($type = NULL, $id = NULL)
|
||
|
{
|
||
|
if ($type === NULL)
|
||
|
{
|
||
|
// Use the default type
|
||
|
$type = Session::$default;
|
||
|
}
|
||
|
|
||
|
if ( ! isset(Session::$instances[$type]))
|
||
|
{
|
||
|
// Load the configuration for this type
|
||
|
$config = Kohana::$config->load('session')->get($type);
|
||
|
|
||
|
// Set the session class name
|
||
|
$class = 'Session_'.ucfirst($type);
|
||
|
|
||
|
// Create a new session instance
|
||
|
Session::$instances[$type] = $session = new $class($config, $id);
|
||
|
|
||
|
// Write the session at shutdown
|
||
|
register_shutdown_function(array($session, 'write'));
|
||
|
}
|
||
|
|
||
|
return Session::$instances[$type];
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @var string cookie name
|
||
|
*/
|
||
|
protected $_name = 'session';
|
||
|
|
||
|
/**
|
||
|
* @var int cookie lifetime
|
||
|
*/
|
||
|
protected $_lifetime = 0;
|
||
|
|
||
|
/**
|
||
|
* @var bool encrypt session data?
|
||
|
*/
|
||
|
protected $_encrypted = FALSE;
|
||
|
|
||
|
/**
|
||
|
* @var array session data
|
||
|
*/
|
||
|
protected $_data = array();
|
||
|
|
||
|
/**
|
||
|
* @var bool session destroyed?
|
||
|
*/
|
||
|
protected $_destroyed = FALSE;
|
||
|
|
||
|
/**
|
||
|
* Overloads the name, lifetime, and encrypted session settings.
|
||
|
*
|
||
|
* [!!] Sessions can only be created using the [Session::instance] method.
|
||
|
*
|
||
|
* @param array $config configuration
|
||
|
* @param string $id session id
|
||
|
* @return void
|
||
|
* @uses Session::read
|
||
|
*/
|
||
|
public function __construct(array $config = NULL, $id = NULL)
|
||
|
{
|
||
|
if (isset($config['name']))
|
||
|
{
|
||
|
// Cookie name to store the session id in
|
||
|
$this->_name = (string) $config['name'];
|
||
|
}
|
||
|
|
||
|
if (isset($config['lifetime']))
|
||
|
{
|
||
|
// Cookie lifetime
|
||
|
$this->_lifetime = (int) $config['lifetime'];
|
||
|
}
|
||
|
|
||
|
if (isset($config['encrypted']))
|
||
|
{
|
||
|
if ($config['encrypted'] === TRUE)
|
||
|
{
|
||
|
// Use the default Encrypt instance
|
||
|
$config['encrypted'] = 'default';
|
||
|
}
|
||
|
|
||
|
// Enable or disable encryption of data
|
||
|
$this->_encrypted = $config['encrypted'];
|
||
|
}
|
||
|
|
||
|
// Load the session
|
||
|
$this->read($id);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Session object is rendered to a serialized string. If encryption is
|
||
|
* enabled, the session will be encrypted. If not, the output string will
|
||
|
* be encoded.
|
||
|
*
|
||
|
* echo $session;
|
||
|
*
|
||
|
* @return string
|
||
|
* @uses Encrypt::encode
|
||
|
*/
|
||
|
public function __toString()
|
||
|
{
|
||
|
// Serialize the data array
|
||
|
$data = $this->_serialize($this->_data);
|
||
|
|
||
|
if ($this->_encrypted)
|
||
|
{
|
||
|
// Encrypt the data using the default key
|
||
|
$data = Encrypt::instance($this->_encrypted)->encode($data);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Encode the data
|
||
|
$data = $this->_encode($data);
|
||
|
}
|
||
|
|
||
|
return $data;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns the current session array. The returned array can also be
|
||
|
* assigned by reference.
|
||
|
*
|
||
|
* // Get a copy of the current session data
|
||
|
* $data = $session->as_array();
|
||
|
*
|
||
|
* // Assign by reference for modification
|
||
|
* $data =& $session->as_array();
|
||
|
*
|
||
|
* @return array
|
||
|
*/
|
||
|
public function & as_array()
|
||
|
{
|
||
|
return $this->_data;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Get the current session id, if the session supports it.
|
||
|
*
|
||
|
* $id = $session->id();
|
||
|
*
|
||
|
* [!!] Not all session types have ids.
|
||
|
*
|
||
|
* @return string
|
||
|
* @since 3.0.8
|
||
|
*/
|
||
|
public function id()
|
||
|
{
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Get the current session cookie name.
|
||
|
*
|
||
|
* $name = $session->name();
|
||
|
*
|
||
|
* @return string
|
||
|
* @since 3.0.8
|
||
|
*/
|
||
|
public function name()
|
||
|
{
|
||
|
return $this->_name;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Get a variable from the session array.
|
||
|
*
|
||
|
* $foo = $session->get('foo');
|
||
|
*
|
||
|
* @param string $key variable name
|
||
|
* @param mixed $default default value to return
|
||
|
* @return mixed
|
||
|
*/
|
||
|
public function get($key, $default = NULL)
|
||
|
{
|
||
|
return array_key_exists($key, $this->_data) ? $this->_data[$key] : $default;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Get and delete a variable from the session array.
|
||
|
*
|
||
|
* $bar = $session->get_once('bar');
|
||
|
*
|
||
|
* @param string $key variable name
|
||
|
* @param mixed $default default value to return
|
||
|
* @return mixed
|
||
|
*/
|
||
|
public function get_once($key, $default = NULL)
|
||
|
{
|
||
|
$value = $this->get($key, $default);
|
||
|
|
||
|
unset($this->_data[$key]);
|
||
|
|
||
|
return $value;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Set a variable in the session array.
|
||
|
*
|
||
|
* $session->set('foo', 'bar');
|
||
|
*
|
||
|
* @param string $key variable name
|
||
|
* @param mixed $value value
|
||
|
* @return $this
|
||
|
*/
|
||
|
public function set($key, $value)
|
||
|
{
|
||
|
$this->_data[$key] = $value;
|
||
|
|
||
|
return $this;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Set a variable by reference.
|
||
|
*
|
||
|
* $session->bind('foo', $foo);
|
||
|
*
|
||
|
* @param string $key variable name
|
||
|
* @param mixed $value referenced value
|
||
|
* @return $this
|
||
|
*/
|
||
|
public function bind($key, & $value)
|
||
|
{
|
||
|
$this->_data[$key] =& $value;
|
||
|
|
||
|
return $this;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Removes a variable in the session array.
|
||
|
*
|
||
|
* $session->delete('foo');
|
||
|
*
|
||
|
* @param string $key,... variable name
|
||
|
* @return $this
|
||
|
*/
|
||
|
public function delete($key)
|
||
|
{
|
||
|
$args = func_get_args();
|
||
|
|
||
|
foreach ($args as $key)
|
||
|
{
|
||
|
unset($this->_data[$key]);
|
||
|
}
|
||
|
|
||
|
return $this;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Loads existing session data.
|
||
|
*
|
||
|
* $session->read();
|
||
|
*
|
||
|
* @param string $id session id
|
||
|
* @return void
|
||
|
*/
|
||
|
public function read($id = NULL)
|
||
|
{
|
||
|
$data = NULL;
|
||
|
|
||
|
try
|
||
|
{
|
||
|
if (is_string($data = $this->_read($id)))
|
||
|
{
|
||
|
if ($this->_encrypted)
|
||
|
{
|
||
|
// Decrypt the data using the default key
|
||
|
$data = Encrypt::instance($this->_encrypted)->decode($data);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Decode the data
|
||
|
$data = $this->_decode($data);
|
||
|
}
|
||
|
|
||
|
// Unserialize the data
|
||
|
$data = $this->_unserialize($data);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Ignore these, session is valid, likely no data though.
|
||
|
}
|
||
|
}
|
||
|
catch (Exception $e)
|
||
|
{
|
||
|
// Error reading the session, usually a corrupt session.
|
||
|
throw new Session_Exception('Error reading session data.', NULL, Session_Exception::SESSION_CORRUPT);
|
||
|
}
|
||
|
|
||
|
if (is_array($data))
|
||
|
{
|
||
|
// Load the data locally
|
||
|
$this->_data = $data;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Generates a new session id and returns it.
|
||
|
*
|
||
|
* $id = $session->regenerate();
|
||
|
*
|
||
|
* @return string
|
||
|
*/
|
||
|
public function regenerate()
|
||
|
{
|
||
|
return $this->_regenerate();
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Sets the last_active timestamp and saves the session.
|
||
|
*
|
||
|
* $session->write();
|
||
|
*
|
||
|
* [!!] Any errors that occur during session writing will be logged,
|
||
|
* but not displayed, because sessions are written after output has
|
||
|
* been sent.
|
||
|
*
|
||
|
* @return boolean
|
||
|
* @uses Kohana::$log
|
||
|
*/
|
||
|
public function write()
|
||
|
{
|
||
|
if (headers_sent() OR $this->_destroyed)
|
||
|
{
|
||
|
// Session cannot be written when the headers are sent or when
|
||
|
// the session has been destroyed
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
// Set the last active timestamp
|
||
|
$this->_data['last_active'] = time();
|
||
|
|
||
|
try
|
||
|
{
|
||
|
return $this->_write();
|
||
|
}
|
||
|
catch (Exception $e)
|
||
|
{
|
||
|
// Log & ignore all errors when a write fails
|
||
|
Kohana::$log->add(Log::ERROR, Kohana_Exception::text($e))->write();
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Completely destroy the current session.
|
||
|
*
|
||
|
* $success = $session->destroy();
|
||
|
*
|
||
|
* @return boolean
|
||
|
*/
|
||
|
public function destroy()
|
||
|
{
|
||
|
if ($this->_destroyed === FALSE)
|
||
|
{
|
||
|
if ($this->_destroyed = $this->_destroy())
|
||
|
{
|
||
|
// The session has been destroyed, clear all data
|
||
|
$this->_data = array();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return $this->_destroyed;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Restart the session.
|
||
|
*
|
||
|
* $success = $session->restart();
|
||
|
*
|
||
|
* @return boolean
|
||
|
*/
|
||
|
public function restart()
|
||
|
{
|
||
|
if ($this->_destroyed === FALSE)
|
||
|
{
|
||
|
// Wipe out the current session.
|
||
|
$this->destroy();
|
||
|
}
|
||
|
|
||
|
// Allow the new session to be saved
|
||
|
$this->_destroyed = FALSE;
|
||
|
|
||
|
return $this->_restart();
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Serializes the session data.
|
||
|
*
|
||
|
* @param array $data data
|
||
|
* @return string
|
||
|
*/
|
||
|
protected function _serialize($data)
|
||
|
{
|
||
|
return serialize($data);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Unserializes the session data.
|
||
|
*
|
||
|
* @param string $data data
|
||
|
* @return array
|
||
|
*/
|
||
|
protected function _unserialize($data)
|
||
|
{
|
||
|
return unserialize($data);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Encodes the session data using [base64_encode].
|
||
|
*
|
||
|
* @param string $data data
|
||
|
* @return string
|
||
|
*/
|
||
|
protected function _encode($data)
|
||
|
{
|
||
|
return base64_encode($data);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Decodes the session data using [base64_decode].
|
||
|
*
|
||
|
* @param string $data data
|
||
|
* @return string
|
||
|
*/
|
||
|
protected function _decode($data)
|
||
|
{
|
||
|
return base64_decode($data);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Loads the raw session data string and returns it.
|
||
|
*
|
||
|
* @param string $id session id
|
||
|
* @return string
|
||
|
*/
|
||
|
abstract protected function _read($id = NULL);
|
||
|
|
||
|
/**
|
||
|
* Generate a new session id and return it.
|
||
|
*
|
||
|
* @return string
|
||
|
*/
|
||
|
abstract protected function _regenerate();
|
||
|
|
||
|
/**
|
||
|
* Writes the current session.
|
||
|
*
|
||
|
* @return boolean
|
||
|
*/
|
||
|
abstract protected function _write();
|
||
|
|
||
|
/**
|
||
|
* Destroys the current session.
|
||
|
*
|
||
|
* @return boolean
|
||
|
*/
|
||
|
abstract protected function _destroy();
|
||
|
|
||
|
/**
|
||
|
* Restarts the current session.
|
||
|
*
|
||
|
* @return boolean
|
||
|
*/
|
||
|
abstract protected function _restart();
|
||
|
|
||
|
} // End Session
|