CodeIgniter Session类 源代码 分析
2013-04-11 19:56
197 查看
一、Session类的参数:可以在application/config/config.php 文件中找到以下的 Session
相关的参数:
二、Session类的构造函数:构造函数做的事情有:
①初始化Session参数
②判断加密密钥是否为空,则返回错误
③加载字符串辅助函数使用strip_slashes()函数
④判断是否加密Session,如果加密Session则加载加密类
⑤判断Session是否写入数据库,则加载数据库类
⑥初始化当前时间
⑦初始化过期时间
⑧初始化$this->sess_cookie_name
⑨判断Session是否存在,如不存在创建Session,若存在更新Session
⑩垃圾回收
三、构造函数中调用的sess_read()方法:获取当前的Session
四:创建Session的方法sess_create()
该方法调用私有成员方法_set_cookie()
五、Session更新方法sess_update()
六、Session销毁方法sess_destroy()
七、设置自定义Session数据方法set_userdata($newdata = array(), $newval = '')
该方法调用成员方法sess_write()
八、垃圾回收方法_sess_gc()
相关的参数:
参数 | 默认 | 选项 | 描述 |
---|---|---|---|
sess_cookie_name | ci_session | 无 | 你想要保存 Session Cookie 的名字。 |
sess_expiration | 7200 | 无 | session 持续的秒数。默认是2个小时(7200秒)。如果将这个数值设为: 0,就可以得到 永久 session。 |
sess_expire_on_close | FALSE | TRUE/FALSE (boolean) | 这个选项决定当浏览器窗口关闭时是否自动使session过期。 |
sess_encrypt_cookie | FALSE | TRUE/FALSE (布尔值boolean) | 是否对 session 数据加密. |
sess_use_database | FALSE | TRUE/FALSE (布尔值boolean) | 是否将 session 数据存放入数据库中。在开启这个选项前,你要先创建一个数据库表。 |
sess_table_name | ci_sessions | 任何有效的 SQL 表名 | session 数据库表的名字。 |
sess_time_to_update | 300 | 时间以秒计算 | 这个选项控制 session 类多久会产生一个新的session 和 session id。 |
sess_match_ip | FALSE | TRUE/FALSE (布尔值boolean) | 是否通过用户的IP地址来读取 session 的数据。 注意 ,有些网络运行商 ISPs 会动态的改变IP, 所以将这个选项设为 FALSE, 才有可能得到永久的 session。 |
sess_match_useragent | TRUE | TRUE/FALSE (布尔值boolean) | 是否要按照对应的 User Agent 来读取 session 数据。 |
①初始化Session参数
②判断加密密钥是否为空,则返回错误
③加载字符串辅助函数使用strip_slashes()函数
④判断是否加密Session,如果加密Session则加载加密类
⑤判断Session是否写入数据库,则加载数据库类
⑥初始化当前时间
⑦初始化过期时间
⑧初始化$this->sess_cookie_name
⑨判断Session是否存在,如不存在创建Session,若存在更新Session
⑩垃圾回收
public function __construct($params = array()) { log_message('debug', "Session Class Initialized"); // Set the super object to a local variable for use throughout the class $this->CI =& get_instance(); // Set all the session preferences, which can either be set // manually via the $params array above or via the config file // 设置session参数,首先判断是否设置$params,如果没有则从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); } // 判断加密密钥是否为空,为空则返回错误 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.'); } // Load the string helper so we can use the strip_slashes() function // 加载字符串辅助函数以使用strip_slashes()函数 $this->CI->load->helper('string'); // Do we need encryption? If so, load the encryption class // 判断是否加密Session,如果加密session则加载类库encrypt if ($this->sess_encrypt_cookie == TRUE) { $this->CI->load->library('encrypt'); } // Are we using a database? If so, load it // 判断是否将Session存入数据库,如果存入则加载数据库类 if ($this->sess_use_database === TRUE AND $this->sess_table_name != '') { $this->CI->load->database(); } // Set the "now" time. Can either be GMT or server time, based on the // config prefs. We use this to set the "last activity" time // 获取当前时间 $this->now = $this->_get_time(); // Set the session length. If the session expiration is // set to zero we'll set the expiration two years from now. // 如果sess_expiration设置为0,则把过期时间设置为两年后 if ($this->sess_expiration == 0) { $this->sess_expiration = (60*60*24*365*2); } // Set the cookie name // 设置Session名称,为$this->cookie_prefix.$this->sess_cookie_name,$this->cookie_prefix在config文件中设置 $this->sess_cookie_name = $this->cookie_prefix.$this->sess_cookie_name; // Run the Session routine. If a session doesn't exist we'll // create a new one. If it does, we'll update it. // 如果Session不存在,则创建Session,否则更新它 if ( ! $this->sess_read()) { $this->sess_create(); } else { $this->sess_update(); } // Delete 'old' flashdata (from last request) $this->_flashdata_sweep(); // Mark all new flashdata as old (data will be deleted before next request) $this->_flashdata_mark(); // Delete expired sessions if necessary $this->_sess_gc(); log_message('debug', "Session routines successfully run"); }
三、构造函数中调用的sess_read()方法:获取当前的Session
function sess_read() { // Fetch the cookie // 获取cookie的值 $session = $this->CI->input->cookie($this->sess_cookie_name); // No cookie? Goodbye cruel world!... // 如果没有cookie,返回错误 if ($session === FALSE) { log_message('debug', 'A session cookie was not found.'); return FALSE; } // Decrypt the cookie data // 判断是否加密session,如果为真则加密session if ($this->sess_encrypt_cookie == TRUE) { $session = $this->CI->encrypt->decode($session); } else { // encryption was not used, so we need to check the md5 hash $hash = substr($session, strlen($session)-3 d3b2 2); // get last 32 chars $session = substr($session, 0, strlen($session)-32); // Does the md5 hash match? This is to prevent manipulation of session data in userspace if ($hash !== md5($session.$this->encryption_key)) { log_message('error', 'The session cookie data did not match what was expected. This could be a possible hacking attempt.'); $this->sess_destroy(); return FALSE; } } // Unserialize the session array $session = $this->_unserialize($session); // Is the session data we unserialized an array with the correct format? // 判断被unserialized的数组是否有正确的session格式,若没有执行sess_destroy 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(); return FALSE; } // Is the session current? // 判断最新的一个活跃时间戳+Session有效期是否小于现在时间,若小于sess_destroy if (($session['last_activity'] + $this->sess_expiration) < $this->now) { $this->sess_destroy(); return FALSE; } // Does the IP Match? // 判断IP是否匹配 if ($this->sess_match_ip == TRUE AND $session['ip_address'] != $this->CI->input->ip_address()) { $this->sess_destroy(); return FALSE; } // Does the User Agent Match? // 判断user_agent是否匹配 if ($this->sess_match_useragent == TRUE AND trim($session['user_agent']) != trim(substr($this->CI->input->user_agent(), 0, 120))) { $this->sess_destroy(); return FALSE; } // Is there a corresponding session in the DB? // 判断数据库中的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); // No result? Kill it! if ($query->num_rows() == 0) { $this->sess_destroy(); return FALSE; } // Is there custom data? If so, add it to the main session array $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; } } } } // Session is valid! $this->userdata = $session; unset($session); return TRUE; }
四:创建Session的方法sess_create()
function sess_create() { // 初始化sessid,并将它用mt_rand(0, mt_getrandmax())循环生成随机值,直到sessid的长度大于32 $sessid = ''; while (strlen($sessid) < 32) { $sessid .= mt_rand(0, mt_getrandmax()); } // To make the session ID even more secure we'll combine it with the user's IP // 为了更安全,将IP地址结合,加到$sessid的末尾 $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' => $this->now, 'user_data' => '' ); // Save the data to the DB if needed // 如果启用了Session存入数据库,则将数据存入数据库中 if ($this->sess_use_database === TRUE) { $this->CI->db->query($this->CI->db->insert_string($this->sess_table_name, $this->userdata)); } // Write the cookie // 设置cookie $this->_set_cookie(); }
该方法调用私有成员方法_set_cookie()
function _set_cookie($cookie_data = NULL) { if (is_null($cookie_data)) { $cookie_data = $this->userdata; } // Serialize the userdata for the cookie // 序列化userdata $cookie_data = $this->_serialize($cookie_data); // 判断是否加密Session if ($this->sess_encrypt_cookie == TRUE) { $cookie_data = $this->CI->encrypt->encode($cookie_data); } else { // if encryption is not used, we provide an md5 hash to prevent userside tampering // 如果加密没有启用,则提供一个md5 hash $cookie_data = $cookie_data.md5($cookie_data.$this->encryption_key); } $expire = ($this->sess_expire_on_close === TRUE) ? 0 : $this->sess_expiration + time(); // Set the cookie setcookie( $this->sess_cookie_name, $cookie_data, $expire, $this->cookie_path, $this->cookie_domain, $this->cookie_secure ); }
五、Session更新方法sess_update()
function sess_update() { // We only update the session every five minutes by default // 默认每五分钟更新一次Session if (($this->userdata['last_activity'] + $this->sess_time_to_update) >= $this->now) { return; } // Save the old session id so we know which record to // update in the database if we need it // 记住旧的Session id所以我们能从数据库中知道哪个记录要更新 $old_sessid = $this->userdata['session_id']; $new_sessid = ''; while (strlen($new_sessid) < 32) { $new_sessid .= mt_rand(0, mt_getrandmax()); } // To make the session ID even more secure we'll combine it with the user's IP $new_sessid .= $this->CI->input->ip_address(); // Turn it into a hash $new_sessid = md5(uniqid($new_sessid, TRUE)); // Update the session data in the session data array $this->userdata['session_id'] = $new_sessid; $this->userdata['last_activity'] = $this->now; // _set_cookie() will handle this for us if we aren't using database sessions // by pushing all userdata to the cookie. $cookie_data = NULL; // Update the session ID and last_activity field in the DB if needed // 如果是Session保存在数据库,则更新相应的记录 if ($this->sess_use_database === TRUE) { // set cookie explicitly to only have our session data $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->now, 'session_id' => $new_sessid), array('session_id' => $old_sessid))); } // Write the cookie $this->_set_cookie($cookie_data); }
六、Session销毁方法sess_destroy()
function sess_destroy() { // Kill the session DB row // 如果Session是存在数据库中,则删除数据库中的指定行 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); } // Kill the cookie // 将过期时间设置为一个过去的时间 setcookie( $this->sess_cookie_name, addslashes(serialize(array())), ($this->now - 31500000), $this->cookie_path, $this->cookie_domain, 0 ); // Kill session data // 将$this->userdata设定为空数组 $this->userdata = array(); }
七、设置自定义Session数据方法set_userdata($newdata = array(), $newval = '')
function set_userdata($newdata = array(), $newval = '') { // 如果$newdata是字符串,则说明是只添加一个用户数据 if (is_string($newdata)) { $newdata = array($newdata => $newval); } // 添加一个数组 if (count($newdata) > 0) { foreach ($newdata as $key => $val) { $this->userdata[$key] = $val; } } $this->sess_write(); }
该方法调用成员方法sess_write()
function sess_write() { // Are we saving custom data to the DB? If not, all we do is update the cookie // 如果不是将Sessin存入数据库,只要更新当前cookie就行了 if ($this->sess_use_database === FALSE) { $this->_set_cookie(); return; } // set the custom userdata, the session data we will set in a second // 自定义的Session数据 $custom_userdata = $this->userdata; $cookie_userdata = array(); // Before continuing, we need to determine if there is any custom data to deal with. // Let's determine this by removing the default indexes to see if there's anything left in the array // and set the session data while we're at it // 将$custom_userdata中不是用户自定义数据的销毁 foreach (array('session_id','ip_address','user_agent','last_activity') as $val) { unset($custom_userdata[$val]); $cookie_userdata[$val] = $this->userdata[$val]; } // Did we find any custom data? If not, we turn the empty array into a string // since there's no reason to serialize and store an empty array in the DB // 如果没有自定义Session数据,我们将空数组转换为空字符串 if (count($custom_userdata) === 0) { $custom_userdata = ''; } else { // Serialize the custom data array so we can store it // 如果设置了自定义Session数据,则将其序列化 $custom_userdata = $this->_serialize($custom_userdata); } // Run the update query // 更新数据库中的last_activity和user_data $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)); // Write the cookie. Notice that we manually pass the cookie data array to the // _set_cookie() function. Normally that function will store $this->userdata, but // in this case that array contains custom data, which we do not want in the cookie. // 设置不是自定义Session数据 $this->_set_cookie($cookie_userdata); }
八、垃圾回收方法_sess_gc()
function _sess_gc() { if ($this->sess_use_database != TRUE) { return; } srand(time()); if ((rand() % 100) < $this->gc_probability) { $expire = $this->now - $this->sess_expiration; $this->CI->db->where("last_activity < {$expire}"); $this->CI->db->delete($this->sess_table_name); log_message('debug', 'Session garbage collection performed.'); } }
相关文章推荐
- Hadoop源代码分析(包hadoop.mapred中的MapReduce接口)
- 如何看懂源代码--(分析源代码方法)
- 通过分析 JDK 源代码研究 TreeMap 红黑树算法实现
- LAV Filter 源代码分析 1: 总体结构
- 如何看懂源代码--(分析源代码方法)
- MySQL系列:innodb源代码分析之内存管理
- FreeRTOS的源代码个人分析(基于KEIL下STM32F103的Demo) 二
- Android应用程序启动过程源代码分析
- Android应用程序进程启动过程的源代码分析
- Tomcat7调试运行环境搭建与源代码分析
- BT源代码学习心得(十五):客户端源代码分析(下载过程中的块选取策略)
- 通过分析 JDK 源代码研究 TreeMap 红黑树算法实现
- SSH框架总结(框架分析+环境搭建+实例源代码下载)
- ListView源代码分析
- x264源代码简单分析:宏块分析(Analysis)部分-帧间宏块(Inter)
- java源代码分析工具PMD 3.1发布
- FFmpeg源代码简单分析:av_write_trailer()
- LAV Filter 源代码分析 2: LAV Splitter
- 11 款用于优化、分析源代码的Java工具
- HEVC官方软件HM源代码简单分析-编码器TAppEncoder