共计 2153 个字符,预计需要花费 6 分钟才能阅读完成。
我们先来分析一下 PHP 中是怎么生成一个 session 的。设计出 session 的目的是保持每一个用户的各种状态来弥补 HTTP 协议的不足 (无状态)。我们现在有一个疑问,我们都知道 session 是保存在服务器的,既然它用于保持每一个用户的状态那它利用什么来区别用户的呢?这个时候就得借助 cookie 了。当我们在代码中调用 session_start(); 时,PHP 会同时往 SESSION 的存放目录(默认为 /tmp/) 和客户端的 cookie 目录各生成一个文件。session 文件名称像这样:
格式为 sess_{SESSIONID},这时 session 文件中没有任何内容,当我们在 session_start(); 添加了这两行代码:
$_SESSION['name'] = 'wanchun0222';$_SESSION['blog'] = 'coderbolg.net'; 这时文件就有内容了:
name|s:11:"wanchun0222";blog|s:13:"coderbolg.net";
这时再看看 cookie:
可以看到服务器为我们自动生成了一个 cookie,cookie 名称为 ”PHPSESSID”,cookie 内容是一串字符,其实这串字符就是 {SESSIONID}。也许你已经明白了,当我们使用 session 时,PHP 就先生成一个唯一的 SESSIONID 号(如2bd170b3f86523f1b1b60b55ffde0f66),再在我们服务器的默认目录下生成一个文件,文件名为sess_{SESSIONID},同时在当前用户的客户端生成一个 cookie,内容已经说过了。这样 PHP 会为每一个用户生成一个 SESSIONID,也就是说一个用户一个 session 文件。PHP 第一次为某个用户使用 session 时就向客户端写入了 cookie,当这个用户以后访问时,浏览器会带上这个 cookie,PHP 在拿到 cookie 后就读出里面的 SESSIONID,拿着这个 SESSIONID 去 session 目录下找 session 文件。找到后在调用$_SESSION[‘blog’] 的时候显示出来。
我们明白了 session 的生成及工作原理,发现在 session 目录下会有许多 session 文件。当然这些文件一定不是永远存在的,PHP 一定提供了一种过期回收机制。在 php.ini 中 session.gc_maxlifetime 为 session 设置了生存时间(默认为 1440s)。如果 session 文件的最后更新时间到现在超过了生存时间,这个 session 文件就被认为是过期的了。在下一次 session 回收的时候就会被删除。那下一次 session 回收是在什么时候呢?这和 php 请求次数有关的。在 PHP 内部机制中,当 php 被请求了 N 次后就会有一次触发回收机制。到底是请求多少次触发一次是通过以下两个参数控制的:
session.gc_probability = 1session.gc_divisor = 100
这是 php.ini 的默认设置,意思是每 100 次 PHP 请求就有一次回收发生。概率是 gc_probability/gc_divisor。我们了解了服务器端的 session 过期机制,再来看看客户端的 cookie 的过期机制。
如果 cookie 失效了浏览器自然发送不了 cookie 到服务器,这时即使服务器的 session 文件存在也没用,因为 PHP 不知道要读取哪个 session 文件。我们知道 PHP 的 cookie 过期时间是在创建时设置的,那么 PHP 在创建 session 的同时为客户端创建的 cookie 的生命周期是多久呢?这个在 php.ini 中有设置:session.cookie_lifetime。这个值默认是 0,代表浏览器一关闭 SESSIONID 就失效。那就是说我们把 session.gc_maxlifetime 和 session.cookie_lifetime 设置成同一个值就可以控制 session 的失效时间了。
由上面的介绍我们可以知道,如果用户关闭了 cookie,那我们的 session 就完全没法工作了。是的,确实是这样。php 中 session 的客户端存储机制只有 cookie 吗?不是的。既然我们的 SESSIONID 不能通过 cookie 传递到各个页面,那我们还有另一个法宝,就是通过页面 GET 传值的方式。
PHP 可以在 cookie 被禁用时自动通过 GET 方式跨页传递 SESSIONID,前提是设置 php.ini 的 session.use_trans_sid 为 1。这时当我们在客户端禁用了 cookie 时使用了 session,并在当前页面通过点击链接到另一页面时,PHP 会自动在链接上添加 SESSIONID 参数,像这样:nextpage.php?SESSIONID=2bd170b3f86523f1b1b60b55ffde0f66。我想你应该看到了这种方式的缺点:好像不够安全啊。