03/15/2014
Redirect a webpage with PHP
<?php
http_response_code(302);
header('Location: https://example.com/new-page');
exit;
Three lines, and each one is load-bearing.
exit is not optional. header() queues a header; it does not stop
the script. Without the exit, everything below still runs — including
the code that deletes the record, sends the email, or charges the card.
The browser will follow the redirect and never show you what happened.
Nothing may be printed first. Headers are sent before the body, so any
output at all — a blank line after ?> in an included file, a BOM at the
start of the file, an accidental space before <?php — sends them early
and the redirect silently does not happen. That is the "stray space"
problem, and it is real; the fix is to leave the closing ?> off any file
that is pure PHP, which is why most modern codebases do.
The URL should be absolute. A relative Location works in practice
because browsers resolve it, but an absolute URL is what the RFC asks for
and it removes a class of surprises behind proxies and rewrites.
301 or 302, and why it is the important choice
This matters more than the code.
302 is temporary. The browser asks again next time. Use it while you are still deciding, for anything conditional, and for a redirect after a form post.
301 is permanent, and browsers cache it aggressively -- often until the cache is cleared by hand. Send a 301 to the wrong place and the people who hit it may keep going there after you have fixed the server, and you cannot reach them to tell them otherwise. Testing a redirect chain in a private window exists because of this.
The practical rule: 302 until you are certain, then 301. A permanent redirect is a promise you cannot easily take back, and there is no penalty for having been temporary first.
For form handling specifically, the redirect-after-post pattern wants 303, which tells the browser to follow with GET regardless of the method that got there. Modern browsers do that for 302 too, which is why 302 usually works, but 303 is the one that says what you mean.
Where PHP is the wrong tool for it
If the redirect is static — an old URL to a new URL, a whole directory moved — do it in the server config rather than in PHP:
Redirect 301 /old-page /new-page
It is faster, it works for files PHP never sees, and it survives the page being deleted. Reach for PHP when the destination depends on something only the application knows: who is logged in, what a lookup returned, which variant a test assigned.
Questions this keeps raising
Why does my PHP redirect not work?
Almost always because something was already output. A blank line after a closing ?> in an included file is the classic cause, and a byte-order mark at the start of the file is the one that is hardest to see. Both send the headers before your Location line. Leaving the closing ?> off pure-PHP files removes the first case entirely.
Do I really need exit after header()?
Yes. header() only queues the header - the rest of the script still runs. Without exit, code below the redirect executes while the browser navigates away, so anything with a side effect happens invisibly.
Should I use 301 or 302?
302 unless you are certain, then 301. Browsers cache a 301 aggressively, often until someone clears their cache by hand, so a 301 to the wrong destination can outlive the mistake by months. There is no cost to having been temporary first.
Can I redirect after sending some HTML?
Not with a Location header - the headers are already gone. Output buffering with ob_start() will hold the body back and let you send headers later, but reaching for it usually means the redirect decision belongs earlier in the request than where it currently sits.