PHP session回收机制

版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://linuxstyle.blog.csdn.net/article/details/7218923


由于PHP的工作机制,它并没有一个daemon线程,来定时地扫描session信息并判断其是否失效。当一个有效请求发生时,PHP会根据全局变量 session.gc_probability/session.gc_divisor(同样可以通过php.ini或者ini_set()函数来修改) 的值,来决定是否启动一个GC(Garbage Collector)。默认情况下,session.gc_probability = 1,session.gc_divisor =100,也就是说有1%的可能性会启动GC。

GC的工作,就是扫描所有的session信息, 用当前时间减去session的最后修改时间(modified date),同session.gc_maxlifetime参数进行比较,如果生存时间已经超过gc_maxlifetime,就把该session删 除。

那为什么会发生gc_maxlifetime无效的情况呢?

在默认情况下,session信息会以文本文件的形式,被保存在系统 的临时文件目录中。在Linux下,这一路径通常为\tmp,在Windows下通常为C:\Windows\Temp。当服务器上有多个PHP应用时, 它们会把自己的session文件都保存在同一个目录中。同样地,这些PHP应用也会按一定机率启动GC,扫描所有的session文件。

问 题在于,GC在工作时,并不会区分不同站点的session。举例言之,站点A的gc_maxlifetime设置为2小时,站点B的 gc_maxlifetime设置为默认的24分钟。当站点B的GC启动时,它会扫描公用的临时文件目录,把所有超过24分钟的session文件全部删 除掉,而不管它们来自于站点A或B。这样,站点A的gc_maxlifetime设置就形同虚设了。

找到问题所在,解决起来就很简单了。修改session.save_path参数,或者使用session_save_path()函数,把保存session的目录指向一个专用的目录,gc_maxlifetime参数工作正常了。

还有一个问题就是,gc_maxlifetime只能保证session生存的最短时间,并不能够保存在超过这一时间之后session信息立即会得到 删除。因为GC是按机率启动的,可能在某一个长时间内都没有被启动,那么大量的session在超过gc_maxlifetime以后仍然会有效。解决这 个问题的一个方法是,把session.gc_probability/session.gc_divisor的机率提高,如果提到100%,就会彻底解 决这个问题,但显然会对性能造成严重的影响。另一个方法是自己在代码中判断当前session的生存时间,如果超出了gc_maxlifetime,就清 空当前session。


php session GC功能,就是Garbage Collector。这个GC启动的时候,会清除那些已经“超时”的session。它的工作原理是这样的:

  1. 用户访问并登陆网站,这时候后台会调用session_start来尝试生成一个会话(如果已经有会话,则相当于一次有效会话请求)
  2. 对于这样的每一次有效会话请求(Request),apache的php模块会根据session相关的全局变量gc_probability/gc_divisor =>计算出启动GC的概率,并由此概率来决定在这次请求中是否应该启动GC。举例来说,session.gc_probability的缺省值为1,session.gc_divisor的缺省值为100,则启动“垃圾回收”器的概率是1%,这就意味着在每100次请求中,会有可能清理一次过期会话
  3. 如果GC启动,则GC会扫描当前会话所在路径(session.save_path)下的所有会话文件,并根据另外一个全局变量session.gc_maxlifetime的多少来判断哪些session已经过期(“当前时间”与“会话文件的atime或者mtime”之间的差大于gc_maxlifetime:过期),并删除这些过期的session
  4. 如果你在一个session启动后,长时间没有任何交互操作(譬如,不停地码字,没有提交或者保存为草稿),那么你的保存在后台的会话文件将得不到机会被修改或者访问,在gc_maxlifetime(缺省值1440秒=24分钟)时间后,它有可能因失效而被清理,这以后你再提交,就会因为会话失效而报错

由此可见,gc_maxlifetime设置为24分钟,对于写某些文章来说还不够。这是一个原因,另外,session.save_path的缺省路径在linux上是/tmp,很少有程序会修改这个设置。如果这台服务器上有多个虚拟主机,那么,/tmp目录下会存放许多不同session_name的会话文件。糟糕的是,php的GC不区分会话归属,它会根据它取得的gc_maxlifetime来清理这个目录下的所有过期session文件。

据以上分析,解决方案是:UTBLOG在.htaccess文件内添加了一条语句,将session.gc_maxlifetime的local value扩大为14400(4小时),同时在后台将session.save_path设置为/tmp/utblog,这样,utblog的会话文件就不受其他网站干扰了,而4小时的失效时间,我想,无论如何应该够用了。

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

