Q2 Datenbanken

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.

Die Aufgabenstellung lautet

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?

GETPOST
Wo stehen die Datenhinten in der URL: seite.php?name=Ritterim Rumpf der Anfrage, unsichtbar
In PHP$_GET['name']$_POST['name']
Sichtbar für den Benutzerja, in der Adresszeilenein
Landet im Verlauf und in Logdateienjanein
Als Lesezeichen speicherbarjanein
Für sensible Datennieja

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.

POST ist trotzdem nicht verschlüsselt. Die Daten sind nur nicht in der URL sichtbar; wer den Netzwerkverkehr mitliest, sieht sie genauso. Verschlüsselt wird erst durch HTTPS. POST ist also die Mindestanforderung, nicht die Lösung.

Aufgabe 3 – Der POST-Test

posttest.html
/* meininfokurs.cmrg.site */
<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>
posttest.php
/* meininfokurs.cmrg.site */
<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:

  1. action="posttest.php" im Formular sagt, welche Datei die Daten bekommt
  2. name="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.

Browser nach dem Abschicken
Das komplette POST-Array:
Array ( [suchbegriff] => Ritter )

Nur der Suchbegriff:
Ritter

Aufgabe 4 – Die Suchabfrage

suchanfrage.html
/* meininfokurs.cmrg.site */
<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>
abfrage.php
/* meininfokurs.cmrg.site */
<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:

Browser
+----+----------+---------+---------+
| ID | Nachname | Vorname | Ort     |
+----+----------+---------+---------+
|  3 | Jörg     | Ritter  | Alsbach |
|  4 | Miriam   | Ritter  | Alsbach |
+----+----------+---------+---------+
In der Testdatenbank stehen Vor- und Nachname vertauscht in den Spalten – in 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.

Aufgabe suchen

Tippe los. Strg+K öffnet die Suche von überall.

Zuletzt angesehen

Werbung