###CI 2 SESSION的诟病 相信无数人在使用CI2的Session类库时,遇到各类的坑,各类抱怨,各类不解。在CI中国论坛能搜到大量关于Session类库的提问,说明要想用好session类库仍是得下一番功夫。 ####Session和cookie的区别 在某些语境中,cookie是session的一种实现方式,Ci 2的类库设计彷佛就这么认为的。因而,产生了CI2中COOKIE即SESSION的说法。在安全性方面,CI 2固然也由考虑,COOKIE是通过加密过的,并且一旦修改,服务器便再也不识别。php
**CI 2的session工做原理 **redis
CI 2提供了一个元数据,咱们能够把这个元数据看为一个自定义的验证机制,其包含如下内容:安全
Array ( [session_id] => 4a5a5dca22728fb0a84364eeb405b601 [ip_address] => 127.0.0.1 [user_agent] => Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_7; [last_activity] => 1303142623 )
其中Session id是重要的,Session id不对,直接拒绝。 验证选项在配置文件里有规定,(IP地址的限制)(user agent限制)(上次活动时间)等服务器
$config['sess_match_ip'] = FALSE; $config['sess_match_useragent'] = TRUE; $config['sess_time_to_update'] = 300;
特别是当设置sess_match_useragent设为TRUE时,会遇到各类的坑: 你用flash组件上传文件,只有登陆的用户才能上传文件,结果你每次判断用户是否登陆都会出错,由于flash发送的http请求有可能更改了user agent; 使用ie切换不一样的模式,好比兼容模式,也会形成user agent不一样; user agent的长度最长是120个字符,手动设置User agent是须要截取字符到最大120个。 另外,若是出现“Cannot modify header information - headers already sent by”错误,基本能够判定是你文件的编码格式有误,请去掉bom头。cookie
####安全问题session
CI使用cookie来传递数据原本就不够安全,并且若是数据量巨大时也会有性能问题。可是CI仍是友好地加入如下几个安全验证机制:tcp
加密令牌memcached
$config['encryption_key'] = 'mahuaz_'; $config['sess_encrypt_cookie'] = TRUE;
设置后,客户端检查cookie时就能够看到加密后的序列化数据。性能
自动更新机制测试
CI默认每五分钟更新一次令牌,更新发生在客户端的一次请求中。客户端每发送一次请求,会把cookie的信息发送到服务器,服务器根据发来的cookie判断是否到了应该更换令牌的时间了,若是是,就会从新换一个新的令牌返回给客户端。这就至关于门卫给你换了令牌,下次要使用新令牌进门。此时即便有坏人伪造了一个令牌也不起做用了,由于旧令牌已经做废。这样就至关于加了一条安全机制。可使用:
$config['sess_time_to_update'] = 300;
来设置多长时间来换一次令牌。这个时间不要设置的过短,更新频繁也会影响性能。这里不要和sess_expiration混淆:
$config['sess_expiration'] = 7200;
这个配置是用来指示整个cookie的过时时间的,至关于令牌彻底失效,再怎么更换都不起做用。
###CI 3的变动 CI3的Session的重大改变就是默认使用了原生的Session,这符合Session类库原本的意思,彷佛更加合理一些。整体来讲,虽然设计理念不一样,但为了保证向后兼容性,类库的使用方法与CI2.0的差异不是很大。通常的使用过程是这样的:
截取一段CI2 SESSION的代码:
if ($this->sess_encrypt_cookie == TRUE) { $this->CI->load->library('encrypt'); } if ($this->sess_use_database === TRUE AND $this->sess_table_name != '') { $this->CI->load->database(); } $this->now = $this->_get_time(); if ($this->sess_expiration == 0) { $this->sess_expiration = (60*60*24*365*2); } $this->sess_cookie_name = $this->cookie_prefix.$this->sess_cookie_name;
截取一段CI3 SESSION的代码:
$class = $this->_ci_load_classes($this->_driver); // Configuration ... $this->_configure($params); $class = new $class($this->_config); if ($class instanceof SessionHandlerInterface) { if (is_php('5.4')) { session_set_save_handler($class, TRUE); } else { session_set_save_handler( array($class, 'open'), array($class, 'close'), array($class, 'read'), array($class, 'write'), array($class, 'destroy'), array($class, 'gc') ); register_shutdown_function('session_write_close'); } } else { log_message('error', "Session: Driver '".$this->_driver."' doesn't implement SessionHandlerInterface. Aborting."); return; }
能够看到CI 3已经彻底重写了SESSION,由不一样的驱动器用来保存SESSION(而且淘汰了COOKIE)。
###CI3 SESSION FOR REDIS 在配置文件中,CI 3的配置也彻底缩减了不少
$config['sess_driver'] = 'files'; $config['sess_cookie_name'] = 'ci_session'; $config['sess_expiration'] = 7200; $config['sess_save_path'] = NULL; $config['sess_match_ip'] = FALSE; $config['sess_time_to_update'] = 300; $config['sess_regenerate_destroy'] = FALSE;
CI 3 能够配置驱动器类型,包括files, database, redis, memcached以及自定义,$config['sess_driver'] 来配置驱动器,默认的驱动器是files。官方推荐用files类型(在通常状况下) 配置session save path 配置节sess_save_path会根据不一样的驱动器,定义不一样。 为了适用redis,我这里将他配置为
tcp://127.0.0.1:6379
在上面的代码中,有下面这两句
$class = new $class($this->_config); if ($class instanceof SessionHandlerInterface){ ... }
确立了$_SEESION 由 redis进行存储,加载的类是Session_redis_driver(位于sytstem/libraries/Session_redis_driver),在测试控制器中, 咱们写一些测试代码:
$_SESSION['test'] = 'There is test!'; var_dump($_SESSION);
会打印出
array(2) { ["__ci_last_regenerate"]=> int(1444637502) ["test"]=> string(13) "There is test" }
咱们在Session_redis_driver的read方法中写到
var_dump($this->_key_prefix.$session_id); //redis key的值,由_key_prefix.$session_id组合构成
会打印出
string(51) "ci_session:23ea4298dc5e7d6b808ca70ddb1665590e5cfb58"
为了测试redis,咱们能够在PHP中测试:
$redis = new redis(); $redis->connect('127.0.0.1',6379); var_dump($redis->get("ci_session:23ea4298dc5e7d6b808ca70ddb1665590e5cfb58"));
会打印出
string(60) "__ci_last_regenerate|i:1444637502;test|s:13:"There is test";"
一样,咱们在redis-cli中输入
get ci_session:23ea4298dc5e7d6b808ca70ddb1665590e5cfb58
会打印出
__ci_last_regenerate|i:1444637502;test|s:13:"There is test
至此,CI 3 使用REDIS做为SESSION存储就分析完毕了