PHP 页面防重复提交常用方法:前端禁用、超时检测与 Token 销毁
在 Web 开发中,用户因网络延迟或误操作导致表单重复提交是常见痛点。本文详细解析了 PHP 环境下防止重复提交的三种主流方案:前端按钮禁用、Session 超时控制以及 Token 验证机制,并提供相应的代码实现与最佳实践建议。
结果或目标
确保用户在一个业务请求完成前,无法再次发起相同操作的提交,从而避免数据库出现脏数据或资源重复消耗。通常采用前端交互限制与后端逻辑校验相结合的双重保障。
准备条件
在进行任何实施之前,需要确认以下基础环境:
- Web 服务器与 PHP 环境:确保 PHP Sessions 已正常启用。
- 前端资源:若采用前端禁用法,需确保页面引入了 jQuery 或具备原生 DOM 操作能力。
- 业务标识符:定义用于生成唯一 Token 的 Key(如用户 ID、时间戳、业务类型等)。
真实操作顺序
第1步:前端按钮即时禁用
目的:从用户体验层面快速拦截重复点击,减少无效的网络请求。
入口:用户点击提交按钮触发的事件监听器。
动作:
- 用户点击提交按钮时,立即通过 JavaScript 获取按钮元素。
- 设置按钮为
disabled状态,并修改按钮文本提示用户“正在提交”。 - 当 AJAX 请求成功返回或发生错误时,移除
disabled属性并恢复原始文本。
重要参数:
- 按钮 ID 选择器,例如
#submit。 - 状态值
'true'或布尔值true。
可观察的完成状态:点击后按钮变灰不可点,直到服务器响应后才恢复可点击状态。
复制代码 代码如下:
$("#submit").attr('disabled','true');
$("#submit").val("正在提交,请稍等");
执行成功后重置按钮:
复制代码 代码如下:
$('#submit').removeAttr('disabled');
$("#submit").val("确定提交");
第2步:Session 过期时间法
目的:在后端设置一个时间窗口,在此窗口内拒绝相同的业务请求。
入口:服务端接收表单数据的函数。
动作:
- 生成唯一的令牌 ID(可由用户信息+固定字符串 MD5 加密得到)。
- 获取当前时间戳。
- 检查 Session 中是否已存在该 Token,且当前时间与记录时间的差值小于设定阈值(如 30 秒)。
- 若满足条件,判定为重复提交,返回 false;否则写入 Session 并强制刷新会话文件。
关键参数:$expire(默认 30 秒),用于控制允许提交的冷却时间。
代码实现:
复制代码 代码如下:
function checkRepeatSubmit($uniqueid = '', $expire = 30) {
// 生成唯一标识
$uniqueid = empty($uniqueid) ? Yii::app()->user->id . Yii::app()->user->name . Yii::app()->user->mihome : $uniqueid;
$token = md5("wms_check_repeat" . $uniqueid);
$time = time();
// 判断是否处于有效期内且存在记录
if (isset($_SESSION['token']) && !empty($_SESSION['token']) && $_SESSION['token'] == $token && ($time - $_SESSION['expire_time'] < $expire)) {
return false;
} else {
$_SESSION['token'] = $token;
$_SESSION['expire_time'] = $time;
// 强制立即写入 Session,避免并发问题
session_write_close();
return true;
}
}
// 清理函数(可选)
function cancelRepeatSubmit() {
unset($_SESSION['token']);
unset($_SESSION['expire_time']);
}
第3步:Token 创建与销毁机制
目的:这是最稳健的后端校验方式。利用一次性 Token 确保每个页面视图只能被提交一次。
入口:页面渲染时生成 Token,表单提交时校验 Token。
动作:
- 页面加载:调用
createToken()生成哈希值存入 Session,并将其作为隐藏字段<input type="hidden" name="form_token">放入 HTML 表单中。 - 提交处理:服务端获取提交的 Token,与 Session 中的进行比对。
- 验证成功:立即从 Session 中删除该 Token(关键步骤)。此后若再次使用同一页面快照提交,因 Session 中无此 Token 而失效。
代码实现:
复制代码 代码如下:
function createToken($uniqueid) {
$uniqueid = empty($uniqueid) ? Yii::app()->user->id . Yii::app()->user->name . Yii::app()->user->mihome : $uniqueid;
$token = md5("wms_check2_repeat" . $uniqueid);
$_SESSION['form_token'] = $token;
session_write_close();
return $token;
}
function checkToken($token) {
if (!isset($_SESSION['form_token']) || empty($_SESSION['form_token']) || $_SESSION['form_token'] != $token) {
return false
} else {
// 验证通过后销毁 Token,使其失效
unset($_SESSION['form_token']);
return true;
}
}
完成判断与排错
完成判断:通过上述任一方法,当用户在短时间内两次提交相同表单时,第二次请求应当被后端明确拒绝或忽略,不会造成业务数据 duplication。
常见问题排查:
- Session 写入延迟:PHP 默认的 Session 机制会在脚本执行结束时才将数据写入磁盘/存储。在网络较慢或并发高时,可能导致第一次提交尚未写入,第二次请求即通过验证。
解决方法:在写入后立即调用session_write_close()强制保存,或将 Session 驱动切换为 Redis/Memcached 以提高读写速度。 - 并发冲突:多标签页同时打开同一表单可能会产生 Token 覆盖问题。建议在生成 Token 时混合当前时间戳或 UUID。
简要总结
单一的防护手段往往存在不足。推荐组合使用:
- 前端:使用 JS 禁用按钮提供即时反馈。
- 后端:采用 Token 销毁法(第3步)作为主要安全防线,因为它能准确识别由浏览器缓存或后退按钮引发的非法重放攻击。
对于高并发场景,可将 Token 和状态检查迁移至 Redis 等内存数据库中,以获得更低的延迟和更高的吞吐量。
以上就是 PHP 页面防重复提交方法的详细内容,更多关于 PHP 表单优化与安全的资料请关注本站其它相关文章!本站声明
本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。













