Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save Nerdmind/fb98991f28217938d783 to your computer and use it in GitHub Desktop.
Save Nerdmind/fb98991f28217938d783 to your computer and use it in GitHub Desktop.
PHP: Eine Einführung in PDO und Prepared Statements

Die PDO-Klasse ist eine tolle Klasse um Datenbankabfragen gleich viel sicherer zu machen. Wer bisher nur die prozedurale MySQL-Funktion oder objektorientierte MySQLi-Klasse verwendet hat, der muss sich ein kleines bisschen umstellen. PDO hört sich aber komplizierter an als es ist. Ich versuche hier nun mal die PDO-Klasse so gut es geht verständlich zu erklären. PDO ist die Profi-Klasse für sichere Datenbankabfragen. Mit PDO kann man wie mit den anderen beiden Funktionen auf herkömmliche Weise Datenbankabfragen an einen SQL-Server schicken. Der Unterschied ist nur die Syntax des Codes. Damit die Datenbankabfragen auch wirklich sicher und vor SQL-Injections geschützt sind, reicht es nicht aus, die normale query()-Methode zu benutzen. Diese eignet sich hervorragend für Abfragen, bei denen keine fremden Eingaben in die Abfrage geschrieben werden. Für Abfragen mit fremden Inhalten sollte immer die prepare()-Methode verwendet werden.

PDO-Verbindung zum SQL-Server herstellen

Bevor wir Abfragen an den Datenbankserver schicken können, muss natürlich zuerst eine Verbindung aufgebaut werden. Also alles schön der Reihe nach damit auch nichts ausbleibt. PDO kann übrigens nicht wie bei MySQLi objektorientiert und prozedural verwendet werden sondern nur objektorientiert. Deshalb ist es sehr von Vorteil von wenn man bereits Erfahrung mit der Syntax der objektorientierten Programmierung hat. Im folgenden schreiben wir das Konfigurationsarray, bauen die Datenbankverbindung auf und fangen die Exception falls es einen Fehler beim Verbindungsaufbau gab. Im nächsten Abschnitt folgt dann die erste Abfrage an den Datenbankserver.

$dbconfig['host'] = 'localhost';
$dbconfig['user'] = 'username';
$dbconfig['base'] = 'database';
$dbconfig['pass'] = 'password';
$dbconfig['char'] = 'utf8';

try {
    $pdo = new PDO('mysql:host='.$dbconfig['host'].';dbname='.$dbconfig['base'].';charset='.$dbconfig['char'].';', $dbconfig['user'], $dbconfig['pass']);
}
catch(PDOException $e) {
    exit('Unable to connect Database.');
}

PDO-Abfrage mit query() an den SQL-Server

Da die Datenbankverbindung aufgebaut und das PDO-Objekt instanziert wurde, kann es auch schon mit der ersten simplen Abfrage an die Datenbank los gehen. Im Beispiel frage ich einfach einen Wert von einer fiktiven Tabelle ab und lasse ihn ausgeben. Vorher müssen die Daten natürlich noch gefetcht werden. Beim fetchen kann man sich ein normales Array, ein assoziatives Array, ein Objekt und noch ein paar weitere zurückgeben lassen. Ich verwende jetzt im gesamten Artikel zur Übersichtlichkeit die normale fetch()-Methode.

// Wenn ein einziger Datensatz erwartet wird
$stmt = $pdo->query('SELECT foo FROM bar WHERE id = 1');
$row = $stmt->fetch();
echo $row['foo'];
// Wenn mehrere Datensätze erwartet werden
$stmt = $pdo->query('SELECT foo FROM bar');
while($row = $stmt->fetch()) {
    echo $row['foo'].'<br />';
}

