Abschnitt 11 · Lektion 1
Ein Formular abschicken
Ein Formular hast du im HTML-Kurs schon gebaut. Es hatte Felder, es hatte einen Knopf, und beim Klick passierte nichts Sinnvolles: Es fehlte die Gegenstelle. Genau die schreibst du jetzt.
Zwei Angaben entscheiden alles
<?php
// Eine Datei, zwei Faelle. Ohne Absenden steht hier das Formular,
// nach dem Absenden zusaetzlich die Antwort.
$name = "";
if ($_SERVER["REQUEST_METHOD"] === "POST") {
$name = trim($_POST["name"] ?? "");
}
?>
<!doctype html>
<html lang="de">
<head>
<meta charset="utf-8">
<title>Wer bist du?</title>
</head>
<body>
<h1>Wer bist du?</h1>
<form method="post" action="/">
<p><label>Dein Name: <input type="text" name="name"></label></p>
<button type="submit">Absenden</button>
</form>
<?php if ($name !== "") { ?>
<p>Hallo, <?= htmlspecialchars($name) ?>. Diesen Satz hat dein Server
gerade zusammengesetzt, in dem Moment, in dem du auf Absenden gedrueckt hast.</p>
<?php } ?>
<p>Angefragt wurde diese Seite gerade mit
<code><?= htmlspecialchars($_SERVER["REQUEST_METHOD"]) ?></code>.</p>
</body>
</html> Am <form>-Element stehen zwei Attribute, und die musst du auseinanderhalten.
action sagt, wohin die Daten gehen. Steht dort /, geht es an die Startseite, also an
dieselbe Datei, die das Formular ausgeliefert hat. Das ist im Kurs der Normalfall und hat einen
guten Grund: Eine Datei, die beide Fälle beherrscht, hält Formular und Auswertung beieinander.
Lässt du action ganz weg, geht es ebenfalls an die aktuelle Adresse; ich schreibe es trotzdem
hin, weil man dann beim Lesen sieht, was gemeint ist.
method sagt, wie die Daten gehen. post packt sie in den Rumpf der Anfrage, get hängt sie
an die Adresse. Mehr ist der Unterschied technisch nicht, und trotzdem hängt daran ziemlich viel.
Das dritte wichtige Attribut steht nicht am Formular, sondern an jedem Feld: name. Es ist der
Schlüssel, unter dem der Wert bei dir ankommt. <input name="ort"> wird zu $_POST["ort"].
Eine Datei, zwei Fälle
Beim ersten Aufruf hat der Besucher noch nichts abgeschickt. Er will das Formular sehen. Nach dem Klick auf Absenden kommt dieselbe Adresse noch einmal dran, diesmal mit Daten, und jetzt soll etwas anderes passieren.
Auseinanderhalten kannst du die beiden an $_SERVER["REQUEST_METHOD"]. Beim Aufruf über einen Link
oder die Adresszeile steht dort GET, nach dem Absenden eines POST-Formulars POST. Das Beispiel
zeigt beides an, damit du beim Klicken zusehen kannst.
Probier es im Browser aus. Trag einen Namen ein und drück auf Absenden. Der Satz, den du dann
liest, ist eine Sekunde vorher noch nicht dagewesen. Und sieh danach in den Reiter Netzwerk:
Dort steht die Anfrage, die dein Klick ausgelöst hat, und zum ersten Mal in diesem Kurs heißt die
Methode POST. Die Adresse ist dabei dieselbe geblieben, der Name steht nicht darin: Er ist im
Rumpf der Anfrage mitgereist. Klapp die Zeile auf, dann liest du ihn im Anfrage-Rumpf: name= und
dahinter das, was du eingetragen hast.
GET fragt ab, POST verändert
<?php
// Dasselbe Formular, nur mit method="get". Sieh dir nach dem
// Absenden die Adresszeile ueber der Seite an.
$suche = trim($_GET["ware"] ?? "");
$waren = ["Apfel", "Birne", "Brot", "Butter", "Kaffee", "Milch"];
$treffer = [];
foreach ($waren as $ware) {
if ($suche !== "" && stripos($ware, $suche) !== false) {
$treffer[] = $ware;
}
}
?>
<!doctype html>
<html lang="de">
<head>
<meta charset="utf-8">
<title>Suche</title>
</head>
<body>
<h1>Was suchst du?</h1>
<form method="get" action="/">
<p><label>Ware: <input type="text" name="ware" value="<?= htmlspecialchars($suche) ?>"></label></p>
<button type="submit">Suchen</button>
</form>
<p>In der Adresse steht gerade:
<code><?= htmlspecialchars($_SERVER["REQUEST_URI"]) ?></code></p>
<?php if ($suche !== "") { ?>
<p><?= count($treffer) ?> Treffer:</p>
<ul>
<?php foreach ($treffer as $ware) { ?>
<li><?= htmlspecialchars($ware) ?></li>
<?php } ?>
</ul>
<?php } ?>
</body>
</html> Die Faustregel ist kurz: GET fragt etwas ab, POST verändert etwas. Eine Suche, eine Sortierung, ein Filter, eine Seitenzahl: alles GET. Eine Bestellung, eine neue Notiz, eine Anmeldung, ein Löschen: alles POST.
Der Unterschied ist nicht Geschmack. Was per GET geht, steht in der Adresse, und eine Adresse ist teilbar, sie landet im Verlauf des Browsers, in den Lesezeichen und im Protokoll des Servers. Für eine Suche ist das ein Vorteil: Du kannst deinem Kollegen den Link zum Suchergebnis schicken. Für ein Passwort ist es eine Katastrophe, und deshalb gilt ohne Ausnahme: Ein Passwort geht nie per GET. Es stünde in drei Protokollen, die du nicht alle kennst.
Beim zweiten Beispiel lohnt sich derselbe Blick in den Reiter Netzwerk: Nach dem Suchen steht
dort GET und dahinter die Adresse mit ?ware= am Ende. Was du eingetippt hast, ist Teil der
Adresse geworden, und genau das ist der Unterschied zum ersten Beispiel.
Dazu kommt eine Eigenheit des Browsers, um die es in Lektion 11.3 geht. Eine Seite, die per GET geladen wurde, lädt er beim Neuladen einfach noch einmal. Eine Seite, die aus einem POST entstanden ist, nicht: Da fragt er erst nach, ob er die Daten wirklich noch einmal schicken soll.
Wo die Werte landen
Für beide Wege gibt es ein Array, das PHP für dich füllt. $_GET kennst du aus Lektion 10.3, und
$_POST funktioniert genauso, nur eben für den Rumpf der Anfrage. Die Schlüssel sind die
name-Attribute aus deinem Markup, die Werte sind immer Text, auch bei einem Zahlenfeld.
Beide Arrays sind übrigens unabhängig voneinander. Ein Formular mit method="post", dessen action
auf /suche?seite=2 zeigt, füllt beide: die Felder landen in $_POST, die seite in $_GET.
Was ohne name passiert
<?php
// Zwei Felder, beide ausgefuellt, und trotzdem kommt nur eines an.
// Der Unterschied steht im Markup unten.
$angekommen = [];
if ($_SERVER["REQUEST_METHOD"] === "POST") {
$angekommen = $_POST;
}
?>
<!doctype html>
<html lang="de">
<head>
<meta charset="utf-8">
<title>Was ankommt</title>
</head>
<body>
<h1>Was ankommt</h1>
<form method="post" action="/">
<p><label>Mit name: <input type="text" name="ort" value="Kiel"></label></p>
<p><label>Ohne name: <input type="text" value="Hamburg"></label></p>
<button type="submit">Absenden</button>
</form>
<p>Von den beiden Feldern sind <?= count($angekommen) ?> angekommen.</p>
<ul>
<?php foreach ($angekommen as $schluessel => $wert) { ?>
<li><?= htmlspecialchars($schluessel) ?> = <?= htmlspecialchars($wert) ?></li>
<?php } ?>
</ul>
</body>
</html> Der häufigste Anfängerfehler bei Formularen ist ein vergessenes name-Attribut. Der Browser
schickt so ein Feld gar nicht erst mit, es taucht also weder in $_POST noch sonst irgendwo auf.
Und weil PHP kein Wort darüber verliert, sucht man den Fehler zuerst im eigenen Code.
Im Beispiel sind beide Felder vorausgefüllt. Drück auf Absenden und zähl nach, was ankommt.
Und ab jetzt gilt: glaub dem Besucher nichts
Der Satz klingt unfreundlich, ist aber nur nüchtern. Alles, was in $_POST ankommt, hat jemand
anderes bestimmt, und dieser Jemand muss weder dein Formular benutzt noch überhaupt einen Browser
verwendet haben. Ein Feld kann leer sein, doppelt so lang wie gedacht, Markup enthalten oder ganz
fehlen, obwohl es im Formular steht.
Das ist kein Grund zur Panik, sondern eine Arbeitsanweisung, und die nächsten drei Lektionen arbeiten sie ab: prüfen, was ankommt (11.2), nach dem Speichern weiterleiten (11.3), und alles entschärfen, was wieder auf die Seite geht (11.4).
Zum Mitnehmen
Bis hierhin hat der Besucher nur gelesen. Ab jetzt schickt er etwas hin, und dein Programm muss damit umgehen. Das ist der Punkt, an dem aus einer Seite eine Anwendung wird, und zugleich der Punkt, an dem du aufhoerst, dem Besucher zu glauben.
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.