PHP:如何检测会话是否已自动过期?

时间:2016-12-15 13:55:05

标签: php session

当定义会话到期时间时,是否可以在事件监听器到期时调用它?

如果不可能,是否可以运行cron作业来检查会话是否已过期?

注意:我对服务器解决方案感兴趣。我正在谈论定义会话到期时间的情况,并且会话因为该期限到期而自动结束。

12 个答案:

答案 0 :(得分:10)

  

是否可以在事件监听器到期时调用它?

简短的回答是

人们往往会忽略一些关于会话的奇怪之处。使用默认处理程序时,会话在gc_maxlifetime结束时不会过期 - 这只是数据符合自动删除条件的时间。会话所有者没有采取任何行动来触发随后的会话删除 - 这是其他人会话的副作用。

当调用session_write_close()时(显式或隐式地通过代码结束),如果随机数生成器(通过相关的gc设置调整)会抛出正确的数字,那么PHP将寻找超过其TTL的数据去掉它。如果您想在此时触发操作,则需要中断默认处理程序并应用自己的操作。这意味着您不仅需要提供一种识别和删除会话的机制,还需要一种方法来决定您的处理程序是否应该启动以及应该删除多少个会话 - 您不需要runaway process killing your server

在Ubuntu中,session.gc_probability = 0,它是一个执行删除陈旧数据文件功能的cron作业。

您的问题中遗漏的非常重要信息是删除会话的原因。

如果您想防止敏感数据持久存在于文件系统上,那么更好的解决方案是使用另一个客户端cookie中存储的密钥(仅)来加密数据。这样您就可以完全消除服务器上未受保护数据的存储。 (请注意,suhosin's encrypted sessions使用从客户端数据派生的密钥和存储在同一主机上的静态密钥 - 这比随机生成的密钥安全得多。 Here's one I prepared earlier

如果您只想在gc_maxlifetime到期后阻止访问,则应考虑将自定义会话处理程序视为缺失的自定义会话处理程序。即它在到期时并未真正注销,但任何后续请求都不能再与会话相关联。 Stackable会话处理程序示例中的安全层实现了这样的控制。

OTOH如果你想在你的事件监听器中使用会话中的数据,那么这是一个不同的故事 - 你肯定无法使用Suhosin或我的加密数据。但更复杂的是,数据的(默认)格式与其他地方使用的格式不同。您需要使用session_encode()和session_decode()。前者只会读取$ _SESSION数组中的数据,因此对会话的窃听需要对session_id()session_start()进行一些小心的颠覆。然而,session_decode()会愉快地转换你投掷的任何东西。

在PHP的最新版本中,您可以指定用于序列化/反序列化的不同函数对。

在考虑会话文件中读取数据的会话垃圾收集器时,考虑__wakeup()方法的潜在影响非常重要 。与此相关的是要求处理此类垃圾收集的进程在与创建会话数据的原始PHP进程相同的uid下运行(否则您具有权限提升后门)。但是,如果会话存储基板是基于文件的,那么无论如何都需要这样。

会话数据解串器的实现是用PHP以外的语言编写的,可以提供针对__wakeup()攻击的保护(尝试使用Google),尽管解决问题可能有点过分,但可能没有积极维护。如果这是一个问题,那么更合适的解决方案可能是使用WDDX(xml)序列化程序并使用传统的XML解析器来读取GC引擎中的数据。

如果您使用本机处理程序正常读取和写入数据但想要实现自己的垃圾收集器,那么您将需要代码将session_id映射到文件路径。如果你按照我给上面的PHP类的链接,你会看到几个会话处理程序的纯PHP实现,包括与本机处理程序兼容的那些。

但是我强烈建议你在选择在删除时回读会话数据之前用尽所有其他途径解决任何潜在问题。

答案 1 :(得分:3)

听起来你想要在服务器端的给定时间消灭会话。您要做的是定义自己的自定义会话处理程序,并将会话数据放在您完全控制的系统中。所以,假设您将会话处理移动到数据库中。现在,您的所有会话数据完全在您的控制范围内。以下是缩写custom session handler

class Sessions implements \SessionHandlerInterface {
    /**
     * Write Session Data
     * @param string $id Session ID to delete
     * @param string $data Data to write into the session
     */
    public function write($id, $data) {
        $time = time() + 3600; // 1 hour for the sake of example
        $sql = 'REPLACE INTO your_session_table
                SET session_id = ?,
                    data = ?,
                    expires = ?';
        $this->db->query($sql);
        $prep = $this->db->prepare($sql);
        $prep->bind_param('ssi', $id, $data, $time);
        $prep->execute();
    }
}

你可以在这里做的是你可以在这里运行自己的清理脚本。现在,我建议您使用中间存储器(memcached,Redis等),这样您就不必每次都从DB加载。运行清理脚本时,您需要清除它(即拉出所有会话即将过期并从缓存中删除)。但是这里的一个简单的SQL语句(例如,运行5分钟的cron作业)可以按需清理会话

 DELETE FROM your_session_table
 WHERE expires < now();

答案 2 :(得分:3)

我在这里做了几个假设。

我假设,无论出于何种原因,您希望能够跟踪过期的会话冷,即,没有通过数据库或第二个隐藏的会话数据的补充跟踪&#39;会话,作为一个结构来确定伪会话何时到期并采取适当的行动。

我还假设你的会话上的黑客攻击在这一点上并不重要。中间人和XSS攻击可以捕获会话ID并将其插入您的系统,并且很难检测到。

这种事情默认由php中的会话cookie处理。我还假设您的会话标识和会话开始也由cookie处理。

几乎没有办法做到这一点&#39; live&#39;,也就是说,保持套接字打开服务器以检测会话到期的时刻。 PHP不是为那种方式工作而设计的;安全问题是广泛的。同样,如果您允许某人通过安全通道远程访问您的服务器,那么您为什么还要首先考虑会话?

$sessionCookie = 'myPHPSessCookieName';
$isSessionExpired = false;

if (isset($_COOKIE[$sessionCookie])) {
  // check cookie expiry time to show warnings / near expiry behaviours
} else {
  // handle missing cookie / session
  $isSessionExpired = true;
}

define('SESSION_EXPIRED', $isSessionExpired);    
session_start(['name' => $sessionCookie]);

在开始会议之前检查cookie必须发生,否则你就有可能给自己一个误报。

[编辑:javascript解决方案]

如果您希望生成模拟套接字的行为,javascript可以执行此操作。客户端的浏览器将使用AJAX请求ping服务器以检查其会话的状态,一旦检测到它已过期,您就可以引发您选择的行为。注意:javascript在当前状态下基本上是不安全的。如果可能的话,所有与数据和安全相关的工作都应由服务器完成。

client.php:

<script>
  $(function(){
    var messageElem = $('#selectorForDisplayElementHere');
    var timeoutID = null;

    var checkSession = function(){
      $
        .ajax({/* your ajax params: url, data, dataType, method etc. */})
        .then(function(response){
          messageElem.html(response.html);
          if (response.stop === 1) { 
            clearTimeout(timeoutID);
          }
        });
    };

    var timeoutID = setInterval(checkSession, 5000); // Every 5 seconds
  });
</script>

ajax.php:

$response = ['html' => '', 'stop' => 0];

if (SESSION_EXPIRED) {
  $response ['html'] = '<b>Your session has expired. Please log in again.</b>';
  $response['stop'] = 1;
}

echo(json_encode($response));

这是一个非常简单的处理系统,可以通过各种功能轻松增强。它使用无处不在的jQuery库和标准的php和html / javascript功能。

答案 3 :(得分:2)

您可以将连接时间存储在某个地方(表格,...),这样您就可以看到用户何时连接并定期检查(cron或服务)以查看日期是否已经过了特定的持续时间(5分钟) ,...)

