You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何实现PHP会话超时自动销毁并更新数据库用户在线状态

根因分析

你现有代码的问题在于,PHP是服务端执行的语言,这段超时判断逻辑仅会在用户主动向服务端发起请求时触发。用户直接关闭浏览器后不会再产生任何服务端请求,因此更新数据库状态、销毁会话的逻辑永远不会自动执行。

可行解决方案

方案1:前端心跳机制(实时性最高)

这是最常用的在线状态判断方案,实现逻辑如下:

  • 前端页面添加定时器,每隔30秒(可自定义)向服务端发送一次心跳请求,证明用户仍处于活跃状态
  • 服务端接收心跳请求后,更新$_SESSION['Logged']为当前时间,同时给table_admin表新增一个last_active datetime类型字段,同步更新该字段为当前时间

前端心跳示例代码:

// 每30秒发一次心跳
setInterval(() => {
  fetch('/heartbeat.php', {
    method: 'POST',
    credentials: 'include' // 携带session cookie
  })
}, 30000)

服务端心跳接口heartbeat.php示例:

<?php
session_start();
// 验证用户已登录
if (isset($_SESSION['Logged']) && isset($id)) {
  // 建议改用预处理语句避免SQL注入
  $stmt = mysqli_prepare($this->conexao, "UPDATE table_admin SET last_active = NOW() WHERE IdUser = ?");
  mysqli_stmt_bind_param($stmt, "s", $id);
  mysqli_stmt_execute($stmt);
  $_SESSION['Logged'] = time();
}
?>

方案2:后端定时任务批量清理

这个方案不需要前端改动,适合对实时性要求不高的场景:

  • 同样给table_admin表新增last_active字段,用户每次发起请求时更新该字段
  • 配置系统定时任务:Linux系统可使用crontab,Windows系统使用计划任务,每隔1分钟执行一次清理脚本
  • 清理脚本逻辑:扫描所有StatusAdmin=1且last_active小于当前时间减15分钟的用户,统一设置StatusAdmin=0,同时销毁对应会话

清理脚本示例:

<?php
// 连接数据库代码略
$timeout = time() - 900; // 15分钟超时
$stmt = mysqli_prepare($conn, "UPDATE table_admin SET StatusAdmin = 0 WHERE StatusAdmin = 1 AND UNIX_TIMESTAMP(last_active) < ?");
mysqli_stmt_bind_param($stmt, "i", $timeout);
mysqli_stmt_execute($stmt);
// 可补充删除对应session文件的逻辑
?>

补充方案:监听页面关闭事件(非100%可靠)

可以监听浏览器beforeunload事件,用户关闭页面时主动发送退出请求,但该方案在浏览器崩溃、强制结束进程、网络异常等场景下不会触发,仅可作为补充:

window.addEventListener('beforeunload', () => {
  // 使用sendBeacon保证请求发送成功
  navigator.sendBeacon('/logout.php');
});

注意事项

原有代码中直接拼接SQL参数$id存在SQL注入风险,建议全部改用预处理语句执行数据库操作。

内容的提问来源于stack exchange,提问作者JM_2021

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.29 08:24:04