PHP - Post-Redirect-Get (PRG)

你好,有志於成為程序員的你!今天,我們將要深入探讨一個重要的網頁開發模式,稱為 Post-Redirect-Get,簡稱為 PRG。別擔心你如果是個編程新手;我會一步一步地引導你理解這個概念,就像我這些年來對無數學生做的一樣。所以,來一杯咖啡(或是你喜歡的飲料),讓我們一起踏上這個令人興奮的旅程!

PHP - Post-Redirect-Get (PRG)

什麼是 Post-Redirect-Get (PRG)?

想像你正在線上填寫訂購披薩的表單。你點擊提交,然後... 哎呀!你不小心刷新了頁面。突然間,你訂了兩份而不是一份披薩!這就是 Post-Redirect-Get 模式試圖解決的問題類型。

PRG 是一種網頁開發設計模式,當用戶在提交表單後刷新頁面時,防止表單重複提交。它就像是你的網頁應用程序中的交通警察,確保數據流暢地傳輸,而不會意外重複。

PRG 如何工作

  1. 用戶使用 POST 請求提交表單。
  2. 伺服器處理表單數據。
  3. 而不是直接發送回應,伺服器發送一個重定向(通常到成功頁面)。
  4. 用戶的瀏覽器跟隨重定向,發出 GET 請求。
  5. 伺服器對 GET 請求回應最終頁面。

現在,讓我們通過一些代碼示例來看看這是如何實現的!

示例 1:簡單的 PRG 實現

讓我們從 PHP 中 PRG 如何工作的基本示例開始。我們將創建一個簡單的表單,讓用戶提交他們喜歡的顏色。

步驟 1:HTML 表單 (form.php)

<!DOCTYPE html>
<html>
<head>
<title>喜歡的顏色表單</title>
</head>
<body>
<h1>你喜歡什麼顏色?</h1>
<form action="process.php" method="post">
<input type="text" name="color" required>
<input type="submit" value="提交">
</form>
</body>
</html>

這個表單在提交時會向 process.php 發送 POST 請求。

步驟 2:處理表單 (process.php)

<?php
session_start();

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$color = $_POST['color'];

// 將顏色保存到會話中
$_SESSION['favorite_color'] = $color;

// 重定向到結果頁面
header('Location: result.php');
exit;
} else {
// 如果有人直接訪問這個頁面,將他們重定向回表單
header('Location: form.php');
exit;
}

讓我們分解一下:

  1. 我們開始一個會話以在頁面之間存儲數據。
  2. 我們檢查請求方法是否為 POST。
  3. 如果是,我們將提交的顏色保存到會話中。
  4. 然後我們重定向用戶到 result.php
  5. 如果有人直接訪問這個頁面(而非通過 POST),我們將他們重定向回表單。

步驟 3:顯示結果 (result.php)

<?php
session_start();

if (isset($_SESSION['favorite_color'])) {
$color = $_SESSION['favorite_color'];
// 清除會話變量以防止在刷新時顯示舊數據
unset($_SESSION['favorite_color']);
} else {
$color = '沒有提交顏色';
}
?>

<!DOCTYPE html>
<html>
<head>
<title>你的喜歡的顏色</title>
</head>
<body>
<h1>你的喜歡的顏色</h1>
<p>你說你喜歡的顏色是:<?php echo htmlspecialchars($color); ?></p>
<a href="form.php">再提交一個顏色</a>
</body>
</html>

這裡發生了什麼:

  1. 我們再次開始會話以訪問存儲的數據。
  2. 我們檢查會話中是否有喜歡的顏色。
  3. 如果有,我們顯示它,然後清除會話變量。
  4. 如果沒有,我們顯示一個默認消息。

現在,即使用戶刷新結果頁面,他們也不會重新提交表單數據。很棒,對吧?

示例 2:帶數據庫交互的 PRG

讓我們把示例進一步擴展,假設我們正在運行一個披薩訂購系統。我們將使用數據庫來存儲訂單,並實現 PRG 以防止重複訂單。

步驟 1:訂單表單 (order_form.php)

