問題描述

有時使用者可能會按 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 輔助翻譯的英文資料結果。如果您對結果不滿意,可以加入我們改善翻譯效果:薇曉朵技術論壇。