这里是用
thinkphp 3.2.0
版本的框架来做分析的
TP
的 session
主要是通过一个 session
函数来操作的,当然也可以使用原生的 $_SESSION
来操作,不过 TP
提供的一些特性就没了。
一些可配置的参数
参数 | 是否必须 | 描述 |
---|---|---|
SESSION_OPTIONS | 否 | session的一些配置参数 |
SESSION_PREFIX | 否 | session的前缀 |
VAR_SESSION_ID | 否 | sessionID变量 |
SESSION_TYPE | 否 | 自定义session存储的类型 |
SESSION_AUTO_START | 否 | 是否自动启动session |
SESSION_OPTIONS
session
的配置参数,主要有下面几个(一般不建议配置):
参数 | 否否必须 | 描述 |
---|---|---|
prefix | 否 | session前缀 |
id | 否 | sessionId |
name | 否 | session名称 |
path | 否 | session的保存路径 |
domain | 否 | cookie_domain |
expire | 否 | gc_maxlifetime |
use_trans_sid | 否 | use_trans_sid |
use_cookies | 否 | use_cookies |
cache_limiter | 否 | 缓存限制器 |
cache_expire | 否 | 缓存的到期时间 |
type | 否 | session存储的类型 |
SESSION_TYPE
在 3.2.0
的版本中,框架只集成了存储到 DB
的功能,如果要存储到 Redis
或者 Memcache
中,需要自己造轮子。
流程解析
session
方法有两个参数,一个是 $name
,是必传的;另一个是 $value
,默认为空。
设置模式
当 $name
是数组时,默认设置模式。
前缀设置
如果配置里有前缀,会使用 C
函数设置 SESSION_PREFIX
。
<?php
if(isset($name['prefix'])) C('SESSION_PREFIX',$name['prefix']);
sessionID变量
如果设置了 VAR_SESSION_ID
,并且请求上也有 VAR_SESSION_ID
,那么就使用 session_id
设置。
否则使用配置中的 id
。(没理解为什么必须要设置 session id
)
<?php
if(C('VAR_SESSION_ID') && isset($_REQUEST[C('VAR_SESSION_ID')])){
session_id($_REQUEST[C('VAR_SESSION_ID')]);
}elseif(isset($name['id'])) {
session_id($name['id']);
}
模式判断
只有 APP_MODE
是 common
时,才能自动启用 session
。
<?php
if('common' != APP_MODE){ // 其它模式可能不支持
ini_set('session.auto_start', 0); array(&$hander,"read"),
array(&$hander,"write"),
array(&$hander,"destroy"),
array(&$hander,"gc"));
}
关于如何使用 Redis
作为 session
驱动,可以看看我之前的文章,PHP SESSION 自定义会话管理器。
启动session
如果配置了默认启动,则会直接启动 session
。
<?php
if(C('SESSION_AUTO_START')) session_start();
}
一些参数的设定
因为应用场景的问题,需求比较小,简单介绍。
<?php
if(isset($name['name'])) session_name($name['name']);
if(isset($name['path'])) session_save_path($name['path']);
if(isset($name['domain'])) ini_set('session.cookie_domain', $name['domain']);
if(isset($name['expire'])) ini_set('session.gc_maxlifetime', $name['expire']);
if(isset($name['use_trans_sid'])) ini_set('session.use_trans_sid', $name['use_trans_sid']?1:0);
if(isset($name['use_cookies'])) ini_set('session.use_cookies', $name['use_cookies']?1:0);
if(isset($name['cache_limiter'])) session_cache_limiter($name['cache_limiter']);
if(isset($name['cache_expire'])) session_cache_expire($name['cache_expire']);
设置session驱动
这里有个细节,当 type
是一个命名空间的时候,会直接作为驱动进行设置。
也就是说,如果用户需要自己编写 Redis
的 session
驱动,不需要改动源码就可以完成。
<?php
if(isset($name['type'])) C('SESSION_TYPE',$name['type']);
if(C('SESSION_TYPE')) { // 读取session驱动
$type = C('SESSION_TYPE');
$class = strpos($type,'\\')? $type : 'Think\\Session\\Driver\\'. ucwords(strtolower($type));
$hander = new $class();
session_set_save_handler(
array(&$hander,"open"),
array(&$hander,"close"),
array(&$hander,"read"),
array(&$hander,"write"),
array(&$hander,"destroy"),
array(&$hander,"gc"));
}
关于如何使用 Redis
作为 session
驱动,可以看看我之前的文章,PHP SESSION 自定义会话管理器。
启动session
如果配置了默认启动,则会直接启动 session
。
<?php
if(C('SESSION_AUTO_START')) session_start();
读取模式
如果 $value
是 ''
,那么就会进行值的读取,但是这里混入了一个不法分子...
神奇的session操作
如果 $name
是以 [
开头的,那就认为是命令,这个很随意...
<?php
if(0===strpos($name,'[')) { // session 操作
if('[pause]'==$name){ // 暂停session
session_write_close();
}elseif('[start]'==$name){ // 启动session
session_start();
}elseif('[destroy]'==$name){ // 销毁session
$_SESSION = array();
session_unset();
session_destroy();
}elseif('[regenerate]'==$name){ // 重新生成id
session_regenerate_id();
}
}
操作列表如下:
操作 | 描述 |
---|---|
[pause] | 暂停session |
[start] | 启动session |
[destroy] | 销毁session |
[regenerate] | 重新生成id |
是否存在某个session
如果想要知道某个 session
是否存在,只需要在 key
之前加上 ?
前缀(支持二维数组)。例如:session('?aa')
、session('?aa.bb')
。
<?php
if(0===strpos($name,'?')){ // 检查session
$name = substr($name,1);
if(strpos($name,'.')){ // 支持数组
list($name1,$name2) = explode('.',$name);
return $prefix?isset($_SESSION[$prefix][$name1][$name2]):isset($_SESSION[$name1][$name2]);
}else{
return $prefix?isset($_SESSION[$prefix][$name]):isset($_SESSION[$name]);
}
}
清空session
如果需要清空整个 session
,只需要将 $name
置为 null
即可(第二个参数必须为 ''
)。例如:session(null)
。
<?php
if(is_null($name)){ // 清空session
if($prefix) {
unset($_SESSION[$prefix]);
}else{
$_SESSION = array();
}
}
获取session
<?php
if($prefix){ // 获取session
if(strpos($name,'.')){
list($name1,$name2) = explode('.',$name);
return isset($_SESSION[$prefix][$name1][$name2])?$_SESSION[$prefix][$name1][$name2]:null;
}else{
return isset($_SESSION[$prefix][$name])?$_SESSION[$prefix][$name]:null;
}
}else{
if(strpos($name,'.')){
list($name1,$name2) = explode('.',$name);
return isset($_SESSION[$name1][$name2])?$_SESSION[$name1][$name2]:null;
}else{
return isset($_SESSION[$name])?$_SESSION[$name]:null;
}
}
删除模式
如果 $value
是 null
,则默认删除当前的 $name
。
<?php
if(is_null($value)){ // 删除session
if($prefix){
unset($_SESSION[$prefix][$name]);
}else{
unset($_SESSION[$name]);
}
}
赋值模式
只要上面的都满足,就可以赋值了。
所以啊,如果想要赋值给某个 session
值为 ''
或者 null
的话,可能就不是你想象的那样了。
<?php
if(is_array($name)) {
}elseif('' === $value){
}elseif(is_null($value)){ // 删除session
}else{ // 设置session
if($prefix){
if (!is_array($_SESSION[$prefix])) {
$_SESSION[$prefix] = array();
}
$_SESSION[$prefix][$name] = $value;
}else{
$_SESSION[$name] = $value;
}
}
最后
作为一个函数,session
是非常强大了,但是,如果不仔细看一下,踩坑的几率还是非常高的。