Abschnitt 12 · Lektion 4
Meldungen nach der Weiterleitung
In Lektion 11.3 hast du gelernt, nach dem Speichern weiterzuleiten, damit ein Neuladen nicht doppelt bestellt. Dabei ist etwas verloren gegangen, und diese Lektion holt es zurück.
Das Loch, das die Weiterleitung reißt
<?php
// Der Ablauf aus Lektion 11.3: speichern, dann weiterleiten. Die
// Bestaetigung wird gesetzt und ist trotzdem nie zu sehen.
//
// Schick im Browser das Formular ab und sieh oben nach.
$gespeichert = false;
if ($_SERVER["REQUEST_METHOD"] === "POST") {
// Hier waere die Meldung faellig, und hier ist sie sinnlos:
// zwei Zeilen weiter ist dieser Lauf zu Ende.
$gespeichert = true;
header("Location: /", true, 302);
exit;
}
?>
<!doctype html>
<html lang="de">
<head>
<meta charset="utf-8">
<title>Ohne Zwischenlager</title>
</head>
<body>
<h1>Neue Notiz</h1>
<?php if ($gespeichert) { ?>
<p><strong>Notiz gespeichert</strong></p>
<?php } ?>
<form method="post" action="/">
<p><label>Notiz: <input type="text" name="text" value="Milch"></label></p>
<button type="submit">Speichern</button>
</form>
</body>
</html> Sieh dir den Ablauf noch einmal genau an. Der POST kommt an, du speicherst, du schickst eine
Weiterleitung, und dann steht dort exit. Danach ist der Lauf zu Ende.
Der Browser holt die genannte Adresse mit einem GET, und dafür startet dein Programm von vorn.
Alle Variablen sind neu, auch die, in der die Bestätigung stand. Der Besucher sieht deshalb eine
Seite, die aussieht, als wäre nichts passiert. Im Reiter Netzwerk stehen die beiden Läufe
untereinander, wie in 11.3: POST / mit 302, darunter GET / mit 200. Zwischen diesen zwei Zeilen
liegt das Loch.
Im ersten Beispiel steht die Zeile, die die Meldung setzt, sogar da. Sie ist nur wirkungslos: Zwei Zeilen weiter unten hört der Lauf auf, in dem sie gesetzt wurde. Schick im Browser das Formular ab und sieh es dir an.
In 11.3 war die Antwort darauf ein Anhang an der Adresse, also Location: /?gespeichert=1. Das
funktioniert, hat aber den Nachteil, den du dort schon gelesen hast: Die Bestätigung steht in der
Adresszeile, und wer diese Adresse kopiert und weitergibt, verschickt eine Bestätigung für etwas,
das bei dem anderen nie passiert ist.
Ein Wert, der genau einmal lebt
<?php
// Derselbe Ablauf, drei Zeilen mehr. Die Meldung wartet in der
// Sitzung auf den naechsten Lauf und wird beim Lesen entfernt.
//
// Schick im Browser ab. Die Meldung erscheint. Lad danach neu: Sie ist
// weg, denn sie war fuer genau eine Anfrage gedacht.
session_start();
if ($_SERVER["REQUEST_METHOD"] === "POST") {
$_SESSION["meldung"] = "Notiz gespeichert";
header("Location: /", true, 302);
exit;
}
$meldung = $_SESSION["meldung"] ?? null;
unset($_SESSION["meldung"]);
?>
<!doctype html>
<html lang="de">
<head>
<meta charset="utf-8">
<title>Mit Zwischenlager</title>
</head>
<body>
<h1>Neue Notiz</h1>
<?php if ($meldung !== null) { ?>
<p><strong><?= htmlspecialchars($meldung) ?></strong></p>
<?php } ?>
<form method="post" action="/">
<p><label>Notiz: <input type="text" name="text" value="Milch"></label></p>
<button type="submit">Speichern</button>
</form>
<p><a href="/">Seite neu laden</a></p>
</body>
</html> Jetzt hast du eine Sitzung, und damit einen Ort, der genau zwischen den beiden Läufen liegt. Der Ablauf bekommt zwei Handgriffe dazu.
Vor der Weiterleitung legst du die Meldung in die Sitzung, also $_SESSION["meldung"] = "Notiz gespeichert";. Sie überdauert das Ende des Laufs, denn sie liegt in einer Datei auf dem Server.
Am Anfang des nächsten Laufs holst du sie mit $meldung = $_SESSION["meldung"] ?? null; heraus
und löschst sie in der Zeile darunter mit unset($_SESSION["meldung"]);.
Diese zwei Zeilen sind das ganze Muster. Man nennt so einen Wert eine Flash-Meldung, weil er einmal aufblitzt und dann verschwindet. In jedem größeren Framework findest du ihn unter genau diesem Namen wieder, und dahinter steckt nichts anderes als das hier.
Was die beiden Läufe verbindet, siehst du im Reiter Netzwerk: Der POST / und der GET /
darunter tragen unter den Anfrage-Kopfzeilen dieselbe cookie: PHPSESSID=…-Zeile. Derselbe
Besucher, zweimal, und dazwischen liegt die Datei mit der Meldung.
Warum das Löschen dazugehört
<?php
// Dasselbe noch einmal, nur ohne das unset. Die Meldung wird gelesen
// und bleibt liegen.
//
// Schick im Browser ab und lad danach ein paar Mal neu. Die Bestaetigung
// steht immer noch da und behauptet etwas, das nicht mehr stimmt.
session_start();
if ($_SERVER["REQUEST_METHOD"] === "POST") {
$_SESSION["meldung"] = "Notiz gespeichert";
header("Location: /", true, 302);
exit;
}
$meldung = $_SESSION["meldung"] ?? null;
?>
<!doctype html>
<html lang="de">
<head>
<meta charset="utf-8">
<title>Ohne Aufraeumen</title>
</head>
<body>
<h1>Neue Notiz</h1>
<?php if ($meldung !== null) { ?>
<p><strong><?= htmlspecialchars($meldung) ?></strong></p>
<?php } ?>
<form method="post" action="/">
<p><label>Notiz: <input type="text" name="text" value="Milch"></label></p>
<button type="submit">Speichern</button>
</form>
<p><a href="/">Seite neu laden</a></p>
</body>
</html> Ohne das unset bleibt die Meldung in der Sitzung liegen, und die Sitzung lebt weiter. Beim
nächsten Aufruf steht sie also wieder da. Und beim übernächsten. Der Besucher liest „Notiz
gespeichert”, obwohl er gerade nur auf einen Link geklickt hat.
Das dritte Beispiel macht genau das. Schick ab, lad ein paar Mal neu, und sieh der Meldung beim Kleben zu.
Wichtig ist die Reihenfolge: erst lesen, dann löschen. Wer zuerst löscht, hat nichts mehr zum Anzeigen. Und beides gehört an den Anfang des Programms, nicht mitten in das Markup: Sobald du die Meldung erst dort ausliest, hängt ihr Verschwinden davon ab, ob dieser Teil der Seite überhaupt erreicht wurde.
Sobald es mehr als eine Meldung gibt
Dann willst du das nicht viermal schreiben. Eine kleine Funktion in der Machart aus Abschnitt 6
reicht: Sie heißt etwa flash($schluessel), gibt mit $_SESSION[$schluessel] ?? null zurück, was
dort liegt, räumt es mit unset() weg und liefert null, wenn nichts da war. Damit steht in deiner
Seite nur noch ein Aufruf, und das Muster ist an genau einer Stelle aufgeschrieben statt an vier.
Denselben Weg nimmt in Lektion 12.5 der Hinweis „Das Passwort stimmt nicht”, und in Abschnitt 16 wird daraus eine der ersten Funktionen, die in eine eigene Datei wandern.
Zum Mitnehmen
Lektion 11.3 hat ein Problem gelöst und dabei ein neues aufgemacht: Nach der Weiterleitung weiß der neue Lauf nichts mehr davon, dass gerade etwas gespeichert wurde. Die Lösung ist ein Wert, der genau eine Anfrage weit lebt, und sie braucht nichts als die Sitzung von eben.
Jetzt du
Basis Konto, kostenlosZu dieser Lektion gehört eine Aufgabe. Du schreibst den Code selbst, und nach jedem Lauf sagt dir eine Prüfliste, was schon stimmt.
Dafür brauchst du das Basis Konto. Es kostet nichts, und ein Passwort gibt es auch nicht.
In diesem Kurs läuft dein Code auf einem Server. Dafür hat das Basis Konto 1 Stunde im Monat, mehr Zeit gibt es mit dem Premium Konto.
Was in dieser Lektion steckt
-
Artikel mit 3 Beispielen zum Ausprobieren
Steht hier, ohne Konto lesbar.
-
Aufgabe, dein Code läuft auf einem Server
Öffnet sich mit dem Basis Konto.