Homepage-Webhilfe Event-Banner

Datenbankzugriffe

Um mit einer Datenbank zu kommunizieren, bietet PHP grundsätzlich 3 verschiedene Module (APIs): mysql, mysqli und PDO. mysql und mysqli können leidglich für die Kommunikation mit MySQL und MariaDB genutzt werden, nicht jedoch z. B. mit MSSQL. Des Weiteren ist die mysql-API seit PHP-Version 5.5 als veraltet gekennzeichnet und wurde in PHP 7 entfernt. Die PDO-API kann von verschiedenen Treibern implementiert werden. Dies hat den Vorteil, dass die PDO-API für unterschiedliche Datenbanktypen genutzt werden kann. Aktuell sind unter anderem Treiber für MySQL, MSSQL, SQLite und PostgreSQL verfügbar. Welche Treiber aktuell verfügbar sind, können Sie in der Ausgabe von phpinfo() im Abschnitt „PDO“ sehen. Die mysqli- und PDO-API haben beide eine objektorientierte Schnittstelle. Auf Grund der Vorteile der PDO-API in Bezug auf die Unterstützung unterschiedlicher Datenbanktypen werden wir in diesem Thema ausschließlich die PDO-API behandeln und empfehlen Ihnen, diese auch in Ihrem Projekt zu verwenden.

Wichtig: Für dieses Thema sind Vorkenntnisse in der Datenbanksprache SQL notwendig. Falls Sie über diese nicht verfügen, empfehlen wir Ihnen, zuerst den SQL-Crashkurs zu lesen.


Um mit einer Datenbank eine Verbindung aufzubauen, müssen Sie ein Objekt der Klasse PDO instanziieren. Als Parameter übergeben Sie den sogenannten DSN (Data Source Name), welcher Informationen über die Verbindung enthält, und optional einen Benutzernamen, ein Passwort und ein assoziatives Array mit Optionen. Die Optionen können im Nachhinein noch mit der Methode setAttribute() gesetzt werden. Dieser wird das Attribut (dafür werden Konstanten der PDO-Klasse genutzt) und ein Wert (evtl. auch über Konstanten) übergeben. Ein Aufruf der Methode setAttribute() ist natürlich erst nach der Objektinstanziierung möglich.

Jede DSN-Zeichenkette verfügt am Anfang über eine Kennung für das jeweilige Datenbanksystem (z. B. mysql für MySQL, pgsql für PostgreSQL und sqlsrv für Microsoft SQL Server). Anschließend folgen ein Doppelpunkt und die einzelnen Eigenschaften, welche sich aus einem Namen, einem Gleichheitszeichen und dem Wert zusammensetzen. Mehrere Eigenschaften werden dabei mit Semikolon getrennt. Die Eigenschaften unterscheiden sich je nach Datenbanktyp. In der DSN-Zeichenkette kann neben der Adresse des Datenbankservers auch die zu verwendende Datenbank selektiert werden. Das folgende Beispiel zeigt eine DSN für MySQL. Hier wird neben dem Host und der Datenbank auch noch ein Zeichensatz festgelegt.

mysql:host=localhost;dbname=meineDatenbank;charset=utf8

Der DSN für PostgreSQL-Datenbanksysteme sieht fast gleich aus. Die Angabe des Zeichensatzes ist hier jedoch nicht möglich. Der Zeichensatz kann daher nur im Nachhinein über das Ausführen des SQL-Statements SET NAMES 'UTF-8' gesetzt werden.

pgsql:host=localhost;dbname=meineDatenbank

Zuletzt wollen wir noch auf den DSN für Microsoft SQL Server eingehen. Hier heißen, wie es bei Microsoft oft der Fall, die Eigenschaften anders. Genauso, wie bei PostgreSQL-Datenbanken auch, ist es hier nicht möglich, den Zeichensatz direkt zu setzen. Daher ist auch hier auf die Verwendung des oben genannten SQL-Statements zurückzugreifen.

sqlsrv:Server=localhost;Database=meineDatenbank

Um eine Datenbankverbindung wieder zu trennen, muss die Variable, in welcher die Instanz der Datenbank gespeichert wurde, lediglich auf null gesetzt werden. Die Ressourcen und die Verbindung zur Datenbank werden dann durch PHP automatisch getrennt und freigegeben. Wird die Datenbank-Verbindung nicht explizit getrennt, so geschieht dies automatisch beim Skriptende. Das folgende Beispiel zeigt einen vollständigen Code zum Aufbau einer Datenbankverbindung zu einem MySQL-Server.

<?php
try
{
	$db = new PDO('mysql:host=localhost;dbname=hwhtest;charset=utf8', 'root', '');
	
	echo 'Verbindung aufgebaut';
	
	$db = null;
}
catch (PDOException $ex)
{
	echo 'Meldung: '.$ex->getMessage();
}
?>
Vorschau

Wichtig: Schlägt die Verbindung zum Datenbank-Server fehl, so wird eine Ausnahme der Klasse PDOException geworfen. Diese sollte unbedingt abgefangen werden, da andernfalls ein fataler PHP-Fehler ausgelöst wird, was einen Skriptabbruch auslöst. Zudem werden u. U. sensible Informationen wie Benutzername und Passwort ausgegeben. Besteht die Verbindung erst einmal, so werden von der PDO-Klasse standardmäßig keine Exceptions mehr geworfen, sondern nur noch Fehlercodes gesetzt, welche mittels der Funktion errorCode() abgerufen werden können. Erweiterte Fehlerinformationen können mittels der Methode errorInfo() abgerufen werden. Das Verhalten bei Fehlern kann jedoch mit der Option ATTR_ERRMODE geändert werden.


