首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 相關知識

PHP 防止表單重複提交:PRG 模式與 Token 驗證雙重保障

     編輯:PHP 相關知識

表單送出後重新整理導致重複寫入是經典問題。本文介紹「Post-Redirect-Get (PRG)」模式與「單次 Token」兩種標準解法,並提供可直接套用的程式碼範本。

方法一:PRG 模式(最簡單、無需 Session)

  1. POST 處理完成後 302 重導向 到同一頁或結果頁(帶成功參數)。
  2. 瀏覽器重新整理時只會重送 GET,不會再觸發 INSERT。
<?php
// handle.php
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    $stmt = $pdo->prepare('INSERT INTO logs (msg) VALUES (?)');
    $stmt->execute([$_POST['msg'] ?? '']);
    // 關鍵:重導向
    header('Location: form.php?saved=1');
    exit;
}
?>
<!-- form.php -->
<?php if (!empty($_GET['saved'])): ?>
    <div class="alert success">儲存成功!</div>
<?php endif; ?>
<form method="post" action="handle.php">
    <input name="msg" required>
    <button type="submit">送出</button>
</form>

方法二:單次 Token (CSRF 同步防禦)

適用於 AJAX 或不想重導向的情境。

<?php
session_start();

// 產生 Token
function csrf_token(): string {
    if (empty($_SESSION['csrf'])) {
        $_SESSION['csrf'] = bin2hex(random_bytes(32));
    }
    return $_SESSION['csrf'];
}

// 驗證並銷毀
function csrf_validate(string $token): bool {
    if (hash_equals($_SESSION['csrf'] ?? '', $token)) {
        unset($_SESSION['csrf']);
        return true;
    }
    return false;
}

// 表單頁
?>
<input type="hidden" name="csrf" value="<?= csrf_token() ?>"> <input name="data" required> <button type="submit">送出</button> </form> <?php // save.php if ($_SERVER['REQUEST_METHOD'] === 'POST' && csrf_validate($_POST['csrf'] ?? '')) { $stmt = $pdo->prepare('INSERT INTO logs (msg) VALUES (?)'); $stmt->execute([$_POST['data']]); echo '成功'; } else { http_response_code(400); echo 'Token 無效或重複提交'; } ?>

進階:資料庫層面唯一約束 (冪等鍵)

若業務允許,給表單加 idempotency_key (UUID),資料表建立 UNIQUE KEY,重複提交直接拋錯誤,應用層捕獲轉友善提示。

總結選擇指南

場景推薦方案
傳統表單、需顯示成功訊息PRG 重導向
AJAX / SPA / 不想跳頁Token 驗證
高併發、分散式系統冪等鍵 + 資料庫唯一索引
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved