Skip to content

PHP Tutorial Forms and User Input

Post/Redirect/Get Pattern

Lesson 144 of 369 2 min read By Deepak Paswan Updated Oct 5, 2026

Imagine a visitor submits a contact form, sees “Thank you!” and then refreshes the page. The browser asks: “Resend the form data?” If they say yes, the message is sent twice.

The cure is the Post/Redirect/Get pattern (PRG):

  1. The form is sent with POST.
  2. PHP processes it, then redirects the browser to a normal page.
  3. The browser loads that page with GET.

A refresh now repeats only the harmless GET.

The redirect

index.php
PHP
<?php
if ($_SERVER["REQUEST_METHOD"] === "POST") {
    // validate and save ...

    header("Location: thanks.php");
    exit;
}

Two rules:

  • header() must run before any output, including spaces and HTML. If it does not, PHP warns “headers already sent”.
  • Always call exit; right after, so the rest of the script does not keep running.

Show a message after the redirect: flash messages

A redirect starts a brand-new request, so a variable from the first request is gone. Store the message in the session for one request.

index.php
PHP
<?php
session_start();

if ($_SERVER["REQUEST_METHOD"] === "POST") {
    // validate and save ...

    $_SESSION["flash"] = "Thank you! Your message was sent.";
    header("Location: contact.php");
    exit;
}

$flash = $_SESSION["flash"] ?? null;
unset($_SESSION["flash"]);   // show it only once
?>
<?php if ($flash): ?>
  <p role="status"><?= htmlspecialchars($flash) ?></p>
<?php endif; ?>

unset() removes the message after it is shown, so a second refresh shows nothing. Sessions are explained in Chapter 16.

Only redirect on success

If validation fails, do not redirect. Show the form again right away with the errors and the old values (see Preserving Form Values). A redirect would lose them.

ResultWhat to do
Validation failedShow the form again with errors, status 200
SuccessRedirect (303 or 302) to a GET page

Which status code?

header("Location: ...") sends status 302 by default, and browsers switch to GET. If you want to be explicit, send 303 See Other:

index.php
PHP
<?php
header("Location: thanks.php", true, 303);
exit;

Redirect safely

Never redirect to a URL taken straight from user input (?next=...). That is an open redirect, which attackers use for phishing. Check that the target is one of your own pages.

index.php
PHP
<?php
function safeRedirectTarget(string $target): string
{
    $allowed = ["/dashboard.php", "/profile.php"];

    return in_array($target, $allowed, true) ? $target : "/dashboard.php";
}

echo safeRedirectTarget("https://evil.example") . "\n";
echo safeRedirectTarget("/profile.php");
Output
OUTPUT
/dashboard.php
/profile.php
warning
Output before header()
A blank line before <?php, a echo or a byte-order mark in the file counts as output. If you see “Cannot modify header information”, look for stray output above the header() call.