WE CERTIFIED WEB DEVELOPER I PHP und MySQL · WE CERTIFIED WEB DEVELOPER I PHP und MySQL mit PDO...
Transcript of WE CERTIFIED WEB DEVELOPER I PHP und MySQL · WE CERTIFIED WEB DEVELOPER I PHP und MySQL mit PDO...
WE CERTIFIED WEB DEVELOPER I
PHP und MySQL
mit PDO
Offizielles Curriculum des Europäischen Webmasterverbandes
WE CERTIFIED WEB DEVELOPER I
PHP und MySQL
mit PDO
Art.-Nr. 011290960
Version 3.1.0 vom 21.9.2012
Autor: Marc Remolt
© webmasters akademie Nürnberg GmbH, Nürnberg, Germany
Das vorliegende Schulungsskript ist urheberrechtlich geschützt. Alle Rechte vorbehalten. Die Ver-
wendung der Texte und Abbildungen, auch auszugsweise, ist ohne schriftliche Genehmigung der
webmasters akademie Nürnberg GmbH urheberrechtswidrig und daher strafbar. Dies gilt insbe-
sondere für die Vervielfältigung, Übersetzung oder Verwendung in elektronischen Systemen sowie
für die Verwendung in Schulungsveranstaltungen.
Die Informationen in diesem Schulungsskript wurden mit größter Sorgfalt erarbeitet. Trotzdem
können Fehler nicht vollständig ausgeschlossen werden. Autoren und Herausgeber übernehmen
keine juristische Verantwortung oder irgendeine Haftung für eventuell verbliebene fehlerhafte
Angaben und deren Folgen.
Inhaltsverzeichnis
6Einführung6Inhalte6Aufgaben zur Selbstkontrolle6Fragen7Aufgaben zur Selbstkontrolle7Optionale Aufgaben7Voraussetzungen
9Objektorientierte Syntax in PHP9Konzept9Objekte
10Methoden
13Einführung in PDO13Das Problem14Einführung in PDO15Datenbank-Verbindung aufbauen15Das PDO-Objekt15Der DSN16Die Test-Datenbank seminarverwaltung17SQL-Anweisungen mit PDO ausführen17PDO::query()18PDO::errorInfo()19Ergebnisse verarbeiten: Die Klasse PDOStatement20PDOStatement::fetchAll()21PDOStatement::fetch()23Ergebnisse zählen24Eine Abfrage schließen25SQL-Wiederholung25SELECT26INSERT27UPDATE28DELETE28CREATE TABLE29ALTER TABLE29TRUNCATE TABLE29DROP TABLE
32Fortgeschrittene PDO-Funktionen32PDO-Attribute
11.11.21.2.11.2.21.2.31.3
22.12.22.3
33.13.23.33.3.13.3.23.43.53.5.13.5.23.63.6.13.6.23.6.33.6.43.73.7.13.7.23.7.33.7.43.7.53.7.63.7.73.7.8
44.1
4
33PDO-Attribute setzen34Auswahl von PDO-Attributen38Vorschlag für eine Standard-PDO-Verbindung38MySQL und Unicode38Unicode-konforme Tabellen erzeugen39Unicode-Daten aus MySQL auslesen40Prepared Statements41Einführung in prepared statements42Mehrfaches Ausführen von prepared statements43Limitierungen von Platzhaltern in prepared statements44Prepared statements mit benannten Platzhaltern45PDO und Sicherheit45SQL-Injection48PDO und SQL-Injections
50PDO in der Praxis50CRUD50Konzept51Vorbereitungen51lib/funktionen.inc.php52READ53Code: index.php54Erklärung54Code: anzeigen.php56Erklärung56CREATE56Code: anlegen.php57Erklärung58DELETE58Code: loeschen.php58Erklärung58UPDATE58Code: bearbeiten.php59Erklärung
4.1.14.1.24.1.34.24.2.14.2.24.34.3.14.3.24.3.34.3.44.44.4.14.4.2
55.15.1.15.1.25.1.35.25.2.15.2.25.2.35.2.45.35.3.15.3.25.45.4.15.4.25.55.5.15.5.2
5
Einführung in PDO
In dieser Lektion lernen Sie:
wie Sie eine Datenbank in PHP ansprechen.wie Sie SQL in PHP einsetzen.welche Vorteile PDO gegenüber den alten Zugriffsmethoden bietet.
3.1 Das Problem
Wahrscheinlich haben Sie bisher Daten Ihrer Webanwendungen in Textdateien
gespeichert. Eventuell haben Sie zu diesem Zweck auch schon die Funktion
serialize() verwendet, die auch komplexe Datenstrukturen wie Arrays oder
Objekte als Text speicherbar macht.
Diese Methode, Daten persistent zu halten, stößt bei komplexeren Datenstrukturen
oder großen Datenmengen aber sehr bald an ihre Grenzen. Große Datenmengen
machen die Zugriffe sehr langsam, das Suchen nach bestimmten Datensätzen gestal-
tet sich zunehmend als schwierig und der gleichzeitige Zugriff von zwei Clients (Web-
seiten) auf die selben Daten kann im schlimmsten Fall Teile der Daten oder den kom-
pletten Datenbestand unbrauchbar machen. Um diese Probleme zu umgehen, wur-
den Datenbanken entwickelt. Sie sind Experten im Speichern von riesigen Datenmen-
gen und komplexen Strukturen.
PHP hat schon seit Jahren eine breite Unterstützung für fast alle auf dem Markt erhält-
lichen Datenbanksysteme, seien es freie oder kommerzielle. Im Zusammenhang mit
PHP hat sich aber besonders die freie Datenbank MySQL als Favorit herauskristallisiert.
Sie werden heutzutage kaum einen Webhoster finden, der nicht zumindest PHP und
eine MySQL-Datenbank als Paket anbietet.
Doch auch die anderen Datenbanken haben ihre Existenzberechtigung. Gerade im
kommerziellen Umfeld wird eher auf die "großen" Datenbank-Systeme wie Post-
greSQL, Microsoft SQL-Server oder Oracle gesetzt. Auf der anderen Seite gibt es Daten-
banken wie SQLite, die ideal für sehr kleine, einfache Applikationen geeignet sind. Alle
diese Systeme werden von PHP natürlich hervorragend unterstützt.
3:::
3.1 Das Problem 13
Bisher war es allerdings so, dass jedes Datenbank-System in PHP eigene Funktionen
hatte, um mit der Datenbank zu kommunizieren. Die Funktion, um sich per MySQL mit
einer Datenbank zu verbinden, heißt mysql_connect() oder mysqli_connect() 2,
die für PostgreSQL pg_connect() und die für Oracle oci_connect(). Die Funktio-
nen für das Senden von SQL-Anfragen unterscheiden sich selbstverständlich ebenfalls
von Datenbank zu Datenbank.
Wenn also Ihre PHP-Applikation mehrere Datenbanken unterstützen sollte, mussten
Sie den kompletten Datenbank-Code mehrfach schreiben.
Diese Funktionen existieren (leider) immer noch, doch seit PHP 5.13 gibt es einen ein-
heitlichen Standard, um auf Datenbanken zuzugreifen: PDO.
3.2 Einführung in PDO
PDO steht für PHP Data Objects und stellt für alle von PHP unterstützten Datenban-
ken eine einheitliche Schnittstelle zur Verfügung. Das bedeutet, dass es nicht mehr für
eine Aufgabe eine Funktion pro Datenbank gibt, sondern nur noch eine einzige Funk-
tion, besser gesagt Methode, für alle Datenbanken. Das vereinfacht die Programmie-
rung mit mehreren Datenbanken ungemein. Daher ist PDO inzwischen die von den
PHP-Entwicklern offiziell empfohlene Methode, in PHP auf Datenbanken zuzugreifen.
Ein weiterer Bonus ist, dass PDO eine komplette Neuentwicklung ist und die PHP-Pro-
grammierer bei der Gelegenheit eine Menge alten Ballast abgeworfen haben. PDO
verfügt über ein objektorientiertes, modernes Interface und unterstützt sogar konse-
quent PHP-Ausnahmen zur Fehlerbehandlung.
Ein Problem löst PDO allerdings nicht. Die verschiedenen Datenbanken verwenden
zwar alle grundsätzlich SQL, haben aber alle eigene Veränderungen und Erweiterun-
gen eingebaut. Wenn Sie für mehrere Datenbanken entwickeln, dann kann es Ihnen
also trotzdem passieren, dass Sie Code mehrfach schreiben müssen.
In diesem Lernheft wird zwar PDO, aber nur in Verbindung mit der MySQL-SQL-Syntax
behandelt. Auf andere Datenbanken werde ich nicht eingehen. Kenntnisse in SQL soll-
ten Sie bereits besitzen. Es befindet sich zwar eine kleine Wiederholung im Skript, was
aber kein Ersatz für eine komplette Schulung in SQL sein kann.
2. Für MySQL bis Version 4.0 mysql_connect(), ab 4.1 mysqli_connect().
3. PDO kann ab PHP 5.0 installiert werden, erst seit Version 5.1 ist es standardmäßig dabei.
14 Einführung in PDO Lektion 3
3.3 Datenbank-Verbindung aufbauen
3.3.1 Das PDO-Objekt
PDO stellt eine objektorientierte Schnittstelle zu Datenbanken zur Verfügung. Dem-
entsprechend wird eine Datenbank auch durch ein Objekt der Klasse PDO repräsen-
tiert, das durch new erzeugt wird.
Beispiel
<?php<?php$db = newnew PDOPDO();
?>?>
Beachten Sie, dass die Klasse PDO entgegen dem sonst üblichen Standard komplett
groß geschrieben wird, da es sich um eine Abkürzung handelt.
3.3.2 Der DSN
Wenn Sie diesen Code ausführen, erhalten Sie von PHP eine Warnung, dass dem Kon-
struktor mindestens ein Parameter übergeben werden muss. Bei diesem handelt es
sich um den sogenannten DSN (Data Source Name), der beschreibt, wo die Daten-
bank zu finden ist. Dieser wird in Form eines URI4 angegeben. Die Form ist für jede der
Datenbanken spezifisch. Für MySQL besteht er aus folgenden Elementen:
Datenbank-Typ: Der Typ der Datenbank, mit der sich PDO verbinden soll. FürMySQL ist das immer der String mysql.
host: Hier können Sie den Hostnamen des Servers angeben, mit dem Sie sichverbinden wollen. Wenn sich die Datenbank auf dem gleichen Rechner wie derWebserver befindet, können Sie hier localhost verwenden.
port: Der TCP/IP-Port, auf dem die Datenbank lauscht. Der Standard-Port vonMySQL ist 3306. Dieser Parameter kann weggelassen werden.
dbname: Der Name der Datenbank, mit der Sie sich verbinden wollen.
Beispiel
Um sich also mit einer Datenbank namens mysql 5 auf dem lokalen Rechner zu verbin-
den, würde folgender Code prinzipiell funktionieren:
1.2.3.
Listing 3.1 code/lektion3/pdo1.php
:
:
:
:
4. Uniform Resource Identifier
5. Eine Datenbank mit diesem Namen existiert in jeder MySQL-Installation
3.3 Datenbank-Verbindung aufbauen 15
<?php<?php$db = newnew PDOPDO('mysql:host=localhost;dbname=mysql;port=3306');
?>?>
Wie gesagt, port dürfen Sie auch weglassen. Wenn Sie diesen Code ausführen, wird
aber trotzdem von PHP ein Fehler gemeldet:
PHP Fatal error: Uncaught exception'PDOException' with message 'SQLSTATE[28000] [1045] Access
denied for user'www-data'@'localhost' (using password: NO)' in code/lektion3/
pdo2.php:2 Stacktrace: #0 code/lektion3/pdo2.php(2):
PDO->__construct('mysql:host=loca...') #1{main} thrown in code/lektion3/pdo2.php on line 2
Die exakte Meldung, genauer der Benutzername, kann sich von System zu System
unterscheiden, aber die Aussage bleibt die selbe. Der genannte Benutzer hat keinen
Zugriff auf die Datenbank. Das liegt daran, dass die von PHP standardmäßig verwen-
deten Login-Daten leider von MySQL nicht akzeptiert werden.
MySQL ist eine Datenbank, die einen Login erfordert, bevor sie Zugang zu Ihren
Datenbanken gewährt. Daher müssen Sie dem Konstruktor von PDO noch einen
Benutzernamen und ein Passwort als weitere, optionale Parameter übergeben. In den
meisten Entwicklungsumgebungen ist das der Benutzer root mit leerem Passwort.
Achten Sie darauf, dass diese Daten weitere PHP-Parameter und nicht Teil des DSN
sind.
Beispiel
<?php<?php$db = newnew PDOPDO('mysql:host=localhost;dbname=mysql;port=3306', 'root', '');
?>?>
Jetzt sollte das PHP-Skript laufen, ohne einen Fehler zu erzeugen.
3.4 Die Test-Datenbank seminarverwaltung
Falls Sie das Lernheft Datenbankentwicklung für Webanwendungen mit MySQL bereits
durchgearbeitet haben, werden Sie die Datenbank seminarverwaltung bereits ken-
nen. Im Verlauf des Lernheftes haben Sie diese Datenbank, die eine Verwaltung von
Seminaren, Terminen und Teilnehmern simuliert, Stück für Stück aufgebaut.
1.2.3.
Listing 3.2 code/lektion3/pdo2.php
1.2.
3.
4.
5.
1.2.3.
Listing 3.3 code/lektion3/pdo3.php
16 Einführung in PDO Lektion 3
Mit dieser Datenbank werden wir nun weiterarbeiten, indem wir die SQL-Abfragen in
PHP einbinden. Ein praktisches Ziel dieses Lernhefts ist, am Ende ein funktionierendes
Webinterface zur Administration der Seminare und Termine zur Verfügung zu haben.
Die Datenbank, inklusive einiger Beispiel-Datensätze, finden Sie im Begleitmaterial
zu diesem Lernheft. Auch wenn Sie das Datenbank-Lernheft bereits durchgearbeitet
haben, also seminarverwaltung bereits in Ihrer MySQL-Installation existiert, rate ich
Ihnen trotzdem, die Datenbank aus dem Begleitmaterial einzuspielen.
Der Grund ist, falls Sie sich nicht exakt an die vorgegebene Struktur gehalten haben,
also z. B. eine Tabelle oder ein Attribut anders benannt haben, werden die Beispiele
aus diesem Lernheft bei Ihnen eventuell nicht funktionieren. Sparen Sie sich die unnö-
tigen Probleme und spielen Sie bitte den SQL-Dump aus dem Begleitmaterial dieses
Lernheftes ein.
Zur Wiederholung, oder zur Einführung, falls Sie das Datenbank-Lernheft nicht ken-
nen, sehen Sie hier die Struktur von seminarverwaltung als physisches Datenbank-
modell:
3.5 SQL-Anweisungen mit PDO ausführen
3.5.1 PDO::query()
Ein PDO-Objekt, also das, was von new PDO() erzeugt wird, verfügt über mehrere
Methoden, um SQL-Anweisungen an die konfigurierte Datenbank zu senden. Im Ver-
lauf des Lernhefts werden Sie mehrere kennenlernen, beginnen werden wir aber mit
der Methode PDO::query().
Abb. 3.1 Die Datenbank seminarverwaltung als physisches Datenbankmodell
3.5 SQL-Anweisungen mit PDO ausführen 17
Diese Methode akzeptiert als einzigen Parameter einen String mit SQL, das dann an
die Datenbank gesendet wird.
Beispiel
<?php<?php$db = newnew PDOPDO('mysql:host=localhost;dbname=seminarverwaltung', 'root',
'');
$db->query('INSERT INTO seminare (titel, beschreibung, preis, kategorie)VALUES ("PDO", "Seminar ?ber PHP, PDO und MySQL", 600,
"programmierung")');?>?>
Da Sie noch nicht gelernt haben, Datensätze auch wieder auszulesen, müssen Sie
momentan leider direkt über die MySQL-Konsole prüfen, ob der INSERT geklappt hat.
3.5.2 PDO::errorInfo()
Eventuell hat die Anweisung aus dem letzten Abschnitt nicht geklappt, es wurde also
kein neuer Datensatz in die Tabelle seminare eingefügt. Trotzdem wurde in PHP
keine Fehlermeldung ausgegeben.
Falls Sie vorhin alles richtig gemacht haben, probieren Sie doch einmal folgenden
Code aus:
Beispiel
<?php<?php$db = newnew PDOPDO('mysql:host=localhost;dbname=seminarverwaltung', 'root',
'');
$db->query('INSERT INTO senare (titel, beschreibung, preis, kategorie)VALUES ("PDO", "Seminar ?ber PHP, PDO und MySQL", 600,
"programmierung")');?>?>
In dieses Beispiel habe ich bewusst einen Fehler eingebaut. Die Tabelle muss natürlich
seminare heißen, nicht senare. Der Datensatz wurde nicht eingefügt (bitte nachprü-
fen) und trotzdem hat PHP keinen Fehler gemeldet.
Um zu sehen, ob die letzte SQL-Anweisung erfolgreich war und, wenn nicht, was das
Problem war, gibt es die Methode PDO::errorInfo(). Diese liefert ein Array beste-
hend aus zwei intern verwendeten, numerischen Fehlercodes und einer für uns hilf-
reicheren Fehlermeldung zurück. Falls kein Fehler aufgetreten ist, enthält das Ergebnis
nur ein Element mit dem Zahlencode 0000.
1.2.
3.4.5.
6.
Listing 3.4 code/lektion3/query1.php
1.2.
3.4.5.
6.
Listing 3.5 code/lektion3/query2.php
18 Einführung in PDO Lektion 3
Beispiel
<?php<?php$db = newnew PDOPDO('mysql:host=localhost;dbname=seminarverwaltung', 'root',
'');
$db->query('INSERT INTO senare (titel, beschreibung, preis, kategorie)VALUES ("PDO", "Seminar ?ber PHP, PDO und MySQL", 600,
"programmierung")');
var_dumpvar_dump($db->errorInfo());?>?>
Das Skript liefert als Ausgabe die Meldung Table 'seminarverwaltung.senare'doesn't exist, was genau unseren Erwartungen entspricht. Eine Tabelle senaregibt es nicht in unserer Beispiel-Datenbank.
array(3) { [0]=> string(5) "42S02" [1]=> int(1146) [2]=> string(46)"Table 'seminarverwaltung.senare' doesn't exist" }
Wie Sie sehen, ist das Standardverhalten von PDO, keine Fehlermeldungen auszuge-
ben. Das mag für den produktiven Einsatz ideal sein, denn weder die Besucher Ihrer
Webseiten möchten hässliche Fehlermeldungen sehen, noch wollen Sie, dass eventu-
ell sensible Informationen (wie z. B. Tabellennamen) öffentlich sichtbar auf Ihrer Web-
seite stehen.
Während Sie aber die Webseite lokal auf Ihrem Rechner entwickeln, wäre es besser,
sofort zu sehen, ob und was schief gelaufen ist. An dieser Stelle möchte ich Sie auf den
Abschnitt verweisen, in dem auf genau dieses Problem eingegangen wird.
3.6 Ergebnisse verarbeiten: Die Klasse PDOStatement
Wenn eine SQL-Abfrage ohne Fehler durchgeführt wird, erhalten Sie als Rückgabewert
der Methode PDO::query() ein neues Objekt, das als Klasse PDOStatement hat. Es
repräsentiert das Ergebnis der SQL-Anweisung und Sie können es verwenden, um die
Ergebnisdaten auszulesen und weiterzuverarbeiten.
Beispiel
<?php<?php$db = newnew PDOPDO('mysql:host=localhost;dbname=seminarverwaltung', 'root',
'');$statement = $db->query('SELECT * FROM seminare');
var_dumpvar_dump($statement);?>?>
1.2.
3.4.5.
6.7.8.
Listing 3.6 code/lektion3/error_info1.php
1.2.
3.4.5.6.
Listing 3.7 code/lektion3/statement1.php
3.6 Ergebnisse verarbeiten: Die Klasse PDOStatement 19
Als Ausgabe des var_dump() erhalten Sie
object(PDOStatement)#2 (1) { ["queryString"]=> string(22) "SELECT* FROM seminare" } .
Wie erwartet handelt es sich bei $statement um ein Objekt der Klasse
PDOStatement. Auffällig ist, dass Sie in der Ausgabe keine Ergebnisdatensätze sehen
können, nur das Original-SQL.
Der Grund ist, das Objekt enthält nicht das Ergebnis, es repräsentiert es nur - ein klei-
ner, aber wichtiger Unterschied. Das Objekt hat also nicht die Datensätze vorrätig, es
weiß aber, wie es an diese herankommt. Sie können das Objekt also jederzeit nach
dem eigentlichen Ergebnis fragen und erhalten die Datensätze als Ergebnis.
3.6.1 PDOStatement::fetchAll()
Dies erreichen Sie über die Methode PDOStatement::fetchAll(), die das Ergebnis
des SELECT in Form eines mehrdimensionalen Arrays zurückgibt.
Beispiel
<?php<?php$db = newnew PDOPDO('mysql:host=localhost;dbname=seminarverwaltung', 'root',
'');
$statement = $db->query('SELECT titel, preis FROM seminare');$daten = $statement->fetchAll();
var_dumpvar_dump($daten);?>?>
array(7) { [0]=> array(4) { ["titel"]=> string(31) "RelationaleDatenbanken & MySQL" [0]=> string(31) "Relationale Datenbanken
& MySQL"["preis"]=> string(6) "975.00" [1]=> string(6) "975.00" }
[1]=> array(4) {["titel"]=> string(13) "Ruby on Rails" [0]=> string(13) "Ruby
on Rails"["preis"]=> string(7) "2500.00" [1]=> string(7) "2500.00" }
... [6]=> array(4) {["titel"]=> string(44) "Digitale Bildbearbeitung mit Adobe
Photoshop" [0]=>string(44) "Digitale Bildbearbeitung mit Adobe Photoshop"
["preis"]=> string(7)"1500.00" [1]=> string(7) "1500.00" } }
Ich habe die Ausgabe um einige Datensätze gekürzt, um das Beispiel nicht zu lang
werden zu lassen. Wahrscheinlich ist Ihnen aufgefallen, dass jedes Attribut doppelt
im Array vorkommt, einmal mit numerischem Index, einmal mit assoziativem. Das
1.2.
3.4.5.6.7.8.
Listing 3.8 code/lektion3/fetch_all1.php
20 Einführung in PDO Lektion 3
ist leider das Standardverhalten von PDO an dieser Stelle, wir werden dies aber in
Abschnitt korrigieren.
Statt dem var_dump() werden wir nun die Datensätze hübsch in Form einer richtigen
HTML-Tabelle ausgeben. Da es sich bei den Datensätzen um ein reguläres PHP-Array
handelt, können Sie es prima mit einer foreach-Schleife durchlaufen.
Beispiel
<?php<?php$db = newnew PDOPDO('mysql:host=localhost;dbname=seminarverwaltung', 'root',
'');$statement = $db->query('SELECT titel, preis FROM seminare');$daten = $statement->fetchAll();
?>?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN""http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"><head>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8" /><title>Seminare</title>
</head><body>
<h1>Seminare</h1><table>
<tr><th>Titel</th><th>Preis</th>
</tr><?php<?php foreachforeach ($daten asas $seminar): ?>?>
<tr><td><?php<?php echoecho $seminar['titel'] ?>?></td><td><?php<?php echoecho $seminar['preis'] ?>?>?</td>
</tr><?php<?php endforeachendforeach; ?>?>
</table>
</body></html>
Wenn man von der Tatsache absieht, dass das Array $daten nun aus einer MySQL
Datenbank befüllt wird, dürfte das gewohntes Terrain für Sie sein.
3.6.2 PDOStatement::fetch()
Hin und wieder möchten Sie nur einen einzelnen Datensatz aus der Datenbank aus-
lesen. Zum Beispiel soll nur eine bestimmte Nachricht oder nur ein Artikel eines Pro-
duktkatalogs gezeigt werden. Sie wissen also, dass nur ein einzelner Datensatz zurück-
kommen wird.
1.2.
3.4.5.6.
7.8.9.
10.11.12.13.14.15.16.17.18.19.20.21.22.23.24.25.26.27.28.
Listing 3.9 code/lektion3/fetch_all2.php
3.6 Ergebnisse verarbeiten: Die Klasse PDOStatement 21
Prinzipiell können Sie auch dort mit PDOStatement::fetchAll() arbeiten, dies hat
jedoch einen kleinen Nachteil. Auch wenn nur ein Datensatz von der Abfrage zurück-
kommt, wird dieser trotzdem in ein zweidimensionales Array verpackt.
Beispiel
<?php<?php$db = newnew PDOPDO('mysql:host=localhost;dbname=seminarverwaltung', 'root',
'');$statement = $db->query('SELECT titel, preis FROM seminare WHERE id=1
LIMIT 1');$daten = $statement->fetchAll();
var_dumpvar_dump($daten);?>?>
array(1) { [0]=> array(4) { ["titel"]=> string(31) "RelationaleDatenbanken & MySQL" [0]=> string(31) "Relationale Datenbanken
& MySQL"["preis"]=> string(6) "975.00" [1]=> string(6) "975.00" } }
Um mit dem Datensatz arbeiten zu können, müssen Sie nun erst das Array auspacken.
Das ist unnötiger Code und schadet der Lesbarkeit. Viel besser ist es, stattdessen die
Methode PDOStatement::fetch() zu verwenden, die immer nur einen Datensatz
zurückgibt. Dieser ist dafür aber auch nicht verpackt.
Beispiel
<?php<?php$db = newnew PDOPDO('mysql:host=localhost;dbname=seminarverwaltung', 'root',
'');$statement = $db->query('SELECT titel, preis FROM seminare WHERE id=1
LIMIT 1');$daten = $statement->fetch();
var_dumpvar_dump($daten);?>?>
array(4) { ["titel"]=> string(31) "Relationale Datenbanken& MySQL" [0]=> string(31) "Relationale Datenbanken & MySQL"
["preis"]=>string(6) "975.00" [1]=> string(6) "975.00" }
Schon viel besser lesbar, oder?
Für den Fall, dass die Ergebnisdaten mehrere Datensätze enthalten, liefert
PDOStatement::fetch() den ersten Datensatz zurück. Rufen Sie die Methode
1.2.
3.
4.5.6.7.
Listing 3.10 code/lektion3/fetch_all3.php
1.2.
3.
4.5.6.7.
Listing 3.11 code/lektion3/fetch1.php
22 Einführung in PDO Lektion 3
erneut auf, erhalten Sie den zweiten, danach den dritten usw. Das Spiel geht so lange
weiter, bis alle Datensätze durchlaufen sind. Dann liefert die Methode false.
Beispiel
<?php<?php$db = newnew PDOPDO('mysql:host=localhost;dbname=seminarverwaltung', 'root',
'');// hole die ersten zwei Datens?tze aus der Tabelle seminare$statement = $db->query('SELECT titel, preis FROM seminare LIMIT 2');
var_dumpvar_dump($statement->fetch()); // Datensatz1var_dumpvar_dump($statement->fetch()); // Datensatz2var_dumpvar_dump($statement->fetch()); // false
?>?>
array(4) { ["titel"]=> string(31) "Relationale Datenbanken& MySQL" [0]=> string(31) "Relationale Datenbanken & MySQL"
["preis"]=>string(6) "975.00" [1]=> string(6) "975.00" } array(4) {
["titel"]=> string(13)"Ruby on Rails" [0]=> string(13) "Ruby on Rails" ["preis"]=>
string(7) "2500.00"[1]=> string(7) "2500.00" } bool(false)
Das erste PDOStatement::fetch() liefert den ersten Datensatz, das zweite den
zweiten Datensatz und das dritte wie erwartet den booleschen Wert false.
Durch dieses Verhalten können Sie die Methode auch sehr bequem in einer while-
Schleife verwenden. Diese soll so lange laufen, wie PDOStatement::fetch() ein
Array mit Daten liefert.
Beispiel
<?php<?php$db = newnew PDOPDO('mysql:host=localhost;dbname=seminarverwaltung', 'root',
'');$statement = $db->query('SELECT titel, preis FROM seminare');
whilewhile ( $daten = $statement->fetch() ) {var_dumpvar_dump($daten);
}?>?>
3.6.3 Ergebnisse zählen
Wenn Sie wissen wollen, wie viele Ergebnisse Ihre Abfrage enthält, können Sie das mit
der PHP-Funktion count() erreichen. Da die Methode PDOStatement::fetchAll()
1.2.
3.4.5.6.7.8.9.
Listing 3.12 code/lektion3/fetch2.php
1.2.
3.4.5.6.7.8.
Listing 3.13 code/lektion3/fetch3.php
3.6 Ergebnisse verarbeiten: Die Klasse PDOStatement 23
ein Array mit Ergebniszeilen zurückliefert, können Sie den Inhalt des Arrays einfach
zählen.
Beispiel
<?php<?php$db = newnew PDOPDO('mysql:host=localhost;dbname=seminarverwaltung', 'root',
'');$abfrage = $db->query('SELECT * FROM seminare;');$ergebnisse = $abfrage->fetchAll();echoecho countcount($ergebnisse);
?>?>
Diese Vorgehensweise ist in Ordnung, wenn Sie die Datensätze ohnehin für diese PHP-
Seite benötigen. Wenn Sie allerdings nur die Anzahl selbst brauchen, wäre es eine
enorme Verschwendung von Ressourcen, alle Datensätze auszulesen und dann nur zu
zählen.
Daher ist es besser, wenn Sie den SQL-Operator COUNT direkt verwenden, da auf diese
Weise nicht alle Datensätze ausgelesen werden müssen, nur um sie zu zählen. Von
MySQL wird nur das Ergebnis, also die Anzahl ausgeliefert.
Beispiel
<?php<?php$db = newnew PDOPDO('mysql:host=localhost;dbname=seminarverwaltung', 'root',
'');$abfrage = $db->query('SELECT COUNT(id) as anzahl FROM seminare;');$ergebnis = $abfrage->fetch();echoecho $ergebnis['anzahl'];
?>?>
3.6.4 Eine Abfrage schließen
Wenn Sie mit einer Abfrage fertig sind und die Daten nicht weiter benötigen, sollten
Sie das PDOStatement-Objekt mit Hilfe der Funktion unset() löschen, da ansonsten
unnötig Ressourcen verschwendet werden und PHP sogar in unter Umständen
Schwierigkeiten hat, mehrere Abfragen gleichzeitig offen zu halten.
Beispiel
<?php<?php$db = newnew PDOPDO('mysql:host=localhost;dbname=seminarverwaltung', 'root',
'');$abfrage = $db->query('SELECT * FROM seminare;');$ergebnisse = $abfrage->fetchAll();// sobald die Datens?tze mit fetch/fetchAll ausgelesen sind, wird das
1.2.
3.4.5.6.
Listing 3.14 code/lektion3/count1.php
1.2.
3.4.5.6.
Listing 3.15 code/lektion3/count2.php
1.2.
3.4.5.
24 Einführung in PDO Lektion 3
// PDOStatement-Objekt nicht l?nger ben?tigt und kann wegger?umt werden.unsetunset($abfrage);
echoecho countcount($ergebnisse);?>?>
Falls Sie den Code in einer Funktion oder Methode aufrufen, die ohnehin kurz darauf
endet, ist das ausdrückliche Löschen der Abfrage natürlich unnötig. Mit dem Ende der
Funktion/Methode wird automatisch auch die Abfrage gelöscht, da alle lokalen Varia-
blen beim Verlassen einer Funktion weggeräumt werden.
3.7 SQL-Wiederholung
Im nächsten Abschnitt finden Sie eine Wiederholung der wichtigsten SQL-Anweisun-
gen und Beispiele, wie diese in PHP verwendet werden. Ich gehe davon aus, dass Sie
bereits mit der Mehrzahl der besprochenen SQL-Anweisungen vertraut sind, aber eine
kleine Wiederholung kann ja nie schaden.
3.7.1 SELECT
Mit Hilfe der SELECT-Anweisung können Sie aus einer Tabelle Datensätze auslesen.
Beispiel
<?php<?php$db = newnew PDOPDO('mysql:host=localhost;dbname=seminarverwaltung', 'root',
'');
$abfrage = $db->query('SELECT * FROM seminartermine LIMIT 2;');$ergebnisse = $abfrage->fetchAll();var_dumpvar_dump($ergebnisse);
?>?>
Die Abfrage können Sie dann wie üblich mit PDOStatement::fetch() oder
PDOStatement::fetchAll() weiterverarbeiten.
Die Methode PDO::query() akzeptiert jede Art von SQL, inklusive JOINS und ande-
ren komplexeren SQL-Anweisungen.
6.7.8.9.
10.11.
Listing 3.16 code/lektion3/unset.php
1.2.
3.4.5.6.7.
Listing 3.17 code/lektion3/select1.php
3.7 SQL-Wiederholung 25
Beispiel
<?php<?php$db = newnew PDOPDO('mysql:host=localhost;dbname=seminarverwaltung', 'root',
'');
$abfrage = $db->query('SELECT st.beginn, st.ende FROM seminartermine stJOIN seminare s ON st.seminar_id = s.id WHERE s.titel LIKE
"%Datenbank%";');$ergebnisse = $abfrage->fetchAll();var_dumpvar_dump($ergebnisse);
?>?>
Auch das Umbenennen von Spalten mit AS ist möglich, die neuen Namen finden Sie
dann als Schlüssel im Ergebnis-Array wieder.
Beispiel
<?php<?php$db = newnew PDOPDO('mysql:host=localhost;dbname=seminarverwaltung', 'root',
'');
$abfrage = $db->query('SELECT beginn AS start, ende FROM seminartermineLIMIT 2;');
$ergebnisse = $abfrage->fetchAll();var_dumpvar_dump($ergebnisse);
?>?>
3.7.2 INSERT
Mit einer INSERT-Anweisung können Sie einen neuen Datensatz in eine Tabelle einfü-
gen.
Beispiel
<?php<?php$db = newnew PDOPDO('mysql:host=localhost;dbname=seminarverwaltung', 'root',
'');
$db->query('INSERT INTO seminartermine (beginn, ende, raum, seminar_id)VALUES ("2010-08-12", "2010-08-25", "Schulungsraum 1", 1)');
?>?>
Wenn der Primärschlüssel in der Tabelle AUTO_INCREMENT aktiviert hat (was er unbe-
dingt sollte) und Sie den eben von INSERT erzeugten Primärschlüssel wissen wollen,
1.2.
3.4.5.
6.7.8.
Listing 3.18 code/lektion3/select2.php
1.2.
3.4.
5.6.7.
Listing 3.19 code/lektion3/select3.php
1.2.
3.4.5.6.
Listing 3.20 code/lektion3/insert1.php
26 Einführung in PDO Lektion 3
können Sie sich diesen bequem von der Methode PDO::lastInsertId() liefern las-
sen.
Beispiel
<?php<?php$db = newnew PDOPDO('mysql:host=localhost;dbname=seminarverwaltung', 'root',
'');
$db->query('INSERT INTO seminartermine (beginn, ende, raum, seminar_id)VALUES ("2010-08-12", "2010-08-25", "Schulungsraum 1", 1)');
echoecho "Die zuletzt erzeugte ID ist: " . $db->lastInsertId();?>?>
Der Aufruf von PDO::lastInsertId()wird Ihnen den Wert des Primärschlüssels von
dem Datensatz zurückgeben, den Sie in Zeile 4 erzeugt haben.
3.7.3 UPDATE
Mit UPDATE können Sie einen oder mehrere vorhandene Datensätze ändern. Welche
Datensätze bearbeitet werden, hängt von der WHERE-Bedingung ab, die Sie verwen-
den. Sollten Sie das WHERE weglassen, so werden alle Datensätze geändert.
Beispiel
<?php<?php$db = newnew PDOPDO('mysql:host=localhost;dbname=seminarverwaltung', 'root',
'');$abfrage = $db->query('UPDATE SEMINARE set preis=499.99 WHERE id=5');
?>?>
Wenn Sie die Information benötigen, wie viele Datensätze Ihre UPDATE-Abfrage ver-
ändert hat, können Sie die Methode PDOStatement::rowCount() verwenden.
Beispiel
<?php<?php$db = newnew PDOPDO('mysql:host=localhost;dbname=seminarverwaltung', 'root',
'');$abfrage = $db->query('UPDATE seminare SET preis=499.99 WHERE id=5');
echoecho "Es wurde " . $abfrage->rowCount() . ' Datensatz ver?ndert.';?>?>
1.2.
3.4.5.6.7.8.
Listing 3.21 code/lektion3/insert2.php
1.2.
3.4.
Listing 3.22 code/lektion3/update1.php
1.2.
3.4.5.6.
Listing 3.23 code/lektion3/update2.php
3.7 SQL-Wiederholung 27
3.7.4 DELETE
Mit der DELETE-Anweisung können Sie Datensätze aus einer Tabelle löschen. Welche
Datensätze gelöscht werden, hängt von der WHERE-Bedingung ab. Alle Datensätze, auf
welche die Bedingung zutrifft, werden entfernt.
Ein DELETE ohne WHERE-Bedingung löscht also alle Datensätze dieser Tabelle.
Beispiel
<?php<?php$db = newnew PDOPDO('mysql:host=localhost;dbname=seminarverwaltung', 'root',
'');$abfrage = $db->query('DELETE FROM seminare');
?>?>
Beispiel
<?php<?php$db = newnew PDOPDO('mysql:host=localhost;dbname=seminarverwaltung', 'root',
'');$abfrage = $db->query('DELETE FROM seminare WHERE id=5');
echoecho "Es wurde " . $abfrage->rowCount() . ' Datensatz gel?scht.';?>?>
Mit Bedingung werden nur die gewünschten Datensätze weggeräumt, hier der Daten-
satz mit id=5.
3.7.5 CREATE TABLE
Mit der Anweisung CREATE TABLE können Sie eine komplett neue Tabelle anlegen.
Beispiel
<?php<?php$db = newnew PDOPDO('mysql:host=localhost;dbname=seminarverwaltung', 'root',
'');$abfrage = $db->query(
'CREATE TABLE mitarbeiter (id INTEGER PRIMARY KEY AUTO_INCREMENT,vorname VARCHAR(50),nachname VARCHAR(50))
');?>?>
1.2.
3.4.
Listing 3.24 code/lektion3/delete1.php
1.2.
3.4.5.6.
Listing 3.25 code/lektion3/delete2.php
1.2.
3.4.5.6.7.8.9.
Listing 3.26 code/lektion3/create_table1.php
28 Einführung in PDO Lektion 3
3.7.6 ALTER TABLE
Mit ALTER TABLE können Sie die Struktur einer Tabelle verändern, z. B. Felder umbe-
nennen, erlaubte Längen ändern oder ein Feld von NULL auf NOT NULL setzen.
Beispiel
<?php<?php$db = newnew PDOPDO('mysql:host=localhost;dbname=seminarverwaltung', 'root',
'');$db->query('ALTER TABLE mitarbeiter ADD email VARCHAR(150)');
?>?>
3.7.7 TRUNCATE TABLE
Mit der Anweisung TRUNCATE TABLE können Sie eine Tabelle komplett leeren. Alle
Datensätze werden gelöscht. Der Unterschied zu DELETE FROM ohne WHERE ist, dass
auch Dinge wie der Autoinkrement- Wert zurückgesetzt werden. Die Tabelle wird tat-
sächlich wieder in einen jungfräulichen Zustand versetzt.
Beispiel
<?php<?php$db = newnew PDOPDO('mysql:host=localhost;dbname=seminarverwaltung', 'root',
'');$db->query('TRUNCATE TABLE mitarbeiter');
?>?>
3.7.8 DROP TABLE
Mit DROP TABLE schließlich können Sie eine Tabelle komplett löschen. Sollten sich in
der Tabelle noch Datensätze befinden, sind diese ebenfalls verloren. Wenn Sie nicht
sicher sind, ob die Tabelle schon existiert und Sie diese nur löschen wollen, falls Sie
existiert, können Sie die SQL-Anweisung um IF EXISTS erweitern. Auf diese Weise
erhalten Sie keinen Fehler, wenn die Tabelle nicht existiert.
Beispiel
<?php<?php$db = newnew PDOPDO('mysql:host=localhost;dbname=seminarverwaltung', 'root',
'');$db->query('DROP TABLE IF EXISTS mitarbeiter');
?>?>
1.2.
3.4.
Listing 3.27 code/lektion3/alter_table1.php
1.2.
3.4.
Listing 3.28 code/lektion3/truncate_table1.php
1.2.
3.4.
Listing 3.29 code/lektion3/drop_table1.php
3.7 SQL-Wiederholung 29
Testen Sie Ihr Wissen
1. Welchen Datentyp hat in PHP eine Datenbank-Verbindung mit PDO?
2. Wie können Sie mit PDO eine SQL-Anweisung ausführen?
3. Auf welche Arten können Sie Datensätze aus einem PDOStatement auslesen?
4. Wann müssen Sie bei SQL INSERT, wann UPDATE verwenden?
5. Wie können Sie alle Datensätze einer Tabelle personen löschen?
6. Wie können Sie eine Tabelle personen löschen?
Aufgaben zur Selbstkontrolle
Aufgabe 1:
Schreiben Sie ein PHP-Skript eintragen.php, das eine Tabelle namens filme mit
den Spalten id, titel, beschreibung und dauer anlegt. Die Spalte id ist der Pri-
märschlüssel.
Aufgabe 2:
Erweitern Sie das Skript, so dass es zu Beginn immer die Tabelle löscht.
Aufgabe 3:
Erweitern Sie das Skript, so dass es drei Datensätze in die Tabelle filme einträgt. Die
Filme dürfen Sie frei wählen.
Aufgabe 4:
Erstellen Sie ein neues PHP-Skript filme_anzeigen.php, das die in der Tabelle
filme vorhandenen Datensätze als HTML-Tabelle auflistet.
30 Einführung in PDO Lektion 3
Optionale Aufgaben
Aufgabe 5:
Erweitern Sie das Skript eintragen.php, so dass es eine Tabelle namens
regisseure mit den Spalten id, vorname und nachname anlegt. Die Tabelle filmeerhält eine neue Spalte regisseur_id, das einen Fremdschlüssel zur Tabelle
regisseure (Spalte id) darstellt.
Aufgabe 6:
Erweitern Sie das Skript eintragen.php, so dass es die passenden Regisseure zu
den Filmen in die Datenbank schreibt. Vergessen Sie nicht, die Filme mit der passen-
den regisseur_id zu versehen.
Aufgabe 7:
Erweitern Sie filme_anzeigen.php, so dass der volle Name des Regisseurs (also
die Inhalte der Spalten vorname und nachname) in einer Spalte Regisseur mit ange-
zeigt wird.
Aufgabe 8:
Erweitern Sie filme_anzeigen.php, so dass der Name des Regisseurs anklickbar ist
und auf eine neue Seite regisseur_anzeigen.php führt. Dort soll der Regisseur
mit vollem Namen angezeigt werden.
Aufgabe 9:
Erweitern Sie eintragen.php um einige zusätzliche Filme und Regisseure, wobei
einige Filme den gleichen Regisseur haben sollten.
Aufgabe 10:
Erweitern Sie regisseur_anzeigen.php, so dass die Titel aller Filme aufgelistet
werden, in denen der Regisseur Regie geführt hat.
3.7 SQL-Wiederholung 31
Index
AALTER TABLE 29
CCRUD 50 60 61
CREATE TABLE 28 38 63
DDSN 15 16 33
Data Source Name 15
DELETE FROM 29 45 62
DROP TABLE 29 63
IINSERT 7 18 26 30 42 50 57 60 62
KKlasse 9 10 11 12 15 19 20 32 62
MMethode 10 11 12 13 14 17 18 19 20 22 23
25 27 35 41 43 44 45 48 57 62
OOOP 7 9 32
objektorientierte Programmierung 9
Objekt 9 10 12 15 17 19 20 24 32 41 52
PPDO::query 17 19 25 40 43 49 62
PDO::prepare 41 42 43
PDO::errorInfo 18 35
PDO::setAttribute 33 34
PDOStatement::fetch 21 22 23 25 35 36 56
62
PDOStatement::fetchAll 20 22 23 25 35 36
37 38 54 56 62
PDOStatement::execute 41 42 44 45 49 57
63
PDO-Attribute 32 33
prepared statements 32 40 41 42 43 44 48
49 63
PDO::ATTR_ERRMODE 33 34 63
PDO::ATTR_PERSISTENT 32 33 34
PDO::ATTR_DEFAULT_FETCH_MODE 35
PDO::MYSQL_ATTR_USE_BUFFERED_QUERY
38
SSQL-Injection 45 56
SET NAMES 39 40 63
SELECT 7 20 25 43 45 50
64 Index
TTRUNCATE TABLE 29 62
UUnicode 32 38 39 40 49 63
UTF-8 39 40 52 63
UPDATE 7 27 30 45 50 56 58 60 62
WWHERE 27 28 29 43 45 50 62
T 65