但是如果你想警告用户(丢失文件......),你可能想在客户端做一个Javascript window.setTimeout

答案 4 :(得分:2)

在一页上设置初始会话。

示例:Login.php

<?php
session_start();
if(...){
   // success
   $_SESSION['logged_time'] = time();
}
?>

现在检查会话已过期或未在其他页面中

示例:Index.php

<?php
   session_start();
   $login_session_duration = 60; // 1 minute 

   if($_SESSION['logged_time']){
      if(((time() - $_SESSION['logged_time']) > $login_session_duration)){ 
         echo 'session expired';
         // session will be exired after 1 minutes
      }else{
         echo 'session alive';
      }
   }
?>

答案 5 :(得分:2)

每次向服务器发送http请求,然后检查会话到期时间。如果会话有效,请做你喜欢的事情,其他明智的重定向你想要的地方。

或者

你可以做一件事来节省你的时间。创建一个检查当前会话有效性的方法,并在您的http请求中调用它。

答案 6 :(得分:2)

你也可以使用这个:)

<? 
session_start();

$time = 3600; // Set expire time with secends.
// Star session here 
if (isset($_SESSION['time']) && (time() - $_SESSION['time']) > $time) {
   // Your Code Here to logout
   header('location: /auth/logout');
   exit();
} else {
  $_SESSION['time'] = time();
 }

答案 7 :(得分:2)

我认为你在寻找的可能就在这里:Access active sessions in PHP

总结一下,您必须创建自己的会话处理程序。这是服务器端。

如果要添加客户端警报,可以存储javascript计时器中使用的会话到期时间限制。如果只剩下x分钟,则会弹出一条消息(可能带有倒计时),向用户显示“您的会话将超时:(此处显示计时器)。”

答案 8 :(得分:1)

非常简单的方法是

获取current_time

$current_time=time();

获取在ini文件中设置的会话过期时间。

$maxlifetime = ini_get("session.gc_maxlifetime");

在javascript / query中使用此值,当时间到期时,通过手动计算使用警报来通知用户或编写您希望执行的脚本。

您可以将这些日期存储在单独的cookie变量中:

session_expire = 1525357483057

但是用户可以更改此变量。

答案 9 :(得分:0)

尝试针对session_cache_expire()进行检查,如果它为零则会话结束。可能必须在您的操作处理程序上实现。这不会在服务器上设置您的会话,只能解决您的客户端浏览器知道何时会过期的问题,这可以作为您的自动检测...

http://php.net/manual/en/function.session-cache-expire.php

答案 10 :(得分:-1)

我们可以使用您定义的会话变量。

if(isset($_SESSION['variable'])){
    //do something
}

示例:

if(isset($_SESSION['name'])){
    echo "Session has not expired"; 
}

答案 11 :(得分:-1)

你要做的是在一个定时间隔运行一个jQuery AJAX请求来检查会话是否过期以及什么时候你可以发送用户注销。

Ajax代码

var checkSession;
function SessionCheck(){
     var str="sessionCheck=true";
     jQuery.ajax({
                   type:"POST",
                   URL:"sessionCheck.php"
                   data: str,
                   success: function(res){
                        if(res==1){
                            //do session expired logic here
                        }
                   }
                });
    }
sessions = setInterval(SessionCheck, 1000); //This will run the SessionCheck function every second

PHP代码

session_start();
$data = $_SESSION["sessionVariable"];
if($data == ''){
    echo "1";
}
else{
    echo "0";
}