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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2133964/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-25 05:11:10  来源:igfitidea点击:

How to prevent multiple inserts when submitting a form in PHP?

phphtmlformsform-submit

提问by user198729

Sometimes the user may press Entertwice, and the post is inserted twice.

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

Is there a solution to prevent this other than check if there is already a post with the same titleand content?

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

回答by Aron Rotteveel

There are several solutions to this problem:

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

  1. Use Javascript to disable the form's submit button when it is posted.Downside to this is that this is ABSOLUTELY not a foolproof way. It's very easy to submit forms without actually clicking the button, and this would also not work for users with JavaScript disabled. I would definitely not recommend this method.

    Example:

    <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. Use PHP sessionsto set a session variable (for example $_SESSION['posttimer']) to the current timestamp on post.Before actually processing the form in PHP, check if the $_SESSION['posttimer'] variable exists and check for a certain timestamp difference (IE: 2 seconds). This way, you can easily filter out double submits.

    Example:

    // 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. Include a unique token on each POST.In this case, you would also set a session variable to the token you want to include and then render the token in the form. Once the form is submitted, you re-generate the token. When the submitted token does not match the token in your session, the form has been re-submitted and should be declared invalid.

    Example:

    // 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. 使用 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'] 变量是否存在并检查特定的时间戳差异(即: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
            }
        }
    }
    

回答by Mats Fredriksson

Use a unique token with the post, so that each post/postback is only handled once.

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

Disabling the submit button is not a very good solution since people could have javascript turned off, or doing other weird things. Client side validation is a good start, but should always be backed up with server side handling as well.

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

回答by Dana the Sane

Generate a unique, one-time use key to submit with the form.

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

Relying on Javascript is a bad idea because it may have been disabled in the client by the user. With the key scheme, when the submit is received by the server, submission for that key can be locked. You can respond to duplicate submits however you like.

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

For this approach to work, keys must be unique and very difficult to predict. Otherwise some forms could be locked due to key collisions. So you don't have to track keys for every form submission and avoid collisions, keys should expire with that user's session. The other thing to watch out for is if malicious users are able to predict the key, your code may be vulnerable to some kind of hiHymaning or DOS exploit.

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

回答by Javi

Prevent Duplicate Form Submissionshows a way of doing it without javascript.

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

回答by mst

Alternatively, use one-time form keys.

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

回答by Aistina

Disable the submit button using Javascript once the form gets submitted (onsubmit).

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

Note that if the user has disabled Javascript, they can still submit twice. Whether or not this happens often enough to justify also checking in your code (as you suggested in your question) is up to you.

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

回答by CSSJediEsck21

I use this:

我用这个:

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

send $form_token with the form, then...

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

I check the form_token:

我检查了 form_token:

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

回答by Diwakar Kumar Singh

Another way to create a confirmation page where user can finally press the submit button. It might reduce the possibilities of this kind.

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

回答by Robert Sinclair

I'm doing the following on the action.php

我正在对 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

}

Note: Always initiate your sessions in the header using session_start();

注意:始终使用 session_start() 在标题中启动会话;

回答by Marius

disable the submit button once the user has submitted the form, using JavaScript. That is what, for example, StackOverflow uses when you answer a question.

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

For example

例如

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