首页 php教程 php手册 CI框架Session.php源码分析

CI框架Session.php源码分析

Jun 06, 2016 pm 08:18 PM
ci框架 session

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', '执行会话垃圾收集。');
  }
 }
}


本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热AI工具

Undresser.AI Undress

Undresser.AI Undress

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

AI Clothes Remover

AI Clothes Remover

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

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

AI Hentai Generator

AI Hentai Generator

免费生成ai无尽的。

热门文章

R.E.P.O.能量晶体解释及其做什么(黄色晶体)
3 周前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳图形设置
3 周前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您听不到任何人,如何修复音频
3 周前 By 尊渡假赌尊渡假赌尊渡假赌
WWE 2K25:如何解锁Myrise中的所有内容
4 周前 By 尊渡假赌尊渡假赌尊渡假赌

热工具

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

SpringBoot Session怎么设置会话超时 SpringBoot Session怎么设置会话超时 May 15, 2023 pm 02:37 PM

问题发现springboot项目生产session-out超时问题,描述下问题:在测试环境通过改动application.yaml配置session-out,经过设置不同时间验证session-out配置生效,于是就直接设置了过期时间为8小时发布到了生产环境。然而中午接到客户反应项目过期时间设置较短,半小时不操作就会话过期需要反复登陆。解决处理开发环境:springboot项目内置Tomcat,所以项目中application.yaml配置session-out是生效的。生产环境:生产环境发布是

session失效怎么解决 session失效怎么解决 Oct 18, 2023 pm 05:19 PM

session失效通常是由于 session 的生存时间过期或者服务器关闭导致的。其解决办法:1、延长session的生存时间;2、使用持久化存储;3、使用cookie;4、异步更新session;5、使用会话管理中间件。

PHP Session 跨域问题的解决方法 PHP Session 跨域问题的解决方法 Oct 12, 2023 pm 03:00 PM

PHPSession跨域问题的解决方法在前后端分离的开发中,跨域请求已成为常态。在处理跨域问题时,我们通常会涉及到session的使用和管理。然而,由于浏览器的同源策略限制,跨域情况下默认情况下无法共享session。为了解决这个问题,我们需要采用一些技巧和方法来实现session的跨域共享。一、使用cookie跨域共享session最常

php session刷新后没有了怎么办 php session刷新后没有了怎么办 Jan 18, 2023 pm 01:39 PM

php session刷新后没有了的解决办法:1、通过“session_start();”开启session;2、把所有的公共配置写在一个php文件内;3、变量名不能和数组下标相同;4、在phpinfo里面查看session数据的存储路径,并查看该文件目录下的sessio是否保存成功即可。

php如何使用CI框架? php如何使用CI框架? Jun 01, 2023 am 08:48 AM

随着网络技术的发展,PHP已经成为了Web开发的重要工具之一。而其中一款流行的PHP框架——CodeIgniter(以下简称CI)也得到了越来越多的关注和使用。今天,我们就来看看如何使用CI框架。一、安装CI框架首先,我们需要下载CI框架并安装。在CI的官网(https://codeigniter.com/)上下载最新版本的CI框架压缩包。下载完成后,解压缩

session php默认失效时间是多少 session php默认失效时间是多少 Nov 01, 2022 am 09:14 AM

session php默认失效时间是1440秒,也就是24分钟,表示客户端超过24分钟没有刷新,当前session就会失效;如果用户关闭了浏览器,会话就会结束,Session就不存在了。

Springboot2 session设置超时时间无效怎么解决 Springboot2 session设置超时时间无效怎么解决 May 22, 2023 pm 01:49 PM

问题:今天项目中遇到了一个设置时间超时的问题,按SpringBoot2的application.properties更改一直不生效。解决方案:server.*属性用于控制SpringBoot使用的嵌入式容器。SpringBoot将使用ServletWebServerFactory实例之一创建servlet容器的实例。这些类使用server.*属性来配置受控的servlet容器(tomcat,jetty等)。当应用程序作为war文件部署到Tomcat实例时,server.*属性不适用。它们不适用,

JavaScript和PHP的cookie之间有哪些区别? JavaScript和PHP的cookie之间有哪些区别? Sep 02, 2023 pm 12:29 PM

JavaScriptCookie使用JavaScriptcookie是记住和跟踪偏好、购买、佣金和其他信息的最有效方法。更好的访问者体验或网站统计所需的信息。PHPCookieCookie是存储在客户端计算机上的文本文件并保留它们用于跟踪目的。PHP透明地支持HTTPcookie。JavaScriptcookie如何工作?您的服务器将一些数据发送到访问者的浏览器cookie的形式。浏览器可以接受cookie。如果存在,它将作为纯文本记录存储在访问者的硬盘上。现在,当访问者到达站点上的另一个页面时

See all articles