防止多次提交相同的表单

问题
希望防止用户将同一个表单提交多次。
解决方案
在表单中包含一个隐藏域,并指定一个唯一的值。验证表单时,查看提交的表单是否已经有这个值。
如果有,则拒绝提交。如果还没有,则处理表单,并记录这个值以备以后使用。
另外,可以使用JavaScript,使得一旦表单提交就禁用表单Submit(提交)按钮。
在表单中插入一个唯一的ID

检查表单是否重新提交
// 检查请求方法是否为POST,通常用于处理表单提交
if($_SERVER['REQUEST_METHOD'] == 'POST'){
// 创建一个新的PDO实例,用于连接到SQLite数据库
// 数据库文件位于/tmp/formjs.db
$db = new PDO('sqlite:/tmp/formjs.db');

// 开始一个数据库事务,这允许我们进行一系列数据库操作
// 并在最后提交或回滚这些操作,以确保数据的一致性
$db->beginTransaction();

// 准备一个SQL查询语句,用于检查是否存在具有相同token的记录
// 这里使用?作为占位符,用于后续的安全地绑定参数
$sth = $db->prepare('SELECT * FROM forms WHERE token = ?');

// 执行准备好的查询语句,并将POST请求中的token值作为参数传递
$sth->execute(array($_POST['token']));

// 获取查询结果,并检查是否有记录返回
// count($sth->fetchAll())会返回结果集中的记录数
if(count($sth->fetchAll())){
    // 如果存在具有相同token的记录,表示表单已经被提交过
    print "This form has already been submitted!";
    
    // 回滚事务,因为表单已经提交过,我们不需要进行任何数据库更新
    $db->rollBack();
}else{
    // 如果没有找到具有相同token的记录,表示这是表单的首次提交
    
    // 准备一个SQL插入语句,用于将新的token值插入到forms表中
    $sth = $db->prepare('INSERT INTO forms (token) VALUES (?)');
    
    // 执行准备好的插入语句,并将POST请求中的token值作为参数传递
    $sth->execute(array($_POST['token']));
    
    // 提交事务,这将使所有在此事务中执行的数据库操作生效
    $db->commit();
    
    // 输出成功消息
    print "The form is submitted successfully.";
    
}

}

有人可能不愿意生成一个随机token,而希望使用一个比数据库表中已有记录数大1的数。这种方法(至少)有两个问题。首先,这会带来一种竞态条件。在第一个人完成表单之前如果第二个人开始了表单,此时会发生什么情况?第二个表单就会与第一个表单有相同的token,这就会出现冲突。这个问题可以通过以下方法来解决,即请求表单时在数据库中创建一个新的空记录,这样第二个人得到的数就会比第一个人得到的数大1。不过,如果用户不想完成这个表单,这样就会导致数据库中增加一些空行。
不建议采用这种做法的另一个原因是,这样做可以轻松编辑数据库中的另一个记录只需要手动地将ID调整为另一个数。取决于你的安全设置,通过提交一个仿造的get或post请求就能毫无困难地修改数据。不过,如果只是修改为一个不同的整数,并不能猜出随机的token。

posted @   kksllss  阅读(4)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
点击右上角即可分享
微信分享提示