PHP: Wie leitet man auf eine andere Seite weiter?
Eine Weiterleitung in PHP ist eine Zeile Code. Trotzdem gibt es dabei zwei Fehler, die so häufig vorkommen, dass sie den größeren Teil dieses Artikels ausmachen.
Der richtige Weg
<?php
header('Location: /ziel.php');
exit;
?>
Das war es schon. header() setzt den HTTP-Header Location, der Browser
folgt ihm. Schauen wir uns die tatsächliche Antwort des Servers an:
HTTP/1.1 302 Found
Content-Type: text/html; charset=UTF-8
Location: /ziel.php
Statuscode 302, ein Location-Header, kein Inhalt. Genau so soll es aussehen.
Fehler 1: das vergessene exit
Der Aufruf von header() beendet dein Skript nicht. Alles was danach
kommt, wird weiterhin ausgeführt und ausgeliefert:
<?php
header('Location: /ziel.php');
echo "GEHEIM: dieser Text wird trotzdem ausgeliefert\n";
?>
Die Antwort des Servers sieht dann so aus:
HTTP/1.1 302 Found
Location: /ziel.php
GEHEIM: dieser Text wird trotzdem ausgeliefert
Im Browser fällt das nicht auf, weil dieser der Weiterleitung folgt und den
Text nie anzeigt. Der Text ist aber Teil der Antwort. Jedes Werkzeug, das der
Weiterleitung nicht folgt, bekommt ihn zu sehen. Ein einfaches curl ohne
-L reicht dafür schon.
Und jetzt stell dir vor, an dieser Stelle steht nicht GEHEIM, sondern der
Inhalt einer Seite, die eigentlich nur für angemeldete Benutzer gedacht ist.
Genau so entsteht eine Zugriffsprüfung, die im Browser funktioniert und sonst
nirgends:
<?php
// So bitte nicht!
if (!$benutzerIstAngemeldet) {
header('Location: /login.php');
// hier fehlt das exit
}
echo $geheimeDaten;
?>
Deshalb: nach jedem header('Location: ...') ein exit.
Fehler 2: es wurde schon etwas ausgegeben
HTTP-Header müssen vor dem Inhalt verschickt werden. Sobald PHP das erste Zeichen ausgegeben hat, sind die Header unterwegs und lassen sich nicht mehr ändern:
<?php
echo "Ausgabe vor dem Redirect\n";
header('Location: /ziel.php');
exit;
?>
Das Ergebnis ist bemerkenswert:
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
Der Statuscode ist 200, es gibt keinen Location-Header. Die
Weiterleitung findet also gar nicht statt. Und auf einem Produktivsystem, wo
display_errors ausgeschaltet ist, siehst du nicht einmal die Warnung —
sondern nur eine Seite, die sich einfach nicht weiterbewegt.
Die häufigsten Auslöser sind:
- ein
echooderprintvor demheader() - eine Leerzeile vor dem einleitenden
<?php - eine Leerzeile nach einem abschließenden
?>in einer eingebundenen Datei - ein BOM am Dateianfang, das dein Editor hinterlassen hat
Der letzte Punkt ist besonders tückisch, weil man das Zeichen nicht sieht. Lass
das schließende ?> in reinen PHP-Dateien am besten ganz weg, dann kann dort
auch nichts mehr hinter dem Code stehen.
Der richtige Statuscode
Ohne weitere Angabe schickt PHP einen 302 Found, also eine temporäre
Weiterleitung. Ist die Seite dauerhaft umgezogen, willst du einen 301:
<?php
header('Location: /ziel.php', true, 301);
exit;
?>
HTTP/1.1 301 Moved Permanently
Location: /ziel.php
Der Unterschied ist nicht kosmetisch. Suchmaschinen übernehmen bei einem 301 die neue Adresse in ihren Index, bei einem 302 nicht. Browser merken sich einen 301 außerdem und rufen die alte Adresse gar nicht mehr auf — was beim Testen gerne für Verwirrung sorgt. Setze also nur dann einen 301, wenn du dir sicher bist.
Leitest du nach einem abgeschickten Formular weiter, ist 303 See Other die
saubere Wahl. Damit stellst du sicher, dass der Browser die Zielseite per GET
anfordert und ein Neuladen die Daten nicht erneut abschickt.
Relative oder absolute Adresse?
Früher schrieb HTTP/1.0 einen vollständigen URI vor. Seit
RFC 7231 sind relative Angaben
ausdrücklich erlaubt und funktionieren in allen aktuellen Browsern. /ziel.php
ist also in Ordnung.
Zusammenfassung
header('Location: ...')gefolgt vonexit.- Ohne
exitwird der restliche Inhalt mit ausgeliefert, auch wenn du ihn im Browser nicht siehst. - Vor dem
header()darf nichts ausgegeben worden sein, sonst gibt es überhaupt keine Weiterleitung. - 302 ist temporär, 301 dauerhaft, 303 nach einem Formular.
Hinweis zu Netcup (Werbung)
Der deutsche Hoster Netcup bietet unter anderem günstige und zugleich leistungsstarke Webhosting Pakete, KVM-basierte Root Server und dezidierte Server an. Mit unseren Gutscheincodes kannst du noch mehr Geld sparen (6€ bei deiner ersten Bestellung, 30% Rabatt auf alle KVM-basierten Root Server, ...).