【问题标题】:How to log user out due to inactivity如何因不活动而注销用户
【发布时间】:2011-04-30 02:41:33
【问题描述】:

纯粹的服务器端 PHP。每次用户提交表单时,我都会更新数据库中的“上次活动”时间。

我想进行定期检查并强制注销非活动用户以释放许可证。

我该怎么做?我是否还应该将会话 ID 存储在数据库中,然后销毁会话?这将为另一个用户释放许可证,当第一个用户最终提交另一个表单时,我可以在每个表单操作文件的顶部检查会话是否仍然存在,并在必要时将用户重定向到登录页面。

这行得通吗?这是“最好”的方式吗?有示例代码吗?


更新:我正在轮询,因为我需要知道用户何时超时才能更新数据库。

【问题讨论】:

  • 会话在php中自动过期,您可以设置会话最大生命周期。
  • +1 哎呀,我忘了提到我需要更新数据库以显示用户已注销,这就是我轮询的原因。我已经更新了问题
  • ps 如何设置会话最大生命周期?我怀疑我需要把它设置得很高。
  • ini_set(‘session.gc_maxlifetime’ ?) 或更新 php.ini 本身。

标签: php session session-timeout


【解决方案1】:

每次登录时,您都需要跟踪会话开始时间,可以这样完成:

$_SESSION['SessionStartTime'] = time();

随着每个用户请求执行任何操作,您需要运行此脚本来监控不活动状态。

<?php
session_start();
$TimeOutMinutes = 15; // This is your TimeOut period in minutes
$LogOff_URL = "login.php"; // If timed out, it will be redirected to this page

$TimeOutSeconds = $TimeOutMinutes * 60; // TimeOut in Seconds
if (isset($_SESSION['SessionStartTime'])) {
    $InActiveTime = time() - $_SESSION['SessionStartTime'];
    if ($InActiveTime >= $TimeOutSeconds) {
        session_destroy();
        header("Location: $LogOff_URL");
    }
}
$_SESSION['SessionStartTime'] = time();
?> 

【讨论】:

  • 如果用户关闭了浏览器,脚本会运行吗?如果不是,我认为不应该,你可以依靠什么来更新数据库?
  • 变量“InactiveTime”中存在拼写错误。第 8 行拼写为“InactiveTime”,第 9 行拼写为“InActiveTime”。感谢您提供的示例,非常有帮助。
【解决方案2】:

这个问题比表面上看起来要困难。

您需要在三个不同的级别考虑会话行为:

  • PHP
  • 数据库
  • 浏览器

PHP

对于 PHP,您需要将会话超时设置为您的限制。这是来自php.net的一些示例代码:

<?php
session_cache_limiter('private');
/* set the cache expire to 30 minutes */
session_cache_expire(30);    
session_start();
?>

数据库

听起来您需要跟踪有多少会话处于活动状态,以便您可以强制执行您的许可。由于您使用的是 PHP,因此您需要在数据库级别执行此操作。每个请求都可以为用户 (UPDATE users SET last_access=NOW() WHERE user_id=?) 写入“最后请求时间”,然后您可以推测活动会话是最近 30 分钟内的会话。

您可以尝试再次在数据库中跟踪活动会话,而不是“上次访问时间”。我不确定如何在 PHP 中最好地做到这一点。我认为您可以修补 PHP 的会话删除代码。我相信它可以在会话到期时调用一个函数,但我没有这样做。

浏览器

可以使用 Javascript 轮询,但不是必需的,只要您有服务器端超时。考虑用户关闭 Javascript,或者您有一些导致脚本停止运行的 Javascript 错误的情况。

我们有一个 Ajax 密集型网站,所以 Javascript 很重要。当用户执行一些无害的操作(例如在页面上打开面板)时,可能会发现超时。 I wrote up my recent experience here.