<!DOCTYPE html>
<html>
<head>
<title>披薩訂購表單</title>
</head>
<body>
<h1>訂購你的披薩</h1>
<form action="process_order.php" method="post">
<label for="pizza_type">披薩類型:</label>
<select name="pizza_type" id="pizza_type" required>
<option value="margherita">瑪格麗塔</option>
<option value="pepperoni">意大利香腸</option>
<option value="veggie">蔬菜</option>
</select>
<br><br>
<label for="size">大小:</label>
<select name="size" id="size" required>
<option value="small">小</option>
<option value="medium">中</option>
<option value="large">大</option>
</select>
<br><br>
<input type="submit" value="下訂單">
</form>
</body>
</html>

步驟 2:處理訂單 (process_order.php)

<?php
session_start();

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$pizza_type = $_POST['pizza_type'];
$size = $_POST['size'];

// 在實際應用程序中,你會想要清洗和驗證這些輸入

// 連接到數據庫(通常你會把這部分放在一個獨立的文件中)
$db = new PDO('mysql:host=localhost;dbname=pizza_shop', 'username', 'password');

// 插入訂單
$stmt = $db->prepare("INSERT INTO orders (pizza_type, size) VALUES (?, ?)");
$stmt->execute([$pizza_type, $size]);

// 獲取訂單 ID
$order_id = $db->lastInsertId();

// 將訂單 ID 存儲到會話中
$_SESSION['last_order_id'] = $order_id;

// 重定向到確認頁面
header('Location: order_confirmation.php');
exit;
} else {
// 如果有人直接訪問這個頁面,將他們重定向回表單
header('Location: order_form.php');
exit;
}

這個腚本:

  1. 處理表單數據。
  2. 將訂單插入數據庫。
  3. 存儲訂單 ID 到會話中。
  4. 重定向到確認頁面。

步驟 3:訂單確認 (order_confirmation.php)

<?php
session_start();

if (isset($_SESSION['last_order_id'])) {
$order_id = $_SESSION['last_order_id'];
// 清除會話變量
unset($_SESSION['last_order_id']);

// 在實際應用程序中,你會從數據庫中獲取訂單詳情
// 在這個示例中,我們只會顯示訂單 ID
$message = "你的訂單(ID: $order_id)已成功提交!";
} else {
$message = "沒有找到最近的訂單。請下新的訂單。";
}
?>

<!DOCTYPE html>
<html>
<head>
<title>訂單確認</title>
</head>
<body>
<h1>訂單確認</h1>
<p><?php echo htmlspecialchars($message); ?></p>
<a href="order_form.php">再下一次訂單</a>
</body>
</html>

這個確認頁面:

  1. 從會話中檢索訂單 ID。
  2. 顯示確認消息。
  3. 清除會話變量,以防止在刷新時顯示相同的訂單。

Why PRG 是重要的

  1. 防止重複提交:如果用戶刷新確認頁面,他們不會意外地重新提交訂單。
  2. 提升用戶體驗:用戶在地址欄中看到的是乾淨的 URL,而不是一長串的表單數據。
  3. 遵循 REST 原則:GET 請求用於獲取數據,而 POST 請求用於提交數據。

常見的 PRG 方法

這裡是一個常見的 PRG 方法表格:

方法 描述
$_SERVER['REQUEST_METHOD'] 檢查 HTTP 請求方法(GET、POST 等。)
header('Location: ...') 發送重定向頭給瀏覽器
exit 確保在重定向後不再執行任何代碼
session_start() 開始一個新的會話或恢復一個現有的會話
$_SESSION 存儲和檢索會話數據
isset() 檢查變量是否已設置且不是 NULL
unset() 摧壞指定的變量

記住,年輕的 Padawans,PRG 模式就像是編程中的原力。它在你的應用程序中帶來平衡,防止了重複表單提交的黑暗面。願代碼與你同在!

總結來說,Post-Redirect-Get 模式是你網頁開發工具包中的強大工具。它通過防止意外重複提交,幫助創建更健壯和用戶友好的應用程序。隨著你繼續在 PHP 和網頁開發方面的學習,你會發現許多情況下 PRG 可以解決問題。持續練習,保持好奇心,並且快樂編程!

Credits: Image by storyset