Web 表單流程 (如註冊、結帳、問卷) 常需防止使用者按「上一頁」回到已完成步驟,造成重複提交或狀態不一致。本文介紹「單一腳本多階段 + Session 狀態機」模式,徹底解決瀏覽器後退問題,無需 JavaScript、跨瀏覽器相容。
step12.php)。<?php
session_start();
// 從步驟 1 進入步驟 2
if (isset($_GET['to_step2'])) {
// 這裡可驗證步驟 1 表單資料
// if (!valid_step1($_POST)) { header('Location: step12.php?err=1'); exit; }
$_SESSION['step'] = 2;
// 可將步驟 1 資料存入 session 供步驟 3 使用
$_SESSION['step1_data'] = $_POST ?? [];
}
// 狀態機輸出
if (($_SESSION['step'] ?? 1) >= 2) {
// ----- 步驟 2 內容 -----
echo '<h1>步驟 2: 確認資料</h1>';
echo '<p>資料: ' . htmlspecialchars(json_encode($_SESSION['step1_data'])) . '</p>';
echo '<a href="step3.php">前往步驟 3</a>';
echo '<p><small>此時按瀏覽器後退鍵,將離開此頁,不會回到步驟 1</small></p>';
} else {
// ----- 步驟 1 內容 -----
echo '<h1>步驟 1: 填寫資料</h1>';
echo '<form method="post" action="?to_step2=1">';
echo '姓名: <input name="name" required><br>';
echo 'Email: <input name="email" type="email" required><br>';
echo '<button type="submit">下一步</button>';
echo '</form>';
}
?>
<?php
session_start();
// 驗證流程完整性
if (($_SESSION['step'] ?? 0) < 2) {
header('Location: step12.php');
exit;
}
// 處理最終提交
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
// 整合所有步驟資料
$allData = array_merge($_SESSION['step1_data'], $_POST);
// 儲存資料庫、發送郵件等...
// 完成:清除流程狀態
unset($_SESSION['step'], $_SESSION['step1_data']);
echo '<h1>提交成功!</h1>';
echo '<a href="step12.php">重新開始</a>';
exit;
}
// 顯示步驟 3 確認頁
echo '<h1>步驟 3: 最終確認</h1>';
echo '<pre>' . htmlspecialchars(print_r($_SESSION['step1_data'], true)) . '</pre>';
echo '<form method="post">';
echo '<input type="checkbox" name="agree" required> 我同意條款<br>';
echo '<button type="submit">確認送出</button>';
echo '</form>';
?>
<?php
abstract class MultiStepFlow {
protected string $sessionKey;
protected array $steps = []; // ['step1' => 'Step1Class', ...]
protected int $currentStep = 1;
public function __construct(string $sessionKey) {
$this->sessionKey = $sessionKey;
session_start();
$this->currentStep = $_SESSION[$this->sessionKey]['step'] ?? 1;
}
public function handleRequest(): void {
$action = $_GET['action'] ?? 'view';
if ($action === 'next' && $this->validateCurrent()) {
$this->saveStepData();
$this->currentStep++;
$_SESSION[$this->sessionKey]['step'] = $this->currentStep;
header('Location: ' . $this->getUrl());
exit;
}
$this->render();
}
protected function validateCurrent(): bool { return true; } // 子類覆寫
protected function saveStepData(): void {
$_SESSION[$this->sessionKey]['data'][$this->currentStep] = $_POST;
}
protected function getAllData(): array {
return $_SESSION[$this->sessionKey]['data'] ?? [];
}
protected function complete(): void {
unset($_SESSION[$this->sessionKey]);
}
abstract protected function render(): void;
abstract protected function getUrl(): string;
}
// 使用範例
class RegisterFlow extends MultiStepFlow {
protected array $steps = [1 => 'basic', 2 => 'profile', 3 => 'confirm'];
protected function render() {
$method = 'renderStep' . $this->currentStep;
$this->$method();
}
protected function renderStep1() { /* 輸出基本資料表單 */ }
protected function renderStep2() { /* 輸出詳細資料表單 */ }
protected function renderStep3() { /* 輸出確認頁 */ }
protected function getUrl() { return '/register.php'; }
}
$flow = new RegisterFlow('register_flow');
$flow->handleRequest();
| 優點 | 缺點 |
|---|---|
| ✅ 瀏覽器後退鍵完全失效 (歷史只有一筆) | ❌ 步驟間無法直接用 URL 分享/書籤 |
| ✅ 無需 JavaScript、跨裝置相容 | ❌ Session 過期會導致流程中斷 |
| ✅ 伺服器端完全控制流程邏輯 | ❌ 多頁簽操作會互相干擾 (共用 Session) |
| ✅ 易於加入驗證、CSRF 保護 | ❌ 不適合極長流程 (建議 < 5 步) |
Session 單頁流程模式是「零前端依賴、快速上線、安全可靠」的經典解法,適合中小型表單精靈、後台管理流程。