PHP - Post-Redirect-Get (PRG)

안녕하세요, 열망하는 프로그래머 여러분! 오늘 우리는 중요한 웹 개발 패턴인 Post-Redirect-Get, 짧게는 PRG라고 부르는 것에 대해 깊이 다룰 것입니다. 프로그래밍 초보자라면 걱정하지 마세요; 단계별로 이 개념을 안내해 드릴게요. 수년 동안 수많은 학생들에게 가르쳐온 경험을 바탕으로 말이죠. 커피 한 잔 (또는 당신의 좋아하는 음료)을 들고, 이 흥미로운 여정에 함께 뛰어들어 보세요!

PHP - Post-Redirect-Get (PRG)

What is Post-Redirect-Get (PRG)? (Post-Redirect-Get은 무엇인가요?)

온라인으로 피자를 주문하는 양식을 작성하고 있을 때를 상상해 보세요. 제출을 클릭하고 나서... 아이고! 실수로 페이지를 새로 고침 했습니다. 갑자기 피자 두 개를 주문하게 되었어요! 이런 문제를 해결해주는 것이 PRG 패턴입니다.

PRG는 사용자가 양식을 제출한 후 페이지를 새로 고침할 때 중복 양식 제출을 방지하는 웹 개발 디자인 패턴입니다. 웹 애플리케이션에서 데이터가 원활하게 흐르고 우연히 중복되지 않도록 하는 교통警察 같은 역할을 합니다.

How PRG Works (PRG은 어떻게 작동하나요?)

  1. 사용자가 POST 요청을 사용하여 양식을 제출합니다.
  2. 서버는 양식 데이터를 처리합니다.
  3. 서버는 직접 응답을 보내지 않고 대신 리디렉션을 보냅니다 (보통 성공 페이지로).
  4. 사용자의 브라우저는 리디렉션을 따라 GET 요청을 보냅니다.
  5. 서버는 GET 요청에 대한 응답으로 최종 페이지를 보냅니다.

이제 코드 예제를 통해 이를 실제로 보겠습니다!

Example 1: A Simple PRG Implementation (간단한 PRG 구현 예제)

PHP에서 PRG가 어떻게 작동하는지 기본적인 예제로 시작해 보겠습니다. 사용자가 좋아하는 색상을 제출할 수 있는 간단한 양식을 만들어 보겠습니다.

Step 1: The HTML Form (form.php) (HTML 양식)

<!DOCTYPE html>
<html>
<head>
<title>Favorite Color Form</title>
</head>
<body>
<h1>What's Your Favorite Color?</h1>
<form action="process.php" method="post">
<input type="text" name="color" required>
<input type="submit" value="Submit">
</form>
</body>
</html>

이 양식은 제출 시 process.php로 POST 요청을 보냅니다.

