Press "Enter" to skip to content

如何设置一个严格30分钟过期的Session

今天在我的微博(Laruence)上发出一个问题:

我在面试的时候, 经常会问一个问题: “如何设置一个30分钟过期的Session?”, 大家不要觉得看似简单, 这里面包含的知识挺多, 特别适合考察基本功是否扎实, 谁来回答试试? 呵呵

为什么问这个问题呢? 1. 我在Twitter上看到了有人讨论这个问题, 2 想起来我经常问这个问题, 所以~~

在这里, 我来解答下这个题目.

第一种回答

那么, 最常见的一种回答是: 设置Session的过期时间, 也就是session.gc_maxlifetime, 这种回答是不正确的, 原因如下:

1. 首先, 这个PHP是用一定的概率来运行session的gc的, 也就是session.gc_probability和session.gc_divisor(介绍参看 深入理解PHP原理之Session Gc的一个小概率Notice), 这个默认的值分别是1和100, 也就是有1%的机会, PHP会在一个Session启动时, 运行Session gc. 不能保证到30分钟的时候一定会过期.

2. 那设置一个大概率的清理机会呢? 还是不妥, 为什么? 因为PHP使用stat Session文件的修改时间来判断是否过期, 如果增大这个概率一来会降低性能, 二来, PHP使用”一个”文件来保存和一个会话相关的Session变量, 假设我5分钟前设置了一个a=1的Session变量, 5分钟后又设置了一个b=2的Seesion变量, 那么这个Session文件的修改时间为添加b时刻的时间, 那么a就不能在30分钟的时候, 被清理了. 另外还有下面第三个原因.

3. PHP默认的(Linux为例), 是使用/tmp 作为Session的默认存储目录, 并且手册中也有如下的描述:

Note: 如果不同的脚本具有不同的 session.gc_maxlifetime 数值但是共享了同一个地方存储会话数据,则具有最小数值的脚本会清理数据。此情况下,与 session.save_path 一起使用本指令。

也就是说, 如果有俩个应用都没有指定自己独立的save_path, 一个设置了过期时间为2分钟(假设为A), 一个设置为30分钟(假设为B), 那么每次当A的Session gc运行的时候, 就会同时删除属于应用B的Session files.

所以, 第一种答案是不”完全严格”正确的.

第二种答案

还有一种常见的答案是: 设置Session ID的载体, Cookie的过期时间, 也就是session.cookie_lifetime. 这种回答也是不正确的, 原因如下:

这个过期只是Cookie过期, 换个说法这点就考察Cookie和Session的区别, Session过期是服务器过期, 而Cookie过期是客户端(浏览器)来保证的, 即使你设置了Cookie过期, 这个只能保证标准浏览器到期的时候, 不会发送这个Cookie(包含着Session ID), 而如果通过构造请求, 还是可以使用这个Session ID的值.

第三种答案

使用memcache, redis等, okey, 这种答案是一种正确答案. 不过, 很显然出题者肯定还会接着问你, 如果只是使用PHP呢?

第四种答案

当然, 面试不是为了难道你, 而是为了考察思考的周密性. 在这个过程中我会提示出这些陷阱, 所以一般来说, 符合题意的做法是:

1. 设置Cookie过期时间30分钟, 并设置Session的lifetime也为30分钟.

2. 自己为每一个Session值增加Time stamp.

3. 每次访问之前, 判断时间戳.

最后, 有同学问, 为什么要设置30分钟的过期时间: 这个, 首先这是为了面试, 第二, 实际使用场景的话, 比如30分钟就过期的优惠劵?

thanks 🙂