另,如果直接改动/etc/php.ini当然也可以。如果没有权限改动php.ini,也没有权限改动apache的conf文件,.htaccess被禁止,那么直接修改plog的sessionmanager.class.php文件,在session_start行前添加ini_alter("session.gc_maxlifetime", 14400)亦可。plog结构良好,只有这一处调用session_start,所以也只有这一处需要修改。我在本地做过测试,可以工作。

--------------------------------------------------------------------------

session.gc_probability integer
session.gc_probabilitysession.gc_divisor 合起来用来管理 gc(garbage collection 垃圾回收)进程启动的概率。默认为 1。详见 session.gc_divisor
session.gc_divisor integer
session.gc_divisorsession.gc_probability 合起来定义了在每个会话初始化时启动 gc(garbage collection 垃圾回收)进程的概率。此概率用 gc_probability/gc_divisor 计算得来。例如 1/100 意味着在每个请求中有 1% 的概率启动 gc 进程。session.gc_divisor 默认为 100
session.gc_maxlifetime integer
session.gc_maxlifetime 指定过了多少秒之后数据就会被视为“垃圾”并被清除。

Note:

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

Note: 如果使用默认的基于文件的会话处理器,则文件系统必须保持跟踪访问时间(atime)。Windows FAT 文件系统不行,因此如果必须使用 FAT 文件系统或者其他不能跟踪 atime 的文件系统,那就不得不想别的办法来处理会话数据的垃圾回收。自 PHP 4.2.3 起用 mtime(修改时间)来代替了 atime。因此对于不能跟踪 atime 的文件系统也没问题了。

--------------------------------------------------------


From:

http://www.php.net/manual/zh/session.configuration.php

http://ydirone.blog.163.com/blog/static/30414895201141711524253/

http://www.utblog.com/plog/1/article/463

http://www.laruence.com/2012/01/10/2469.html

展开阅读全文

php参数传递问题-session

06-18

显示内容页面:detail.php?u_id=999rnrn没有登陆,有部分内容看不到rnrn登陆后需要返回u_id=999页面,查看完整内容rn点登陆,用login.php?go_u_id=把当前的u_id=999传递到login.php页面,到此,在地址栏可以看到rnrnhttp://xxxxxx/login.php?go_u_id=999rnrnecho $_GET['go_u_id']; 可以返回 999rnrn这个时候输入用户名 密码,登陆后,要求跳转到刚才登陆前页面 detail.php?u_id=999rn用 detail.php?u_id= ---这是系统自动匹配的参数,但是测试时候报错:rnrnParse error: parse error, unexpected T_ENCAPSED_AND_WHITESPACE, expecting T_STRING or T_VARIABLE or T_NUM_STRING in E:\AppServ\xxxxxxx\login.php on line 12rnrndetail.php?u_id= 这一行有错rnrn我怎么把参数再传回去呢?rnrn-------------rn我做了以下尝试:rn1、在detail.php页定义rnrn$_SESSION['go_u_id']=$row_myRecset_detail['u_id']rnrn在login.php页定义跳转rndetail.php?u_id= cookie是默认开启的,不需要什么.SID.吧?(这个是什么东东?)rnrn以上尝试失败rnrn2、在detail.php页定义rn$HTTP_POST_VARS['go_u_id']=$row_myRecset_detail['u_id']rnrn在login.php页定义跳转rndetail.php?u_id= 这一行报错,还是失败rnrn--------------------------rnBTW:rnrn在detail.php,注册连接上传递参数go_u_idrnrn打开login.php时候在地址栏可以看到rnrnhttp://xxxxxx/login.php?go_u_id=999rnrnecho $_GET['go_u_id']; 可以返回 999rnrn说明参数从A传递到B成功,但是再把这个参数从B重新传回A就没办法了rnrn大家帮帮我吧rnrn用cookie我不知道怎么写代码rnrn 论坛

php取得session的问题

06-12

