Session类并不使用PHP本身的session,而是使用类自己的session,这样做,可以给开发者提供更大的弹性。下面我们就来仔细分析下CI框架的Session类Session.php文件
CI的Session并不是原生的session,正是我前面所有的cookie based session,另外,CI可以根据用户选择配置是否将session存入数据库中,本人很喜欢这个功能,,还有就是“闪出数据”的功能,既闪出数据只是对下次服务器请求可以,之后就会被自动清除。常见使用方法有:
$this->session->set_userdata('some_name', 'some_value'); //设置session数据
$this->session->userdata('item'); //获取session数据
$this->session->unset_userdata('some_name'); //删除session数据
$this->session->sess_destroy(); //销毁session数据
$this->session->set_flashdata('item', 'value'); //设置闪存数据
$this->session->flashdata('item'); //获取闪存数据
$this->session->keep_flashdata('item'); //保留闪存数据
复制代码 代码如下:
/**
* CI 是基于会话的 cookie
*/
class CI_Session {
var $sess_encrypt_cookie = FALSE; //是否对session加密
var $sess_use_database = FALSE; //是否将session存入数据库
var $sess_table_name = ''; //session存入数据的表名
var $sess_expiration = 7200; //session的过期时间
var $sess_expire_on_close = FALSE; //当浏览器窗口关闭时是否自动使session过期
var $sess_match_ip = FALSE;//是否通过用户的IP地址来读取 session 的数据
var $sess_match_useragent = TRUE; //是否要按照对应的 User Agent 来读取 session 数据。
var $sess_cookie_name = 'ci_session'; //cookie名称
var $cookie_prefix = ''; //cookie前缀
var $cookie_path = ''; //cookie路径
var $cookie_domain = ''; //cookie作用域
var $cookie_secure = FALSE; //是否在安全的https协议下才有效
var $sess_time_to_update = 300; //session cookie多久更新一次
var $encryption_key = ''; //加密key
var $flashdata_key = 'flash';
var $time_reference = 'time';
var $gc_probability = 5; //回收session的能力
var $userdata = array(); //用户session数据保存变量
var $CI; //CI超级句柄
var $now; //当前时间
public function __construct($params = array())
{
log_message('debug', "Session Class Initialized");
// 获取CI超级类
$this->CI =& get_instance();
// 获取config文件中的配置数据
foreach (array('sess_encrypt_cookie', 'sess_use_database', 'sess_table_name', 'sess_expiration', 'sess_expire_on_close', 'sess_match_ip', 'sess_match_useragent', 'sess_cookie_name', 'cookie_path', 'cookie_domain', 'cookie_secure', 'sess_time_to_update', 'time_reference', 'cookie_prefix', 'encryption_key') as $key)
{
$this->$key = (isset($params[$key])) ? $params[$key] : $this->CI->config->item($key);
}
//必须设置encryption_key
if ($this->encryption_key == '')
{
show_error('In order to use the Session class you are required to set an encryption key in your config file.');
}
// 加载string helper函数
$this->CI->load->helper('string');
// D如果对cookie进行加密,则引入加密类
if ($this->sess_encrypt_cookie == TRUE)
{
$this->CI->load->library('encrypt');
}
// 如果session计入数据库,则引入db
if ($this->sess_use_database === TRUE AND $this->sess_table_name != '')
{
$this->CI->load->database();
}
// 获取当前时间
$this->now = $this->_get_time();
// 如果没有设置session的有效时间,默认两年
if ($this->sess_expiration == 0)
{
$this->sess_expiration = (60*60*24*365*2);
}
// 获取cookie名称
$this->sess_cookie_name = $this->cookie_prefix.$this->sess_cookie_name;
// 如果session不存在,创建新会话
if ( ! $this->sess_read())
{
$this->sess_create();
}
else
{
$this->sess_update();
}
// 闪出标记old的闪出数据
$this->_flashdata_sweep();
//将新的闪出数据标记成old 标记成old的数据的数据将会在下次请求时闪出
$this->_flashdata_mark();
//回收/删除 过期的session
$this->_sess_gc();
log_message('debug', "Session routines successfully run");
}
// ------------------------------------------------ --------------------
/**
* 读取session数据
*/
函数 sess_read()
{
// 获取会话
$session = $this->CI->input->cookie($this->sess_cookie_name);
// 没有会话 拜拜
if ($session === FALSE)
{
log_message('debug', '未找到会话 cookie。');
返回FALSE;
}
// 如果加密了cookie
if ($this->sess_encrypt_cookie == TRUE)
{
$session = $this->CI->加密->解码($session);
}
其他
{
// 没有使用加密,所以我们需要检查 md5 哈希
$hash = substr($session, strlen($session)-32); // 获取最后 32 个字符
$session = substr($session, 0, strlen($session)-32);
// md5 哈希值是否匹配? 这是为了防止在用户空间中操纵会话数据
if ($hash !== md5($session.$this->encryption_key))
{
log_message('error', '会话 cookie 数据与预期不符。这可能是黑客尝试。');
$this->sess_destroy();
返回FALSE;
}
}
// 反序列化存入cookie的会话吞吐量
$session = $this->_unserialize($session);
// 检测会话的数据
if ( ! is_array($session) OR ! isset($session['session_id']) OR ! isset($session['ip_address']) OR ! isset($session['user_agent']) OR ! isset($session ['last_activity']))
{
$this->sess_destroy();
返回FALSE;
}
// session数据已经过期
if (($session['last_activity'] $this->sess_expiration) now)
{
$this->sess_destroy();
返回FALSE;
}
// 是否是根据用户ip来读取session数据
if ($this->sess_match_ip == TRUE AND $session['ip_address'] != $this->CI->input->ip_address())
{
$this->sess_destroy();
返回FALSE;
}
// 是否根据ua来匹配session数据
if ($this->sess_match_useragent == TRUE AND trim($session['user_agent']) != trim(substr($this->CI->input->user_agent(), 0, 120)) )
{
$this->sess_destroy();
返回FALSE;
}
// 如果session入库了,这种方式应该更安全点,当然负载大时,就不建议了,数据库读写压力大
if ($this->sess_use_database === TRUE)
{
$this->CI->db->where('session_id', $session['session_id']);
if ($this->sess_match_ip == TRUE)
{
$this->CI->db->where('ip_address', $session['ip_address']);
}
if ($this->sess_match_useragent == TRUE)
{
$this->CI->db->where('user_agent', $session['user_agent']);
}
$query = $this->CI->db->get($this->sess_table_name);
// 没有结果? 杀了它!
if ($query->num_rows() == 0)
{
$this->sess_destroy();
返回FALSE;
}
// 是否有自定义数据? 如果是,则将其添加到主会话数组
$row = $query->row();
if (isset($row->user_data) AND $row->user_data != '')
{
$custom_data = $this->_unserialize($row->user_data);
if (is_array($custom_data))
{
foreach ($custom_data as $key => $val)
{
$session[$key] = $val;
}
}
}
}
// 会话有效!
$this->userdata = $session;
未设置($session);
返回 TRUE;
}
// ------------------------------------------------ --------------------
/**
* 将读取的session数据写入
*/
函数 sess_write()
{
// 是否写入db
if ($this->sess_use_database === FALSE)
{
$this->_set_cookie();
返回;
}
// 设置自定义用户数据,我们稍后将设置会话数据
$custom_userdata = $this->userdata;
$cookie_userdata = array();
// 在继续之前,我们需要确定是否有任何自定义数据需要处理。
// 让我们通过删除默认索引来确定这一点,看看数组中是否还剩下任何东西
// 并设置会话数据
foreach (array('session_id','ip_address','user_agent','last_activity') as $val)
{
取消设置($custom_userdata[$val]);
$cookie_userdata[$val] = $this->userdata[$val];
}
// 我们找到任何自定义数据了吗? 如果没有,我们将空数组转为字符串
// 因为没有理由在数据库中序列化和存储空数组
if (count($custom_userdata) === 0)
{
$custom_userdata = '';
}
其他
{
// 序列化自定义数据数组以便我们可以存储它
$custom_userdata = $this->_serialize($custom_userdata);
}
// 更新会话记录
$this->CI->db->where('session_id', $this->userdata['session_id']);
$this->CI->db->update($this->sess_table_name, array('last_activity' => $this->userdata['last_activity'], 'user_data' => $custom_userdata ));
// 写入cookie。 请注意,我们手动将 cookie 数据数组传递给
// _set_cookie() 函数。通常该函数将存储 $this->userdata,但是
// 在这种情况下,数组包含自定义数据,我们不希望在 cookie 中包含这些数据。
$this->_set_cookie($cookie_userdata);
}
// ------------------------------------------------ --------------------
/**
* 创建一个新的session
*/
函数 sess_create()
{
//保证sessid安全唯一
$sessid = '';
while (strlen($sessid)
{
$sessid .= mt_rand(0, mt_getrandmax());
}
$sessid .= $this->CI->input->ip_address();
$this->userdata = array(
'session_id'=>; md5(uniqid($sessid, TRUE)),
'ip_address' =>; $this->CI->input->ip_address(),
'user_agent' =>; substr($this->CI->input->user_agent(), 0, 120),
'last_activity'=>; $这个->现在,
'user_data' =>; ''
);
// 如果需要,将数据保存到数据库
if ($this->sess_use_database === TRUE)
{
$this->CI->db->query($this->CI->db->insert_string($this->sess_table_name, $this->userdata));
}
// 写入cookie
$this->_set_cookie();
}
// ------------------------------------------------ --------------------
/**
* 更新session
*/
函数 sess_update()
{
// 默认五分钟更新
if (($this->userdata['last_activity'] $this->sess_time_to_update) >= $this->now)
{
返回;
}
// 保存旧的会话 ID,以便我们知道哪个记录要
// 如果需要的话更新数据库
$old_sessid = $this->userdata['session_id'];
$new_sessid = '';
while (strlen($new_sessid)
{
$new_sessid .= mt_rand(0, mt_getrandmax());
}
// 为了使会话 ID 更加安全,我们将其与用户的 IP 结合起来
$new_sessid .= $this->CI->input->ip_address();
// 将其转换为哈希
$new_sessid = md5(uniqid($new_sessid, TRUE));
// 更新会话数据数组中的会话数据
$this->userdata['session_id'] = $new_sessid;
$this->userdata['last_activity'] = $this->now;
// 如果我们不使用数据库会话,_set_cookie() 将为我们处理这个问题
// 将所有用户数据推送到 cookie。
$cookie_data = NULL;
// 更新数据库中内容
if ($this->sess_use_database === TRUE)
{
// 显式设置 cookie 仅包含我们的会话数据
$cookie_data = array();
foreach (array('session_id','ip_address','user_agent','last_activity') as $val)
{
$cookie_data[$val] = $this->userdata[$val];
}
$this->CI->db->query($this->CI->db->update_string($this->sess_table_name, array('last_activity' => $this->;现在, 'session_id' => $new_sessid), array('session_id' => $old_sessid)));
}
// 重新写入会话
$this->_set_cookie($cookie_data);
}
// ------------------------------------------------ --------------------
/**
*销毁当前所有session数据
*/
函数 sess_destroy()
{
// 杀死会话数据库行
if ($this->sess_use_database === TRUE && isset($this->userdata['session_id']))
{
$this->CI->db->where('session_id', $this->userdata['session_id']);
$this->CI->db->delete($this->sess_table_name);
}
// 杀死 cookie
setcookie(
$this->sess_cookie_name,
addslashes(序列化(array())),
($这个->现在 - 31500000),
$this->cookie_path,
$this->cookie_domain,
0
);
// 杀死会话数据
$this->userdata = array();
}
// ------------------------------------------------ --------------------
/**
* 获取session数组指定元素的值
*/
函数用户数据($item)
{
return ( !isset($this->userdata[$item])) ? FALSE : $this->userdata[$item];
}
// ------------------------------------------------ --------------------
/**
* 获取所有session数据
*/
函数 all_userdata()
{
返回 $this->userdata;
}
// ------------------------------------------------ --------------------
/**
* 添加和修改自定义的session数据
*/
函数 set_userdata($newdata = array(), $newval = '')
{
if (is_string($newdata))
{
$newdata = array($newdata => $newval);
}
//支持备份方式组合
if (count($newdata) > 0)
{
foreach ($newdata as $key => $val)
{
$this->userdata[$key] = $val;
}
}
$this->sess_write();
}
// ------------------------------------------------ --------------------
/**
* 删除session数组中的元素,
*/
函数 unset_userdata($newdata = array())
{
if (is_string($newdata))
{
$newdata = array($newdata => '');
}
if (count($newdata) > 0)
{
foreach ($newdata as $key => $val)
{
取消设置($this->userdata[$key]);
}
}
$this->sess_write();
}
// ------------------------------------------------ ------------------------
/**
* 添加或更改 flashdata,仅可用
* 直到下一个请求
*
* @access 公共
* @param 混合
* @param字符串
* @return void
*/
函数 set_flashdata($newdata = array(), $newval = '')
{
if (is_string($newdata))
{
$newdata = array($newdata => $newval);
}
if (count($newdata) > 0)
{
foreach ($newdata as $key => $val)
{
$flashdata_key = $this->flashdata_key.':new:'.$key;
$this->set_userdata($flashdata_key, $val);
}
}
}
// ------------------------------------------------ ------------------------
/**
* CI支持闪出数据也就是说 Session数据只对下次服务器请求可用,有时候如果你还想在下个请求后的请求还有效。。。
* keep_flashdata功能就是讲持续保持闪出数据,使其在下个请求也有效
*/
函数 keep_flashdata($key)
{
//将闪出数据标记成新
$old_flashdata_key = $this->flashdata_key.':old:'.$key;
$value = $this->userdata($old_flashdata_key);
$new_flashdata_key = $this->flashdata_key.':new:'.$key;
$this->set_userdata($new_flashdata_key, $value);
}
// ------------------------------------------------ ------------------------
/**
* 获取闪出数据
*/
函数 flashdata($key)
{
$flashdata_key = $this->flashdata_key.':old:'.$key;
返回 $this->userdata($flashdata_key);
}
// ------------------------------------------------ ------------------------
/**
* 将闪出数据标记成old,以便_flashdata_sweep清除数据
*/
函数_flashdata_mark()
{
$userdata = $this->all_userdata();
foreach ($userdata as $name => $value)
{
$parts =explode(':new:', $name);
if (is_array($parts) && count($parts) === 2)
{
$new_name = $this->flashdata_key.':old:'.$parts[1];
$this->set_userdata($new_name, $value);
$this->unset_userdata($name);
}
}
}
// ------------------------------------------------ ------------------------
/**
* 将标记成old的闪出数据闪出
*/
函数_flashdata_sweep()
{
$userdata = $this->all_userdata();
foreach ($userdata as $key => $value)
{
if (strpos($key, ':old:'))
{
$this->unset_userdata($key);
}
}
}
//获取当前时间
函数_get_time()
{
if (strtolower($this->time_reference) == 'gmt')
{
$现在 = 时间();
$time = mktime(gmdate("H", $now), gmdate("i", $now), gmdate("s", $now), gmdate("m", $now), gmdate("d" , $now), gmdate("Y", $now));
}
其他
{
$时间 = 时间();
}
返回$时间;
}
// ------------------------------------------------ --------------------
/**
* 写入session cookie
*
*/
函数 _set_cookie($cookie_data = NULL)
{
if (is_null($cookie_data))
{
$cookie_data = $this->userdata;
}
// 序列化吞吐量
$cookie_data = $this->_serialize($cookie_data);
//加密数据
if ($this->sess_encrypt_cookie == TRUE)
{
$cookie_data = $this->CI->加密->编码($cookie_data);
}
其他
{
// 如果不使用加密,我们提供一个 md5 哈希来防止用户端篡改
$cookie_data = $cookie_data.md5($cookie_data.$this->加密密钥);
}
//sess_expire_on_close为TRUE则,浏览器关闭,会话失效
$expire = ($this->sess_expire_on_close === TRUE) ? 0 : $this->sess_expiration time();
// 设置cookie
setcookie(
$this->sess_cookie_name,
$cookie_data,
$过期,
$this->cookie_path,
$this->cookie_domain,
$this->cookie_secure
);
}
// ------------------------------------------------ --------------------
/**
* 序列化数组
*/
函数_serialize($data)
{
if (is_array($data))
{
foreach ($data as $key => $val)
{
if (is_string($val))
{
$data[$key] = str_replace('\', '{{slash}}', $val);
}
}
}
其他
{
if (is_string($data))
{
$data = str_replace('\', '{{slash}}', $data);
}
}
返回序列化($data);
}
// ------------------------------------------------ --------------------
/**
* 反序列化数组
*/
函数_unserialize($data)
{
$data = @unserialize(strip_slashes($data));
if (is_array($data))
{
foreach ($data as $key => $val)
{
if (is_string($val))
{
$data[$key] = str_replace('{{slash}}', '\', $val);
}
}
返回 $data;
}
返回(is_string($data))? str_replace('{{slash}}', '\', $data) : $data;
}
// ------------------------------------------------ --------------------
/**
* 回收/删除数据库中失效的session信息
*/
函数_sess_gc()
{
if ($this->sess_use_database != TRUE)
{
返回;
}
srand(时间());
if ((rand() % 100) gc_probability)
{
$expire = $this->now - $this->sess_expiration;
$this->CI->db->where("last_activity
$this->CI->db->delete($this->sess_table_name);
log_message('debug', '执行会话垃圾收集。');
}
}
}

热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

Video Face Swap
使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热门文章

热工具

SublimeText3 Linux新版
SublimeText3 Linux最新版

SublimeText3 Mac版
神级代码编辑软件(SublimeText3)

Atom编辑器mac版下载
最流行的的开源编辑器

EditPlus 中文破解版
体积小,语法高亮,不支持代码提示功能

禅工作室 13.0.1
功能强大的PHP集成开发环境