PHP - Post-Redirect-Get (PRG)
你好,有志於成為程序員的你!今天,我們將要深入探讨一個重要的網頁開發模式,稱為 Post-Redirect-Get,簡稱為 PRG。別擔心你如果是個編程新手;我會一步一步地引導你理解這個概念,就像我這些年來對無數學生做的一樣。所以,來一杯咖啡(或是你喜歡的飲料),讓我們一起踏上這個令人興奮的旅程!
什麼是 Post-Redirect-Get (PRG)?
想像你正在線上填寫訂購披薩的表單。你點擊提交,然後... 哎呀!你不小心刷新了頁面。突然間,你訂了兩份而不是一份披薩!這就是 Post-Redirect-Get 模式試圖解決的問題類型。
PRG 是一種網頁開發設計模式,當用戶在提交表單後刷新頁面時,防止表單重複提交。它就像是你的網頁應用程序中的交通警察,確保數據流暢地傳輸,而不會意外重複。
PRG 如何工作
- 用戶使用 POST 請求提交表單。
- 伺服器處理表單數據。
- 而不是直接發送回應,伺服器發送一個重定向(通常到成功頁面)。
- 用戶的瀏覽器跟隨重定向,發出 GET 請求。
- 伺服器對 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;
}
讓我們分解一下:
- 我們開始一個會話以在頁面之間存儲數據。
- 我們檢查請求方法是否為 POST。
- 如果是,我們將提交的顏色保存到會話中。
- 然後我們重定向用戶到
result.php
。 - 如果有人直接訪問這個頁面(而非通過 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>
這裡發生了什麼:
- 我們再次開始會話以訪問存儲的數據。
- 我們檢查會話中是否有喜歡的顏色。
- 如果有,我們顯示它,然後清除會話變量。
- 如果沒有,我們顯示一個默認消息。
現在,即使用戶刷新結果頁面,他們也不會重新提交表單數據。很棒,對吧?
示例 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;
}
這個腚本:
- 處理表單數據。
- 將訂單插入數據庫。
- 存儲訂單 ID 到會話中。
- 重定向到確認頁面。
步驟 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>
這個確認頁面:
- 從會話中檢索訂單 ID。
- 顯示確認消息。
- 清除會話變量,以防止在刷新時顯示相同的訂單。
Why PRG 是重要的
- 防止重複提交:如果用戶刷新確認頁面,他們不會意外地重新提交訂單。
- 提升用戶體驗:用戶在地址欄中看到的是乾淨的 URL,而不是一長串的表單數據。
- 遵循 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