繁体   English   中英

PHP 中的会话超时:最佳实践

[英]Session timeouts in PHP: best practices

session.gc_maxlifetimesession_cache_expire()之间的实际区别是什么?

假设我希望用户会话在 15 分钟非活动(而不是首次打开后 15 分钟)后无效。 其中哪一项会帮助我呢?

我也知道我可以做session_set_cookie_params()它可以将用户的 cookie 设置为在一段时间内过期。 但是,cookie 过期和服务器端实际会话过期是不一样的; 当 cookie 过期时,这是否也会删除会话?

我想到的另一个解决方案是简单的$_SESSION['last_time'] = time()对每个请求,并将会话与当前时间进行比较,然后基于此删除会话。 我希望有一个更“内置”的机制来处理这个问题。

谢谢。

我花了一些时间寻找 php.ini 服务器设置如何使会话过期的好答案。 我找到了很多信息,但花了一段时间才弄清楚为什么这些设置会按照它们的方式工作。 如果你和我一样,这可能对你有帮助:

会话存储为 cookie(客户端 PC 上的文件)或服务器端存储为服务器上的文件。 这两种方法各有优缺点。

对于存储在服务器上的会话,使用了三个变量。

session.gc_probability session.gc_divisor session.gc_maxlifetime

(session.gc_probability/session.gc_divisor) 产生垃圾收集例程运行的概率。 当垃圾收集器运行时,它会检查至少在 session.gc_maxlifetime 内未被访问的会话文件并删除它们。

这在论坛帖子中都得到了很好的解释(尤其是这个!) - 但确实出现了以下问题:

1.) 这个概率是如何应用的? 服务器什么时候掷骰子?

答:在服务器上的任何活动会话期间,每次调用 session_start() 时,服务器都会掷骰子。 所以这意味着如果你有 session.gc_probability = 1 和 session.gc_divisor = 100 的默认值,你应该看到垃圾收集器大约每 100 次调用 session_start() 运行一次

2.) 在低容量服务器上会发生什么?

答:当 session_start() 被调用时,它首先刷新会话并使会话值对您可用。 这会更新服务器上会话文件的时间。 它然后掷骰子,如果它赢了(100 次机会中的 1 次),它会调用垃圾收集器。 垃圾收集器然后检查所有会话 id 文件并查看是否有任何可以删除的文件。

因此,这意味着如果您是服务器上唯一的人,您的会话将永远不会处于非活动状态,并且看起来好像更改设置没有任何效果。 假设您将 session.gc_maxlifetime 更改为 10,将 session.gc_probability 更改为 100。这意味着垃圾收集器有 100% 的机会运行,并且会清除过去 10 秒内未访问的所有会话文件。

如果您是服务器上唯一的一个,您的会话将不会被删除。 您至少需要运行 1 个其他活动会话才能使您的会话处于非活动状态。

所以基本上,在低容量服务器或低容量时间 - 在垃圾收集器实际运行和会话实际删除之前,它可能比 session.gc_maxlifetime 长得多。 在不知道它是如何工作的情况下,它对您来说可能完全是随机的。

3.) 为什么他们使用概率?

一场表演。 在更高容量的服务器上,您不希望垃圾收集器在 session_start() 的每个请求上运行。 它会不必要地减慢服务器的速度。 因此,根据您的服务器容量,您可能希望增加或减少垃圾收集器运行的概率。

我希望这能为你把事情联系在一起。 如果您像我一样尝试了 session.gc_maxlifetime 并且它似乎不起作用(因为您在开发服务器上尝试了它以免打扰任何人),那么这篇文章希望能让您免于头疼。

祝你好运!

每次调用session_start 时,会话文件时间戳(如果存在)都会更新,用于计算 session.gc_maxlifetime 是否已超过。

更重要的是,在超过 session.gc_maxlifetime 时间后,您不能依赖会话过期。

PHP 在加载当前会话后对过期会话运行垃圾收集,并通过使用session.gc_probabilitysession.gc_divisor计算垃圾收集运行的概率。 默认情况下,它的概率为 1%。

如果您的访问者数量较少,则不活动的用户可能会访问本应已过期并被删除的会话。 如果这对您很重要,您将需要在会话中存储时间戳并计算用户不活动的日志。

此示例替换session_start并强制执行超时:

function my_session_start($timeout = 1440) {
    ini_set('session.gc_maxlifetime', $timeout);
    session_start();

    if (isset($_SESSION['timeout_idle']) && $_SESSION['timeout_idle'] < time()) {
        session_destroy();
        session_start();
        session_regenerate_id();
        $_SESSION = array();
    }

    $_SESSION['timeout_idle'] = time() + $timeout;
}

session.gc_maxlifetime基于上次修改会话文件的时间。 因此,每次修改会话文件或在单独的页面中调用 session_start() 时,gc_maxlifetime 的倒计时都会重新开始并且用户保持“登录”状态。 这就是您正在寻找的价值。 您可以通过 php 文件中的 ini_set() 修改它,或者如果您有权访问它,则编辑 php.ini

session_cache_expire()仅控制 HTTP “Expires”标头。 此标头控制下载的页面内容在用户浏览器缓存中停留的时间。

要检查当前值,此代码将很有帮助:

$gc_maxlifetime = ini_get('session.gc_maxlifetime');
$gc_probability = ini_get('session.gc_probability');
$gc_divisor     = ini_get('session.gc_divisor');

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM