PHP - Post-Redirect-Get (PRG)

こんにちは、未来のプログラマーたち!今日は、Web開発における重要なパターンであるPost-Redirect-Get、略してPRGについて深く掘り下げます。プログラミングが初めての方也不用担心;私はこの概念をステップバイステップでガイドします。これまでに多くの学生を指導してきました。コーヒー(またはお気に入りの飲み物)を手に取り、一緒にこの興奮する旅に出発しましょう!

PHP - Post-Redirect-Get (PRG)

Post-Redirect-Get (PRG)とは?

オンラインでピザを注文するフォームを想像してみてください。フォームを送信した後、間違ってページをリフレッシュしてしまうと、突然、ピザが2つ注文された!このような問題を解決するのがPRGパターンの役割です。

PRGは、ユーザーがフォームを送信した後ページをリフレッシュしたときの重複フォーム送信を防止するWeb開発のデザインパターンです。Webアプリケーションのための交通警察官のように、データがスムーズに流れ、誤って重複しないようにします。

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. POSTの場合、送信された色をセッションに保存します。
  4. ユーザーをresult.phpにリダイレクトします。
  5. 直接このページにアクセスされた場合、フォームにリダイレクトします。

ステップ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. セッション変数をクリアします。

これにより、ユーザーが確認ページをリフレッシュしても、誤って同じ注文を再送信しません。

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() 指定された変数を破壊します

若いパダワンたち、PRGパターンはWeb開発におけるフォースのように、フォームの重複送信を防止する力を持っています。アプリケーションにバランスをもたらし、ユーザー体験を向上させます。コードに力を注ぎ、幸せなプログラミングを!

Credits: Image by storyset