PHP Session浅析
缘由
配合客户做一个免密登录跳转接口,因为双方均采用独立的php环境,且部署在一台服务器上。出现了先登录我方系统后不可登录对方系统,先登录对方系统后登录不了我方系统,怀疑为会话机制出现问题。故重新梳理Session会话机制。
声明与使用
Session的设置不同于Cookie,必须先启动,在PHP中必须调用session_start()
。语法格式如下:
Bool session_start(void) // 创建Session,开始一个会话,进行Session初始化
注意:session_start()
函数之前不能有任何输出
当第一次访问网站时,seesion_start()
函数就会创建一个唯一的Session ID,并自动通过HTTP的响应头,将这个Session ID保存到客户端Cookie中。同时,也在服务器端创建一个以Session ID命名的文件,用于保存这个用户的会话信息。当同一个用户再次访问这个网站时,也会自动通过HTTP的请求头将Cookie中保存的Seesion ID再携带过来,这时session_start()
函数就不会再去分配一个新的Session ID,而是在服务器的硬盘中去寻找和这个Session ID同名的Session文件,将这之前为这个用户保存的会话信息读出,在当前脚本中应用,达到跟踪这个用户的目的。 Session以数组的形式使用,如:$_SESSION['session名']
注册和读取
在PHP中使用Session变量,除了要启动之外,还要经过注册的过程。注册和读取Session变量,都要通过访问$_SESSION
数组完成。在$_SESSION
关联数组中的键名具有和PHP中普通变量相同的命名规则。注册Session变量的代码如下所示:
<?php
// 启动session的初始化
session_start();
// 注册session变量,赋值为一个用户的名称
$_SESSION["username"]="skygao";
// 注册session变量,赋值为一个用户的ID
$_SESSION["uid"]=1;
?>
执行该脚本后,两个Session变量就会被保存在服务器端的某个文件中,该文件的位置是通过php.ini
文件,在session.save_path
属性指定的目录下。
注销与销毁
当使用完一个Session变量后,可以将其删除,当完成一个会话后,也可以将其销毁。如果用户退出Web系统,就需要为他提供一个注销的功能,把他的所有信息在服务器中销毁。销毁和当前Session有关的所有的资料,可以调用session_destroy()
函数结束当前的会话,并清空会话中的所有资源。该函数的语法格式如下所示:
Bool session_destroy(void) // 销毁和当前Session有关的所有资料
该函数并不会释放和当前Session相关的变量,也不会删除保存在客户端Cookie中的SessionID。因为$_SESSION
数组和自定义的数组在使用上是相同的,所以我们可以使用unset()函数来释放在Session中注册的单个变量。如下所示:
unset($_SESSION['键名']);
一定要注意,不要使用unset($_SESSION)
删除整个$_SESSION
数组,这样将不能再通过$_SESSION
超全局数组注册变量了。但如果想把某个用户在Session中注册的所有变量都删除,可以直接将数组变量$_SESSION
赋上一个空数组。如下所示:
$_SESSION=array()
PHP默认的Session是基于Cookie的,SessionID被服务器存储在客户端的Cookie中,所以在注销Session时也需要清除Cookie中保存的SessionID,而这就必须借助setCookie()
函数完成。在PHP脚本中,可以通过调用session_name()
函数获取Session名称。删除保存在客户端Cookie中的SessionID,代码如下所示:
<?php
// 判断Cookie中是否存在session ID
if(isset($_COOKIE[session_name()])){
// 删除包含Session ID的cookie,注意第四个参数一定要和php.ini设置的路径相同
setcookie(session_name(), '', time() - 3600, '/');
}
?>
通过前面的介绍可以总结出,Session的注销过程共需要4个步骤。在下例中,提供完整的四个步骤代码,运行该脚本就可以关闭Session,并销毁与本次会话有关的所有资源。代码如下所示:
<?php
//第一步:开启Session并初始化
session_start();
//第二部:删除所有Session的变量,也可以用unset($_SESSION[XXX])逐个删除
$_SESSION = array();
//第三部:如果使用基于Cookie的session,使用setCookkie()删除包含Session ID的cookie
if(isset($_COOKIE[session_name()])) {
setCookie(session_name(), "", time()-42000, "/");
}
//第四部:最后彻底销毁session
session_destroy();
?>
php.ini
配置
php.ini
文件和Session有关的几个常用配置选项:
session.auto_start = 0;
在请求启动时初始化session
session.cache_expire = 180;
设置缓存中的会话文档在 n 分钟后过时
session.cookie_lifetime = 0;
设置按秒记的cookie的保存时间,相当于设置Session的过期时间,为0时表示直到浏览器被重启
session.auto_start=1;
这样就无需每次使用session之前都要调用session_start()
不建议使用.但启用该选项也有一些限制,如果确实启用了 session.auto_start
,则不能将对象放入会话中,因为类定义必须在启动会话之前加载以在会话中重建对象。
session.cookie_path = /;
cookie的有效路径
session.cookie_domain = ;
cookie的有效域
session.name = PHPSESSID;
用在cookie里的session的名字
session.save_handler = files;
用于保存/取回数据的控制方式
session.save_path = /tmp;
在 save_handler 设为文件时传给控制器的参数, 这是数据文件将保存的路径.
session.use_cookies = 1;
是否使用cookies
Session的垃圾自动回收机制
可以通过session_destroy()
函数在页面中提供一个“退出”按钮,通过单击销毁本次会话。但如果用户没有单击退出按钮,而是直接关闭浏览器,或断网等情况,在服务器端保存的Session文件是不会删除的。虽然关闭浏览器,下次需要重新分配一个新的Session ID重新登录,但这只是因为在php.ini
中的设置
seesion.cookie_lifetime=0;
,来设定Session ID在客户端Cookie中的有效限期,以秒为单位指定了发送到浏览器的Cookie的生命周期。当系统赋予Session有效期限后不管浏览器是否开启,Session ID都会自动消失。而客户端Session ID消失服务器端保存的Session文件并没有被删除。所以没有被Sessoin ID引用的服务器端Session文件,就成为了“垃圾”。
服务器保存的Session文件就是一个普通文本文件,所以都会有文件修改时间。“垃圾回收程序”启动后就是根据Session文件的修改时间,将所有过期的Session文件全部删除。通过在php.ini中设置session.gc_maxlifetime
选项来指定一个时间(单位:秒),例如设置该选项值为1440(24分钟)。“垃圾回收程序”就会在所有Session文件中排查,如果有修改时间距离当前系统时间大于1440秒的就将其删除。
“session垃圾回收程序”是怎样的启动机制呢?“垃圾回收程序”是在调用session_start()
函数时启动的。而一个网站有多个脚本,没有脚本又都要使用session_start()
函数开启会话,又会有很多个用户同时访问,这就很可能session_start()
函数在1秒内被调用N次,而如果每次都会启动“session垃圾回收程序”,这样是很不合理的。可以通过php.ini
文件中修改“session.gc_probability
和session.gc_divisor
”两个选项,设置启动垃圾回收程序的概率。会根据“session.gc_probability
/session.gc_divisor
”公示计算概率,例如选项session.gc_probability=1
,而选项session.gc_divisor=100
,这样的概率就是“1/100”,即session_start()
函数被调用100次才会有一次可能启动“垃圾回收程序”。
php.ini中相关的配置
session.cookie_lifetime=0;
关闭浏览器相应的cookie文件即被删除
session.gc_maxlifetime;
设置过期session时间,默认1440秒(24分钟)
session.gc_probability
/session.gc_divisor;
启动垃圾回收机制的概率(建议值为1/1000——5000)
最终方案
梳理后推断为 session.name
一致,导致 跳转(默认自动带Cookie)后 会话无法读取Session ID命名的文件导致Session注册失败。故修改我方php.ini
配置文件中的 session.name
使Session完成初始化。
由于时间仓促,错误与疏忽之处在所难免,希望各位朋友们以邮件的形式反馈问题给我,再次表示感谢!
- 作者:xmlwch
- 原文链接:https://m730.xmlwch.cn/2021/06/28/php/session.html
- 版权声明:本作品采用 知识共享 署名-相同方式共享 4.0 国际(CC BY-SA 4.0)许可协议 进行许可,转载无需与我联系,但请注明出处。