HOWTO · PHP
在 PHP 中设置会话超时
本教程介绍如何在 PHP 中跟踪用户活动,并据此实施 30 分钟闲置超时。
本页内容
PHP 不会自动在应用层会话闲置达到指定时长后使其过期。若要实施 30 分钟超时策略,可将最后一次请求的时间存入 $_SESSION,并在每次请求时与当前时间比较;当两者相差达到或超过 1,800 秒时执行相应操作。闲置时间结束后,只有收到下一次请求时才能检测到超时;浏览器停止发送请求的那一刻,服务器无法主动执行操作。
如何跟踪 PHP 会话超时
在读取或更改 $_SESSION 之前调用 session_start()。首次收到请求时还没有已保存的活动时间,因此需要先初始化。之后的请求则将保存的时间与 time() 比较。达到 1,800 秒限值时,清除会话数据并结束请求;否则,刷新活动时间,让 30 分钟计时重新开始。
运行以下示例:
本节中的代码以及显示的标签或输出仍为英文。
<?php
session_start();
$timeoutSeconds = 30 * 60;
$now = time();
if (isset($_SESSION['last_activity']) &&
$now - $_SESSION['last_activity'] >= $timeoutSeconds) {
session_unset();
session_destroy();
echo "Session expired" . PHP_EOL;
exit;
}
$_SESSION['last_activity'] = $now;
echo "Session active" . PHP_EOL;
Session active
首次请求会初始化 last_activity,并走活动状态的处理路径。之后每次请求都会先检查上一次的时间戳,再更新它。随附的执行证据显示,活动状态路径输出 Session active,退出码为 0;证据未显示过期路径已执行。在应用中,应在调用 session_start() 之后、处理受保护内容之前进行检查,以免将已过期的请求当作已通过身份验证的请求来处理。
闲置 30 分钟后销毁会话
超时后,示例会同时调用 session_unset() 和 session_destroy()。session_unset() 会移除当前会话变量;session_destroy() 则会移除当前会话处理器存储的会话数据。销毁服务器端数据本身不会移除浏览器中的会话 Cookie。如果应用也需要让该 Cookie 过期,就必须发送过期 Cookie,并使用相同的名称、路径和域设置;具体 Cookie 处理方式取决于应用的会话配置。
这是应用层的超时策略:只有请求到达执行检查的代码时,检查才会运行。PHP 的会话存储生存期设置用于控制存储清理,与这项逐请求执行的闲置超时策略彼此独立。请参阅 PHP 手册中的 session_unset() 和会话配置选项。
使用 unset() 移除会话变量
使用 unset($_SESSION['cart']) 可以移除一个条目,同时保留其他会话条目。当用户只想移除某项状态(例如购物车),而不结束整个会话时,这种做法很合适。单独使用它并不能实现闲置超时。若要管理一组相关值,可将它们存放在数组键下,然后使用 unset($_SESSION['account_state']) 只移除该键;如果后续超时检查需要 registered 元素,就不要把这个数组替换成时间戳。
调用 session_start() 后即可使用 $_SESSION 超全局变量。请参阅 PHP 手册中的 $_SESSION。
将会话 ID 轮换与超时处理分开
session_regenerate_id() 会替换当前会话标识符;它不会检测闲置时间、销毁会话数据,也不会自动要求用户重新登录。可在应用身份验证流程中的适当时机单独使用它来执行标识符轮换策略,而不是将其并入超时检查。旧会话数据是否保留,取决于该函数的选项和会话处理方式,因此不要仅凭 ID 轮换就认定用户已登出,或认定先前的标识符已无法使用。
session_id() 函数用于读取当前标识符;session_start() 则会恢复与请求关联的会话。详情请参阅 PHP 手册中的 session_regenerate_id() 和 session_id() 函数。