【问题标题】:PHP Session ExpirationPHP 会话过期
【发布时间】:2011-04-07 21:29:47
【问题描述】:

关于 PHP 中的 Session Expiration 的问题。

如果该用户有一段时间不活动(出于测试目的,5 秒),我需要我的服务器丢弃会话信息。

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

我一直在我的 PHP.ini 中查看session.gc_maxlife 和相关参数,但我无法按照我想要的方式进行这项工作。

对这个问题有什么建议吗?

【问题讨论】:

  • 如果您不想在下一个请求时销毁过期会话,您希望发生什么?
  • 我认为这里没有问题,除非您依赖到期代码进行某种额外的清理。如果是这种情况,那么 cron 脚本可能是更好的选择?
  • 我确实希望它被销毁,但不想依赖用户在会话实际被销毁之前发出另一个请求。
  • 您误会了:垃圾收集适用于 any 用户为所有过期用户触发它。特定用户无需在其数据被清除之前拨打过期电话。
  • 我要感谢大家,尤其是 Gumbo 和 Saul 的回复。由于实际上确实需要在会话到期时管理一些数据库更改,因此我选择了 Saul 的答案。 Gumbo 的回答也有帮助,但它让我意识到如果不运行额外的作业,我将无法看到会话实际上已过期,该作业也可以修改数据库以反映过期的会话。

标签: php session


【解决方案1】:

垃圾收集器不是按会话调用的,垃圾收集器有一个基于 tge gc_* 值调用的更改,这可能会使多个会话无效。所以只要有人触发,其他人就可以登出。如果您需要更可靠的方法,如果您的超时以分钟为单位,请使用 cronjob,如果您的超时以秒为单位,您将不得不使用某种守护进程。

【讨论】:

    【解决方案2】:

    如果您需要调用特定的过期逻辑(例如,为了更新数据库)并希望独立于请求,那么实现一个查看会话文件访问时间的外部会话处理程序守护进程是有意义的。 daemon script 应该为指定时间内未访问的每个会话文件执行任何必要的操作。

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

    【讨论】:

    • 只是作为一个书呆子,Windows does use accessed times - 从一开始就这样做了 - 尽管出于性能原因在最近的版本中它是 disabled by default。 FAT 系统只允许 1 天的分辨率!但 NTFS 更精确。它仍然不是一个理想的选择,因为 NTFS 可能会延迟存储新的时间戳,直到写入不会影响磁盘性能(最坏的情况,最多一个小时)。
    【解决方案3】:

    session expiration logic I mentioned 已经完成了您的预期:会话一旦过期就无法使用。

    会话数据是否仍在存储中并不重要,因为它在过期后无法使用;下次垃圾收集器运行时,它将被删除。在每个session_start 调用中,session.gc_probability 除以session.gc_divisor 的概率会发生这种情况(另请参阅How long will my session last?)。


    编辑    由于您想在过期会话上执行一些额外的任务,我宁愿建议使用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')
                             );
    

    【讨论】:

      【解决方案4】:

      您可以执行此操作的一种方法是使用 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>
      

      【讨论】:

      • 是的,使用心跳是一种选择,但在您的示例中,“onUnload”事件需要一个再见功能。即使这样,如果用户代理只是断开连接,也无法保证到期事件。但从接受的答案来看,Timo 并不是在寻找一种在会话到期时在服务器上执行自定义代码的防弹方法。我猜他只是担心会话破坏。
      猜你喜欢
      • 2013-03-06
      • 1970-01-01
      • 2012-01-12
      • 2013-09-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-04-13
      相关资源
      最近更新 更多