浅谈php处理session

来源:互联网 发布:播放器 p2p m3u 网络 编辑:程序博客网 时间:2024/06/05 17:59

写日志,月报,最后提交的关头,有时候会出现”请登陆后进行操作”信息,结果是刚才的心血全部白费,痛哉!究其原因,是因为php session有一个GC功能,就是Garbage Collector。这个GC启动的时候,会清除那些已经“超时”的session。

1. php中session过期时间设置及回收机制详解: 

1)  session在server端(一般是Apache with PHP module)如何存在的?
默认的,php会将session保存在/tmp目录下,文件名为这个样子:sess_01aab840166fd1dc253e3b4a3f0b8381。每一个文件对应了一个session(会话)。
more /tmp/sess_01aab840166fd1dc253e3b4a3f0b8381
username|s:9:”phpzixue.cn”;admin|s:1:”0″;
#变量名|类型:长度:值
删除这里的session文件,就表示对应的session失效了。
2)  session在client端(一般是浏览器)如何存在的?
session在浏览器端,只需要保存session ID(由server端生成的唯一ID)就可以了。有两种保存方式:在cookie中、在url里面。如果cookie中保存session ID,就可以看到浏览器的cookie中有一个PHPSESID变量。如果是URL传递的,就可以看到形如:
index.php?PHPSESID=01aab840166fd1dc253e3b4a3f0b8381的URL。(在server端通过session.use_cookies来控制使用哪一种方式)
3)  在server端,php如何判断session文件是否过期?
如果”最后的修改时间”到”现在”超过了gc_maxlifetime(默认是1440)秒,这个session文件就被认为是过期了,在下一次session回收的时候,如果这个文件仍然没有被更改过,这个session文件就会被删除(session就过期了)。
简单的说,如果我登录到某网站,如果在1440秒(默认值)内没有操作过,那么对应的session就认为是过期了。
所以,修改php.ini文件中的gc_maxlifetime变量就可以延长session的过期时间了:(例如,我们把过期时间修改为86400秒)
session.gc_maxlifetime = 86400
然后,重启你的web服务(一般是apache)就可以了。
注意:php5里面session过期使用了回收机制。这里设置时间为86400秒,如果session在86400秒内没有被修改过,那么在下一次“回收”时才真的被删除。
4)  session“回收”何时发生?
默认情况下,每一次php请求,就会有1/100的概率发生回收,所以可能简单的理解为“每100次php请求就有一次回收发生”。这个概率是通过以下参数控制的
#概率是gc_probability/gc_divisor
session.gc_probability = 1
session.gc_divisor = 100
注意1:假设这种情况gc_maxlifetime=120,如果某个session文件最后修改时间是120秒之前,那么在下一次回收(1/100的概率)发生前,这个session仍然是有效的。
注意2:如果你的session使用session.save_path中使用别的地方保存session,session回收机制有可能不会自动处理过期session文件。这时需要定时手动(或者crontab)的删除过期的session:cd /path/to/sessions; find -cmin +24 | xargs rm 

 

很多人都遇到过PHP的SESSION总是会出现不过期的现象,随着浏览器进程走,这里简单介绍下:
在PHP中,设置php.ini,找到session.gc_maxlifetime = 1440 (PHP5默认24秒)
这里你可以随便设置一下过期时间.但是有人说设置以后,好象不起作用!
其实不是不起作用,而是因为系统默认:
session.gc_probability = 1
session.gc_divisor = 1000 
也就是说,garbage collection 有个概率的,1/1000就是session 1000次才有一次被回收。
只要你的访问量大了,那就能达到回收的效果.要不然你也可以设置一下session.gc_divisor 的值. session.gc_divisor = 1,这样就能明显的看到SESSION过期的效果了.但是这样当然会增大服务器的负载.

2. 下面我们来讨论一下延长session过期时间的问题:

1)       代码+修改配置:

LINUX下修改配置:

首先需要在/tmp文件夹下建一个文件夹,此处我新建了一个stnts的文件夹.并且把所有者设为www-data(网络用户).

在.htaccess文件内添加了语句,将session.gc_maxlifetime的local value扩大为14400(4小时),同时将session.save_path设置为/tmp/stnts

具体代码如下:





这样做的好处是

a) 多站点之间的SESSION不会互相影.

b) 同时服务器的负载也会略微降低.

测试下来,一切如我所愿。

但是在LINUX下存在一个问题.www-data用户没有tmp文件夹下创建文件夹的权限,因为涉及安全性问题,所以此方案还需要斟酌一下.

 

WINDOWS 下的修改配置:

配置基本一样.也同样存在权限问题.

因为回收机制会检查文件的“最后修改时间”,所以如果某个会话是活跃的,但是session的内容没有改变过,那么对应的session文件也就没有改变过,回收机制会认为这是一个长时间没有活跃的session而将其删除。这是我们不愿看到的,可以通过增加如下的简单代码解决这个问题:



代码会每隔60秒,尝试修改修改一次session。
总结:如果想修改session过期时间,修改变量gc_maxlifetime就可以了。php5的session采用被动的回收机制(garbage collection)。过期的session文件不会自己消失,而是通过触发“回收”来处理过期的session。

 

2)       把Session存入数据库:

因为浏览器每次访问 web 服务器完成后,浏览器与服务器的连接(有就是通讯通道)就关闭了,这一次访问就是一个 session (会话),等下次访问的时候就有是一个新的session了,本来这两个session在通讯数据上讲是没有任何关系的。可是需求要求我们让他们产生关系,也就是说访问的session(会话)间要有一些信息需要共享,比如说就像我现在用的QQ问问回答问题时有验证图片的,可是当我们看到浏览器获取的图片后,获取图片这个session就已经结束了,当提交回答的时候输入的验证码是一个新的session了,服务器如果不把上一个session中生成的验证码存储起来,就没法验证提交的验证码的正确性
而完成这个任务用的方法首先是浏览器要支持cookie(其实如果不支持的话也有办法,那就是把session标识直接附加到url地址上)
当需要保持session间的信息的时候,服务器先生成一个不可能重复的 session id,也就是一串字符啦,这个id会在发生新的session时被浏览器发送到服务器上(当然方法也有两种啦,cookie和url参数),而服务器根据这个id可以用文件名的形式或者是存到数据库里用一个唯一字段标识的方法,来存储跟这个session id有关的数据。达到在不同的浏览器访问session时共享session间的数据,就好象是在进行一个可以暂停的访问那样。
这里面有一个问题就是访问总是有客户端发出,因此服务器端如果要处理session的话,首先的触发条件就是客户端有访问才行(当然如果在服务器上设置定时器的话也行)。
php 本来有一套基于文件存储的简单session方法,同时也提供了可自行管理的session_set_save_handler 方法,这个方法一经使用就要求所有session的维护(除了session id的生成仍然有session_start自动生成),如:保存,修改,删除session数据。都要手工代码进行.

如果是用php提供的文件存储的方法的话,可以通过php.ini配置来自动删除过期数据,可是你用session_set_save_handler存储到数据库里的数据就无能为力啦,因为你已经接管了session数据的管理权,php不管啦。
当然存储到数据库里的session有一些好处,比如在多服务器间共享更容易。
如何删除过去的数据库保存的session数据呢?可以通过在表里保存session活动(更新)的时间,然后不管是那一个用户访问了服务器,都写代码去检查所有的过期数据,然后进行处理,可是这样的话,服务器压力就大啦。至少有两种方法是可以减缓这个问题的


a) 设置阀值,比如说来个1-100的随机数,如果这个数是x的话就去检查过期数据.
b) 在服务器上设置定时器(计划任务),定期自动去执行代码处理数据库过期session数据.

 

我在我的DEMO 里面运用了第一种方法.因为这就类似php原生的回收机制.我想还是经过深思熟虑的解决方案. 不过我觉得session的gc清理,可以被作为系统的进程来执行。或者可放在网站的后台,进行人为的操作…

3. 数据库,文件系统存储session比较:

1) 从效率上讲文件系统超过数据库数倍.我尝试读取写入200个session数据,数据如下:

读取SESSION:

文件系统

0.0016

0.0004

0.0015

0.0015

0.0004

0.0010

数据库

0.0052

0.0084

0.0089

0.0055

0.0150

0.0086

写入SESSION:

文件系统

0.0004

0.0011

0.0003

0.0004

0.0011

0.0006

数据库

0.0048

0.0075

0.0082

0.0073

0.0077

0.0071

由此可见,未经优化的数据库效率,和文件系统效率不是一个数量级的.

2) SESSION数据库的优点,如果服务器起采用群集的方式的话就不能保持session的一致性,所以我们就绪要采用数据库的方式来保存session,这样,不管有几台服务器同时使用,只要把他们的session保存在一台数据库服务器上就可以保存session的完整了.还有诸如:控制一个帐号只能一个人登录,统计在线人数,踢出某个在线用户.总之用户的状态就掌握在我们手里了.并且不用修改代码.

P.S.  SESSION数据库中的session_data会以数组序列化的形式存储在数据库里,因此存在一个数据上限的问题,我在DEMO里把session_data字段定义为longtext.一般的应用是完全足够的,不过为了提高效率也可以根据具体情况对字段做相应的修改.

3. SESSION的一些安全问题:

首先要明白PHPSESSID看似多次刷新都不会改变其实是没有删除本地相关联的cookie,删除的方法

session_destroy();//删除服务器端的session文件

setcookie(session_name(),'',time()-3600,'/');//删除本地相关联的cookie

session_unset();//清空内存中的cookie或者是$_SESSION = array(); 

可能PHP开发者心中多少都思考过这么两个问题:

种植在客户端浏览器中的PHPSESSIONID会出现重复吗?
PHPSESSIONID安全性如何,有没可能被黑客轻易的仿造呢?
带上这个问题,我稍微注意了一下PHP的源码后,疑问也就有了答案。

PHP在使用默认的 session.save_handler = files 方式时,PHPSESSIONID的生产算法原理如下:


hash_func = md5 / sha1 #可由php.ini配置
PHPSESSIONID = hash_func(客户端IP + 当前时间(秒)+ 当前时间(微妙)+ PHP自带的随机数生产器)

从以上hash_func(*)中的数据采样值的内容分析,多个用户在同一台服务器时所生产的PHPSESSIONID重复的概率极低(至少为百万份之一),设想,但台动态Web Server能到2000/rps已经很强悍了。

另外,黑客如果要猜出某一用户的PHPSESSIONID,则他也必须知道“客户端IP、当前时间(秒、微妙)、随机数”等数据方可模拟。

所以SESSION_ID的可靠性和安全性还是很有保障的.

 DEMO下载地址 (来自http://hbly123.com)

请先导入SQL,修改index.php里的数据库相关信息,再运行程序..