Um einen SQL-Befehl (zumeist als SQL-Statement bezeichnet) auszuführen, benötigen wir die Methode query(). Als Parameter wird dieser das SQL-Statement übergeben. Wird der Befehl erfolgreich ausgeführt, so wird eine Instanz der Klasse PDOStatement zurückgegeben. Auf deren Verwendung gehen wir später ein. Schlägt das Ausführen des Statements fehl, so wird false zurückgegeben.

<?php
try
{
	$db = new PDO('mysql:host=localhost;dbname=hwhtest;charset=utf8', 'root', '');
	
	if ($db->query('UPDATE `php-tutorial-kunden` SET `Nachname`=\'Schulze\' WHERE `Nummer`=6') !== false)
		echo 'Befehl ausgeführt!';
	else
	{
		echo '<pre>';
		print_r($db->errorInfo());
		echo '</pre>';
	}
	
	$db = null;
}
catch (PDOException $ex)
{
	echo 'Meldung: '.$ex->getMessage();
}
?>
Vorschau

Wollen Sie Datensätze aus einer Datenbank abrufen, so nutzen wir ebenfalls die Methode query(). Damit wird jedoch nur das Statement ausgeführt und noch keine Daten abgeholt. Deshalb wollen wir uns jetzt mit dem PDOStatement-Objekt, welches von der Methode query() zurückgegeben wird, beschäftigen. Die Klasse PDOStatement bietet 3 wichtige Funktionen, um die Daten abzuholen: fetch(), fetchAll() und fetchColumn(). Die Funktionen fetch() und fetchAll() holen alle Spalten (bzw. alle die angegeben wurden) ab und geben diese zurück. Die Art wie diese zurückgegeben wurden, kann der Funktion als Parameter mitgegeben werden. Hierbei sind FETCH_NUM für ein indiziertes Array, FETCH_ASSOC für ein assoziatives Array und FETCH_OBJ für ein anonymes Objekt zu erwähnen. fetch() gibt das Ergebnis eines einzelnen Datensatzes zurück. fetchAll() hingegen gibt ein Array mit allen Datensätzen zurück. Im Fehlerfall, oder wenn keine Datensätze (mehr) verfügbar sind, wird false zurückgegeben. Die Funktion fetchColumn() gibt den Wert einer einzelnen Spalte eines Datensatzes zurück. Als Parameter wird der Funktion fetchColumn() die Spaltennummer übergeben. Es gilt jedoch zu beachten, dass nach dem Aufruf von fetchColumn() der Zeiger auf die nächste Zeile gesetzt wird und somit keine weitere Spalte dieses Datensatzes mehr abgerufen werden kann.

<?php
try
{
	$db = new PDO('mysql:host=localhost;dbname=hwhtest;charset=utf8', 'root', '');
	
	$result = $db->query('SELECT * FROM `php-tutorial-kunden`');
	if ($result !== false)
	{
		echo '<table>';
		echo '<tr><th>Nummer</th><th>Vorname</th><th>Nachname</th></tr>';
		while (($row = $result->fetch(PDO::FETCH_ASSOC)) !== false)
			echo '<tr><td>'.$row['Nummer'].'</td><td>'.$row['Vorname'].'</td><td>'.$row['Nachname'].'</td></tr>';
		echo '</table>';
	}
	else
	{
		echo '<pre>';
		print_r($db->errorInfo());
		echo '</pre>';
	}
	
	$db = null;
}
catch (PDOException $ex)
{
	echo 'Meldung: '.$ex->getMessage();
}
?>
Vorschau

SQL-Injektion-Icon Unter SQL-Injektion (engl. SQL Injection) versteht man das gezielte Manipulieren von SQL-Statements, um somit Daten zu verändern, zu löschen, auszuspähen oder anderen Unfug auf dem Server anzustellen.

Als erstes wollen wir daher kurz erklären, wie eine solche SQL-Injektion funktioniert. Meistens enthalten die ausgeführten SQL-Statements Daten, welche von URL-Parametern oder Formulardaten stammen. Hierzu ein Beispiel:

Aufruf:
index.php?seite=12
Resultierendes SQL:
SELECT * FROM seiten WHERE id=12

Der Aufruf kann nun so manipuliert werden, dass wir z. B. einen DROP TABLE-Befehl ausführen. Dies sieht dann z. B. so aus:

Aufruf:
index.php?seite=12;DROP+TABLE+seiten
Resultierendes SQL:
SELECT * FROM seiten WHERE id=12;DROP TABLE seiten

Doch was kann man dagegen tun? Grundsätzlich muss darauf geachtet werden, dass keine Daten direkt an die Datenbank übergeben werden. Die PDO-Klasse stellt hier die Methode quote() dar, um Sonderzeichen zu maskieren und sich somit vor SQL-Injektionen zu schützen. Hierzu ein Beispiel:

<?php
$sql = 'SELECT * FROM seiten WHERE id='.$db->quote($_GET['seite']);
?>
Um unsere Webseite für Sie optimal zu gestalten und fortlaufend verbessern zu können, verwenden wir Cookies. Durch die weitere Nutzung der Webseite stimmen Sie der Verwendung von Cookies zu. Weitere Informationen OK