Formulare: HTML und PHP
Lösung geprüft
Die Aufgabe der heutigen Stunde ist die Kommunikation zwischen HTML und PHP! Bis jetzt stand die Abfrage fest im Code. Jetzt soll der Benutzer selbst eingeben können, wonach gesucht wird – und dafür braucht es ein Webformular.
Aufgabe 3: Erzeugung einer Testausgabe von $_POST.
Die Kommunikation erfolgt über Webformulare. Es gibt zwei Methoden zur
Übertragung der Eingaben aus HTML-Formen: GET und POST. Bei der
GET-Methode werden die Parameter an den Pfad drangehängt. Die Daten
werden im Klartext übertragen und in Log-Files abgespeichert. Die Daten
werden im Array $_GET gespeichert. Bei der POST-Methode
sind die Eingaben nur im Array $_POST gespeichert. Für
sensible Daten darf nur die Post-Methode verwendet werden.
Erzeugen Sie eine HTML-STRICT-1.0-Datei posttest.html mit
Scriptly. Erzeugen Sie eine Datei posttest.php. Führen Sie
einen Test durch.
Aufgabe 4: Erstellung einer Suchabfrage. Öffnen Sie
die Datei posttest.html und speichern Sie sie unter
suchanfrage.html. Erzeugen Sie eine Datei
abfrage.php. Führen Sie einen Test durch.
GET oder POST?
| GET | POST | |
|---|---|---|
| Wo stehen die Daten | hinten in der URL: seite.php?name=Ritter | im Rumpf der Anfrage, unsichtbar |
| In PHP | $_GET['name'] | $_POST['name'] |
| Sichtbar für den Benutzer | ja, in der Adresszeile | nein |
| Landet im Verlauf und in Logdateien | ja | nein |
| Als Lesezeichen speicherbar | ja | nein |
| Für sensible Daten | nie | ja |
Der entscheidende Satz aus der Aufgabe: für sensible Daten darf nur POST verwendet werden. Ein Passwort per GET zu schicken heißt, dass es im Browserverlauf, in den Server-Logdateien und in jedem Proxy dazwischen im Klartext steht – und dort bleibt es auch.
Aufgabe 3 – Der POST-Test
<body>
<form action="posttest.php" method="post">
<p>
<label for="suchbegriff">Suchbegriff:</label>
<input type="text" name="suchbegriff" id="suchbegriff" />
<input type="submit" value="Abschicken" />
</p>
</form>
</body>
<body>
<?php
/**
* Testausgabe des $_POST-Arrays
* @meininfokurs.cmrg.site
*/
echo "Das komplette POST-Array:<br />";
print_r($_POST);
echo "<br /><br />Nur der Suchbegriff:<br />";
echo $_POST['suchbegriff'];
?>
</body>
Zwei Stellen müssen zusammenpassen, sonst kommt nichts an:
action="posttest.php"im Formular sagt, welche Datei die Daten bekommtname="suchbegriff"im Eingabefeld bestimmt den Schlüssel – in PHP heißt es dann genau so:$_POST['suchbegriff']
Das name-Attribut ist der wichtigste Teil. Ohne
name wird das Feld beim Abschicken einfach ignoriert, und
$_POST bleibt leer – ohne jede Fehlermeldung. Das
id-Attribut hat damit nichts zu tun, das ist nur für das
<label> und für CSS da.
Das komplette POST-Array:
Array ( [suchbegriff] => Ritter )
Nur der Suchbegriff:
Ritter
Aufgabe 4 – Die Suchabfrage
<body>
<h1>Schülersuche</h1>
<form action="abfrage.php" method="post">
<p>
<label for="nachname">Nachname:</label>
<input type="text" name="nachname" id="nachname" />
<input type="submit" value="Suchen" />
</p>
</form>
</body>
<body>
<?php
/**
*
* Suchabfrage mit Prepared Statement
*
* @version 1.0 vom 23.05.2019
* @meininfokurs.cmrg.site
*/
$pdo = new PDO('mysql:host=localhost;dbname=schule', 'root', '',
array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8"));
$nachname = $_POST['nachname'];
// Prepared Statement: der Suchbegriff wird NICHT in den SQL-Text geklebt,
// sondern getrennt uebergeben. Der Platzhalter ist das Fragezeichen.
$sth = $pdo->prepare("SELECT * FROM schüler WHERE nachname = ?");
$sth->execute(array($nachname));
$treffer = $sth->fetchAll();
if (count($treffer) == 0) {
echo "Kein Schüler mit dem Nachnamen <b>".htmlspecialchars($nachname)."</b> gefunden.";
} else {
echo "<table border='1'>";
echo "<tr><th>ID</th><th>Nachname</th><th>Vorname</th><th>Ort</th></tr>";
foreach ($treffer as $row) {
echo "<tr>";
echo "<td>".$row['id']."</td>";
echo "<td>".$row['nachname']."</td>";
echo "<td>".$row['vorname']."</td>";
echo "<td>".$row['ort']."</td>";
echo "</tr>";
}
echo "</table>";
}
?>
</body>
Warum das Fragezeichen und nicht die Variable
Die naheliegende Schreibweise wäre diese – und sie ist die gefährlichste Zeile, die man in PHP schreiben kann:
// NIEMALS so schreiben
$sql = "SELECT * FROM schüler WHERE nachname = '".$_POST['nachname']."'";
Hier wird die Benutzereingabe direkt in den SQL-Text geklebt. Gibt jemand
statt eines Namens ' OR '1'='1 ein, steht am Ende
WHERE nachname = '' OR '1'='1' da – und das ist für jede
Zeile wahr. Die Abfrage liefert die komplette Tabelle. Das nennt sich
SQL-Injection und ist das Thema der nächsten Stunden.
Mit prepare() und dem Fragezeichen kann das nicht passieren:
die Datenbank bekommt erst die Anfrage und danach getrennt den Wert. Was
der Benutzer eintippt, wird immer als Text behandelt und nie als
SQL-Befehl – selbst wenn ein Anführungszeichen drinsteht.
htmlspecialchars bei der Ausgabe
Beim Zurückschreiben der Eingabe steht htmlspecialchars(...)
drumherum. Das wandelt < und > in
harmlosen Text um. Sonst könnte jemand <script> in das
Suchfeld tippen, und der Browser würde es als Programm ausführen – das
wäre eine Cross-Site-Scripting-Lücke.
Merksatz für beides: Beim Hineingeben in die Datenbank schützt das Prepared Statement, beim Herausgeben auf die Seite schützt htmlspecialchars. Man braucht beides, sie ersetzen sich nicht gegenseitig.
Das Ergebnis
Sucht man nach „Ritter", kommen zwei Zeilen:
+----+----------+---------+---------+
| ID | Nachname | Vorname | Ort |
+----+----------+---------+---------+
| 3 | Jörg | Ritter | Alsbach |
| 4 | Miriam | Ritter | Alsbach |
+----+----------+---------+---------+
nachname steht „Jörg" und in
vorname steht „Ritter". Die Suche funktioniert trotzdem, man
muss nur wissen, in welcher Spalte wirklich was steht. Ein gutes Beispiel
dafür, dass man die Daten anschauen sollte und nicht nur die
Spaltennamen.