有一个生成验证码的文件--image.php,我现在调用的时候是这样的rnrnimage.php如下:rn$height) $size=$height;rn$left = ($width-$len*($size+$size/10))/$size;rnfor ($i=0; $i<$len; $i++)rnrn $randtext = rand(0, 9);rn $code .= $randtext;rn $textColor = imageColorAllocate($image, rand(0, 100), rand(0, 100), rand(0, 100));rn $font = rand(1,4).".ttf"; rn $randsize = rand($size-$size/10, $size+$size/10);rn $location = $left+($i*$size+$size/10);rn imagettftext($image, $randsize, rand(-18,18), $location, rand($size-$size/10, $size+$size/10), $textColor, $font, $randtext); rnrnif($noise == true) setnoise();rn$bordercolor = getcolor($bordercolor); rnif($border==true) imageRectangle($image, 0, 0, $width-1, $height-1, $bordercolor);rnheader("Content-type: image/png");rn$_SESSION['code'] = $code;rnimagePng($image);rnimagedestroy($image);rnfunction getcolor($color)rnrn global $image;rn $color = eregi_replace ("^#","",$color);rn $r = $color[0].$color[1];rn $r = hexdec ($r);rn $b = $color[2].$color[3];rn $b = hexdec ($b);rn $g = $color[4].$color[5];rn $g = hexdec ($g);rn $color = imagecolorallocate ($image, $r, $b, $g); rn return $color;rnrnfunction setnoise()rnrn global $image, $width, $height, $back, $noisenum;rn for ($i=0; $i<$noisenum; $i++)rn $randColor = imageColorAllocate($image, rand(0, 255), rand(0, 255), rand(0, 255)); rn imageSetPixel($image, rand(0, $width), rand(0, $height), $randColor);rn rnrn?> rn现在的情况是:如果图片显示1234 那么$_session['code']的值将是另外一个值(上一次)。刷新页面之后,图片显示假如是 3342,那么$_session['code']则是1234.请问怎样才能即时取得图片的值? 论坛

php session监听

09-15

我想在页面关闭,也就是session失效的时候,添加一条用户退出的日志..rn网上有php session的监听代码,可是不知道放在哪里,怎么使用....rn[code=PHP]rnsession_set_save_handler rnrn$SESSION_LIFE = get_cfg_var("session.gc_maxlifetime");rn//$SESSION_LIFE = 1440;rnrnfunction sess_open ($save_path, $session_name)rnrn global $sess_save_path, $sess_session_name;rnrn $sess_save_path = $save_path;rn $sess_session_name = $session_name;rn return(true);rnrnrnfunction sess_close()rnrn return(true);rnrnrnfunction sess_read ($key)rnrn global $sess_save_path, $sess_session_name, $SESSION_LIFE, $sqlca;rnrn $query = "SELECT session_value FROM ts_sessions WHERE session_key = '$key' AND session_expiry > " . time();rn //echo "query='$query' ";rn $sqlca->query($query);rnrn if ($sqlca->next_record())rn rn return $sqlca->f(0);rn rn elsern rn return("");rn rnrnrnfunction sess_write ($key, $val)rnrn global $sess_save_path, $sess_session_name, $SESSION_LIFE, $sqlca;rnrnrn $expiry = time() + $SESSION_LIFE;rn //$value = addslashes($val);rn $value = $val;rnrn $sqlca->query("SELECT session_key,session_expiry FROM ts_sessions WHERE session_key='$key'");rn if($sqlca->next_record())rn rn $query = "UPDATE ts_sessions SET session_value = '$value', session_expiry = $expiry WHERE session_key = '$key' AND session_expiry > " . time();rn rn elsern rn $query = "INSERT ts_sessions VALUES('$key', '$value', $expiry)";rn rnrn //echo "query='$query' ";rn $sqlca->query($query);rnrn return $sqlca->Query_ID;rnrnrnfunction sess_update_time ($key)rnrn global $SESSION_LIFE, $sqlca;rnrn $expiry = time() + $SESSION_LIFE;rnrn $query = "UPDATE ts_sessions SET session_expiry = $expiry WHERE session_key = '$key'";rn return $sqlca->query($query);rnrnrnfunction sess_destroy ($key)rnrn global $sqlca;rnrn $query = "DELETE FROM ts_sessions WHERE session_key = '$key'";rn $sqlca->query($query);rnrn return $sqlca->Query_ID;rnrnrnfunction sess_gc ($maxlifetime)rnrn global $sqlca;rnrn $query = "DELETE FROM ts_sessions WHERE session_expiry < " . time();rn $sqlca->query($query);rnrn return $sqlca->Query_ID;rnrnrnsession_set_save_handler ("sess_open", "sess_close", "sess_read", "sess_write", "sess_destroy", "sess_gc");rnsession_start();rnrn[/code]rn 论坛

没有更多推荐了,返回首页