You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

262 lines
7.9 KiB

<?php
/**
* li₃: the most RAD framework for PHP (http://li3.me)
*
* Copyright 2009, Union of RAD. All rights reserved. This source
* code is distributed under the terms of the BSD 3-Clause License.
* The full license text can be found in the LICENSE.txt file.
*/
namespace lithium\storage\session\adapter;
use lithium\util\Set;
use RuntimeException;
use lithium\core\ConfigException;
use lithium\core\Libraries;
/**
* A minimal adapter to interface with native PHP sessions.
*
* This adapter provides basic support for `write`, `read` and `delete`
* session handling, as well as allowing these three methods to be filtered as
* per the Lithium filtering system.
*/
class Php extends \lithium\core\ObjectDeprecated {
/**
* Default ini settings for this session adapter. Will disabl cookie lifetime,
* set cookies to HTTP only and the cache_limiter to `'nocache'`.
*
* @link http://php.net/session.configuration.php
* @link http://php.net/session.configuration.php#ini.session.cookie-lifetime
* @link http://php.net/session.configuration.php#ini.session.cookie-httponly
* @link http://php.net/session.configuration.php#ini.session.cache-limiter
* @var array Configuration options matching the pattern `'session.*'` are session
* ini settings. Please consult the PHP documentation for further information.
*/
protected $_defaults = [
'session.cookie_lifetime' => '0',
'session.cookie_httponly' => true,
'session.cache_limiter' => 'nocache'
];
/**
* Constructor. Takes care of setting appropriate configurations for this object. Also sets
* session ini settings.
*
* @see lithium\storage\session\adapter\Php::$_defaults
* @param array $config Configuration options matching the pattern `'session.*'` are interpreted
* as session ini settings. Please consult the PHP documentation for further
* information.
* A few ini settings are set by default here and will overwrite those from
* your php.ini. To disable sending a cache limiter set `'session.cache_limiter'`
* to `false`.
* @return void
*/
public function __construct(array $config = []) {
if (empty($config['session.name'])) {
$config['session.name'] = basename(Libraries::get(true, 'path'));
}
parent::__construct($config + $this->_defaults);
}
/**
* Initialization of the session.
*
* @todo Split up into an _initialize() and a _start().
*/
protected function _init() {
if ($this->isStarted()) {
return true;
}
$config = $this->_config;
unset($config['adapter'], $config['strategies'], $config['filters'], $config['init']);
foreach ($config as $key => $value) {
if (strpos($key, 'session.') === false) {
continue;
}
if (ini_set($key, $value) === false) {
throw new ConfigException('Could not initialize the session.');
}
}
}
/**
* Starts the session.
*
* @return boolean `true` if session successfully started
* (or has already been started), `false` otherwise.
*/
protected function _start() {
if ($this->isStarted()) {
return true;
}
session_cache_limiter();
return session_start();
}
/**
* Obtain the status of the session.
*
* @return boolean True if a session is currently started, False otherwise. If PHP 5.4
* then we know, if PHP 5.3 then we cannot tell for sure if a session
* has been closed.
*/
public function isStarted() {
if (function_exists('session_status')) {
return session_status() === PHP_SESSION_ACTIVE;
}
return isset($_SESSION) && session_id();
}
/**
* Sets or obtains the session ID.
*
* @param string $key Optional. If specified, sets the session ID to the value of `$key`.
* @return mixed Session ID, or `null` if the session has not been started.
*/
public function key($key = null) {
if ($key !== null) {
return session_id($key);
}
return session_id() ?: null;
}
/**
* Checks if a value has been set in the session.
*
* @param string $key Key of the entry to be checked.
* @param array $options Options array. Not used for this adapter method.
* @return \Closure Function returning boolean `true` if the key exists, `false` otherwise.
*/
public function check($key, array $options = []) {
if (!$this->isStarted() && !$this->_start()) {
throw new RuntimeException('Could not start session.');
}
return function($params) {
return Set::check($_SESSION, $params['key']);
};
}
/**
* Read a value from the session.
*
* @param null|string $key Key of the entry to be read. If no key is passed, all
* current session data is returned.
* @param array $options Options array. Not used for this adapter method.
* @return \Closure Function returning data in the session if successful, `false` otherwise.
*/
public function read($key = null, array $options = []) {
if (!$this->isStarted() && !$this->_start()) {
throw new RuntimeException('Could not start session.');
}
return function($params) {
$key = $params['key'];
if (!$key) {
return $_SESSION;
}
if (strpos($key, '.') === false) {
return isset($_SESSION[$key]) ? $_SESSION[$key] : null;
}
$filter = function($keys, $data) use (&$filter) {
$key = array_shift($keys);
if (isset($data[$key])) {
return (empty($keys)) ? $data[$key] : $filter($keys, $data[$key]);
}
};
return $filter(explode('.', $key), $_SESSION);
};
}
/**
* Write a value to the session.
*
* @param string $key Key of the item to be stored.
* @param mixed $value The value to be stored.
* @param array $options Options array. Not used for this adapter method.
* @return \Closure Function returning boolean `true` on successful write, `false` otherwise.
*/
public function write($key, $value, array $options = []) {
if (!$this->isStarted() && !$this->_start()) {
throw new RuntimeException('Could not start session.');
}
return function($params) {
return $this->overwrite(
$_SESSION, Set::insert($_SESSION, $params['key'], $params['value'])
);
};
}
/**
* Delete value from the session
*
* @param string $key The key to be deleted.
* @param array $options Options array. Not used for this adapter method.
* @return \Closure Function returning boolean `true` if the key no longer
* exists in the session, `false` otherwise
*/
public function delete($key, array $options = []) {
if (!$this->isStarted() && !$this->_start()) {
throw new RuntimeException('Could not start session.');
}
return function($params) {
$key = $params['key'];
$this->overwrite($_SESSION, Set::remove($_SESSION, $key));
return !Set::check($_SESSION, $key);
};
}
/**
* Clears all keys from the session.
*
* @param array $options Options array. Not used for this adapter method.
* @return \Closure Function returning boolean `true` on successful clear, `false` otherwise.
*/
public function clear(array $options = []) {
if (!$this->isStarted() && !$this->_start()) {
throw new RuntimeException('Could not start session.');
}
return function($params) {
return session_destroy();
};
}
/**
* Determines if PHP sessions are enabled.
*
* @return boolean Returns `true` if enabled (PHP session functionality
* can be disabled completely), `false` otherwise.
*/
public static function enabled() {
if (function_exists('session_status')) {
return session_status() !== PHP_SESSION_DISABLED;
}
return in_array('session', get_loaded_extensions());
}
/**
* Overwrites session keys and values.
*
* @param array $old Reference to the array that needs to be
* overwritten. Will usually be `$_SESSION`.
* @param array $new The data that should overwrite the keys/values in `$old`.
* @return boolean Always `true`.
*/
public function overwrite(&$old, $new) {
if (!empty($old)) {
foreach ($old as $key => $value) {
if (!isset($new[$key])) {
unset($old[$key]);
}
}
}
foreach ($new as $key => $value) {
$old[$key] = $value;
}
return true;
}
}
?>