问题描述

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

有没有一个解决方案来防止这个,除了检查是否已经有相同的 titlecontent 的帖子?

最佳解决办法

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

  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 上包含唯一的令牌。在这种情况下,您还可以将会话变量设置为要包含的令牌,然后以该表单呈现令牌。一旦提交表单,您就可以使用 re-generate 令牌。当提交的令牌与您的会话中的令牌不匹配时,该表单已被 re-submitted,并且应被声明为无效。

    例:

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

次佳解决办法

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

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

第三种解决办法

生成一个独特的,one-time 使用密钥提交与表单。

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

对于这种工作方式,键必须是独一无二的,很难预测。否则由于关键碰撞,某些形式可能被锁定。因此,您不必为每个表单提交跟踪密钥,并避免冲突,密钥应该与该用户的会话过期。要注意的另一件事是,如果恶意用户能够预测密钥,您的代码可能会受到某种劫持或 DOS 漏洞的攻击。

参考文献

注:本文内容整合自 Google/Baidu/Bing 辅助翻译的英文资料结果。如果您对结果不满意,可以加入我们改善翻译效果:薇晓朵技术论坛。