49 Comments

  1. qq76213232
    qq76213232 2017-07-14

    上面说的很是在理,但是其实我们需要一个简单的答案,鸟哥却把答案说太复杂了。
    其实严格30分钟过期时间并不需要服务器端清除Session小文本文件,可以通过文件的访问时间和修改时间来判断,即使服务器的文件还存在,一样是一个无效的文件,所以简单的设置session的失效时间30分钟,其实就是一条语句的问题,跟客户端的cookie没有关系。
    个人理解,如果说得有问题,希望鸟哥和大家批评指正

  2. xpisme
    xpisme 2016-10-24

    我说这篇文章讲的真好!透彻!清晰。

    一看域名原来是鸟哥。

  3. soft456
    soft456 2016-07-26

    不谢!

  4. Winsen
    Winsen 2015-04-09

    鸟哥,问一下,有没有办法仅用PHP来判断一个SESSION是否还有效。场景是这样的,如果用户离开这个网站或者关闭浏览器,将用户的登录状态设置为下线。Ajax的方式已经考虑过了,有没有只用PHP就能解决的方式咧?

  5. […] ps:我的问题没有考虑到为每个session的值设独立过期时间问题; —————————————————————————————————————————————————— ↓ 解决方案 ↓ 推荐你看看 @Laruence 大神的文章 如何设置一个严格30分钟过期的Session […]

  6. 王楠
    王楠 2013-08-13

    一遍 没看懂,多看几遍,表示很有用。。

  7. gong
    gong 2013-07-18

    2. 自己为每一个Session值增加Time stamp.
    re:
    请大侠就上面的文字写一行代码让俺见见什么叫“自己为每一个Session值增加Time stamp.”

  8. […] 作者地址: http://www.laruence.com/2012/01/10/2469.html 版权信息:8090社团>>如何设置一个严格30分钟过期的Session本文链接:http://www.liaolz.com/index.php/archives/33 转载请注明出处.如果喜欢:点此订阅本站 7K tohilary 查看Ta的专栏 关于本文小编 各种观点 […]

  9. tudou
    tudou 2012-09-10

    写入数据库数量大了,数据库压力也很大,,求第三中方法的深入教程,,鸟个

  10. 小谈博客
    小谈博客 2012-07-06

    session存到数据库,这样是不是不能设置过期时间

  11. Zachary
    Zachary 2012-04-23

    不根据session文件的创建时间来判断是必需的. 因为session本身的主要职责就是维持这个会话的活动性. 他的本意就是只要这个会话在我规定的时间段内有一次活动那他就是活得. 如果从创建时间算起. 那上面的这个主要职责就被推翻了.

    一般不会把session存在实体文件里面. 多服务器之间这是个大问题. 多数的做法是直接使用cookie. 或者把session的处理设置到memcache之类的分布式载体上. 既然自定义了php的session处理函数. 那这个题目就easy了. 我的地盘我做主..

  12. Jagger Wang
    Jagger Wang 2012-04-17

    2. 那设置一个大概率的清理机会呢? 还是不妥, 为什么? 因为PHP使用stat Session文件的修改时间来判断是否过期

    如果Session文件在创建后又被修改了,那Session的过期时间从这个修改时间段算起?好怪异,为什么不从创建时间算起。

  13. hwz
    hwz 2012-04-11

    您的第三种方法,跟使用缓存时,是缓存主动过期很相似,看来编程思想很重要啊

  14. callme小刀
    callme小刀 2012-03-22

    我一般用第三种方案,对用第四种方案,个人认为可以解决问题,仅仅是可以解决问题而已~~

  15. sk
    sk 2012-02-05

    非常好的文章哦,博主加油!

  16. silentime
    silentime 2012-01-12

    实际的应用场景如果需要严格过期的话,应该不会用session机制把?

  17. enzo
    enzo 2012-01-11

    session.gc_maxlifetime既然不能严格控制session的过期时间,这算不算bug?我的愚建是既然有个这样的配置就应该保证这个配置对应的功能能起到确定的作用。

  18. 四不象
    四不象 2012-01-11

    为什么我觉得第一种回答的第一点不成立呢。那个设置是gc,垃圾回收,并非是没被回收的session文件不会过期。PHP的session默认的file引擎在读取session文件前还是会判断文件最后修改时间的,如果超出session.gc_maxlifetime就不会读取这个session文件

  19. wclssdn
    wclssdn 2012-01-10

    好吧.. 我的第一反应就是session中存时间戳.. 如果session中变量需要设置过期.. 那就为变量添加时间戳….
    貌似这个方法最可靠了~~
    使用内存缓存之类的… 是使用它们替换session存储位置?
    那同样没有设置过期时间的地方… 只能再此基础上封装成类.. 在方法中添加过期时间. 传递给redis.. 而这样.. 就跟添加时间戳没区别了…

  20. heyli
    heyli 2012-01-10

    第一回答 php.ini 修改 至于修改那里 不记得要回去查下
    第二 要严格的 我会考虑写进数据库

  21. treesky
    treesky 2012-01-10

    引用部分的那个歪字体看起来十分费劲。

  22. 鑫爷
    鑫爷 2012-01-10

    好东西啊。学习了。。

  23. peng
    peng 2012-01-10

    thanks

Leave a Reply

Your email address will not be published. Required fields are marked *