【讨论】:

    【解决方案3】:

    我想定期检查并 强制注销非活动用户以释放 许可证

    我假设您的意思是..当会话已经(应该)过期时,您需要“做一些事情”来释放许可证,并且您希望它在服务器端受到控制。

    session.gc_maxlifetime 在这里很痛苦,因为 PHP 在销毁会话时不会发送通知。

    您需要一个 cron 作业来扫描 PHP 会话文件夹以查找 atime 已超过您的超时的会话并释放它们的许可证(并删除会话)。这样一个脚本的开始是

    cd /path/to/sessions;找到-cmin +24 | xargs rm

    取自底部 http://www.php.net/manual/en/session.configuration.php#ini.session.gc-maxlifetime 您将用对您更有用的东西替换 xargs rm

    【讨论】:

    • +1 是的,我肯定是按照这些思路思考的。谢谢
    【解决方案4】:

    您可以完全使用 JavaScript 来做到这一点。启动倒数计时器。然后等待活动并重置此计时器。如果没有活动并且计时器关闭,您可以调用您的注销序列。

    例如:

    <body onmousemove="reset_interval()" onclick="reset_interval()" onkeypress="reset_interval()" onscroll="reset_interval()">
    
    
    <script type="text/javascript">
    function set_interval(){
      //the interval 'timer' is set as soon as the page loads
      timer=setInterval("auto_logout()",10000);
      // the figure '10000' above indicates how many milliseconds the timer be set to.
      //Eg: to set it to 5 mins, calculate 5min= 5x60=300 sec = 300,000 millisec.So set it to 3000000
    }
    
    function reset_interval(){
      //resets the timer. The timer is reset on each of the below events:
      // 1. mousemove   2. mouseclick   3. key press 4. scroliing
      //first step: clear the existing timer
      clearInterval(timer);
      //second step: implement the timer again
      timer=setInterval("auto_logout()",10000);
      ..completed the reset of the timer
    }
    
    function auto_logout(){
      //this function will redirect the user to the logout script
      window.location="your_logout_script_location_here";
    }
    </script>
    

    希望对您有所帮助。

    PS:参考来自:http://www.w3hobbyist.com/web-designing/auto-logout-after-some-time-of-inactivity-with-javascript/

    【讨论】:

    • 对不起,它是纯服务器端 PHP
    • 谢谢,如果用户在同一个站点上打开多个窗口,这将不起作用。例如,如果用户打开一个窗口,然后在 10 分钟后打开另一个窗口。第一个窗口将重定向到 logout.php 以终止不应该的用户会话,因为用户在过去 15 分钟内仍处于活动模式。
    • 如果 auto_logout 函数正在向负责处理会话的 PHP 脚本发出 fetch 请求,则此方法可能有效,因此基于 PHP 脚本的响应,JavaScript 函数将注销用户。
    【解决方案5】:

    所有这些解决方案都很有趣并且效果很好。

    但是:如果您在基于框架的内容窗口中怎么办?

    那么有两种选择:

    1. 在注销或调用注销脚本之前,必须到达基于框架的页面顶部(可以使用 JavaScript 命令“解除”框架内当前位置的深度)

    2. 或者,可以调用 frame buster 或 frame killer 脚本来重置到顶部的位置,例如

    &lt;style&gt; html{display : none ; } &lt;/style&gt;
    &lt;script&gt;
    if( self == top ) {
    document.documentElement.style.display = 'block' ;
    } else {
    top.location = self.location ;
    }
    &lt;/script&gt;

    (转自维基百科:http://en.wikipedia.org/wiki/Framekiller

    通过简单的互联网搜索“framebuster”或“framekiller”,可以从各种来源阅读更多关于帧破坏者和帧杀手的信息。

    【讨论】:

      【解决方案6】:

      这是我的版本,直接基于 RKh 的回答。

      如果会话尚未超时,此版本将重新设置计时器。因此,您可以将整个块粘贴到 session_start() 下方,而不必在每次用户请求执行操作时单独调用它。

      /* Control Session Timeout */
      if (!isset($_SESSION['LastActivity'])) {
      $_SESSION['LastActivity'] = time();
      }
      //Set Timeout Window in Minutes
      $TimeOutMinutes = 5;
      //TimeOut in Seconds
      $TimeOutSeconds = $TimeOutMinutes * 60; 
      
      if (isset($_SESSION['LastActivity'])) {
          $InactiveTime = time() - $_SESSION['LastActivity'];
              //If Inactive Time more than timeout value log the user out
              if ($InactiveTime >= $TimeOutSeconds) {
                  session_destroy();
                  header("Location: $baseURL");
              }
              //If Inactive Time less than timeout reset the last activity to current time
              elseif ($InactiveTime < $TimeOutSeconds) {
                  $_SESSION['LastActivity'] = time();
              }
          }
      

      【讨论】:

        【解决方案7】:

        我使用 jQuery 得到了这个简单的解决方案。

        var idleTime = 0;
        var start = new Date();
        var end;
        
        // if mousemove, a keypressed or a mouse click events fired
        $(document).on('mousemove keydown click', function() {
            end = new Date();
            idleTime = (end.getTime() - start.getTime()) /1000;
            // 30 seconds of idle time
            if ( idleTime > 30 ) {
                // logout/endsession code here 
                //window.location.href="logout.php";
            }
        }); 
        

        最好的问候。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2014-09-28
          • 2011-03-05
          • 1970-01-01
          • 2023-03-16
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-06-27
          相关资源
          最近更新 更多