【问题标题】:How to find out that session has expired in PHP?如何在 PHP 中找出会话已过期?
【发布时间】:2018-04-16 14:56:32
【问题描述】:

我正在尝试改进 Web 应用程序的会话管理。我的主要问题是会话到期以及如何处理它。为此,我想知道会话是否仍然可用。我使用的是默认的基于文件的会话(PHP 7.1、Apache 2.4、Fedora/RHEL),它是基于 cookie 的。

我发现当调用session_start() 时会执行会话GC。它与脚本执行的开始或结束无关,它发生在此函数中。我觉得奇怪的是,如果session_start() 和 GC 认为会话已过期并想要删除相应的会话文件,则 $_SESSION 首先会定期填充,然后该文件将被删除。这很令人惊讶。

在这种行为下,只有下一个请求会导致空的 $_SESSION。我希望之前的调用会出现这种情况 - 删除文件的调用。因此,如果我想知道当前请求中的会话是否已过期,我必须检查在session_start() 调用之后会话文件是否仍然存在。这对我来说似乎很奇怪。

除了查看文件系统之外,还有其他更好的方法来检查会话是否已过期?

我想我可以检查 $_SESSION 是否为空来确定会话是否已更新 - 但这显然是不可能的。


更新:我发现了以下处理该问题的错误报告:thisthat。还有一个关于过期问题的SO entry。当前 PHP 源代码:php_session_start 调用 php_session_initialize 调用 php_session_gc


您可能想玩这个脚本(虚幻设置仅用于测试目的):

ini_set('session.gc_maxlifetime', 2); // Session gets expired after 2 seconds
ini_set('session.gc_divisor',     1); // Delete expired session files immediately
ini_set('session.save_path',      '/some/safe/path/for/testing'); // Must be accessible for the server
//ini_set('session.use_strict_mode', true); // Uncomment if the id should be renewed, what makes no difference here

echo "Session files before session_start call<br>";
listSessionFiles();

session_start();

echo "Session files after session_start call<br>";
listSessionFiles();

echo "<hr>";

echo "Session id: "      . session_id() . "<br>";
echo "Session content: " . print_r($_SESSION, true);
$_SESSION['x'] = time(); // Populate the session with something 


function listSessionFiles() {
    echo "<ul>";
    $none = true;
    $dir  = dir(ini_get('session.save_path'));        
    while ($entry = $dir->read()) {
        if (preg_match('/^sess_/', $entry)) {
            echo "<li>" . $entry . "</li>";
            $none = false;
        }
    }
    $dir->close();
    if ($none) echo "<li>None</li>";
    echo "</ul>";
}

只需重新加载页面几次。等待至少两秒钟以上。否则会话不会过期。

【问题讨论】:

  • 将 GC 设置为在每个请求上运行是相当荒谬的。 PHP 会话没有实际的过期时间,它们只有最短的生命周期。如果你想要一个 max 生命周期,那么你应该自己实现 - 将最后一次访问时间存储在会话中,并在下一次访问时与当前时间进行比较,然后决定是继续还是终止本次会议。
  • @CBroe 那个脚本只是用来玩的。当然我不使用这些设置。不,我不想要最长的寿命。我只是想知道会话是否已过期。
  • 确实像 @CBroe 所说的 Setting the GC to run on every single request is rather nonsense. 此外,由于需要磁盘 i/o,它可能会导致延迟。
  • @RaymondNijland 我知道。脚本只是为了尝试。但是,问题不受这些设置的影响。
  • "我发现会话 GC 是在 session_start() 被调用时执行的。它不是脚本执行的开始或结束,它发生在这个函数上.” - 是经过验证的事实(通过检查 PHP 源代码),还是只是一个假设,因为从您所看到的情况来看它“感觉像它”?我认为,2 秒的生命周期也可能会扭曲您的结果/观察结果。除非这是在半现实条件下进行测试,否则我认为这现在根本证明不了任何事情。

标签: php session session-cookies


【解决方案1】:

解决此问题的一种方法是使用具有特定生命周期(低于会话生命周期)的 cookie。如果 cookie 过期,它将不会被发送到服务器。然后,当调用session_start() 时,PHP 将创建一个新会话,因此 $_SESSION 将为空。

这可能足以发现会话不可用。尽管在 PHP 中无法区分会话是否已过期或出现任何问题。您可以告诉没有可用的会话数据,然后做适当的事情(除其他外,还破坏新创建的空会话)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-09-22
    • 1970-01-01
    • 2016-08-04
    • 2012-10-12
    • 1970-01-01
    • 1970-01-01
    • 2013-12-03
    • 2011-04-07
    相关资源
    最近更新 更多