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

PHP 多步驟表單防重複提交與防刷新完整解決方案

     編輯:PHP 相關知識

三步驟註冊流程:防止跳過步驟、重複提交、返回修改的完整對策

典型註冊流程:協議頁 → 輸入頁 → 結果頁。常見問題:1) 直接訪問輸入頁跳過協議;2) 結果頁刷新導致重複寫入;3) 返回修改後再次提交造成資料不一致。本文提供基於 Session 令牌與 POST-Redirect-GET 模式的完整解決方案。

核心機制設計

  • 步驟令牌:Session 記錄當前允許的步驟($_SESSION['step'])。
  • 表單令牌:每個表單攜帶一次性 Token,驗證後立即失效,防重複提交。
  • PRG 模式:POST 處理完畢 必須 302 重導向至 GET 頁面,徹底解決刷新重複提交。
  • 輸出緩衝控制:設定防快取 Header,避免瀏覽器回退顯示舊表單資料。

config.inc.php:全域環境初始化

<?php
session_start();

// 禁止瀏覽器快取,確保回退時重新請求伺服器
header('Expires: ' . date('D, d M Y H:i:s', mktime(0,0,0,1,1,2000)) . ' GMT');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
header('Cache-Control: private, no-cache, must-revalidate');
header('Pragma: no-cache');
?>

register.php:主控制器

<?php
require_once "config.inc.php";

// 步驟 3:處理表單提交
if (isset($_SESSION['step2_token']) && isset($_POST['step2_token'])) {
    // 驗證 Token 防重複提交
    if ($_POST['step2_token'] !== $_SESSION['step2_token']) {
        die("非法請求或重複提交");
    }
    unset($_SESSION['step2_token']); // 一次性 Token 即時失效

    // 驗證輸入
    $errors = [];
    $username = trim($_POST['username'] ?? '');
    $address  = trim($_POST['address'] ?? '');
    if ($username === '') $errors[] = "用戶名不可為空";
    if ($address === '')  $errors[] = "地址不可為空";

    if ($errors) {
        // 驗證失敗:回步驟 2 頁面,攜帶錯誤訊息
        $_SESSION['form_errors'] = $errors;
        $_SESSION['form_data'] = $_POST; // 回填資料
        header("Location: register.php?step=2");
        exit;
    }

    // 業務邏輯:寫入資料庫等...
    // $db->insert('users', ['username'=>$username, 'address'=>$address]);

    // 成功:清理 Session 步驟狀態,重導向至步驟 3 成功頁
    unset($_SESSION['step1_token'], $_SESSION['step2_token'], $_SESSION['form_errors'], $_SESSION['form_data']);
    header("Location: register.php?step=3");
    exit;
}

// 步驟 2:顯示輸入表單
if (isset($_SESSION['step1_token']) && isset($_GET['step']) && $_GET['step'] == '2') {
    // 發放步驟 2 專用 Token
    $_SESSION['step2_token'] = bin2hex(random_bytes(16));
    include 'step2.html';
    exit;
}

// 步驟 1:顯示協議頁
// 發放步驟 1 專用 Token
$_SESSION['step1_token'] = bin2hex(random_bytes(16));
include 'step1.html';
?>

step1.html:協議頁(含隱藏 Token)

<form method="get" action="register.php">
  <input type="hidden" name="step" value="2">
  <input type="hidden" name="step1_token" value="<?= $_SESSION['step1_token'] ?>">
  <p>用戶協議內容...</p>
  <button type="submit">我同意,進入註冊</button>
</form>

step2.html:輸入頁(含錯誤顯示、資料回填、步驟 2 Token)

<?php
$errors = $_SESSION['form_errors'] ?? [];
$data   = $_SESSION['form_data'] ?? [];
unset($_SESSION['form_errors'], $_SESSION['form_data']); // 讀取後即清除
?>
<?php if ($errors): ?>
  <div style="color:red;"><ul><?php foreach($errors as $e) echo "<li>$e</li>"; ?></ul></div>
<?php endif; ?>

<form method="post" action="register.php">
  <input type="hidden" name="step2_token" value="<?= $_SESSION['step2_token'] ?>">
  <p>用戶名:<input name="username" value="<?= htmlspecialchars($data['username'] ?? '') ?>"></p>
  <p>地址:<input name="address" value="<?= htmlspecialchars($data['address'] ?? '') ?>"></p>
  <button type="submit">提交註冊</button>
</form>

step3.html:成功頁(純顯示,無表單)

<h1>註冊成功!</h1>
<p>歡迎加入,<?= htmlspecialchars($_SESSION['registered_username'] ?? '') ?>。</p>
<p><a href="index.php">返回首頁</a></p>

關鍵點總結

  1. Token 驗證:每步驟獨立 Token,驗證後銷毀,杜絕重複提交與 CSRF。
  2. PRG 流程:POST 處理完畢 header("Location: ...") 導向 GET,瀏覽器歷史記錄無 POST,刷新無害。
  3. 防快取 Header:配合 session_start() 前輸出,強制瀏覽器回退時重新請求,獲得最新狀態(如 Token 已失效)。
  4. 錯誤與資料回填:透過 Session 暫存,導向後讀取並清除,體驗流暢。

擴充應用

  • 檔案上傳、多步驟精靈、付款流程同樣適用此模式。
  • 結合資料庫交易(Transaction)確保資料一致性。
  • 前端加入 JavaScript 防止重複點擊提交按鈕(disabled),雙重保障。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved