php中session的创建时间,php中session的过期时间

一般情况下,保存用户的登陆信息可以使用session,如果要控制这个信息的有效期,该如何来呢。一时间还真懵了,赶紧一补。

首先,什么是session,为什么要有这个东西。session的英文意思是会话,两人聊天,从开始“你好”,到最后“再见”,这就构成了一次会话。php里的session就是指客户端与服务器端数据交换的对话,从打开客户端访问服务器端,最后关闭客户端,这就是一个会话。举一个通俗的例子来看计算机中如何实现会话:

服务端好比一个理发店,客户端好比每一个去理发的客人,很多理发店都有这种促销手段,连续消费10次的客人,可以免费一次,大概有三种方式来实现:

理发师傅记性太好,你来过几次,他看一眼就知道——这叫协议本身支持会话;

每个客人发一个会员卡,你每次消费,都要带着这个卡片,消费一次记录一笔,当然还要加盖印章——这叫通过cookie实现会话,缺点是安全性不高,我完全可以伪造会员卡或者公章;

理发店准备一个大帐本,客人每人对应一个会员号或者自己的个人资料,甚至密码,每个客人来消费,报一下自己的会员号,再把消费次数记录到大帐本里——这就是session实现会话,客人脑子里的会员号就是保存在客户端的SESSIONID,大帐本就是保存在服务端的session数据,这样相比第二种方法,安全性要高很多,除非你说你把自己的会员号和密码都搞丢了,这叫做伪造客户端的SESSIONID。

因为http协议是无状态的,所以php要实现会话只能通过后面两种方式,前一种cookie,缺点已经说了,安全性不高,所以重要的会话会选择使用session。session会话必须依靠一个标识,也可以理解成一个暗号,就是SESSIONID。这是个经过加密的串,保存在客户端,通常在cookie里,客户端与服务端的每次交流都是通过这个SESSIONID,客户端先自报家门,服务器才能找到你在服务端保存的会话数据,继续通话。

是否自动启动会话,也就是浏览器一访问php脚本就启动session,相当于自动执行session_start(),无须手动,在php.ini中可以通过设置session.auto_start = 1实现,默认应该是0,也就是需要手动启动。会话启动后,拿PHPSSID的值(这个名字也可以设置为其他的,是通过cookie传还是url的get方式传也都可以配置,一般使用默认的通过cookie传,这样通过$_COOKIE能获得)作为密钥查找对应的数据是否存在,数据默认会存到/tmp目录(windows下是c:/window/temp)下,以文件形式保存,文件名是”sess_”+PHPSSID,当然存到哪是以文件形式还是入库都可以设置,那不是本文关注的(其实我也不懂~.~)。如果数据存在,那就用这之前的数据,也就是所谓听session没有过期啦!如果通过这个密钥找不到数据,那就是“过期”了再重新创建一个。

说到这里,想必已经想到思路了。先来看网上普遍的针对这个问题的做法:

一、设置session.gc_maxlifetime 等于要求的过期时间值。

这是错误的,原因:session.gc_maxlifetime的含义是session触发gc回收机制前的最大时间,也就是一个session最后一次被访问的时间离当前时间超过了这个值,php认为这个session该过期了,gc机制扫描session时会把它当成是垃圾,会进行清理删除。但是,触发gc是有概率的,这个概率由另外两个参数决定,gc触发概率=session.gc_probability(默认1)/session.gc_divisor(默认1000),也就是说,一个session被认为”垃圾了”,也只有千分之一的概率被删除。有人说那把另外两个参数也改了,把概率弄到1。兄弟,你很有前途~^~一来这个概率增大后会占用不少资源,拖慢php速度,不提倡。二来如果PHPSSID不变,gc机制的执行应该是在访问了这个session之后才执行。举例说明,如果我设置这个maxlifetime为10秒,概率弄到1,浏览器访问一次服务器产生一个session,10秒过后,刷新这个浏览器session还是没有过期,因为刷新时是先访问了session,它的最后一次被访问时间变成了刷新时候,访问过一次session才运行gc,gc是对超10秒没有访问的session才进行清理,因此你这个session就永远不会过期。但是,如果在这个期间如果有别人访问了服务器,别人的请求触发了gc有可能把你的session给删除了,这时你的也就过期了。

这里我只里是只考虑单个数据,如果多个数据每个的过期时间都不一致,比如存数据a过期时间是10秒,5秒后又存入数据b过期时间是10秒。那么离存a时过去10秒后整个session没有过期数据a也就还在没有过期,因为你存了b最后访问时间变成了存b时的时间而不是存a时了的。再比如服务器上有多个网站,没有分别设置session的存入目录都是用默认的,访问A网站时的触发了gc把B网站的session也给删除了,这可糟糕透了,因此,通过设置session.gc_maxlifetime再把gc概率改高,是逗比的做法。

二、设置COOKIE的过期时间等于要求的过期时间

方法一的根本原理是将session删除,达到了”过期”的效果。这个方法二根本原理是更改PHPSSID,也就是改变密钥,这样子服务器通过密钥查找session数据的时候就肯定找不到了,从而新建一个session数据达到“过期”效果。个人猜测,session_start()时会先获取客户端(也就是浏览器)Name为PHPSSID的cookie值,如果有,通过它在服务器上查找对应的session数据,如果找到,会话继续,该增增该删删,如果找不到,新建session数据,之前的session用不了了,就“过期”了。如果一开始从客户端获得不到Name为PHPSSID的cookie值,先在服务器生成新的session数据,同样的之前的也用不到,“过期”了,再在客户端生成Name为PHPSSID值为session_name()的cookie值,这个在客户端生成cookie可以由我们控制,比如像下面这个样子:

setcookie(session_name(), session_id(), time() + 3600, "/");

我们就把当前的会话密钥以PHPSSID为Name存到了客户端的cookie中,这个cookie值有效时间为3600秒,也就是会话密钥被保存了1个小时,也即在这个小时之内,服务器都能获得这个密钥,都能取得相同的session数据。过了这个小时,密钥过期,产生新的密钥,也就找不到之前的session数据,“过期”。如果我们不控制,php默认的存入方式是浏览器关闭cookie就失效,当然这个也可以在php.ini中由session.cookie_lifetime来设置,默认0。

这种做法对不对呢?严格来说也不太对,因为这是控制Cookie的过期,是客户端上边的过期;session是在服务器上的,需要服务器上的过期。虽然过期后从客户端获取不到之前的密钥,但如果能力伪造,将客户端过期了的cookie给弄成不过期,这样子服务器取的时候就获得了过期的密钥(这个不懂,只是理论)。但至少,比第一种方法要好得多,其实大部分时候也这么干了。

有没有更完善一点的做法呢,就是即使伪造了cookie返回了过期的密钥,也能判断数据是过期了。当然有,那就是为每个session数据都加入时间啊。这看上去很low,但确实是有效的,当前服务器的时间你总不能伪造得到吧,当前时间与存入时的时间一减,就知道有没有过期了。

总结:

其实最后的办法也要前面的为前提,如果gc触发时间过短,即使概率很低,也有可能被删除;存了时间又如何,密钥都变了,肯定过期啦,因此需要将前面的两个操作一并给执行了才是最终比较好的方案:

设置cookie过期时间和session.gc_maxlifetime为目标过期时间;

为每个session数据添加存入时间;

取时判断是否过期

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值