您应该实现自己的会话超时。其他人提到的两个选项(会话.gc_maxlifetime and session.cookie_lifetime)不可靠。我将解释其原因。
First:
会话.gc_maxlifetime
会话.gc_maxlifetime指定多少秒后数据将被视为“垃圾”并被清除。垃圾收集发生在会话启动期间。
但垃圾收集器仅以以下概率启动会话.gc_概率除以会话.gc_divisor。如果使用这些选项的默认值(分别为 1 和 100),可能性仅为 1%。
那么,您可以简单地调整这些值,以便更频繁地启动垃圾收集器。但是当垃圾收集器启动时,它会检查每个注册会话的有效性。这是成本密集型的。
此外,当使用 PHP 的默认值时会话.save_handler文件,会话数据存储在指定路径的文件中会话.保存路径。使用该会话处理程序,会话数据的寿命是根据文件的上次修改日期而不是上次访问日期计算的:
Note:如果您使用默认的基于文件的会话处理程序,您的文件系统必须跟踪访问时间 (atime)。 Windows FAT 则不然,因此,如果您遇到 FAT 文件系统或任何其他无法进行时间跟踪的文件系统,您将不得不想出另一种方法来处理会话的垃圾收集。从 PHP 4.2.3 开始,它使用 mtime(修改日期)而不是 atime。因此,对于无法进行时间跟踪的文件系统,您不会遇到问题。
因此,还可能出现会话数据文件被删除而会话本身仍被视为有效的情况,因为会话数据最近未更新。
第二:
session.cookie_lifetime
session.cookie_lifetime指定发送到浏览器的 cookie 的生命周期(以秒为单位)。 […]
恩,那就对了。这只会影响 cookie 的生存期,并且会话本身可能仍然有效。但使会话无效是服务器的任务,而不是客户端的任务。所以这没有任何帮助。事实上,拥有session.cookie_lifetime set to 0
将使会话的 cookie 成为真实的会话cookie这仅在浏览器关闭之前有效。
结论/最佳解决方案:
最好的解决方案是实现您自己的会话超时。使用一个简单的时间戳来表示上次活动(即请求)的时间,并根据每个请求更新它:
if (isset($_SESSION['LAST_ACTIVITY']) && (time() - $_SESSION['LAST_ACTIVITY'] > 1800)) {
// last request was more than 30 minutes ago
session_unset(); // unset $_SESSION variable for the run-time
session_destroy(); // destroy session data in storage
}
$_SESSION['LAST_ACTIVITY'] = time(); // update last activity time stamp
使用每个请求更新会话数据还会更改会话文件的修改日期,以便垃圾收集器不会过早删除会话。
您还可以使用附加时间戳定期重新生成会话 ID,以避免对会话的攻击,例如会话固定:
if (!isset($_SESSION['CREATED'])) {
$_SESSION['CREATED'] = time();
} else if (time() - $_SESSION['CREATED'] > 1800) {
// session started more than 30 minutes ago
session_regenerate_id(true); // change session ID for the current session and invalidate old session ID
$_SESSION['CREATED'] = time(); // update creation time
}
Notes:
-
session.gc_maxlifetime
应至少等于此自定义过期处理程序的生命周期(本例中为 1800);
- 如果您想在 30 分钟后使会话过期activity而不是30分钟后自开始以来,您还需要使用
setcookie
过期时间为time()+60*30
保持会话 cookie 处于活动状态。