December 22, 2012

Prepared Statements: Schnellere Queries mit PHP und mysqli

Was sind Prepared Statements?

Prepared Statements (deutsch: “vorbereitete Anweisungen”) sind vorbereitete Datenbank-Queries ohne Werte für die einzelnen Parameter. Statt der wirklichen Parameterwerte werden in der Anweisung Variablen verwendet, die dann zur Laufzeit befüllt werden.

Warum Prepared Statements nutzen

Die vorbereiteten Anweisungen haben mehrere Vorteile:

Mehr Geschwindigkeit bei wiederholter Ausführung

Ein Prepared Statement ist ein Anweisungstemplate. So ein Template wird beim Aufruf der prepare()-Methode analysiert, kompiliert und optimiert. Ab dann wird bei wiederholten Anweisungen immer dieses vorkompilierte und optimierte Template mit den geänderten Werten benutzt. Dadurch verbrauchen Prepared Statements wesentlich weniger Ressourcen und sind schneller als herkömmliche Standard-Queries.

Schutz gegen SQL Injections

Mit Prepared Statements sind keine SQL Injections möglich, solange die Statements intern generiert werden. Mit ‘intern’ meine ich Stellen im Code, über die du die Kontrolle hast, d.h. keine Komponenten des Statements werden aus externen Quellen generiert. Die Variablen müssen nicht escaped werden, die Datenbank prüft selbst auf Sauberkeit.

Ablauf von Prepared Statements

Ein Prepared Statement besteht aus 2 Teilen: der Vorbereitung und der Ausführung.

Vorbereitung:

<?php
// Datenbankverbindung, falls noch nicht vorhanden
$handler = new mysqli("zu","gangs","da","ten");
// Prepare Statement
// Hier wird das Query von der Datenbank analisiert, kompiliert und vorbereitet
$stmt = $handler->prepare("Anweisung, z.B. SELECT, INSERT,... mit Variablen, z.B. WHERE id = ?");
// Variable(n) aus dem Prepare Statement mit PHP Variable(n) binden
// ? wird zum Zeitpunkt der execute()-Methode mit dem Wert von $phpVar (1. Parameter 's' = String) ersetzt
$stmt->bind\_param('s', $phpVar);
?>

Ausführung:

<?php
// Der vorher gebundenen Variable $phpVar einen Wert zuweisen
foreach ($foundIds as $phpVar) {
    // Das Prepared Statement ausführen
    $stmt->execute();
    // Auf Ergebnis prüfen und holen
    if (!($res = $stmt->get\_result())) {
        // Fehlerbehandlung
    } else {
        $results\[$foundId\] = $res->fetch\_assoc();
    }
}
 // Schliessen
$stmt->close();
?>

Prepared Statements: Beispiele

Beispiel: SELECT als Prepared Statement

<?php

// Schritt 1: Datenbankverbindung
$handler = new mysqli("dbhost", "dbuser", "dbpass", "db");

// Schritt 2: Statement Vorbereiten
$stmt = $handler->prepare("SELECT \* FROM people WHERE (name = ?)");

// Schritt 3: den Platzhalter mit einem String "binden"
$stmt->bind\_param('s', $name);

// Schritt 4: $name belegen
$name = "kushellig";

// Schritt 5: Das Query ausführen
$stmt->execute();

// Schritt 6: Daten zuweisen
if (!$stmt->get\_result()) {
    var\_dump("no data in 'people' with name = '$name'");
    // Schritt 6.1: Query mit einem anderen Wert wiederholen
    $name = "jan";
    $stmt->execute();
    // ...
} else {
    // Ausgabe des Ergebnisses
    var\_dump($res->fetch\_all());
}

// Schritt 7: schliessen
$stmt->close();

?>

Beispiel: INSERT als Prepared Statement

<?php
// Query Vorbereitung
$stmt = $handler->prepare("INSERT INTO user (id, name) VALUES (?, ?)");
// Platzhalter binden ("is" = integerstring)
$stmt->bind\_param("is", $id, $name);
// $id einen Wert zuweisen
$id = 123;
// $name einen Wert zuweisen
$name = "Klaus";
// Ausführen
$stmt->execute();
// Schliessen
$stmt->close();
?>

Fazit

Gerade am Anfang ist das Benutzen von Prepared Statements gewöhnungsbedürftig und scheint umständlich. Doch wenn man das Schema erst einmal verstanden und verinnerlicht hat, ist der Umgang mit Prepared Statements ganz easy und natürlich. Warum mysqli aber eigentlich doch nicht das Gelbe vom Ei ist, zeigt dir der Artikel Prepared Statements mit PDO”).

Ist noch etwas unklar? Fehlt dir etwas in diesem Artikel? Hilf mir, ihn zu verbessern, und hinterlasse unten bitte ein Kommentar oder bewerte ihn!

Weiterführende Quellen