Im vorherigen Beispiel wurde eine simple Abfrage einmal mit einem einzigen Datensatz und einmal mit mehreren Datensätzen die zurückgegeben werden, ausgeführt. Allerdings ist diese Methode nicht sicher vor fremden Benutzereingaben. Würde man beispielsweise dort einen Get-Parameter hart reinschreiben, dann wäre dort auf jeden Fall eine SQL-Injection möglich. Diese Abfrageart eigenet sich also nur für Abfragen, bei denen wirklich keine Eingaben von außen in den Query gelangen können.

PDO Prepared Statements

Um zu verhindern das böse Jungs SQL-Injections ausführen, können wir Prepared Statements benutzen. Die prepare()-Methode sollte man auch immer dann nutzen, wenn fremde Eingaben mit in den Query geschrieben werden. Bei Prepared Statements wird anstatt der Variable eine Kennzeichnung an die entsprechende Stelle des Querys geschrieben. Die SQL-Abfrage wird danach über eine spezielle Methode namens execute() an den Server geschickt an die dann ein Array mit den Kennzeichnungen und den tatsächlichen Werten übergeben wird.

$stmt = $pdo->prepare('SELECT foo, bla FROM bar WHERE id = :paramEins AND bla = :paramZwei');
$array = array(
    ':paramEins' => $_GET['id'],
    ':paramZwei' => $_GET['bla']
);
$stmt->execute($array);

while($row = $stmt->fetch()) {
    echo $row['foo'].'<br />';
    echo $row['bla'].'<br />';
}

Meiner Meinung nach sollte das Beispiel schon verständlich genug sein. Es wird lediglich die Prepare-Methode anstatt der Query-Methode genutzt und um den SQL-Befehl an die Datenbank zu schicken wird Execute benutzt. An execute() wird dann ein Array übergeben, das die Kennzeichnungen und die dazugehörigen originalen Daten enthält. Der Rest funktioniert genau so wie ganz oben bereits erklärt.

PDO Prepared Statements mit bindParam()

Ähnlich wie im vorherigen Abschnitt lassen sich mit der bindParam()-Methode ebenfalls sichere SQL-Abfragen ausführen. Allerdings ist diese Methode etwas komplizierter. Man kann hier ebenfalls Platzhalter setzen, muss aber als zweiten Parameter eine Variable übergeben. Man darf keine Werte direkt als zweiten Parameter übergeben da dies sonst einen Fatal Error hervorruft. Als dritten Parameter kann man optional noch einen Datentyp angeben. Und wenn man will auch noch einen vierten vom Typ Integer der die Länge enthält.

$stmt = $pdo->prepare('SELECT * FROM foo WHERE bar = :eins AND bla = :zwei');
$stmt->bindParam(':eins', $_GET['bar']);
$stmt->bindParam(':zwei', $_GET['bla']);
$stmt->execute();

Das gleiche funktioniert aber nicht nur mit selbstdefinierten Platzhaltern sondern auch mit Fragezeichen. Welche Methode man benutzt, bleibt jedem selber überlassen. Aber mit den Fragezeichen wird es ein bisschen übersichtlicher als mit selbstdefinierten Platzhaltern.

$stmt = $pdo->prepare('SELECT * FROM foo WHERE bar = ? AND bla = ?');
$stmt->bindParam(1, $_GET['bar']);
$stmt->bindParam(2, $_GET['bla']);
$stmt->execute();

PDO Prepared Statements mit bindValue()

Diese Methode funktioniert genau so wie die bindParam()-Methode. Nur ist man bei der bindValue()-Methode nicht gezwungen eine Variable (also eine Referenz) als zweiten Parameter zu übegeben. Man kann hier also einen String oder einen beliebigen anderen Datentyp direkt hart als zweiten Parameter übergeben. Außerdem kann man hier keinen vierten Parameter wie bei bindParam() übergeben.

$stmt = $pdo->prepare('SELECT * FROM foo WHERE bar = ? AND bla = ?');
$stmt->bindValue(1, $_GET['bar']);
$stmt->bindValue(2, $_GET['bla']);
$stmt->execute();

Weiterführende Links

  1. PHP-Manual | Die PDO-Klasse im Überblick
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment