初始化 Session 类:
this−>load−>library(‘session′);初始化之后,就可以使用
this->session来访问 Session 对象了。
在 CLI 模式下,Session 类将自动关闭。
在 CodeIgniter 之前的版本中,Session 类并没有实现锁机制,这也就意味着, 两个 HTTP 请求可能会同时使用同一个 session 。说的更专业点就是, 请求是非阻塞的。(requests were non-blocking)
在处理 session 时使用非阻塞的请求同样意味着不安全,因为在一个请求中修改 session 数据(或重新生成 Session ID)会对并发的第二个请求造成影响。这是导致很多问题的根源,同时也是为什么 CodeIgniter 3.0 对 Session 类完全重写的原因。
Session 类自带了 4 种不同的驱动(或叫做存储引擎)可供使用:
files/database/redis/memcached。默认情况下,初始化 session 时将使用文件驱动
SESSION实现的类关系图
一、接口:SessionHandlerInterface.php定义了包含6个方法的接口
自定义session驱动见文章《PHP中用户自定义Session处理机制 》
interface SessionHandlerInterface {
public function open($save_path, $name);
public function close();
public function read($session_id);
public function write($session_id, $session_data);
public function destroy($session_id);
public function gc($maxlifetime);
}
二、抽像类:CI_Session_driver
抽像类CI_Session_driver定义了session五个接口(除read方法是返回数据外)返回值(成功/失败)的规范
并定义了加锁/解锁方法,在接下来说的CI_Session类中会用到锁
abstract class CI_Session_driver implements SessionHandlerInterface {
protected $_config;
protected $_fingerprint;//保存session文件内容的md5摘要
protected $_lock = FALSE;
protected $_session_id;
//定义SessionHandlerInterface接口方法中返回成功或失败的值
protected $_success, $_failure;
public function __construct(&$params)
{
$this->_config =& $params;
//接口方法中,所有函数需要返回成功或失败。
//PHP7以前的版本用0表示成功,-1表示失败。在PHP7改成了true代表成功,false代表失败。
//如果不注意区分,那么0值在不同版本的意义就截然相反了。
//所以在构造函数中,根据当前php版本,对属性$this->_success, $this->_failure进行了定义。
if (is_php('7'))
{
$this->_success = TRUE;
$this->_failure = FALSE;
}
else
{
$this->_success = 0;
$this->_failure = -1;
}
}
//当调用destory()方法时,清空客户端的cookie
protected function _cookie_destroy()
{
return setcookie(
$this->_config['cookie_name'],
NULL,
1,
$this->_config['cookie_path'],
$this->_config['cookie_domain'],
$this->_config['cookie_secure'],
TRUE
);
}
//session锁机制,给当前请求中的session对像上锁
protected function _get_lock($session_id)
{
$this->_lock = TRUE;
return TRUE;
}
//session锁机制,给当前请求中的session对像解锁
protected function _release_lock()
{
if ($this->_lock)
{
$this->_lock = FALSE;
}
return TRUE;
}
}
三、SESSION类,暴露给用户调用的类
config配置
session常见配置参考《PHP.INI配置:Session配置详细说明 》
$config['sess_driver'] = 'files';//驱动类型
$config['sess_cookie_name'] = 'ci_session'; //客户端存储sessionid的cookies键值
$config['sess_expiration'] = 7200; //session过期时间
$config['sess_save_path'] = NULL; //存储路径
$config['sess_match_ip'] = FALSE;
$config['sess_time_to_update'] = 300;
$config['sess_regenerate_destroy'] = FALSE;
获取 Session 数据
1、
name=
_SESSION[‘name’];
2、
name=
this->session->name;
由__get魔术方法实现
public function __get($key)
{
//如果请求的KEY存在,则返回
if (isset($_SESSION[$key]))
{
return $_SESSION[$key];
}
//如果是$this->session->session_id,就返回session_id()
elseif ($key === 'session_id')
{
return session_id();
}
return NULL;
}
3、
name=
this->session->userdata(‘name’);//如果访问项不存在,返回 NULL
获取所有已存在的:$this->session->userdata();
public function userdata($key = NULL)
{
//如果$key存在且命中,则返回值;如果没有命中则返回NULL
if (isset($key))
{
return isset($_SESSION[$key]) ? $_SESSION[$key] : NULL;
}
//如果key为null,同时$_SESSION还没有数据,则返回空数组
elseif (empty($_SESSION))
{
return array();
}
//下面开始处理$key为NULL情况下,函数返回全部$_SESSION的情况
$userdata = array();
//返回值中要排除的两种特殊的数据用到的key,一种是使用一次就失效的flash_key,一种是过期就失效的temp_key
//因为他们都保存在__ci_vars键中,所以__ci_vars本身这个key也要排除
$_exclude = array_merge(
array('__ci_vars'),
$this->get_flash_keys(),
$this->get_temp_keys()
);
//遍历$_SESSION并生成$userdata
foreach (array_keys($_SESSION) as $key)
{
if ( ! in_array($key, $_exclude, TRUE))
{
$userdata[$key] = $_SESSION[$key];
}
}
return $userdata;
}
添加 Session 数据
$newdata = array(
'username' => 'johndoe',
'email' => 'johndoe@some-site.com',
'logged_in' => TRUE
);
$this->session->set_userdata($newdata);
$this->session->set_userdata('some_name', 'some_value');
//set_userdata函数如下:
public function set_userdata($data, $value = NULL)
{
//解析数组方式
if (is_array($data))
{
foreach ($data as $key => &$value)
{
$_SESSION[$key] = $value;
}
return;
}
//解析键值对方式
$_SESSION[$data] = $value;
}
删除 Session 数据
unset($_SESSION['some_name']);
// or multiple values:
unset(
$_SESSION['some_name'],
$_SESSION['another_name']
);
//or
$this->session->unset_userdata('some_name');
//unset_userdata实现
public function unset_userdata($key)
{
//数组方式
if (is_array($key))
{
foreach ($key as $k)
{
unset($_SESSION[$k]);
}
return;
}
//单个键
unset($_SESSION[$key]);
}
销毁 Session
session_destroy();
// or
$this->session->sess_destroy();
//sess_destroy就是调用原生session_destroy()方法
public function sess_destroy()
{
session_destroy();
}
当 session 已经处理完毕不再需要时, 你还将 session 保持是打开的状态是容易引发低效的。所以,必须当结束当前请求时, 将不再需要的 session 关闭掉。简单来说就是:当不再需要使用某个 session 变量时,就使用 session_write_close() 方法来关闭它。
register_shutdown_function(‘session_write_close’);