2010-09-03 102 views
3

关于PHP中Session过期的问题。PHP会话到期

我需要我的服务器扔掉会话的信息,如果用户已经停用一段时间(用于测试,5秒)。

我已经看过this question,特别是在Gumbo(+28票)的答案,我一直在想这个答案对于非活跃用户的可​​行性。在我的网站上,我已经实施了这个建议,并且它工作正常,只要用户在会话过期后至少请求一次数据。但不活跃用户的问题是他们不要求新的数据。所以过期代码永远不会被调用。

我一直期待在我的php.ini session.gc_maxlife和相关参数,但我不能做这样的工作,我想它的方式。

对此问题的任何建议?

+0

如果您不希望在下一个请求中销毁过期的会话,您希望发生什么? – Gumbo 2010-09-03 14:34:13

+1

我没有看到这里的问题,除非你依赖过期代码做一些额外的清理。如果是这种情况,那么也许一个cron脚本将是一个更好的选择? – 2010-09-03 14:37:24

+0

我确实希望它被销毁,但不希望依赖用户在会话实际销毁之前发出另一个请求。 – Timo 2010-09-03 14:39:14

回答

1

如果您需要调用特定的到期逻辑(例如,为了更新数据库),并希望从独立的请求那么它将使意义实现了外部的会话处理器守护进程,着眼于会话文件的访问时间。 daemon script应执行任何必需的每个会话文件,在指定的时间内未被访问。

这个解决方案有两个先决条件:服务器的文件系统支持的访问时间(Windows没有),你可以从session save path读取文件。

+0

只是为了成为一个学者,Windows [确实使用访问时间](http://msdn.microsoft.com/en-gb/library/windows/desktop/ms724290(v = vs.85).aspx) - 并已完成自从开始以来 - 尽管由于性能方面的原因,它在最近的版本中已被[默认禁用](http://superuser.com/a/251265/11305)。 FAT系统只允许1天的分辨率!但NTFS更精确。它仍然不是一个理想的配置,因为NTFS可以延迟存储新的时间戳,直到写入不会影响磁盘性能(最差情况,长达一个小时)。 – Basic 2014-05-31 22:55:46

1

垃圾收集器不是会话调用时,垃圾收集器有一个变化基于TGE gc_ *值被调用,它可以作废多个会话。所以只要有人触发它,其他人就可以注销。如果你需要一个更可靠的方法,如果你的超时时间在几分钟内,使用一个cronjob,如果你的超时时间在几秒钟内,你将不得不使用某种守护进程。

3

session expiration logic I mentioned确实已经在做你期待什么:一旦它已过期,不能使用的会话。

会话数据仍在存储中并不重要,因为它在到期后不能使用;它将在垃圾收集器下次运行时被删除。在session_start拨打电话(另请参阅How long will my session last?)之后,session.gc_probability的概率除以session.gc_divisor


编辑既然你想在一个过期的会话执行一些其他任务,我宁愿建议使用custom session save handler

当使用的会话保存处理的一类,你可以写两个类,一个用于基础存储处理器和一个与执行额外的任务延长垃圾收集器,如:

interface SessionSaveHandler { 
    public function open(); 
    public function close(); 
    public function read($id) 
    public function write($id, $data); 
    public function destroy($id); 
    public function gc($callback=null); 
} 
class SessionSaveHandler_WithAdditionalTasks implements SessionSaveHandler { 
    // … 
    public function gc($callback=null) { 
     if (!is_null($callback) && (!is_array($callback) || !is_callable($callback))) return false; 
     while (/* … */) { 
      if ($callback) $callback[0]::$callback[1]($id); 
      // destroy expired sessions 
      // … 
     } 
    } 
    public static function doAdditionalTasksOn($id) { 
     // additional tasks with $id 
    } 
} 
session_set_save_handler(array('SessionSaveHandler_DB_WithAdditionalTasks', 'open'), 
         array('SessionSaveHandler_DB_WithAdditionalTasks', 'close'), 
         array('SessionSaveHandler_DB_WithAdditionalTasks', 'read'), 
         array('SessionSaveHandler_DB_WithAdditionalTasks', 'write'), 
         array('SessionSaveHandler_DB_WithAdditionalTasks', 'destroy'), 
         array('SessionSaveHandler_DB_WithAdditionalTasks', 'gc') 
         ); 
1

的一种方式你可以这样做,就是使用javascript在超时时间后稍微刷新页面。授予您的用户必须启用Javascript才能使其工作。您还可以添加额外的功能,例如让javascript弹出超时通知以及倒计时等等。所以必不可少的会话过期由于您的设置,然后刷新命中,清理运行和完成。

<html> 
<head> 
<script type="text/JavaScript"> 
<!-- 
function timedRefresh(timeoutPeriod) { 
    setTimeout("location.reload(true);",timeoutPeriod); 
} 
// --> 
</script> 
</head> 
<body onload="JavaScript:timedRefresh(5000);"> 
</body> 
</html> 
+0

是的,使用心跳是一种选择,但在您的示例中,“onUnload”事件需要再见功能。即使如此,如果useragent简单地删除连接,则不能保证到期事件。但从接受的答案来看,Timo并没有寻找一种防弹的方式来在会话过期时在服务器上执行自定义代码。我认为他只是担心会话破坏。 – Saul 2010-09-05 14:42:50