首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 數據庫知識 >  >> MySQL 資料庫 >> MySQL 綜合教學

PHP + MySQL 表單防重複提交:Session Token 機制完整實現

     編輯:MySQL 綜合教學

問題背景

用戶重複點擊提交、瀏覽器刷新、網路重傳導致同一表單資料重複寫入資料庫。核心解決思路:生成唯一 Token → 表單隱藏域攜帶 → 伺服端驗證並標記已用 → 阻止二次處理。

完整實現流程

步驟 1:表單頁生成 Token(form.php)

<?php
session_start();

// 生成唯一 Token:時間戳 + 隨機數 + 雜湊
$token = 'form_' . bin2hex(random_bytes(16));
$_SESSION['form_tokens'][$token] = time();  // 存入陣列支援多表單並發

// 可選:清理過期 Token(超過 1 小時)
foreach ($_SESSION['form_tokens'] as $k => $v) {
    if (time() - $v > 3600) unset($_SESSION['form_tokens'][$k]);
}
?>
<!DOCTYPE html>
<html>
<head><meta charset="utf-8"><title>發布笑話</title></head>
<body>
<form action="input.php" method="POST">
    <p>笑話內容:<br>
    <textarea name="joketext" rows="10" cols="40" required></textarea></p>

    <!-- 關鍵:隱藏域攜帶 Token -->
    <input type="hidden" name="form_token" value="<?php echo htmlspecialchars($token); ?>">

    <input type="submit" name="submitjoke" value="送出">
</form>
</body>
</html>

步驟 2:處理頁驗證 Token(input.php)

<?php
session_start();

// 1. 連線資料庫(PDO 現代寫法)
$pdo = new PDO("mysql:host=localhost;dbname=jokes;charset=utf8mb4", 'root', 'password', [
    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
]);

// 2. 驗證 Token
$token = $_POST['form_token'] ?? '';
if (empty($token) || empty($_SESSION['form_tokens'][$token])) {
    die('無效或過期的表單提交,請重新操作。');
}

// 3. 標記 Token 已使用(防重放)
unset($_SESSION['form_tokens'][$token]);

// 4. 業務邏輯:寫入資料
if (($_POST['submitjoke'] ?? '') === '送出') {
    $sql = "INSERT INTO jokes (joketext, created_at) VALUES (?, NOW())";
    $stmt = $pdo->prepare($sql);
    $stmt->execute([$_POST['joketext']]);
    echo '<p>笑話已新增!</p>';
}

// 5. 顯示現有資料
$stmt = $pdo->query("SELECT joketext FROM jokes ORDER BY id DESC");
while ($row = $stmt->fetch()) {
    echo '<p>' . htmlspecialchars($row['joketext']) . '</p>';
}
?>

進階防重策略對比

策略實現複雜度適用場景缺點
Session Token(本文)低一般表單、後台管理Session 依賴 Cookie,無狀態架構需共享存儲
資料庫唯一約束低業務鍵天然唯一(如訂單號、手機號)需捕獲 Duplicate Entry 異常
Redis 分布式鎖中高併發、微服務、跨節點引入 Redis 依賴,需處理鎖超時
前端按鈕防抖極低輔助手段,體驗優化不可信,繞過前端即失效
PRG 模式(Post-Redirect-Get)低所有表單提交需配合 Token 才能完全防重

最佳實踐組合拳

<?php
// 1. PRG 模式:處理完 POST 後 303 重導向 GET 頁面
if ($stmt->execute([$joketext])) {
    header('Location: list.php?success=1', true, 303);
    exit;
}

// 2. 資料庫層面加唯一索引(業務允許時)
// ALTER TABLE jokes ADD UNIQUE KEY uk_joke_text (joketext);

// 3. 前端提交後禁用按鈕
// document.querySelector('form').addEventListener('submit', () => btn.disabled = true);

常見問題 FAQ

  1. Session 丟失導致 Token 驗證失敗? 檢查 session.save_path 權限、跨域 Cookie 設定、負載均衡 Session 共享
  2. 用戶開多個分頁提交同一表單? Token 存為陣列 $_SESSION['form_tokens'][$token] 支援並發
  3. API 無狀態怎麼辦? 改用 JWT 自包含 Token 或 Redis 存儲 Token 狀態

延伸閱讀

  • MySQL 大表備份的簡單方法
  • MySQL 分表處理的實現方法
  • MySQL 授權表使用示例
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved