PHP: How do you redirect to another page?
A redirect in PHP is one line of code. There are two mistakes around it that happen so often, though, that they make up the larger part of this article.
The right way
<?php
header('Location: /target.php');
exit;
?>
That is all. header() sets the HTTP Location header and the browser follows
it. Let us look at the server’s actual response:
HTTP/1.1 302 Found
Content-Type: text/html; charset=UTF-8
Location: /ziel.php
Status code 302, a Location header, no content. That is exactly how it should
look.
Mistake 1: the forgotten exit
Calling header() does not end your script. Everything after it still runs
and still gets delivered:
<?php
header('Location: /target.php');
echo "SECRET: this text is delivered anyway\n";
?>
The server’s response then looks like this:
HTTP/1.1 302 Found
Location: /ziel.php
GEHEIM: dieser Text wird trotzdem ausgeliefert
In a browser you will not notice, because it follows the redirect and never
displays the text. The text is part of the response all the same. Any tool that
does not follow the redirect gets to see it. A plain curl without -L is
enough.
Now imagine that instead of SECRET there is the content of a page that is only
meant for logged-in users. That is exactly how you end up with an access check
that works in a browser and nowhere else:
<?php
// Please do not do this!
if (!$userIsLoggedIn) {
header('Location: /login.php');
// the exit is missing here
}
echo $secretData;
?>
So: an exit after every header('Location: ...').
Mistake 2: something has already been output
HTTP headers have to be sent before the content. As soon as PHP has output its first character, the headers are on their way and can no longer be changed:
<?php
echo "Output before the redirect\n";
header('Location: /target.php');
exit;
?>
The result is remarkable:
HTTP/1.1 200 OK
Ausgabe vor dem Redirect
Warning: Cannot modify header information - headers already sent by
(output started at /var/www/html/nach-ausgabe.php:3) in ... on line 4
The status code is 200 and there is no Location header. So the
redirect does not happen at all. And on a production system, where
display_errors is off, you will not even see the warning — only a page that
simply refuses to move on.
The most common causes are:
- an
echoorprintbefore theheader() - a blank line before the opening
<?php - a blank line after a closing
?>in an included file - a BOM at the start of the file, left there by your editor
The last one is particularly nasty because you cannot see the character. Best
leave the closing ?> out of pure PHP files entirely, then nothing can end up
after your code.
The right status code
Without further instruction PHP sends a 302 Found, that is a temporary
redirect. If the page has moved permanently, you want a 301:
<?php
header('Location: /target.php', true, 301);
exit;
?>
HTTP/1.1 301 Moved Permanently
Location: /ziel.php
The difference is not cosmetic. Search engines take the new address into their index on a 301 but not on a 302. Browsers also remember a 301 and stop requesting the old address at all — which reliably causes confusion while testing. So only send a 301 when you are sure.
If you redirect after a submitted form, 303 See Other is the clean choice. It
makes sure the browser requests the target page with GET, so a reload does not
submit the data again.
Relative or absolute address?
HTTP/1.0 used to require a full URI. Since
RFC 7231 relative references are
explicitly allowed and work in every current browser. So /target.php is fine.
Summary
header('Location: ...')followed byexit.- Without the
exitthe remaining content is delivered too, even if you do not see it in a browser. - Nothing may have been output before the
header(), otherwise there is no redirect at all. - 302 is temporary, 301 permanent, 303 after a form.
About Netcup (advertisement)
The German host Netcup offers, among other things, affordable and powerful web hosting packages, KVM-based root servers and dedicated servers. With our voucher codes you can save even more (6€ off your first order, 30% off all KVM-based root servers, ...).