PHP PDO (PHP Data Objects)
Datenbankschnittstellen in PHP
-
mysql - seit PHP 7 entfernt ( veraltet / unsicher)
-
mysqli - MySQL-spezifisch, prozedural + OOP
-
PDO (PHP Data Objects) - abstrakte Datenbankschnittstelle, unterstützt mehrere DB-Treiber (MySQL, PostgreSQL, SQLite, MSSQL, Oracle, ...)
-
DBx
-
SDO
PDO
DSN (Data Source Name)
// MySQL
$dsn = 'mysql:host=localhost;dbname=datenbank;charset=utf8mb4';
// SQLite
$dsn = 'sqlite:datenbank.db';
// PostgreSQL
$dsn = 'pgsql:host=localhost;port=5432;dbname=datenbank';
Verbindung
Verbindung herstellen ... mit Optionen direkt im Konstruktor
$pdo = new PDO($dsn, 'username', 'passwort', [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, // Exceptions bei Fehlern
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, // Standard: assoziatives Array
PDO::ATTR_EMULATE_PREPARES => false // echte Prepared Statements
]);
... oder nachträglich setAttribute
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
einfache Query
nur wenn keine Parameter benötigt werden
$pdo->query("SELECT * FROM users WHERE id = 123");
Achtung !!!
$pdo->query("SELECT * FROM users WHERE name = '$name'");
Warum ist das gefährlich?
Benutzereingaben werden direkt in den SQL-String eingebaut
Angreifer können SQL-Befehle injizieren ... SQL-Injections!
'; DROP TABLE users;--
Prepared Statements
Parameter placeholder ?
$stmt = $pdo->prepare("SELECT * FROM users WHERE email = ?");
$stmt->execute(['email@example.com']);
$user = $stmt->fetch();
benannte Parameter :name
$stmt = $pdo->prepare("SELECT * FROM users WHERE id = :id AND status = :status");
$stmt->execute([':id' => 1, ':status' => 'aktiv']);
Prepared Statements ?
-
Parameter werden separat vom SQL-Template übergeben
-
DB-Treiber interpretiert Werte als Daten, nie als SQL-Code
-
Automatische Escapung durch das DBMS
-
Performance bei wiederholten Queries (Wiederverwendung möglich)
Binding (manuell)
Parameter in execute Funktion unterstützt keine Parameterüberprüfung
🡲 bindParam(param, var, data_type)
$stmt = $pdo->prepare("INSERT INTO users (name, email) VALUES (?, ?)");
$stmt->bindValue(1, 'Max', PDO::PARAM_STR);
$stmt->bindValue(2, 'max@test.de', PDO::PARAM_STR);
$stmt->execute();
// oder direkt beim Execute
$stmt->execute(['Max', 'max@test.de']);
| Konstante | Typ |
|---|---|
PDO::PARAM_BOOL |
Boolean |
PDO::PARAM_INT |
Integer |
PDO::PARAM_STR |
String |
PDO::PARAM_LOB |
Large Object (Bild, Audio, ...) |
PDO::PARAM_NULL |
NULL |
Fetch-Möglichkeiten
// assoziatives Array
$row = $stmt->fetch(PDO::FETCH_ASSOC);
// numerisches Array
$row = $stmt->fetch(PDO::FETCH_NUM);
// beides kombiniert (assoziativ + numerisch)
$row = $stmt->fetch(PDO::FETCH_BOTH);
// als Objekt (stdClass)
$row = $stmt->fetch(PDO::FETCH_OBJ);
// eigene Klasse instanziieren
$row = $stmt->fetch(PDO::FETCH_CLASS, 'User');
// Schluessel-Wert-Paare (erste Spalte = Key, zweite = Value)
$options = $stmt->fetchAll(PDO::FETCH_KEY_PAIR);
Schleifen für Fetch
$stmt = $pdo->query("SELECT id, name, email FROM users");
// foreach direkt auf Statement - empfohlen
foreach ($stmt as $row) {
echo $row['name'];
}
// while + fetch() – klassisch
while ($row = $stmt->fetch()) {
echo $row['name'];
}
// ... fetch-Status ueberpruefen
while (($row = $stmt->fetch()) !== false) {
// ...
}
// fetchAll() – alle auf einmal (bei kleinen Ergebnissen)
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
foreach ($rows as $row) {
// ...
}
sonstige Zusätze
// Transaktionen
$pdo->beginTransaction();
$pdo->exec("INSERT INTO ... ");
$pdo->commit();
// bei Fehler: $pdo->rollBack();
// letzte eingefuegte ID
$lastId = $pdo->lastInsertId();
// betroffene Zeilen (UPDATE/DELETE)
$count = $stmt->rowCount();
// Fehlerbehandlung – Exception-Modus
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
// Fehler-Info auslesen
$error = $stmt->errorInfo();
// Attribut setzen / nachfragen
$pdo->getAttribute(PDO::ATTR_DRIVER_NAME); // z.B. 'mysql'
// SQLSTATE-Code
$sqlstate = $stmt->errorCode();
Fehlerbehandlung
try {
$pdo = new PDO($dsn, $user, $pass);
} catch (PDOException $e) {
die("Connection failed: " . $e->getMessage());
}