Abschnitt 11 · Lektion 2
Eingaben prüfen
Ein Formular nimmt alles entgegen, was jemand hineinschreibt. Was danach passiert, entscheidest du, und deshalb steht zwischen dem Absenden und dem Speichern immer eine Prüfung.
Die drei Fragen
Zu jedem einzelnen Feld gehören drei Fragen, und sie bauen aufeinander auf.
Ist es überhaupt da? Das ist keine überflüssige Frage, obwohl das Feld ja im Formular steht. Wer
die Anfrage selbst zusammenbaut, lässt es einfach weg. Zuständig ist isset(), und danach trim(),
weil ein Feld mit drei Leerzeichen für einen Menschen leer ist und für PHP nicht.
Hat es die richtige Form? Sieht die E-Mail-Adresse wie eine aus, ist die Menge eine Zahl, hat die Postleitzahl fünf Stellen? Dafür gibt es fertige Prüfer.
Ist der Wert plausibel? Die Form kann stimmen und der Wert trotzdem Unsinn sein: eine Menge von minus drei, ein Geburtsdatum im Jahr 2093, eine Bestellung über null Stück. Das weiß keine Funktion für dich, das sind deine Regeln.
Da oder nicht da
<?php
// Drei Fragen an dasselbe Feld, und sie haben drei verschiedene
// Antworten. Schick das Formular einmal ganz leer ab und einmal
// mit nichts als zwei Leerzeichen darin.
$bericht = [];
if ($_SERVER["REQUEST_METHOD"] === "POST") {
$roh = $_POST["name"] ?? null;
$bericht["Feld angekommen (isset)"] = isset($_POST["name"]) ? "ja" : "nein";
$bericht["Roher Wert"] = var_export($roh, true);
$bericht["Nach trim() noch etwas übrig"] = trim((string) $roh) !== "" ? "ja" : "nein";
$bericht["Was empty() sagt"] = empty($roh) ? "leer" : "nicht leer";
}
?>
<!doctype html>
<html lang="de">
<head>
<meta charset="utf-8">
<title>Ist es da</title>
</head>
<body>
<h1>Ist es da, oder sieht es nur so aus</h1>
<form method="post" action="/">
<p><label>Name: <input type="text" name="name"></label></p>
<button type="submit">Absenden</button>
</form>
<ul>
<?php foreach ($bericht as $frage => $antwort) { ?>
<li><?= htmlspecialchars($frage) ?>: <strong><?= htmlspecialchars($antwort) ?></strong></li>
<?php } ?>
</ul>
</body>
</html> isset() beantwortet die erste Frage und sonst nichts: Es sagt, ob der Schlüssel existiert und
nicht null ist. Ein leer abgeschicktes Textfeld existiert sehr wohl, es enthält nur eine leere
Zeichenkette. isset() sagt dafür also ja.
empty() stellt eine andere Frage, nämlich die aus Lektion 2.5: Hält PHP diesen Wert für falsch?
Damit ist ein leeres Feld leer, aber auch die Eingabe 0, und genau deshalb ist empty() für
Formularfelder eine Falle. Eine Menge von 0 ist eine Angabe und kein fehlendes Feld.
Im Alltag prüfst du deshalb meistens so: Wert mit ?? "" abholen, trim() darauflegen, und dann
gegen "" vergleichen. Drei Schritte, die zusammen genau das bedeuten, was du meinst.
Die Form prüfen, ohne sie selbst zu beschreiben
<?php
// Beim ersten Aufruf stehen zwei Werte im Formular, die beide
// knapp danebenliegen. Druck einfach auf Absenden und sieh dir
// an, was filter_var dazu sagt.
$istPost = $_SERVER["REQUEST_METHOD"] === "POST";
$email = $istPost ? trim($_POST["email"] ?? "") : "mia@example";
$menge = $istPost ? trim($_POST["menge"] ?? "") : "3 Stück";
// Zurueck kommt der geprueft brauchbare Wert oder false. Bei der
// Zahl ist der Rueckgabewert deshalb interessant: aus dem Text
// "3" wird ein echtes int.
$emailGeprueft = filter_var($email, FILTER_VALIDATE_EMAIL);
$mengeGeprueft = filter_var($menge, FILTER_VALIDATE_INT);
?>
<!doctype html>
<html lang="de">
<head>
<meta charset="utf-8">
<title>filter_var</title>
</head>
<body>
<h1>Hat es die richtige Form?</h1>
<form method="post" action="/">
<p><label>E-Mail: <input type="text" name="email" value="<?= htmlspecialchars($email) ?>"></label></p>
<p><label>Menge: <input type="text" name="menge" value="<?= htmlspecialchars($menge) ?>"></label></p>
<button type="submit">Prüfen</button>
</form>
<ul>
<li>FILTER_VALIDATE_EMAIL gibt zurück:
<strong><?= htmlspecialchars(var_export($emailGeprueft, true)) ?></strong></li>
<li>FILTER_VALIDATE_INT gibt zurück:
<strong><?= htmlspecialchars(var_export($mengeGeprueft, true)) ?></strong></li>
</ul>
<p>Probier auch <code>mia@example.com</code> und <code>3</code>.</p>
</body>
</html> Eine E-Mail-Adresse mit einem eigenen Muster zu prüfen, ist eine Übung, die man einmal macht und danach bereut. Die Regeln sind unangenehm, und die meisten selbst gebauten Prüfungen weisen gültige Adressen ab.
filter_var() nimmt dir das ab. Der zweite Parameter sagt, worauf geprüft wird:
FILTER_VALIDATE_EMAIL für Adressen, FILTER_VALIDATE_INT für ganze Zahlen,
FILTER_VALIDATE_FLOAT für gebrochene, FILTER_VALIDATE_URL für Adressen im Netz.
Wichtig ist der Rückgabewert. Die Funktion gibt nicht true oder false zurück, sondern den
geprüften Wert oder false. Bei der Zahl ist das ein Geschenk: Aus dem Text "3" wird ein echtes
int, mit dem du sofort rechnen kannst. Bei "3 Stück" kommt false, denn eine Zahl mit Anhang
ist keine Zahl.
Und weil false zurückkommt, prüfst du mit === false und nicht mit !. Bei einer eingegebenen
0 wäre das sonst der Fehler, der einen halben Nachmittag kostet: 0 ist gültig, aber PHP hält es
für falsch.
Warum der Browser die Prüfung nicht übernimmt
Im HTML-Kurs hast du required, type="email" und min kennengelernt, und die sind auch weiterhin
richtig. Sie sind allerdings ausschließlich eine Bequemlichkeit für den Besucher: Der Browser sagt
sofort Bescheid, statt ihn eine Seite weiterzuschicken.
Aufhalten tun sie niemanden. Wer die Anfrage nicht über dein Formular schickt, sondern selbst
zusammenbaut, sieht dein Markup nie. Und das ist nicht einmal böse gemeint, das macht jedes Werkzeug
so, mit dem man Schnittstellen ausprobiert. Eines davon hast du im Terminal: curl mit -d schickt
einen POST mit genau den Feldern, die du ihm nennst, an jedem Formular vorbei. Die Prüfliste macht
seit Abschnitt 10 nichts anderes, und in der Aufgabe unten tust du es einmal selbst.
Die Regel lautet deshalb: Der Browser prüft für den Besucher, der Server prüft für dich. Beides gehört hin, und nur eines davon zählt.
Alle Fehler auf einmal
<?php
// Dieselben drei Pruefungen, zweimal ausgewertet. Links bricht die
// Auswertung beim ersten Fehler ab, rechts sammelt sie alles ein.
// Schick das Formular leer ab, dann siehst du den Unterschied.
$istPost = $_SERVER["REQUEST_METHOD"] === "POST";
$name = trim($_POST["name"] ?? "");
$email = trim($_POST["email"] ?? "");
$menge = trim($_POST["menge"] ?? "");
$alle = [];
if ($name === "") {
$alle[] = "Bitte trag deinen Namen ein";
}
if (filter_var($email, FILTER_VALIDATE_EMAIL) === false) {
$alle[] = "Die E-Mail-Adresse stimmt nicht";
}
if (filter_var($menge, FILTER_VALIDATE_INT) === false) {
$alle[] = "Die Menge muss eine ganze Zahl sein";
}
$erster = $alle === [] ? [] : [$alle[0]];
?>
<!doctype html>
<html lang="de">
<head>
<meta charset="utf-8">
<title>Fehler sammeln</title>
<style>
.spalten { display: flex; gap: 2rem; }
</style>
</head>
<body>
<h1>Ein Fehler oder alle</h1>
<form method="post" action="/">
<p><label>Name: <input type="text" name="name"></label></p>
<p><label>E-Mail: <input type="text" name="email"></label></p>
<p><label>Menge: <input type="text" name="menge"></label></p>
<button type="submit">Absenden</button>
</form>
<?php if ($istPost) { ?>
<div class="spalten">
<div>
<h2>Beim ersten Fehler abgebrochen</h2>
<ul>
<?php foreach ($erster as $meldung) { ?>
<li><?= htmlspecialchars($meldung) ?></li>
<?php } ?>
</ul>
</div>
<div>
<h2>Alles eingesammelt</h2>
<ul>
<?php foreach ($alle as $meldung) { ?>
<li><?= htmlspecialchars($meldung) ?></li>
<?php } ?>
</ul>
</div>
</div>
<?php } ?>
</body>
</html> Beim ersten Fehler abzubrechen, ist die naheliegende Bauart und die unangenehmste Bedienung, die man sich ausdenken kann: Der Besucher schickt ab, korrigiert eine Kleinigkeit, schickt ab, korrigiert die nächste. Bei drei Feldern sind das drei Runden.
Die bessere Form ist ein Array. Jede Prüfung, die scheitert, hängt ihre Meldung hinten an, und danach fragst du einmal, ob etwas darin steht. Ist das Array leer, war alles in Ordnung, und du darfst weiterarbeiten. Genau diese Form baust du in der Aufgabe, und ab Lektion 11.5 begleitet sie dich durch den Rest des Kurses.
Zum Mitnehmen
Drei Fragen stellst du an jedes Feld, und sie sind wirklich verschieden: Ist es da? Hat es die richtige Form? Ist der Wert plausibel? Wer eine davon überspringt, merkt es meistens erst, wenn ein Datensatz in der Datenbank steht, mit dem niemand mehr etwas anfangen kann.
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.