在提交时避免PHP中的竞争条件:请不要多次单击提交!

在提交时避免PHP中的竞争条件:请不要多次单击提交!,php,Php,不久前,在线应用常说“不要点击提交超过一次”,现在这句话已经不存在了,对吧?比如说,在PHP中如何防范这种情况 我正在使用的一种解决方案是在会话中放入一个变量,这样您就不能每10秒提交一次以上的页面。这样,数据库工作将完成,以便进行正常检查。显然,这感觉像是黑客攻击,而且可能是 编辑:感谢大家提供Javascript解决方案。那很好,但这是一点工作。1) 这是一个输入类型=图像,2)提交必须一直启动,直到用户说可以。基本上,这篇编辑只是我在抱怨,因为我想象在看了这些令人兴奋的东西之后,我能把它弄

不久前,在线应用常说“不要点击提交超过一次”,现在这句话已经不存在了,对吧?比如说,在PHP中如何防范这种情况

我正在使用的一种解决方案是在会话中放入一个变量,这样您就不能每10秒提交一次以上的页面。这样,数据库工作将完成,以便进行正常检查。显然,这感觉像是黑客攻击,而且可能是

编辑:感谢大家提供Javascript解决方案。那很好,但这是一点工作。1) 这是一个输入类型=图像,2)提交必须一直启动,直到用户说可以。基本上,这篇编辑只是我在抱怨,因为我想象在看了这些令人兴奋的东西之后,我能把它弄明白

编辑:并不是说任何人都会与Spry东西集成,但这里是我使用document.getElementByid原型的最后代码。欢迎评论

function onSubmitClick() {
    var allValid = true;
    var queue = Spry.Widget.Form.onSubmitWidgetQueue; 
    for (var i=0;i<queue.length; i++) {
        if (!queue[i].validate()) {
            allValid = false;
            break;
        }
    }

    if (allValid) {
        $("theSubmitButton").disabled = true;
        $("form").submit();
    }
}
submitclick()上的函数{ var allValid=true; var queue=Spry.Widget.Form.onSubmitWidgetQueue;
对于(var i=0;i来说,一个解决方案是使用Javascript立即禁用单击按钮。这显然依赖于客户端浏览器上的Javascript


服务器端技巧更好,因为如果用户编辑同一条记录两次,它将捕获多个浏览器窗口之间的竞争条件。

我通常在按下提交按钮后禁用它。会话限制对直接攻击很好,但我不想在不属于它的地方混合接口逻辑。

这是一个excellent是jQuery有用的示例(但您可以在任何Javascript中使用它)。添加以下代码:

$("form").submit(function() {
  $(":submit",this).attr("disabled", "disabled");
});

单击一次它就会禁用提交按钮。

正如其他人所指出的,您可以禁用该按钮。我更喜欢服务器端检查,尽管-JS可能被禁用,用户可能会点击刷新(尽管如果您正确使用POST,将生成警告),等等


您可以在表单中添加时间戳并在会话中跟踪它-要求发布的时间戳大于跟踪的时间戳。这将防止大多数重复发布,而不会明显影响UI。

还需要注意,如果PHP检测到用户“取消”请求,它的默认行为也很重要(通过关闭浏览器,按“停止”,或者第二次按“提交”)可以停止执行脚本。如果您正在执行某种长时间的事务,这是不可取的。更多详细信息。

您应该同时执行客户端和服务器端保护

客户端-禁用按钮,如cletus所述,通过jquery禁用按钮


服务器端-在表单中放置一个令牌。如果有两个提交使用相同的令牌,则忽略后者。使用这种方法,您可以避免受到攻击。

我认为最好的选择是让PHP脚本首先在会话数组中设置一个标志,以指示它正在处理表单。这样,第二个请求可以e设置为等待原始请求完成(使用休眠呼叫服务器端等待标志清除)

重要的是不要过多地干扰提交按钮和过程,因为web的性质是不确定的;如果没有答案,用户可能希望再次单击,并且您不希望丢失他们的数据。如果第一个请求丢失,并且您禁用了他们提交的唯一方式,则可能会发生这种情况(并因此存储)数据


一个更简洁的解决方案是提交请求,并使用javascript显示一条消息,说“正在处理”,这样用户可以看到正在发生的事情,但不会阻止他们重新提交数据。

我在使用ASP.NET AJAX时使用javascript做了一个简单的版本,但在任何情况下都应该可以在您的按钮具有实际ID之前

我在button onclick事件中执行以下步骤:

  • 禁用触发onclick事件的按钮
  • 将按钮id存储在魔术变量
    closureId
    中,我可以稍后通过闭包引用该变量
  • 使用
    setTimeout
    函数在指定的毫秒数(5000ms=5秒)后执行动态定义的回调
  • 在回调函数中,我可以引用magic
    closureId
    ,并在超时后重新启用按钮
  • 下面是一个简单的HTML按钮,您可以将其自身放入test.HTML文件中使用:


    嗯,这是一个辅助控件,对吗?我的意思是,这不是一个UI问题:如果有两个提交出于任何原因,你想限制它们。在你真正控制用户的计算机之前……这是一个UI决定,因为允许表单重新提交是一个问题。这可能还与用户没有获得足够的反馈有关这是一个正在处理的东西——又是一个UI故障。我还不确定我在想什么……我确实认为你进入了用户的头脑,并假设他或她是合乎逻辑的,但事实并非如此。另一方面,你必须假设UI正在运行……这不是合乎逻辑的——这是很自然的。如果你不给用户反馈,他会怀疑他是否使用了表单发送或未发送-导致他再次尝试提交。通常是连接速度慢和延迟的问题。真的,Eran,你对这个UI案例的看法是正确的。如果UI设计不正确,用户应该再次单击,这不是我们想要的。是的,我想说:我真的需要JQuery来禁用一个有id的东西吗?一直都喜欢这样$(thinger,虽然…,你也可以使用普通javascript来做,正如cletus提到的是的,普通JS也可以做,但是(imho)jQuery要优雅得多。首先,上面的代码片段可以放在标准包含的Javascript文件中,而不是散落在HTML中,它可以在任何形式上工作。+1-像jQuery或Prototype这样的库可以节省大量时间,并允许您添加所有排序