MySQLi Prepared Statements

Mit Prepared Statements aus dem MySQLi-Modul von PHP kann man bei der Interaktion mit der MySQL-Datenbank mehr Performance rausholen.

Technisch funktioniert das vereinfacht ausgedrückt, weil PHP und MySQL im normalen MySQL-Modul von PHP über ein Text-Protokoll miteinander kommunizieren, das auf beiden Seiten zusammengebaut und auf der anderen Seite dann interpretiert werden muss. Bei MySQLi umgeht man das, weil die Daten binär ausgetauscht werden, also nicht mehr aus dem Text-Protokoll herausinterpretiert werden müssen.

Nachteil ist eine wesentlich kompliziertere Handhabung.

Prepared Statements haben aber noch einen anderen Vorteil: da man die Werte direkt übergibt, sie also nicht mehr escapen und in den Query schreiben muss, ist man sicherer vor Injections.

Auch bei MySQLi verbinden wir uns im gewohnten Weg zur Datenbank, neu ist hier, dass wir eine OOP-API geliefert bekommen. Statt die mysql_connect Funktion aufzurufen, instanzieren wir ein mysqli-Objekt:

<?php
    $mysqli = new mysqli("localhost", "db_benutzer", "db_password", "db_name");
 
    $name = 'Otto von Oberunteringen';
	$stadt = 'Wien';
 
    $stmt = $mysqli->prepare('SELECT id,email,strasse FROM benutzer WHERE name=? AND stadt=?');
    $stmt->bind_param('ss', $name, $stadt);
    $stmt->execute();
    $stmt->bind_result($id, $email, $passwort);
    $stmt->fetch();
    $stmt->close();
 
    echo "Der Benutzer $name mit der id Nr. $id hat die E-Mail $email und wohnt in der Straße $strasse.";
 
    $mysqli->close();
?>

Nehmen wir an, wir haben eine Benutzer-Tabelle und suchen nun darin nach „Otto von Oberunteringen“ aus Wien. Wir haben seinen Namen in der Variabel $name hinterlegt und die Stadt in $stadt.

Normalerweise würden wir jetzt mysql_query aufrufen und mit einem SQL-Befehl á la WHERE name="'.mysql_real_escape_string($name).'" danach suchen. Wie du oben im Code aber siehst, steht bei Prepared Statements nur ein Fragezeichen im SQL-Befehl: WHERE name=?

Das liegt daran, weil wir in diesem Fall die Variabeln direkt übergeben, sie also nicht als Text in den SQL-Query schreiben. Für die Übergabe ist die Methode bind_param zuständig. Dieser Methode übergibt man zuerst einen Text-Parameter wo man mit Buchstaben erklären muss welchen Typ die einzelnen Variabeln haben. Für Strings, gibt man hier ein kleines s und für Zahlen ein kleines i an. Wir haben zwei Strings, also: ss.

Danach füllt man die Variabeln mit den Werten nach denen man sucht in genau der Reihenfolge ein, wie die Fragezeichen im SQL-Query sind.

Über den Aufruf execute() wird unser Statement nun verarbeitet.

Auch die Auswertung ist mit mysqli anders: während wir im Normalfall nun mit mysql_fetch_arraymysql_fetch_assoc oder mysql_fetch_object die Ausgabe der Datenbank verarbeiten würden, füllt und MySQLi das Ergebnis gleich direkt in Variabeln, die wir in bind_result() nacheinander angeben.

Es füllt die Variabeln in genau der Reihenfolge ein, die wir bei SELECT id,email,strasse FROM angegeben haben.

Das war die Variante mit einem Datensatz, hier noch das ganze mit while-Schleife:

<?php
    $mysqli = new mysqli("localhost", "db_benutzer", "db_password", "db_name");
 
    $name = 'Otto von Oberunteringen';
    $stadt = 'Wien';
 
    $stmt = $mysqli->prepare('SELECT id,email,strasse FROM benutzer WHERE name=? AND stadt=?');
    $stmt->bind_param('ss', $name, $stadt);
    $stmt->execute();
    $stmt->bind_result($id, $email, $passwort);
 
    while ($stmt->fetch()) {
        echo "Der Benutzer $name mit der id Nr. $id hat die E-Mail $email und wohnt in der Straße $strasse.";
    }
 
    $stmt->close();
    $mysqli->close();
?>