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

时间:2010-01-25 16:56:41

标签: php html forms form-submit

有时用户可能会按Enter两次,并且帖子会被插入两次。

除了检查是否已存在具有相同titlecontent的帖子之外,是否有解决方案可以阻止此问题?

15 个答案:

答案 0 :(得分:49)

这个问题有几种解决方案:

  1. 使用Javascript在发布时禁用表单的提交按钮。这是绝对的,这绝对不是万无一失的方式。在没有实际单击按钮的情况下提交表单非常容易,这对于禁用JavaScript的用户也不起作用。 我绝对不会推荐这种方法。

    示例:

    <script language="javascript">
    <!--
        function disableSubmitButton() {
            // you may fill in the blanks :)
        }
    -->
    </script>
    <form action="foo.php" method="post">
        <input type="text" name="bar" />
        <input type="submit" value="Save" onclick="disableSubmitButton();">
    </form>
    
  2. 使用PHP sessions将会话变量(例如$ _SESSION ['posttimer'])设置为post上的当前时间戳。在PHP中实际处理表单之前,检查$ _SESSION ['posttimer']变量是否存在并检查某个时间戳差异(IE:2秒)。这样,您就可以轻松过滤掉双提交。

    示例:

    // form.html
    <form action="foo.php" method="post">
        <input type="text" name="bar" />
        <input type="submit" value="Save">
    </form>
    
    // foo.php
    if (isset($_POST) && !empty($_POST)) 
    {
        if (isset($_SESSION['posttimer']))
        {
            if ( (time() - $_SESSION['posttimer']) <= 2)
            {
                // less then 2 seconds since last post
            }
            else
            {
                // more than 2 seconds since last post
            }
        }
        $_SESSION['posttimer'] = time();
    }
    
  3. 在每个POST上包含唯一标记。在这种情况下,您还可以将会话变量设置为要包含的标记,然后在表单中呈现标记。提交表单后,您将重新生成令牌。如果提交的令牌与会话中的令牌不匹配,则表单已重新提交,应声明为无效。

    示例:

    // 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
            }
        }
    }
    

答案 1 :(得分:30)

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

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

答案 2 :(得分:5)

生成一个唯一的一次性使用密钥以使用表单提交。

依赖Javascript是一个坏主意,因为它可能已被用户在客户端中禁用。使用密钥方案,当服务器收到提交时,可以锁定对该密钥的提交。您可以随意回复重复的提交。

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

答案 3 :(得分:2)

Prevent Duplicate Form Submission显示了一种不使用javascript的方式。

答案 4 :(得分:1)

表单提交后,使用Javascript禁用提交按钮(onsubmit)。

请注意,如果用户已停用Javascript,他们仍然可以提交两次。这种情况是否足以证明您的代码检查(正如您在问题中所建议的那样)取决于您自己。

答案 5 :(得分:1)

或者,使用一次性表格键。

答案 6 :(得分:1)

我用这个:

$form_token = $_SESSION['form_token'] = md5(uniqid());

使用表单发送$ form_token,然后......

我查看了form_token:

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

答案 7 :(得分:0)

在用户使用JavaScript提交表单后,禁用提交按钮。例如,当你回答一个问题时,StackOverflow会使用它。

例如

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

答案 8 :(得分:0)

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

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

答案 9 :(得分:0)

很少提交两次提交导致多次插入,但如果你想要一个简单的解决方法,请使用

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

在表单标记中,前提是您提交了提交按钮id="submit"

答案 10 :(得分:0)

另一种创建确认页面的方法,用户最终可以按下提交按钮。它可能会减少这种可能性。

答案 11 :(得分:0)

我正在对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()在标头中启动会话;

答案 12 :(得分:-1)

Aron Rotteveel的在每个POST上包含一个唯一的令牌为我工作。但是,当用户刷新页面时,我的表单仍然会提交(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() );
    }
}

哦!不要忘记在session_start();

之前添加<!DOCTYPE>

我是一名PHP新手,如果您发现违规行为,请纠正我。

答案 13 :(得分:-1)

使用JavaScript阻止其发送

答案 14 :(得分:-1)

$(document).ready(function() {
  $('#postHideBtn').show();
  $('#postHideBtn').click(function() {
    $('#postHideBtn').hide();
  });
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<form action="foo.php" method="post">
  <input type="text" name="bar" />
  <input type="submit" value="Save" id="postHideBtn" />
</form>