Datensätze über SQL-Anweisungen einfügen

Die SQL-Anweisung für das Einfügen von Datensätzen hat folgenden Aufbau:

INSERT INTO kontakte (vorname, nachname, anmerkung, erstellt) 
VALUES ('Axel', 'Maier', 'Mehr Infos zu Axel M.', NOW());

Diese Anweisung können wir jetzt über phpMyAdmin und den Reiter SQL ausführen lassen. Das sollte dann folgende Bild ergeben und einen weiteren Datensatz:

Wenn wir die SQL-Anweisung über PHP ausführen lassen wollen, dann brauchen wir unser schon bekannte query:

$erg->query(
"INSERT INTO kontakte (vorname, nachname, anmerkung, erstellt) 
VALUES ('Axel', 'Maier', 'Mehr Infos zu Axel M.', NOW());
");
echo $erg->affected_rows;

Als Ergebnis sollten wir nun 1 auf dem Bildschirm erhalten. Es ist ein Datensatz betroffen – und zwar der neu angelegte Datensatz.

Nutzer-Eingaben: Exkursion Sicherheit

SQL-Injektion-Versuche sind unangenehme Erscheinungen. Manche Nutzer wollen Anwendungen korrumpieren oder auch den ganzen Server übernehmen. Daher wird auch über den Weg von Nutzereingaben probiert, ob hier Tür und Tor offensteht. Daher müssen wir Eingaben von Nutzern absichern, damit nichts Böses passiert.

Schauen wir uns an, was passieren kann. Wir erstellen in unserem Code eine Variable mit dem Namen $vorname. Diese solle die Nutzereingabe darstellen, die „missbraucht“ wird.

Diese Variable wird über die SQL-Anweisung in die Datenbank eingetragen:

$vorname = "Bösewicht";
$db->query("
INSERT INTO kontakte (vorname, nachname, anmerkung, erstellt) 
VALUES ('{$vorname}', 'Maier', 'Mehr Infos zu Axel M.', NOW());
");
echo $db->affected_rows; 

Die geschweifte Klammer um die Variable bewirkt, dass trotz der einfachen Anführungszeichen die Variable ausgewertet wird und somit für die SQL-Anweisung zur Verfügung steht.

Hier wird jetzt ungeprüft die Nutzereingabe in die Datenbank eingetragen, was natürlich ins Auge gehen kann!

Wenn wir jetzt diese Anweisung ausführen, erhalten wir einen weiteren Datensatz mit dem Vornamen „Bösewicht“. Unsere PHP-Anweisungen funktionieren also.

Unsere Daten kommen über Formulareingaben rein. Formulare (wir erstellen später noch eins) senden die Daten über GET oder POST, damit die eingetragenen Daten zur Verfügung stehen. Der einfachhalber nehmen wir GET an, damit es im Folgenden einfacher zum Demonstrieren ist. Technisch ist POST aber genauso unsicher wie GET, daher muss jegliche Form abgesichert werden!

$vorname = $_GET['vorname'];
$db->query("
INSERT INTO kontakte (vorname, nachname, anmerkung, erstellt) 
VALUES ('{$vorname}', 'Maier', 'Mehr Infos zu Axel M.', NOW());
");
echo $db->affected_rows; 

Jetzt können wir unser Formular simulieren, indem wir die URL im Browser ergänzen um „?vorname=Schlitzohr“. Meine Beispiel-URL sieht dann komplett wie folgt aus:

http://localhost:8888/adressbuch/index.php?vorname=Schlitzohr

In die Datenbank wird nun der Vorname „Schlitzohr“ eingetragen.

Soweit, so schlecht. Was passiert aber, wenn das Schlitzohr Beispielsweise ein einfaches Anführungszeichen später im Formular einträgt bzw. jetzt über die URL übergeben wird.

http://localhost:8888/adressbuch/index.php?vorname=Schlitzohr’

Wenn wir es testen, sieht man, dass irgendwie nichts passiert.

Warum ist das so?

Wenn wir uns die zusammengebaute SQL-Anweisung ansehen, wird klar, dass diese gegen die Wand fährt.

In $vorname steckt: Schlitzohr'

Somit wir aus

INSERT INTO kontakte (vorname, nachname, anmerkung, erstellt) 
VALUES ('{$vorname}', 'Maier', 'Mehr Infos zu Axel M.', NOW());

dann

INSERT INTO kontakte (vorname, nachname, anmerkung, erstellt) 
VALUES ('Schlitzohr'', 'Maier', 'Mehr Infos zu Axel M.', NOW());

Unsere SQL-Anweisung verliert ihre Begrenzung des Feldes, da 2 x ein einfaches Anführungszeichen kommt. Das ist natürlich schlecht.

Daher wird die Eingabe überprüft und entsprechend korrigiert. Es kommt ja durchaus vor, dass Namen Anführungszeichen haben.

Also lassen unsere Variable über die Datenbankfunktion real_escape_string laufen und die Anführungszeichen werden maskiert und somit sauber eingetragen:

$vorname = $db->real_escape_string($_GET['vorname']);
$db ->query("
INSERT INTO kontakte (vorname, nachname, anmerkung, erstellt) 
VALUES ('{$vorname}', 'Maier', 'Mehr Infos zu Axel M.', NOW());
");
echo $db ->affected_rows;

Jetzt passt es auch für alle Musketiere à la d'Artagnan bzw. dem irischen O'Connor.

Schaut man es sich nun in PHP an, was bei real_escape_string passiert, lässt man sich einfach die Variable $vorname ausgeben:

$vorname = $db->real_escape_string($_GET['vorname']);
echo "<p>". $vorname . "</p>";
$db->query("
INSERT INTO kontakte (vorname, nachname, anmerkung, erstellt) 
VALUES ('{$vorname}', 'Maier', 'Mehr Infos zu Axel M.', NOW());
");
echo $db->affected_rows;

Testen wir es mit dem irischen Nachnamen O'Connor

http://localhost:8888/adressbuch/index.php?vorname=O'Connor

Und nun sieht man sehr schön, dass der Inhalt maskiert wird, d.h. vor dem einfachen Anführungszeichen taucht ein Backslash auf „O’Conner“ auf.

Jetzt sollten wir noch versehentliche Leerzeichen am Anfang und am Ende abfangen und nur bei vorhandenen Werte einen Datenbankeintrag machen:

$vorname = $db->real_escape_string(trim($_GET['vorname']));
echo $vorname;
if(isset($vorname)) {
    $db->query("
    INSERT INTO kontakte (vorname, nachname, anmerkung, erstellt) 
    VALUES ('{$vorname}', 'Maier', 'Mehr Infos zu Axel M.', NOW());
    ");
    echo $db->affected_rows;
}