在PHP中提交表单时如何防止多次插入?

在PHP中提交表单时如何防止多次插入?,php,html,forms,form-submit,Php,Html,Forms,Form Submit,有时,用户可能会按两次[code>Enter],然后插入两次帖子 除了检查是否已经存在具有相同标题和内容的帖子之外,是否有其他解决方案可以防止这种情况发生?一旦表单提交,就使用Javascript禁用提交按钮(onsubmit) 注意,如果用户禁用了Javascript,他们仍然可以提交两次。这种情况是否经常发生,是否有理由也签入您的代码(正如您在问题中所建议的那样)取决于您。一旦用户提交表单,请使用JavaScript禁用提交按钮。例如,这就是StackOverflow在回答问题时使用的方法

有时,用户可能会按两次[code>Enter],然后插入两次帖子


除了检查是否已经存在具有相同
标题和
内容的帖子之外,是否有其他解决方案可以防止这种情况发生?

一旦表单提交,就使用Javascript禁用提交按钮(
onsubmit


注意,如果用户禁用了Javascript,他们仍然可以提交两次。这种情况是否经常发生,是否有理由也签入您的代码(正如您在问题中所建议的那样)取决于您。

一旦用户提交表单,请使用JavaScript禁用提交按钮。例如,这就是StackOverflow在回答问题时使用的方法

比如说

<input type="submit" onclick="this.disabled=true" />

单击按钮后,立即使用JavaScript禁用该按钮

onclick="this.disabled=true;forms[0].submit();"

按两次submit很少会导致多个插入,但如果您想要一个非常简单的解决方案,请使用

onsubmit="document.getElementById('submit').disabled = true"

在表单标签中,如果您提供提交按钮,则显示了一种不使用javascript的方式。

对帖子使用唯一的标记,以便每个帖子/回发只处理一次


禁用submit按钮不是一个很好的解决方案,因为人们可能会关闭javascript,或者做其他奇怪的事情。客户端验证是一个良好的开端,但也应始终使用服务器端处理进行备份。

有几种解决方案可以解决此问题:

  • 发布表单时,使用Javascript禁用表单的提交按钮。缺点是,这绝对不是一种万无一失的方法。在不点击按钮的情况下提交表单非常容易,这对禁用JavaScript的用户也不起作用我绝对不推荐这种方法。

    例如:

    // form.php
    <?php
        // obviously this can be anything you want, as long as it is unique
        $_SESSION['token'] = md5(session_id() . time());
    ?>
    <form action="foo.php" method="post">
        <input type="hidden" name="token" value="<?php echo $_SESSION['token'] ?>" />
        <input type="text" name="bar" />
        <input type="submit" value="Save" />
    </form>
    
    // foo.php
    if (isset($_SESSION['token']))
    {
        if (isset($_POST['token']))
        {
            if ($_POST['token'] != $_SESSION['token'])
            {
                // double submit
            }
        }
    }
    
    
    
  • 用于将会话变量(例如$\u session['posttimer'])设置为post上的当前时间戳。在PHP中实际处理表单之前,请检查$\u session['posttimer']变量是否存在,并检查某个时间戳差异(即:2秒)。这样,您就可以很容易地过滤掉双重提交

    例如:

    // form.php
    <?php
        // obviously this can be anything you want, as long as it is unique
        $_SESSION['token'] = md5(session_id() . time());
    ?>
    <form action="foo.php" method="post">
        <input type="hidden" name="token" value="<?php echo $_SESSION['token'] ?>" />
        <input type="text" name="bar" />
        <input type="submit" value="Save" />
    </form>
    
    // foo.php
    if (isset($_SESSION['token']))
    {
        if (isset($_POST['token']))
        {
            if ($_POST['token'] != $_SESSION['token'])
            {
                // double submit
            }
        }
    }
    
    //form.html
    //foo.php
    如果(isset($\ U POST)和&!空($\ U POST))
    {
    如果(isset($_会话['posttimer']))
    {
    
    如果((time()-$\u SESSION['posttimer'])或者,使用一次性表单键。

    生成一个唯一的一次性使用键以与表单一起提交

    依赖Javascript是一个坏主意,因为用户可能已在客户端禁用它。使用密钥方案,当服务器收到提交时,可以锁定该密钥的提交。您可以根据自己的喜好对重复提交进行响应

    要使这种方法起作用,密钥必须是唯一的,并且很难预测。否则,某些表单可能会由于密钥冲突而被锁定。因此,您不必跟踪每次表单提交的密钥并避免冲突,密钥应该随着该用户的会话而过期。另一件需要注意的事情是,如果恶意用户能够预测密钥,您的代码可能容易受到某种劫持或DOS攻击。

    我使用以下方法:

    $form_token = $_SESSION['form_token'] = md5(uniqid());
    
    将$form_令牌与表单一起发送,然后

    我检查表单\u令牌:

    if($_SESSION['form_token'] != $_POST['form_token']) {
       echo 'Error';
    }
    

    Aron Rotterveel的在为我工作的每篇帖子上都包含一个唯一的标记。但是,当用户刷新页面时,我的表单仍会提交(F5)。我通过添加重置来解决此问题:

                // reset session token
                $_SESSION['token'] = md5( $_POST['token'] . time() );
    
    我的最终脚本如下所示:

    if (isset($_SESSION['token'])) {
        if (isset($_POST['token'])) {
            if ($_POST['token'] != $_SESSION['token']) {
                echo '<h3>Oops! You already submitted this request.</h3>';
            } else {
                // process form
                // reset session token
                $_SESSION['token'] = md5( $_POST['token'] . time() );
            }
        } else {
            echo 'post token not set';
            $_SESSION['token'] = md5( $somevariable . time() );
        }
    }
    
    if(isset($\u会话['token'])){
    如果(isset($_POST['token'])){
    如果($\u POST['token']!=$\u会话['token']){
    echo“哎呀!您已经提交了此请求。”;
    }否则{
    //过程形式
    //重置会话令牌
    $_SESSION['token']=md5($_POST['token'].time());
    }
    }否则{
    回显“未设置post令牌”;
    $\会话['token']=md5($somevariable.time());
    }
    }
    
    哦!别忘了在


    我是一名PHP新手,因此如果您发现异常情况,请纠正我。

    使用JavaScript阻止它发送另一种方法来创建确认页面,用户可以最终按下提交按钮。这可能会减少此类可能性。

    我正在action.PHP上执行以下操作

    if($_SESSION && isset($_SESSION['already_submitted'])) {
    
      # If already submitted just redirect to thank you page
    
    } else {
    
        # If first submit then assign session value and process the form
        $_SESSION['already_submitted'] = true;
    
        # Process form
    
    }
    
    注意:始终使用session_start();

    $(文档).ready(函数(){
    $('#postHideBtn').show();
    $('#postHideBtn')。单击(函数(){
    $('#postHideBtn').hide();
    });
    });
    
    
    如果表单是通过键盘笔划提交的,则
    onclick
    处理程序将不会运行,例如,用户在关注提交按钮的同时按下enter键。最好像其他海报建议的那样使用
    onsubmit
    。@asah:我确实喜欢@Mats建议的令牌想法。但是如果我们留在客户端,它实际上可能会最好有一个同时包含单击和提交的方法。在onsubmit实际启动之前,2次鼠标单击可以在IE中注册。愚蠢,但我看到了。这是我使用的方法。每当呈现页面时生成GUID,每当保存表单时将其包含在数据库中。在提交处理代码中,确保GUID在插入之前不存在于数据库中。您通常使用哪种类型的GUID生成算法?+1-这是最常用的方法,并且没有客户端依赖关系。为什么不接受此作为答案?@Steve not true。帖子不应是幂等的。如果您想知道当我们第二次单击“提交”。这是无用的代码。只需在表单提交后执行HTTP重定向。我希望这样做,但我的表单可以在一个页面中工作。我最初希望使用jquery unload(),但我发现这在用户无意中
    if($_SESSION && isset($_SESSION['already_submitted'])) {
    
      # If already submitted just redirect to thank you page
    
    } else {
    
        # If first submit then assign session value and process the form
        $_SESSION['already_submitted'] = true;
    
        # Process form
    
    }