表單送出後重新整理導致重複寫入是經典問題。本文介紹「Post-Redirect-Get (PRG)」模式與「單次 Token」兩種標準解法,並提供可直接套用的程式碼範本。
<?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>
適用於 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;
}
// 表單頁
?>
若業務允許,給表單加 idempotency_key (UUID),資料表建立 UNIQUE KEY,重複提交直接拋錯誤,應用層捕獲轉友善提示。
| 場景 | 推薦方案 |
|---|---|
| 傳統表單、需顯示成功訊息 | PRG 重導向 |
| AJAX / SPA / 不想跳頁 | Token 驗證 |
| 高併發、分散式系統 | 冪等鍵 + 資料庫唯一索引 |