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

use*_*729 30 html php forms form-submit

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

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

Aro*_*eel 50

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

  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>
    
    Run Code Online (Sandbox Code Playgroud)
  2. 使用PHP会话将会话变量(例如$ _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();
    }
    
    Run Code Online (Sandbox Code Playgroud)
  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
            }
        }
    }
    
    Run Code Online (Sandbox Code Playgroud)

  • +1很棒的答案,但我会编辑所以你的推荐是第一位的,然后你按照你不推荐的方法 - 会更容易阅读.那就是说,它应该是公认的答案. (3认同)
  • 对于javascript解决方案,您可以为表单提交事件创建该功能,而不是提交按钮单击.将调用该函数并禁用提交按钮. (2认同)
  • 可见方法三是完美的 (2认同)

Mat*_*son 30

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

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

  • +1 - 这是最常用的方法,没有客户端依赖项.为什么不接受这个答案? (2认同)

Dan*_*ane 5

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

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

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


Ais*_*ina 1

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

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