web-dev-qa-db-ja.com

PHPでフォームを送信するときに複数の挿入を防ぐ方法は?

ユーザーがEnterを2回押すと、投稿が2回挿入されることがあります。

同じtitlecontentの投稿が既に存在するかどうかを確認する以外に、これを防ぐ解決策はありますか?

30
user198729

この問題にはいくつかの解決策があります。

  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
            }
        }
    }
    
49
Aron Rotteveel

ポストで一意のトークンを使用して、各ポスト/ポストバックが一度だけ処理されるようにします。

人々がJavaScriptをオフにしたり、他の奇妙なことをしたりする可能性があるため、送信ボタンを無効にすることはあまり良い解決策ではありません。クライアント側の検証は適切な出発点ですが、常にサーバー側の処理でもバックアップする必要があります。

30

フォームとともに送信する一意の1回限りの使用キーを生成します。

ユーザーがクライアントでJavascriptを無効にしている可能性があるため、JavaScriptに依存することはお勧めできません。キースキームを使用すると、送信がサーバーによって受信されたときに、そのキーの送信をロックできます。重複した送信には、好きなように応答できます。

このアプローチが機能するには、キーが一意であり、予測が非常に困難である必要があります。そうしないと、キーの衝突により一部のフォームがロックされる可能性があります。したがって、すべてのフォーム送信のキーを追跡して衝突を回避する必要はありません。キーはそのユーザーのセッションで期限切れになるはずです。もう1つの注意点は、悪意のあるユーザーがキーを予測できる場合、コードが何らかのハイジャックまたはDOSエクスプロイトに対して脆弱になる可能性があることです。

5
Dana the Sane

重複フォーム送信の防止 は、JavaScriptなしでそれを行う方法を示しています。

2
Javi

私はこれを使います:

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

$ form_tokenをフォームと一緒に送信します...

Form_tokenを確認します。

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

フォームが送信されたら、JavaScriptを使用して送信ボタンを無効にします(onsubmit)。

ユーザーがJavaScriptを無効にしている場合でも、2回送信できることに注意してください。これが頻繁に発生してコードをチェックインすることを正当化できるかどうか(質問で提案したとおり)は、あなた次第です。

1
Aistina

または、1回限りのフォームキーを使用します。

1
mst

ユーザーが最終的に送信ボタンを押すことができる確認ページを作成する別の方法。この種の可能性を減らすかもしれません。

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()を使用してセッションを開始してください。

0
Robert Sinclair

ユーザーがJavaScriptを使用してフォームを送信したら、送信ボタンを無効にします。これは、たとえば、質問に答えるときにStackOverflowが使用するものです。

例えば

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

JavaScriptを使用して、ボタンをクリックするとすぐにボタンを無効にします。

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

送信を2回押すと、めったに複数の挿入が行われませんが、完全に単純なソリューションが必要な場合は、

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

送信ボタンid="submit"

0
raveren