Step 2: Processing the Form (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. 직접 접근 시 양식 페이지로 리디렉션합니다.

Step 3: Displaying the Result (result.php) (결과 표시)

<?php
session_start();

if (isset($_SESSION['favorite_color'])) {
$color = $_SESSION['favorite_color'];
// 세션 변수를 지우기 위해 데이터를 지운 후
unset($_SESSION['favorite_color']);
} else {
$color = 'No color submitted';
}
?>

<!DOCTYPE html>
<html>
<head>
<title>Your Favorite Color</title>
</head>
<body>
<h1>Your Favorite Color</h1>
<p>You said your favorite color is: <?php echo htmlspecialchars($color); ?></p>
<a href="form.php">Submit another color</a>
</body>
</html>

이 확인 페이지는 다음과 같은 작업을 수행합니다:

  1. 세션을 다시 시작하여 저장된 데이터에 접근합니다.
  2. 좋아하는 색상이 세션에 저장되어 있는지 확인합니다.
  3. 저장되어 있으면 표시하고 세션 변수를 지웁니다.
  4. 저장되어 있지 않으면 기본 메시지를 표시합니다.

이제 사용자가 결과 페이지를 새로 고침해도 양식 데이터를 다시 제출하지 않습니다. 멋지죠?

Example 2: PRG with Database Interaction (데이터베이스와 상호작용하는 PRG)

이제 우리의 예제를 한 단계 더 발전시키고, 피자 주문 시스템을 운영하고 있다고 상상해 보겠습니다. 주문을 데이터베이스에 저장하고 PRG를 사용하여 중복 주문을 방지하겠습니다.

Step 1: The Order Form (order_form.php) (주문 양식)

<!DOCTYPE html>
<html>
<head>
<title>Pizza Order Form</title>
</head>
<body>
<h1>Order Your Pizza</h1>
<form action="process_order.php" method="post">
<label for="pizza_type">Pizza Type:</label>
<select name="pizza_type" id="pizza_type" required>
<option value="margherita">Margherita</option>
<option value="pepperoni">Pepperoni</option>
<option value="veggie">Veggie</option>
</select>
<br><br>
<label for="size">Size:</label>
<select name="size" id="size" required>
<option value="small">Small</option>
<option value="medium">Medium</option>
<option value="large">Large</option>
</select>
<br><br>
<input type="submit" value="Place Order">
</form>
</body>
</html>

Step 2: Processing the Order (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. 사용자를 확인 페이지로 리디렉션합니다.
  5. 직접 접근 시 양식 페이지로 리디렉션합니다.

Step 3: Order Confirmation (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 = "Your order (ID: $order_id) has been placed successfully!";
} else {
$message = "No recent order found. Please place a new order.";
}
?>

<!DOCTYPE html>
<html>
<head>
<title>Order Confirmation</title>
</head>
<body>
<h1>Order Confirmation</h1>
<p><?php echo htmlspecialchars($message); ?></p>
<a href="order_form.php">Place another order</a>
</body>
</html>

이 확인 페이지는 다음과 같은 작업을 수행합니다:

  1. 세션에서 주문 ID를 가져옵니다.
  2. 확인 메시지를 표시하고 세션 변수를 지웁니다.
  3. 최근 주문이 없으면 기본 메시지를 표시합니다.

이제 사용자가 확인 페이지를 새로 고침해도 중복 주문이 발생하지 않습니다.

Why PRG is Important (PRG의 중요성)

  1. Prevents Duplicate Submissions: 사용자가 확인 페이지를 새로 고침하면 우연히 주문을 다시 제출하지 않습니다.
  2. Improves User Experience: 사용자는 깨끗한 URL을 브라우저의 주소 표시줄에서 볼 수 있으며, 양식 데이터가 긴 문자열로 표시되지 않습니다.
  3. Follows REST Principles: GET 요청은 데이터를检索하는 데 사용되고, POST 요청은 데이터를 제출하는 데 사용됩니다.

Common PRG Methods (PRG에서 사용되는 일반 방법)

다음은 PRG 패턴에서 사용되는 일반적인 메서드 표입니다:

Method Description
$_SERVER['REQUEST_METHOD'] HTTP 요청 메서드 (GET, POST 등)를 확인합니다
header('Location: ...') 브라우저로 리디렉션 헤더를 보냅니다
exit 리디렉션 후 추가 코드가 실행되지 않도록 합니다
session_start() 새로운 세션을 시작하거나 기존 세션을 계속합니다
$_SESSION 세션 데이터를 저장하고检索합니다
isset() 변수가 설정되어 있고 NULL이 아닌지 확인합니다
unset() 지정된 변수를 파괴합니다

젊은 파다와안, PRG 패턴은 웹 개발에서 힘을 사용하는 것처럼입니다. 중복 양식 제출의 어둠 쪽을 방지하여 애플리케이션에 균형을 가져옵니다. 코드가 당신과 함께 하길 바랍니다!

결론적으로, Post-Redirect-Get 패턴은 웹 개발 도구箱에서 강력한 도구입니다. 우연한 중복 제출을 방지하여 더 견고하고 사용자 친화적인 애플리케이션을 만들어줍니다. PHP와 웹 개발을 계속하면서 PRG가 당신을 구원할 많은 상황을 만날 것입니다. 계속 연습하고, 호기심을 잃지 마세요, 행복한 코딩을 기원합니다!

Credits: Image by storyset