PHP redirects: how to redirect

PHP redirects: how to redirect
If you work with PHP, sooner or later you will need to send a visitor from one URL to another: after saving a form, when a page changes address, or when you want to protect a private area of your site. That action is called a redirect, and it is one of the most common tasks in web development. In this article we show you how to do a redirect in PHP the right way: what a redirect is, what it is used for, how to use header() with Location, the difference between a 301 and a 302, and the most common mistakes to avoid. Let us go straight to the point, with clear explanations and code examples you can run as they are. If you only want the short answer: in PHP you make a redirect by sending the HTTP Location header with the header() function and stopping execution with exit. But, as with everything related to HTTP, the details matter: when you call the function, the status code that goes with it and how you handle the script output are the difference between a redirect that works and an annoying headers already sent warning on screen.What is a redirect in PHP
To understand redirects in PHP you first need to remember how the web works. When a browser requests a page, the server answers with an HTTP message made of three parts: a status line with a code (for example 200 OK), a set of headers, and optionally the body with the HTML. PHP is the program that runs on the server and builds that response. A redirect is simply a special HTTP response: instead of returning the page content, the server sends a Location header with the URL the browser should go to, plus a status code that tells whether the move is permanent or temporary. The browser receives that response, reads the new URL and automatically issues a second request. To the user it looks instant: they type one address and land on another. That is the correct approach, and the one search engines use. Other techniques can take users to another page, such as the HTML meta refresh tag or JavaScript with window.location, but none of them replaces a real HTTP redirect when you need to move a URL, preserve rankings or protect a route: a PHP redirect happens on the server, before a single line of HTML is sent.Why you need a redirect in PHP
There are many scenarios in which a page needs to answer with a PHP redirect. These are the most common:- The page changed its address: if you reorganize your site structure, migrate to another domain or remove a page, you redirect the old URL to the new one so nobody runs into a 404 error.
- Friendly and canonical URLs: with redirects you unify the variants of the same page, for example from http to https, from www to non-www or from index.php to the root, so all traffic and SEO point to a single URL.
- After submitting a form: when a form saves data, the correct response is a redirect to a confirmation page instead of plain HTML; that way, if the user refreshes, the browser does not resubmit the form or duplicate the order. This is the PRG pattern we will see later.
- 301 redirects for SEO: a 301 tells Google that the page moved permanently and transfers most of the authority of the old URL to the new one.
- Protecting access: if a page requires a logged-in user or a specific role, the script redirects visitors to the login page when the condition is not met.
How to make a redirect in PHP with header and Location
The key function is header(), which sends a raw HTTP header. To redirect, you send the Location header with the destination URL. The simplest example of a PHP redirect looks like this:- <?php
- // Redirect the browser to another URL
- header("Location: https://www.example.com/new-page");
- exit;
301 vs 302 redirects: permanent or temporary
Not all redirects mean the same thing. The HTTP status code that accompanies Location tells browsers and search engines whether the move is permanent or temporary, and that has practical consequences:| Code | Name | When to use it |
|---|---|---|
| 301 | Moved Permanently | The page moved forever: search engines update the URL, SEO is preserved and users bookmarks are updated. |
| 302 | Found | The move is temporary: maintenance, promotions or short-lived changes. Search engines keep the original URL. |
| 303 | See Other | After processing a form sent with POST: the browser makes a GET request to the confirmation page (PRG pattern). |
| 307 | Temporary Redirect | Like 302 but keeping the HTTP method: if the request was POST, the repeated request will also be POST. |
- header("Location: https://www.example.com/new-page", true, 301);
- exit;
- http_response_code(301);
- header("Location: https://www.example.com/new-page");
- exit;
PRG pattern: redirecting after a form submission
One of the most valuable uses of the PHP redirect is the Post/Redirect/Get pattern, known as PRG. The problem it solves is classic: an order, registration or contact form sends its data with POST and the server processes it. If the script answers by printing the confirmation page, the browser keeps the POST request in its history; when the user presses F5 or goes back, the browser asks whether to resubmit the form and, if accepted, the order is processed twice. The PRG solution is that the script receiving the POST does not return HTML: after validating and saving the data, it answers with a redirect, normally 303 See Other, to a page reached with GET. That way refreshing only reloads the confirmation page, with no side effects:- <?php
- // save_order.php: receives the form via POST
- if ($_SERVER["REQUEST_METHOD"] === "POST") {
- // validate and save the order here
- save_order($_POST);
- // 303 so refreshing does not repeat the submission
- header("Location: /order-confirmed.php", true, 303);
- exit;
- }
Conditional redirects: protecting pages and choosing the destination
A PHP redirect is almost never a single line on its own: it usually depends on a condition. The typical case is protecting a private page. If the user is not logged in, they are redirected to the login page before seeing any content:- <?php
- session_start();
- // if there is no active session, send the visitor to login
- if (!isset($_SESSION["user"])) {
- header("Location: /login.php");
- exit;
- }
- // the rest of the page only runs with an active session
- <?php
- // allowed destinations
- $sections = array(
- "profile" => "/profile.php",
- "orders" => "/orders.php",
- "help" => "/help.php"
- );
- $key = $_GET["go"] ?? "profile";
- if (isset($sections[$key])) {
- header("Location: " . $sections[$key]);
- exit;
- }
- // if the key does not exist, go to the homepage
- header("Location: /home");
- exit;
Redirecting after a delay
Sometimes you do not want to jump immediately, but to show a message and take the user to the new page a few seconds later. The simple way is the Refresh header, which, although not part of the HTTP standard, is supported by all browsers:- header("Refresh: 5; url=https://www.example.com/new-page");
- echo "We are redirecting you to the new page in 5 seconds...";
- exit;
Common mistakes when making a PHP redirect
Even though the mechanics are simple, some mistakes repeat across projects. Knowing them will save you hours of debugging. 1. The headers already sent warning. It is the most searched error in PHP development and it appears when you call header() after the script has already sent output. Anything counts: an echo, a line of HTML, a space or line break outside the PHP tags, and even an invisible UTF-8 BOM that some editors add at the beginning of the file. Once the body of the response has started being sent, headers cannot be modified and the redirect does not happen:- <?php
- echo "Welcome to the store";
- // on a server without output buffering this already sends HTML
- header("Location: /home");
- // Warning: Cannot modify header information - headers already sent
- Place header() and its logic at the beginning of the script, before any output: structure the code to decide the redirect before rendering HTML.
- Omit the closing ?> tag at the end of files that only contain PHP, so no trailing spaces or line breaks are sent as output.
- If you cannot avoid earlier output, enable the output buffer with ob_start() at the start of the script; output is held back and header() can run afterwards.
- Check that the file was not saved with a UTF-8 BOM, because those three invisible bytes at the beginning also count as output.
- Review that there are no spaces or blank lines before the opening <?php tag.
- <?php
- ob_start(); // from here on, output stays in the buffer
- // ... any echo or HTML is held back ...
- header("Location: /home"); // no conflict anymore
- exit;
- curl -I https://www.example.com/old-page
- HTTP/1.1 301 Moved Permanently
- Location: https://www.example.com/new-page
In summary
Making a redirect in PHP is simple, but doing it well requires understanding HTTP. The rule that summarizes the whole article is: header("Location: URL") before any output, with the right status code and followed by exit.- header() with Location sends the browser to another URL and must be called before any output.
- Without an explicit code, PHP answers with a temporary 302; use the third argument of header() or http_response_code() to send 301, 303 and the rest.
- The PRG pattern answers a POST with a 303 redirect to avoid duplicates when refreshing.
- Use conditional redirects to protect pages and always validate the destination against a whitelist.
- If you see headers already sent, review previous output, remove the closing PHP tag and try ob_start().
- Check your redirects with curl -I to see the real status code and destination URL.