31

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

除了检查是否已经有相同的帖子和之外,是否有其他解决方案可以防止这种情况title发生content

4

15 回答 15

53

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

  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 会话将会话变量(例如 $_SESSION['posttimer'])设置为发布时的当前时间戳。在 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
            }
        }
    }
    
于 2010-01-25T17:02:45.827 回答
31

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

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

于 2010-01-25T17:01:20.103 回答
5

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

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

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

于 2010-01-25T17:06:34.070 回答
2

防止重复表单提交展示了一种无需 javascript 的方式。

于 2010-01-25T17:00:47.750 回答
1

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

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

于 2010-01-25T16:58:31.150 回答
1

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

于 2010-01-25T17:02:48.537 回答
1

我用这个:

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

将 $form_token 与表单一起发送,然后...

我检查了form_token:

if($_SESSION['form_token'] != $_POST['form_token']) {
   echo 'Error';
}
于 2010-01-25T23:35:23.393 回答
0

用户提交表单后,使用 JavaScript 禁用提交按钮。例如,这就是 StackOverflow 在您回答问题时使用的内容。

例如

<input type="submit" onclick="this.disabled=true" />
于 2010-01-25T16:58:39.017 回答
0

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

onclick="this.disabled=true;forms[0].submit();"
于 2010-01-25T16:58:49.030 回答
0

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

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

在表单标签中,只要您提供提交按钮id="submit"

于 2010-01-25T17:00:47.140 回答
0

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

于 2017-07-20T07:52:57.940 回答
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(); 在标头中启动会话;

于 2018-07-30T16:28:59.943 回答
-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 新手,如果您发现违规行为,请纠正我。

于 2011-11-20T07:44:36.747 回答
-1

使用 JavaScript 阻止它发送

于 2012-01-27T13:00:24.273 回答
-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>

于 2021-05-28T06:24:55.790 回答