Beruflich Dokumente
Kultur Dokumente
PHP Schnelleinstieg
PHP Schnelleinstieg
ISBN 978-3-7475-0396-6
1. Auflage 2022
www.mitp.de
E-Mail: mitp-verlag@sigloch.de
Telefon: +49 7953 / 7189 - 079
Telefax: +49 7953 / 7189 - 082
Mit freundlicher Genehmigung der HfG Schwäbisch Gmünd verwenden einige Abbildun-
gen Emojis von OpenMoji (https://openmoji.org) – dem Open-Source Emoji- und Icon-
Projekt.
Dieses Werk, einschließlich aller seiner Teile, ist urheberrechtlich geschützt. Jede Ver-
wertung außerhalb der engen Grenzen des Urheberrechtsgesetzes ist ohne Zustimmung
des Verlages unzulässig und strafbar. Dies gilt insbesondere für Vervielfältigungen,
Übersetzungen, Mikroverfilmungen und die Einspeicherung und Verarbeitung in elektro-
nischen Systemen.
Die Wiedergabe von Gebrauchsnamen, Handelsnamen, Warenbezeichnungen usw. in die-
sem Werk berechtigt auch ohne besondere Kennzeichnung nicht zu der Annahme, dass
solche Namen im Sinne der Warenzeichen- und Markenschutz-Gesetzgebung als frei zu
betrachten wären und daher von jedermann benutzt werden dürften.
Inhalt
Einleitung
E.1 Programmieren lernen in 14 Tagen ............................................. 11
E.2 Der Aufbau des Buchs .............................................................. 11
E.3 Programmtexte und Lösungen zum Download .............................. 12
E.4 Fragen und Feedback ............................................................... 12
5
Inhalt
Funktionen
5.1 Native Funktionen aus der PHP-Bibliothek verwenden ................... 105
5.2 Eigene Funktionen definieren .................................................... 122
5.3 Übungen ............................................................................... 127
6
Inhalt
7
Inhalt
8
Inhalt
Stichwortverzeichnis
9
Einleitung
E.1 Programmieren lernen in 14 Tagen
Mit diesem Buch haben Sie sich für einen einfachen, praktischen und fundier-
ten Einstieg in die Welt der Programmierung entschieden. Sie lernen ohne
unnötigen Ballast alles, was Sie wissen müssen, um PHP und MySQL effektiv
für Projekte in Ihrem Berufs- und Interessensgebiet einzusetzen.
Wenn Sie Zeit genug haben, können Sie jeden Tag ein neues Kapitel durchar-
beiten und so innerhalb von zwei Wochen Programmieren lernen. Alle Erklä-
rungen sind leicht verständlich und setzen keine Vorkenntnisse voraus. Am
besten lesen Sie das Buch neben der Computer-Tastatur und probieren die
Programmbeispiele und Übungen gleich aus. Sie werden schnell erste Erfolge
erzielen und Freude an der Programmierung finden.
11
Einleitung
Am Ende des Buchs finden Sie ein Stichwortverzeichnis, das Ihnen hilft, be-
stimmte Themen im Buch schneller zu finden.
12
Erste Schritte mit PHP
Dieses Kapitel gibt eine praxisnahe Einführung in eine der populärsten Pro-
grammiersprachen des Internets: PHP. Um die 80 % aller Webseiten werden
von PHP erzeugt. Das Spektrum reicht von Internetpräsenzen, Blogs, Porta-
len, Online-Shops und spezialisierten Web-Anwendungen bis zu Schnittstel-
len für die Datenverarbeitung von Mobile Apps und dem Internet of Things.
PHP ist für Hobby-Anwender und den professionellen Einsatz in geschäfts-
kritischen Softwaresystemen gleichermaßen geeignet. PHP-Kenntnisse eröff-
nen Ihnen die Welt hinter den graphischen Benutzeroberflächen des Internets
und unzählige Möglichkeiten, um selbst privat oder beruflich in die Web
entwicklung einzusteigen.
Nach einem Überblick zu den Einsatzgebieten von PHP führe ich Sie in die-
sem Kapitel zur erfolgreichen Ausführung Ihres ersten PHP-Programms auf
dem eigenen Computer. Dabei erlernen Sie wichtige Grundkenntnisse und
die Einrichtung einer Entwicklungsumgebung. Durch erste Programmbei-
spiele machen Sie sich »hands-on« an der Tastatur Ihres Computers mit den
Grundeigenschaften von PHP vertraut. Zum Abschluss des Kapitels erhalten
Sie einen Überblick zur Entstehungsgeschichte von PHP.
Wo vorhanden, verwendet dieses Buch deutsche Fachbegriffe. Da die
englischen Entsprechungen für Recherchen, Fehlersuchen oder in der
Kommunikation mit anderen Programmierern unerlässlich sind, ma-
che ich Sie nebenbei auch mit den englischen Begriffen vertraut.
13
Kapitel 1 Erste Schritte mit PHP
14
Wofür wird PHP eingesetzt? 1.1
HTML ermöglicht die Strukturierung der Inhalte mit Hilfe von maschinen
lesbaren Hinweisen, den HTML-Tags. Die HTML-Tags markieren einge-
schlossene Inhalte dabei mit einer gewünschten Bedeutung, zum Beispiel
Überschrift, Link, Liste etc. Dies nennt man semantische Strukturierung. Die
Redaktion verwendet im Beispiel Elemente für eine Überschrift ersten Grades
(heading 1 = h1), Hyperlinks (anchor = a) und eine ungeordnete Liste (unordered
list = ul) mit Listenelementen (list item = li). Die Auszeichnungen beginnen
mit einem öffnenden Tag <element> und enden mit einem schließenden Tag
</element>:
15
Kapitel 1 Erste Schritte mit PHP
Bald kommt in der Zeitungsredaktion eine neue Idee auf: Sie möchte das
aktuelle Tagesdatum ohne tägliche manuelle Bearbeitung einblenden. Doch
HTML kann keine Inhalte erzeugen und hat keinen Zugriff auf eine Uhr mit
dem aktuellen Datum. Für diesen Zweck ist Programmierlogik erforderlich.
Die Zeitung engagiert eine Webagentur. Die Agentur aktiviert PHP auf dem
Webserver, benennt articles.html in articles.php um und beginnt PHP-
Programmlogik zur Anzeige des aktuellen Datums in das HTML einzubetten:
<h1>Nachrichten</h1>
<p>Heute ist der <?php echo date('d.m.Y'); ?>!</p>
<ul>...</ul>
16
Wofür wird PHP eingesetzt? 1.1
Aus dem bestehenden HTML und den durch PHP dynamisch ergänzten
Inhalten ergibt sich die gewünschte Webseite, die an den Browser zurück-
geschickt wird. Bei einem Abruf der Webseite am 13. März 2022 lautet der
generierte Inhalt:
<h1>Nachrichten</h1>
<p>Heute ist der 13.03.2022!</p>
<ul>...</ul>
Aufgabe 1
Aus Sicht des Browsers auf dem eigenen Computer, des Clients, erscheint die
empfangene Webseite genauso statisch wie zuvor. Die dynamische Erzeugung
erfolgte bereits serverseitig auf dem entfernten Webserver. Eine Installation
von PHP ist daher nur auf dem Webserver erforderlich, nicht auf den Compu-
tern der Webseiten-Besucher. Der Browser kümmert sich wie zuvor nur um
die Darstellung, unabhängig von der Entstehung des Inhalts.
Abb. 1.6: Der Kreislauf aus Anfrage und Antwort mit PHP
17
Kapitel 1 Erste Schritte mit PHP
Die Pflege der Zeitungsartikel in der Datei durch die Redakteure erfordert
HTML-Kenntnisse, Absprachen zwischen den Redakteuren und ständige
Übertragungen neuer Versionen auf den Webserver. Mit fortgeschrittenen
Methoden der PHP-Entwicklung kann die Webagentur den nächsten Wunsch
der Zeitungsredaktion realisieren: Eine Vereinfachung der Artikel-Verwal-
tung, die von den Redakteuren keine technischen Kenntnisse mehr erfordert.
Die Artikelinhalte werden nicht länger in der Datei articles.php gepflegt,
sondern in eine Datenbank ausgelagert. PHP kann die Artikel zum Zeitpunkt
des Abrufs der Webseite aus der Datenbank lesen und ähnlich wie zuvor das
Tagesdatum dynamisch in das HTML einbauen. Weitere Abrufe der Webseite
wiederholen die Generierung der Inhalte und damit den Abruf der Artikel aus
der Datenbank. Neu in die Datenbank eingepflegte Artikel erscheinen somit
automatisch auf der Webseite.
Zur Erstellung neuer Artikel durch Redakteure ergänzt die Webagentur einen
durch Login geschützten Bereich mit einem Eingabeformular für neue Arti-
kel. PHP überträgt die Eingaben in die Datenbank. Außer der Browserbedie-
nung benötigen die Redakteure keine weiteren technischen Kenntnisse.
Aufgabe 2
Was geschieht, wenn Sie eine PHP-Datei direkt im Browser öffnen? Zie-
hen Sie zum Ausprobieren eine PHP-Datei in das Browserfenster (Drag &
Drop). Vergleichen Sie mit Dateien vom Typ TXT, HTML, ZIP und PDF.
18
Wofür wird PHP eingesetzt? 1.1
Da sich mit PHP neben HTML auch jede andere Art von Ausgabe erzeugen
lässt, kann PHP der Mobile App als Backend dienen. Statt HTML gibt das
PHP-Skript JSON aus:
<?php
$articles = Abruf der Artikel aus der Datenbank;
echo json_encode($articles);
?>
19
Kapitel 1 Erste Schritte mit PHP
Mit Hilfe von PHP stellt der Webserver die Artikel als Service über das In-
ternet zur Verfügung – als Webservice. Im Vergleich zu einer Webseite für
menschliche Benutzer richtet sich das Angebot eines Webservice an andere
Software – unabhängig vom endgültigen Verwendungszeck.
Später entscheidet sich die Zeitung zur Veröffentlichung ihres Webservice. Ein
Newsletter-Versender kann die verfügbaren Daten zum Beispiel unabhängig
von der Zeitungs-Webseite nutzen, um seinen wöchentlichen E-Mail-News-
letter automatisiert mit Inhalten der Zeitung anzureichern. In umgekehrter
Weise erweitert die Zeitung ihr eigenes Angebot um einen Wetterbericht, des-
sen Daten sie vom Webservice eines Drittanbieters abruft.
Ein Webservice wird oft auch technischer als Web-API (Web Ap-
plication Programming Interface) bezeichnet – eine Programmier-
Schnittstelle über das Internet.
Weitere Beispiele für Webservices beziehungsweise Web-APIs: Wäh-
rungs- und Aktienkurse, Fahrpläne, SMS- und E-Mail-Versand, Daten zu
Sportereignissen, Steuerung von Smart-Home-Geräten, Bonitätsauskünfte,
Validierung von Postadressen und vieles mehr. Auch die großen Tech-Un-
ternehmen wie Twitter, Facebook, Google, Amazon etc. stellen Web-APIs
zur Integration in eigene Angebote bereit.
Mit Hilfe von PHP können Sie sowohl eigene Webservices bereitstellen (pro-
duzieren) als auch fremde Webservices nutzen (konsumieren). Mit entspre-
chenden Maßnahmen kann ein Webservice auch gegen Bezahlung angeboten
werden.
20
Wofür wird PHP eingesetzt? 1.1
21
Kapitel 1 Erste Schritte mit PHP
Abonnenten und Artikel des letzten Tags aus der Datenbank und versendet
die dynamisch erstellte Artikelübersicht per E-Mail.
Weitere Anwendungsbeispiele für Cronjobs:
Erinnerungs-SMS an Kunden einer Autowerkstatt für einen bevorste-
henden Termin.
Nächtliche Generierung von Verkaufsberichten für einen Online-Shop.
Regelmäßige Löschung nicht mehr benötigter Daten gemäß DSGVO.
22
Schwächen von PHP 1.3
23
Kapitel 1 Erste Schritte mit PHP
Die große Verbreitung von PHP trägt auch zu einer Verbreitung zweifelhafter
Programmierpraktiken bei, weshalb der Sprache gelegentlich ein schlechter
Ruf anhaftet. PHP selbst ist jedoch sehr sicher und mit sauberer Programmie-
rung bestehen keine Bedenken. Im Laufe des Buchs lernen Sie den sicheren
Umgang mit einigen typischen Sicherheitsproblemen kennen.
Keine Schwäche der Programmiersprache PHP selbst ist die Tatsache, dass
JavaScript als vormals nur clientseitig im Browser eingesetzte Sprache auch
serverseitig einsetzbar geworden ist. JavaScript kann daher ohne Wechsel der
Sprache die Programmierung für das Frontend (den Webbrowser) und das
Backend (den Webserver) gleichzeitig abdecken; damit stellt es eine beliebte
Alternative zu PHP dar.
24
Quelltext und PHP-Interpreter 1.5
Die ersten PHP-Programme führen Sie unkompliziert direkt mit Hilfe der
Kommandozeile (Command Line Interface, abgekürzt CLI) aus. Später nutzen
Sie den in PHP eingebauten Webserver, um selbst programmierte, dynami-
sche Webseiten auf dem lokalen Computer zu simulieren, als wären sie über
das Internet verfügbar. Sie lernen auch, wie Sie diese Webseiten tatsächlich im
Internet veröffentlichen können.
Alle im Buch eingesetzten Entwicklungswerkzeuge sind entweder in
Ihrem Betriebssystem enthalten oder können kostenlos heruntergela-
den werden. Einfache Webseiten können Sie im Internet zu geringen
Kosten veröffentlichen.
Um das Programm im Sinne von PHP auszuführen, benötigen Sie auf Ihrem
Computer eine Software, die PHP-Quelltext einlesen, analysieren und die ent-
haltenen Anweisungen ausführen kann - den PHP-Interpreter. Er nimmt PHP-
Quelltext entgegen und führt diesen direkt aus. Dabei kann das Programm
verschiedenste Aufgaben erledigen, z.B. Dateien bearbeiten, Informationen
aus dem Internet abrufen, Daten aus einer Datenbank laden, Berechnungen
durchführen, E-Mails versenden, PDFs generieren, Daten aufbereiten und
vieles mehr. Im Laufe eines Programms erfolgen meist sichtbare Ausgaben an
den Benutzer, um Daten anzuzeigen oder Rückmeldung über den Erfolg bzw.
Misserfolg eines Vorgangs zu geben.
25
Kapitel 1 Erste Schritte mit PHP
Da der Quellcode von PHP direkt durch einen Interpreter ausgeführt wird,
zählt PHP zu den interpretierten Programmiersprachen. Im Gegensatz dazu
stehen kompilierte Programmiersprachen wie Java oder C. In kompilierten
Sprachen übersetzt zunächst ein Compiler das Programm in Maschinencode
für das entsprechende Betriebssystem. Das übersetzte (»kompilierte«) Pro-
gramm kann erst dann vom Betriebssystem ausgeführt werden. PHP macht
den Einstieg in dieser Hinsicht also sehr leicht. Interpretierte Programmier-
sprachen werden auch Skriptsprachen genannt. Deren Programme bzw. Quell-
text-Dateien heißen daher auch Skripte. PHP gehört zur Kategorie der Skript-
sprachen.
PHP-Skripte werden in Dateien mit der Endung .php abgespeichert. Dabei
bleibt der Inhalt weiterhin reiner Text. Mit Hilfe der passenden Endung kann
eine PHP-Datei in verschiedenen Situationen von Benutzern und Maschinen
(z.B. Editoren oder Webservern) als solche erkannt und entsprechend behan-
delt werden.
Zur Ausführung des Programms muss die Skriptdatei dem PHP-Interpreter
zugeführt werden. Nach der Installation von PHP kann der Interpreter über
den Befehl php auf der Kommandozeile Ihres Computers angewiesen werden,
die Datei auszuführen. Sehen wir uns daher zunächst Grundlagen im Umgang
mit einer Kommandozeile an.
26
Kommandozeile nutzen 1.6
zeigt der Prompt zur besseren Orientierung auch das Verzeichnis an, in dem
Sie sich aktuell befinden.
Abb. 1.8: Kommandozeile iTerm auf dem Mac mit Anzeige des aktuellen Verzeichnisses. Der
Cursor wartet auf die Eingabe eines Kommandos.
Eine fertige Eingabe bestätigen Sie mit der Eingabetaste. Der Computer führt
Ihr Kommando aus - oder quittiert es mit einer Fehlermeldung, falls es fehl-
schlägt bzw. keinen Sinn ergibt.
Windows
Windows bringt mit der Eingabeaufforderung ein Kommandozeilen-Pro-
gramm mit, welches allerdings nicht sehr komfortabel ist. Sehr gut geeignet
hingegen ist die Git Bash, eine Nachahmung (»Emulation«) des Kommando-
zeilen-Programms Bash aus der Unix-Welt. Dazu installieren Sie zunächst Git
for Windows (https://gitforwindows.org) mit allen vorausgewählten Stan-
dardoptionen. Git selbst ist eine Software zur Quelltext-Verwaltung (siehe Ka-
pitel 14), wir interessieren uns an dieser Stelle jedoch lediglich für die nützli-
che »Beigabe« der Git Bash.
Drücken Sie nach der Installation die [Windows]-Taste, suchen Sie nach »Git
Bash« und starten Sie das Programm. Die Git Bash startet im Kontext des Be-
nutzerverzeichnisses, abgekürzt durch die Tilde ~.
27
Kapitel 1 Erste Schritte mit PHP
Alternativ können Sie die Git Bash aus dem Kontextmenü des Windows-Ex-
plorers in einem vorausgewählten Verzeichnis öffnen. Klicken Sie im Explorer
mit der rechten Maustaste auf das gewünschte Verzeichnis und wählen Sie aus
dem Kontextmenü den Eintrag Git Bash Here.
Linux
Linux-Distributionen bringen bereits ein geeignetes Kommandozeilen-Pro-
gramm mit, z.B. unter Ubuntu-Linux das Programm _Terminal_.
1.6.2 Kommandozeilen-Einmaleins
Im Rahmen des Buchs reicht es aus, wenn Sie Befehle ausführen und sich im
Dateisystem bewegen können.
28
Kommandozeile nutzen 1.6
Die Git Bash unter Windows arbeitet wie unter Unix üblich mit
dem gewöhnlichen Schrägstrich (/) als Verzeichnistrenner. So lautet
etwa der Pfad zum Benutzerverzeichnis C:\Benutzer\Philipp dort
/C/'Benutzer/Philipp.
Mit dem Befehl ls (list) listen Sie den Inhalt des aktuellen Verzeichnisses auf.
Im Beispiel sind drei Unterverzeichnisse zu sehen:
> ls
Desktop Downloads my-php-project
Mit dem Befehl cd (change directory) wechseln Sie das Verzeichnis. Das ge-
wünschte Zielverzeichnis übergeben Sie mit Leerzeichen getrennt als so ge-
nanntes Argument an den Befehl. Möchten Sie eine Verzeichnisebene höher
wechseln, in das übergeordnete Verzeichnis, drücken Sie dies mit zwei Punk-
ten (..) als Argument aus.
> cd my-php-project
> pwd
/Users/philipp.rieber/my-php-project
> cd ..
> pwd
/Users/philipp.rieber
Egal, wo Sie sich gerade im Dateisystem befinden, ein absoluter Pfad ist im-
mer eindeutig. Ohne Schrägstrich zu Beginn handelt es sich um einen relati-
ven Pfad aus Sicht des aktuellen Verzeichnisses. Die Beispiele verdeutlichen
den Unterschied:
29
Kapitel 1 Erste Schritte mit PHP
> pwd
/Users
> cd philipp.rieber/my-php-project
> pwd
/Users/philipp.rieber/my-php-project
> cd /Users/philipp.rieber/Dokumente
> pwd
/Users/philipp.rieber/Dokumente
> cd ../my-php-project
> pwd
/Users/philipp.rieber/my-php-project
> cd /
> pwd
/
Das Heimatverzeichnis des eingeloggten Benutzers kann mit der Tilde (~) ab-
gekürzt werden. Dies ist hilfreich, wenn Sie auf schnellstem Weg »nach Hau-
se« wollen.
> pwd
/usr/local/bin
> cd ~
> pwd
/Users/philipp.rieber
Auf der Git Bash unter Windows gelangen Sie von der Wurzel des Dateisys-
tems (/) aus in die einzelnen Festplattenpartitionen, d.h. Laufwerk C unter /C,
Laufwerk D unter /D usw.
> pwd
/C/Users/Philipp
> cd /D/my-php-projects
> pwd
/D/my-php-projects
30
PHP installieren 1.7
1.7.1 Windows
Laden Sie PHP von der Website https://windows.php.net/download als ZIP-
Archiv herunter, siehe Abbildung 1.12. Wählen Sie dabei die Variante x64 Non
Thread Safe. »x64« steht für 64-bit Betriebssysteme, den heutigen Standard.
Threadsicherheit (thread safety) ist nur in Kombination mit bestimmten Web-
servern erforderlich. Das Archiv hat einen ähnlichen Namen wie php-8.0.12-
nts-Win32-vs16-x64.zip mit der zum Zeitpunkt des Downloads aktuellsten
PHP-Versionsnummer. Entpacken Sie das Archiv in ein Verzeichnis und ver-
schieben Sie das ganze Verzeichnis nach C:\Programme (diesen Vorgang müs-
sen Sie als Administrator bestätigen). Benennen Sie das Verzeichnis um in
php. Die PHP-Installation befindet sich somit in C:\Programme\php.
Beachten Sie die Hinweise in der linken Spalte der Downloads-Website: Zum
Zeitpunkt des Schreibens dieses Buchs ist zusätzlich die Installation von
Visual C++ Redistributable for Visual Studio 2015-2019 erforderlich. Der
Download zur einer entsprechenden Installationsdatei ist verlinkt. Laden Sie
diese herunter und führen Sie die Installation durch.
31
Kapitel 1 Erste Schritte mit PHP
32
PHP installieren 1.7
Die Angabe des vollständigen Pfads zum PHP-Befehl wäre auf Dauer um-
ständlich. Windows kann jedoch mitgeteilt werden, Befehle ohne vollständige
Pfadangabe automatisch auch im Verzeichnis C:\Programme\php zu suchen.
Dazu bearbeiten Sie die Umgebungsvariable mit dem Namen Path. Drücken
Sie die [Windows]-Taste und suchen Sie nach »Umgebungsvariablen«.
33
Kapitel 1 Erste Schritte mit PHP
Wählen Sie aus der Liste der Benutzervariablen im oberen Teilfenster den Ein-
trag Path und klicken Sie auf Bearbeiten.
Im neuen Dialogfenster klicken Sie auf die Schaltfläche Neu und geben den
Pfad zum Verzeichnis der PHP-Installation ein: C:\Programme\php
Bestätigen Sie alle Dialoge mit OK und starten Sie die Git Bash neu. Wieder-
holen Sie die Versionsprüfung mit dem verkürzten Befehl php:
34
PHP installieren 1.7
> php –v
PHP 8.0.12
1.7.2 macOS
Mindestens bis zur macOS-Version 11 (Big Sur) ist PHP bereits vorinstalliert.
Allerdings handelt es sich immer um eine veraltete Version und zukünftige
macOS-Versionen werden ohne PHP erscheinen. Eine aktuelle PHP-Versi-
on installieren Sie am bequemsten mit Hilfe des Paketmanagers Homebrew
(https://brew.sh). Öffnen Sie die Kommandozeile und folgen Sie den Instal-
lationsanweisungen auf der Homebrew-Website. Nach Abschluss der Instal-
lation steht der Befehl brew zur Verwaltung von Software-Paketen auf Ihrem
Mac zur Verfügung. Zur Installation von PHP führen Sie folgenden Befehl
aus:
> brew install php
Starten Sie die Kommandozeile neu und prüfen Sie die PHP-Installation mit
der Befehlsoption -v zur Anzeige der Version:
> php -v
PHP 8.0.12
1.7.3 Linux
Diese Anleitung beschreibt die PHP-Installation unter Ubuntu-Linux und
sollte auf andere Linux-Distributionen übertragbar sein, die ebenfalls den
APT-Paketmanager verwenden (Debian, Mint u.a.). Unter Ubuntu können
Sie Software-Pakete mit dem Befehl apt auf der Kommandozeile verwalten.
Da dabei Änderungen am System erfolgen, muss allen apt-Befehlen der Befehl
sudo (»substitute user and do ...«) vorangestellt werden, um sie im Namen des
root-Benutzers (dem Haupt-Administrator) auszuführen. Beim ersten Befehl
werden Sie nach dem root-Passwort gefragt, danach gewährt Ihnen Ubuntu
ein Zeitfenster, in dem Sie das Passwort nicht erneut eingeben müssen.
Vor jeder Software-Installation aktualisieren Sie zunächst die interne Liste der
verfügbaren Software-Pakete:
35
Kapitel 1 Erste Schritte mit PHP
Diese PHP-Version ist allerdings meist etwas veraltet. Eine aktuelle Version
befindet sich in einem zusätzlichen, externen Paketarchiv. Zur Verwaltung ex-
terner Paketarchive installieren Sie zunächst das Paket software-properties-
common:
Mit dem nun verfügbaren Befehl add-apt-repository fügen Sie Ihrem System
das externe Paketarchiv ondrej/php hinzu. Das Präfix ppa steht dabei für »Per-
sonal Package Archive«:
> sudo add-apt-repository ppa:ondrej/php
Nach einer erneuten Aktualisierung der Paketliste können Sie PHP in der ak-
tuellen Version installieren:
> sudo apt update
> sudo apt install php
Anschließend steht der php-Befehl zur Verfügung. Prüfen Sie mit der Befehls
option -v die installierte Version:
> php -v
PHP 8.0.12
36
Quelltext-Editor verwenden: Visual Studio Code 1.8
fiehlt sich jedoch die Verwendung eines spezialisierten Editors. Eine gute
Wahl für den Start ist Visual Studio Code (kurz VS Code), ein kostenloser
Quelltext-Editor für verschiedene Programmiersprachen von Microsoft. VS
Code gibt es für Windows, macOS und Linux zum Download unter https://
code.visualstudio.com. Nach dem ersten Start können Sie direkt von der
Willkommensseite eine Erweiterung zur PHP-Unterstützung aktivieren, siehe
Pfeil in Abbildung 1.17.
37
Kapitel 1 Erste Schritte mit PHP
Eigene PHP-Dateien legen Sie durch Klicken auf das kleine Datei-Symbol an.
Im professionellen Umfeld ist der kommerzielle Editor PhpStorm sehr
beliebt. Dieser bringt viele weitere Spezialfunktionen für die PHP-
Entwicklung mit, z.B. Werkzeuge zur Fehleranalyse oder eine Daten-
bank- und Quellcodeverwaltung. Einen solchen vollumfänglichen
Editor bezeichnet man als integrierte Entwicklungsumgebung (engl.
Integrated Development Environment, kurz: IDE).
Die Dateiendung spielt übrigens gar keine Rolle. Kopieren Sie welcome.php
in eine neue Datei mit einer beliebigen anderen oder ganz ohne Dateiendung
und führen Sie sie aus:
> php willkommen
Willkommen bei PHP!
38
Basiswissen in der Praxis 1.10
Dennoch dient die Endung einem Zweck: Editoren können die Datei richtig
zuordnen und PHP-Unterstützung anbieten. Webserver erkennen, dass die
Datei vor Auslieferung durch PHP interpretiert werden muss.
Aufgabe 3
Was fällt Ihnen bei der Ausführung von php-tags.php auf? Achten Sie auf
die ausgegebenen Zeilenumbrüche.
Das Short echo Tag »<?= ...« ist eine Kurzform für einfache Ausgaben, es
entspricht »<? echo ...«:
<?= date('Y-m-d'); ?>
Ein schließendes Tag ist nicht immer erforderlich. Das Weglassen des schlie-
ßenden Tags ist bei reinen Programmdateien, die ausschließlich PHP-Code
enthalten, sogar üblich. Es verhindert versehentliche Ausgaben außerhalb der
39
Kapitel 1 Erste Schritte mit PHP
<?php
echo 'Besser nur ';
echo 'eine je Zeile';
40
Wie entstand PHP? 1.11
Aufgabe 4
Was bewirken die Optionen -m und -i? Tipp: Die Option -h bietet Hilfe.
41
Kapitel 1 Erste Schritte mit PHP
der Sprachkern war hierfür jedoch oft nicht leistungsfähig genug. So began-
nen Gutmans und Suraski bereits kurz darauf mit einer Überarbeitung des
Kerns, der die Bezeichnung »Zend Engine« erhielt. Zusammen mit weiteren
neuen Sprachelementen und grundlegenden Features wie den Benutzer-Ses-
sions für personalisierte Webseiten (Logins) wurde die Zend Engine im Jahr
2000 mit PHP 4 eingeführt. Dieser Zeitpunkt fiel mit dem Boom des Internets
zusammen. Der Bedarf an leistungsfähigen, dynamischen Webanwendungen
und damit auch Webentwicklern stieg. Die Spezialisierung von PHP auf die
Webentwicklung und die daraus resultierende einfache Erlernbarkeit ver-
drängten daraufhin andere Sprachen wie das zuvor häufig eingesetzte, aber
für diesen Zweck unhandliche Perl.
Neben einer erneuten Verbesserung der Zend Engine verlagerte sich 2004 mit
der Veröffentlichung von PHP 5 der Fokus auf die objektorientierte Program-
mierung (OOP). Ein Trend, der bis heute anhält und PHP zu einer profes
sionellen Programmiersprache ausgebaut hat. Die für PHP 6 begonnene Uni-
code-Unterstützung erwies sich als nicht durchführbar, die Versionsnummer
wurde übersprungen. Anschließend standardisierte man den unregelmäßigen
Release-Prozess, neue Veröffentlichungen folgen seitdem einem festgelegten,
transparenten Rhythmus.
PHP 7 brachte 2015 eine beachtliche Leistungssteigerung von 30 %. Die Un-
terversionen bauten nach dem Vorbild anderer Sprachen wie Java die Unter-
stützung für striktere Daten-Typisierung und objektorientierte Programmie-
rung weiter aus.
PHP 8 erschien Ende 2020. Neben weiteren fortschrittlichen Sprachfeatures
brachte es dem allgemeinen Trend anderer Sprachen folgend einen Just-in-
Time (JIT) Compiler mit, der weitere Leistungsverbesserungen ermöglichen
soll.
1.12 Übungen
Übung 1
Erweitern Sie das Programm dice.php aus Abschnitt 1.1.3 für zwei Würfel.
Übung 2
Schreiben Sie ein PHP-Kommandozeilenprogramm datetime.php zur Ausga-
be des aktuellen Datums mit Uhrzeit.
42
Variablen, Datentypen
und Konstanten
Computer-Programme verarbeiten Daten. Daten können dazu in zwei Arten
von »Containern« erfasst werden: Variablen für veränderliche und Konstanten
für unveränderliche Daten.
Variablen sind eine Art Platzhalter im Quelltext. Sie stehen stellvertretend für
Daten, die erst bei der Ausführung eines Programms konkret werden, z.B.
Benutzereingaben, Datenbankinhalte oder Zwischenergebnisse bei Berech-
nungen. Konstanten beinhalten Daten, die fester Bestandteil eines Programms
sind, etwa das Zugangspasswort zu einer Datenbank oder eine feste mathema-
tische Größe wie die Kreiszahl π (Pi).
Daten gehören immer einer bestimmten Art an, dem Datentyp. Jeder Da-
tentyp weist andere Eigenschaften auf und kann unterschiedlich eingesetzt
werden. Einfache Datentypen sind Zeichenketten (Texte), Zahlen und Wahr-
heitswerte (wahr oder falsch). Mit dem zusammengesetzten Datentyp Array
werden Daten-Sammlungen dargestellt, z.B. eine Liste aus Zahlen.
Dieses Kapitel zeigt Ihnen den Umgang mit Variablen, Konstanten und Da-
tentypen. Sie erfahren außerdem Grundlegendes zu Programmstrukturen.
43
Kapitel 2 Variablen, Datentypen und Konstanten
Das Ergebnis kann natürlich auch ohne PHP-Code erreicht werden. Aber be-
obachten Sie im Folgenden, wie sich das Beispiel mit Hilfe einer Variablen
in ein Programm mit dynamischer Ausgabe entwickelt. Um das bislang fest
vorgegebene Thema der Begrüßung (»PHP«) dynamisch austauschbar zu ma-
chen, wird die Zeichenkette durch eine Variable als Platzhalter ersetzt. Eine
Variable beginnt mit einem Dollarzeichen ($), dem ein beliebiger Name folgt.
»$topic« (engl. Thema) erscheint als passender Variablenname:
Willkommen bei <?php echo $topic; ?>
Der Inhalt der Variable muss zuvor erfasst werden. Er wird der Variablen mit
einem Gleichheitszeichen zugewiesen:
<?php $topic = 'PHP'; ?>
Willkommen bei <?php echo $topic; ?>!
Letztlich ist die Ausgabe des Programms immer noch statisch, die Variab-
le $topic enthält einen unveränderlichen Wert. Mit der in PHP eingebauten
Funktion readline() kann es jedoch dem Aufrufer des Programms bei jeder
Ausführung selbst überlassen werden, den Inhalt der Variable zu bestimmen.
Der Funktionsaufruf unterbricht die Programmausführung zur Erfassung ei-
44
Daten in einer Variablen erfassen 2.1
Nach Drücken der Eingabetaste fährt das Programm mit der Ausführung fort
und weist die Eingabe der Variablen $topic zu. Abbildung 2.1 zeigt einige
Beispielaufrufe.
45
Kapitel 2 Variablen, Datentypen und Konstanten
Auf der Kommandozeile können Daten wie gezeigt interaktiv vom Benutzer
erfasst werden. Im Browser können die Daten z.B. aus einem Formular, Coo-
kies oder der URL stammen.
Hinweis
Im weiteren Programmverlauf dient die Variable als Referenz für den Zugriff
auf die enthaltenen Daten, z.B. zur Ausgabe:
echo $topic; // => PHP
Hinweis
Eine Variable kann überall verwendet werden, wo der enthaltene Wert und
dessen Datentyp Sinn ergeben. Folgendes Beispiel mit der bereits bekannten
date()-Funktion zeigt eine indirekte Übergabe des gewünschten Datumsfor-
mats mit einer Variablen:
$format = 'd.m.Y';
echo date($format); // z.B. => 22.03.2022
46
Daten in einer Variablen erfassen 2.1
Für eine gute Lesbarkeit empfiehlt sich die Verwendung einer einheitlichen
Schreibweise der Variablen-Bezeichner, zum Beispiel der sogenannten camel-
Case-Schreibweise (»Kamelhöcker-Schreibweise«). Dabei wird grundsätzlich
klein geschrieben, nur neue Wörter beginnen mit einem Großbuchstaben:
47
Kapitel 2 Variablen, Datentypen und Konstanten
$theMostBeautifulCity = 'Neustadt';
Statt einer Zeichenkette ist es auch möglich, Zahlen zuzuweisen, die frei von
Anführungszeichen stehen:
$number = 8; // Zahl; keine Anführungszeichen!
An dieser Stelle kommt das Konzept der Datentypen ins Spiel. Jeder Wert im
Programm kann einem Datentyp zugeordnet werden. Bislang sahen Sie die
Typen Zeichenkette (engl. String) und Ganzzahl (engl. Integer). PHP erkennt
Datentypen praktischerweise automatisch im Hintergrund. Kommt es zur
Addition zweier Zahlen, kann PHP die Rechnung nach den Regeln der Ma-
thematik lösen. Kommt es zu einer Addition der Zeichenketten PHP und MySQL
wie im letzten Listing, reagiert PHP mit einem Fehler, da eine Addition zweier
Wörter nicht sinnvoll möglich ist:
PHP Fatal error: Uncaught TypeError: Unsupported operand types:
string + string
48
Daten in einer Variablen erfassen 2.1
1 Der Datentyp der Variablen $topic ist String (Zeichenkette). Der String
hat 3 Zeichen und lautet PHP.
2 Der Datentyp der Variable $number ist Integer (Ganzzahl, Abkürzung
int), ihr Wert ist die Zahl 8.
Der Datentyp einer Variablen kann sich im Laufe eines Skripts durch eine
neue Zuweisung auch einfach ändern:
$number = 8; // Datentyp: Integer
$number = 'Acht'; // Neuer Datentyp: String
Programmierer müssen den Datentyp bei der Deklaration nicht angeben und
eine Variable ist nicht dauerhaft auf einen bestimmten Datentyp festgelegt.
Dieses Merkmal von Skriptsprachen heißt dynamische Typisierung und macht
den Umgang bequem und einsteigerfreundlich.
Die dynamische Typisierung sorgt in vielen Situationen auch für automati-
sche Umwandlungen des Datentyps. Die Anpassungen erscheinen häufig völ-
lig logisch, wie hier die Ausgabe einer Zahl:
$number = 8; echo $number; // => 8
49
Kapitel 2 Variablen, Datentypen und Konstanten
PHP erkennt die beiden Strings in der Situation der Addition als numerisch
und führt während der Skriptausführung eine implizite, d.h. nicht ausdrück-
lich sichtbare Umwandlung der Strings in Ganzzahlen durch. Auch das Er-
gebnis ist ein Wert vom Typ Integer; die ursprünglichen Variablen bleiben
Strings. Wie im weiteren Verlauf des Buchs zu sehen, versucht PHP in vielen
Situationen, die Datentypen dynamisch anzupassen. Nicht immer sind die
Umwandlungen so logisch zu erklären wie in den letzten Beispielen; oft führt
dieses bequeme PHP-Feature auch zu unerwartetem Verhalten oder Sicher-
heitsproblemen.
Zum Vergleich: In Programmiersprachen mit statischer Typisierung (z.B. Java,
C#, Swift) muss der Datentyp einer Variablen bereits bei der Deklaration ei-
ner Variablen festgelegt werden und kann sich später auch nicht ändern. Eine
String-Variable kann nur Strings aufnehmen, eine Integer-Variable nur eine
Ganzzahl usw. Für die Ausgabe einer Zahl etwa muss der Programmierer die
Umwandlung der Zahl in einen String explizit anweisen. Dieser strikte Um-
gang mit Datentypen ermöglicht die Erkennung bestimmter Fehler bereits bei
der Kompilierung, d.h. bevor das Programm überhaupt ausgeführt werden
kann, und macht Programme dadurch sehr zuverlässig. Der Einstieg in eine
Programmiersprache mit solch strikter Typisierung fällt jedoch schwerer, da
mehr Hintergrundwissen, Schreibarbeit und Achtsamkeit erforderlich ist.
Auch PHP unterstützt mittlerweile in weiten Teilen eine strenge Ty-
pisierung, die optional eingeschaltet werden kann. Damit erlaubt
PHP einen einfachen Einstieg und professionelle Programmierung
gleichermaßen. Im Verlauf des Buchs lernen Sie Beispiele für strenge
Typisierung kennen.
50
Einfache Datentypen 2.2
51
Kapitel 2 Variablen, Datentypen und Konstanten
$name = 'Max';
echo $name; // => Max
echo 'Hallo $name!'; // => Hallo $name!
Man sagt, der Backslash maskiert das Anführungszeichen und hebt damit sei-
ne besondere Bedeutung auf.
Doppelte Anführungszeichen
Die Verwendung doppelter Anführungszeichen aktiviert bestimmte Sonder-
funktionen. Zum einen ersetzt PHP Variablen, die in einen String eingebettet
sind, durch ihre Werte. Man sagt auch, Variablen werden in ihre Werte »auf-
gelöst«:
$name = 'Max';
echo "Hallo $name!"; // => Hallo Max!
Die Ausgabe:
Hallo Max!
Hallo Max!
Die Maskierung mit einem Backslash unterbindet die Aktivierung von Son-
derfunktionen und auch die Bedeutung eines doppelten Anführungszeichens:
52
Einfache Datentypen 2.2
$name = 'Max';
echo "Hallo \"\$name\"!\n";
echo "Tabulator: \\t\n";
echo "Zeilenumbruch: \\n\n";
echo "Laufwerk C:\\\n";
Die Ausgabe:
Hallo "$name"!
Tabulator: \t
Zeilenumbruch: \n
Laufwerk C:\
Der Verknüpfungsoperator
Der Punkt (.) verknüpft (bzw. konkateniert) zwei Werte zu einer Zeichenket-
te, z.B. einen String-Literal mit einer String-Variablen:
$topic = 'PHP';
echo 'Hallo ' . $topic; // => Hallo PHP
Verknüpfender Zuweisungsoperator
Der Verknüpfungsoperator kann mit dem Zuweisungsoperator zu einem
»verknüpfenden Zuweisungsoperator« kombiniert werden (.=). Der Inhalt
einer Variablen wird dadurch erweitert statt überschrieben:
53
Kapitel 2 Variablen, Datentypen und Konstanten
Zur besseren Lesbarkeit können große Zahlen optional mit Unterstrichen un-
terteilt werden:
$amount = 1_455_001; // enspricht: 1455001
Arithmetische Operationen
Die arithmetischen Operatoren erlauben das Rechnen mit Zahlen:
54
Einfache Datentypen 2.2
Ist eine Division zweier Ganzzahlen nicht ohne Rest möglich, entsteht eine
Gleitkommazahl (siehe Abschnitt 2.2.4):
echo 10 / 3; // => 3.3333333333333
Arithmetische Zuweisungsoperatoren
Möchte man für eine existierende Variable eine neuen Wert berechnen, wo-
bei die Variable selbst Teil der Berechnung ist, gibt es für jede arithmetische
Operation als Abkürzung einen »kombinierten Zuweisungsoperator«. Diese
Operatoren sparen häufig Schreibarbeit:
55
Kapitel 2 Variablen, Datentypen und Konstanten
$x = 2;
// Verringert erst $x um 1 und gibt es dann aus:
echo --$x; // Entspricht 2 Anweisungen: $x-=1; echo $x; => 1
// Gibt erst $x aus und verringert es dann um 1:
echo $x--; // Entspricht 2 Anweisungen: echo $x; $x-=1; => 1
echo $x; // Erst hier hat $x zuletzt verringerten Wert => 0
56
Einfache Datentypen 2.2
Besonders große oder kleine Zahlen lassen sich auch in der wissenschaftli-
chen Exponentialschreibweise ausdrücken. Dabei wird der Dezimalpunkt nach
links bzw. rechts verschoben und durch eine Multiplikation mit einer positi-
ven bzw. negativen Zehnerpotenz ausgeglichen. Der Exponent wird mit dem
Buchstaben E von der Zahl separiert. Üblicherweise verschiebt man das Kom-
ma so lange, bis eine Zahl zwischen 1 und 10 entstanden ist.
57
Kapitel 2 Variablen, Datentypen und Konstanten
$sunIsShining = true;
$ticketIsPaid = false;
Ist die Bedingung wahr, ist das Ergebnis des Operators der Wert1, ansonsten
der Wert2.
$age = 18;
echo ($age > 17) ? 'Ja' : 'Nein'; // => Ja
Der NULL-Datentyp und sein einziger Wert null sind nicht mit der
Ganzzahl Null (0) zu verwechseln!
58
Der vielseitige Datentyp: Array 2.4
Der Zugriff auf ein Element erfolgt durch Angabe des Schlüssels in eckigen
Klammern hinter der Array-Variable:
$planets = ['Merkur', 'Venus', 'Erde'];
echo $planets[0]; // => Merkur
echo $planets[1]; // => Venus
echo $planets[2]; // => Erde
Mit Angabe des Schlüssels lässt sich auch ein neues Element einfügen:
$planets[3] = 'Mars';
Bei Angabe einer leeren Klammerpaars fügt PHP automatisch den Wert mit
dem nächsthöheren Schlüssel in das Array ein:
$planets[] = 'Jupiter'; // enspricht $planets[4]
59
Kapitel 2 Variablen, Datentypen und Konstanten
Ein Element kann wie eine Variable verwendet und daher auch überschrieben
werden:
$planets[2] = 'Unsere';
$planets[2] .= ' Erde';
Die Ausgabe:
array(5) {
[0]=> string(6) "Merkur"
[1]=> string(5) "Venus"
[2]=> string(11) "Unsere Erde"
[3]=> string(4) "Mars"
[4]=> string(7) "Jupiter"
}
Jeden Schlüssel kann es nur genau einmal im Array geben, d.h. ein Schlüssel
ist immer eindeutig. Unter verschiedenen Schlüsseln können gleiche Werte
jedoch mehrfach auftreten:
$earths = ['Erde', 'Erde', 'Erde'];
60
Der vielseitige Datentyp: Array 2.4
Auch nach der Deklaration kann ein Element mit bisher nicht vergebenem
Schlüssel erzeugt werden:
$planets[44] = 'Jupiter';
echo $planets[44]; // => Jupiter
Aufgabe 1
61
Kapitel 2 Variablen, Datentypen und Konstanten
Die Ausgabe:
array(4) {
["speedOfLight"] => int(299792458)
[0] => bool(true)
["home"] => string(4) "Erde"
[1] => float(3.33)
}
Das Beispiel zeigt auch, dass Arrays Elemente verschiedener Datentypen auf-
nehmen können.
62
Datentypen umwandeln 2.5
$employees = [
'IT' => ['Mark', 'Lisa', 'Frank'],
'Personal' => ['Jana'],
'Verkauf' => ['Elena', 'Peter'],
];
Der Zugriff auf tiefere Ebenen erfordert für jede Dimension einen weiteren
Schlüssel in eckigen Klammern:
echo $employees['Verkauf'][1]; // => Peter
Die Ausgabe hängt vom Wert der Variablen $age ab. Ist ihr Wert größer als 17,
ist der Vergleich wahr (true) und es kommt zur Ausgabe des ersten Werts, an-
sonsten ist der Vergleich falsch (false) und der zweite Wert wird ausgegeben.
Interessanterweise führt das Skript auch zum erwarteten Ergebnis, wenn der
Variablen $age ein String zugewiesen wird. Damit findet in der Bedingung des
ternären Operators ein Vergleich zwischen String und Integer statt:
$age = '21'; // $age ist ein String!
echo ($age > 17) ? 'volljährig' : 'minderjährig'; // => volljährig
PHP greift hier im Hintergrund automatisch ein und führt einen Vergleich
durch, als ob $age eine Ganzzahl wäre. Das heißt, PHP konvertiert $age für
diesen Vergleich intern in eine Ganzzahl.
63
Kapitel 2 Variablen, Datentypen und Konstanten
Andere Castings führen hingegen zu Datenverlust, da ein Wert für den neuen
Datentyp passend gemacht werden muss. Die Umwandlung einer Gleitkom-
1
https://www.php.net/manual/language.types.type-juggling
64
Datentypen umwandeln 2.5
mazahl in eine Ganzzahl führt etwa zum Verlust des Dezimalanteils (Run-
dung auf 0):
var_dump((int) 3.9); // => int(3)
Bei der Konvertierung eines Strings in eine Zahl versucht PHP eine Zahl zu
interpretieren, wenn sie am Anfang steht. Ansonsten ergibt das Casting die
Zahl 0:
var_dump((int) '4 Gewinnt'); // => int(4)
var_dump((int) 'Die Wilde 13'); // => int(0)
Aufgabe 2
65
Kapitel 2 Variablen, Datentypen und Konstanten
2.6 Programmstrukturen
Sie haben bereits einige Sprachelemente von PHP kennengelernt. Dieser Ab-
schnitt setzt die verschiedenen Elemente in den Kontext der Programmstruk-
tur und vermittelt dabei wichtige Begriffe.
2.6.1 Ausdrücke
Ein Ausdruck (engl. expression) ist ein Sprachbaustein, der durch Auswertung
bestimmter Regeln einen Wert ergibt. Die Auswertung eines Ausdrucks wird
auch Auflösung oder Evaluierung des Ausdrucks genannt.
Bereits Literale sind Ausdrücke: Der Ausdruck 3 steht für den Zahlenwert
Drei, der Ausdruck 'PHP' für den Text PHP, der Ausdruck true für den Wahr-
heitswert wahr. Literale Ausdrücke stehen folglich einfach für sich selbst.
Interessanter wird die Bedeutung von Ausdrücken beim Zusammenspiel von
mehreren Literalen oder Variablen. Der Ausdruck 3+4 verknüpft zwei nume-
rische Literale mit dem +-Operator, die Auflösung des Ausdrucks ergibt den
Wert 7. Der Ausdruck 'Hallo'.$name verknüpft ein String-Literal mit einer
Variablen und ergibt einen neuen String. Der Ausdruck $age>18 vergleicht
zwei Zahlen und resultiert in einem Wahrheitswert. Der Funktionsaufruf
date('d.m.Y') stellt ebenfalls einen Ausdruck dar: Die Evaluierung ergibt
eine Zeichenkette mit dem aktuellen Datum.
Ein Ausdruck lässt sich also stets in einen Wert übersetzen, entfaltet jedoch
selbst keine Wirkung. Ein Ausdruck führt nicht zu einer Ausgabe, er schreibt
nichts in eine Datenbank, er versendet keine E-Mail usw. Ausdrücke sind
Bausteine der nächstgrößeren Einheit in der Struktur eines Programms: den
Anweisungen.
2.6.2 Anweisungen
Eine Anweisung (engl. statement) ist ein einzelner Teilschritt im Programm-
code, der mit einem Semikolon abschließt. Ein Programm besteht aus einer
Folge von Anweisungen. Ein Ausdruck kann als Anweisung verwendet wer-
den, bewirkt für sich allein jedoch nichts. Das folgende Programm ist korrekt,
erzeugt aber keine Ausgabe oder irgendeinen anderen Seiteneffekt:
3 < 5; // Ausdruck als Anweisung ohne Wirkung
Eine sinnvolle Anweisung führt eine Aktion mit einer Wirkung aus, wobei
Ausdrücke Teile der Anweisung sind. Betrachten Sie folgende drei Programm
66
Konstanten 2.7
anweisungen zur Simulation eines Würfelwurfs. Der Spieler erhält bei einer
Sechs den Hinweis, nochmal würfeln zu dürfen:
$number = random_int(1, 6); // "Würfelwurf" 1
echo "Gewürfelt: $number\n"; 2
echo ($number < 6) ? 'Nächster' : 'Nochmal'; 3
2.7 Konstanten
Im Vergleich zu einer Variablen ist eine Konstante während der gesamte Pro-
grammausführung unveränderlich und daher konstant.
Der Ausdruck 'PHP' für sich allein ist eine literale Konstante, sie steht unver-
änderlich im Quelltext. Eine literale Konstante ist eine unbenannte Konstan-
te, da sie nicht von einer anderen Stelle im Quelltext aus referenziert werden
67
Kapitel 2 Variablen, Datentypen und Konstanten
kann. Auch die Wahrheitswerte true/false und der spezielle Wert null sind
für sich allein literale Konstanten.
Eine Konstante kann nicht überschrieben werden, der Versuch gibt eine War-
nung aus:
define('VERSION', '3.1');
define('VERSION', '3.2');
// => Warning: Constant VERSION already defined
echo VERSION; // => 3.1
68
Konstanten 2.7
Die Ausgabe:
Kreisumfang r=3m: 18.849555921539m
Sie verwenden PHP 8.0.12
Aktuelles Datum: 2021-04-06T20:27:13+00:00
Aufgabe 3
<?php
echo __FILE__; // Skriptname => /projects/book/magic.php
echo __DIR__; // Verzeichnisname => /projects/book
echo __LINE__; // Vierte Zeile => 4
echo __LINE__; // Fünfte Zeile => 5
69
Kapitel 2 Variablen, Datentypen und Konstanten
__DIR__ kommt häufig zur Bildung absoluter Pfade zum Einsatz (siehe Kapitel 8
und 14), die sich dynamisch der Umgebung anpassen, in der die Software aus-
geführt wird:
$uploadDir = __DIR__ . '/../uploads';
echo $uploadDir; // => /projects/book/../uploads
Der absolute Pfad in $uploadDir passt sich dynamisch an, wenn das Skript
in ein anderes Verzeichnis (auch auf einem anderen Computer) verschoben
wird.
2.8 Übungen
Übung 1
Welche Variablen-Bezeichner sind erlaubt?
§book, $eBook, $_1, $1_, $Irobot, $te$t, $bücher, VERSION
Übung 2
Schreiben Sie ein Skript zur Volumen-Berechnung eines Quaders:
Eingabe: Erfassen Sie die Angaben zu Höhe, Breite und Tiefe in Zentime-
tern interaktiv mit der Funktion readline().
Verarbeitung: Berechnung Sie das Volumen mit der Formel Höhe (cm) x
Breite (cm) x Tiefe (cm) = cm3.
Ausgabe: Geben Sie das Ergebnis in Kubikzentimetern (cm3) und Litern
aus (1cm3 = 1/1000 Liter).
Übung 3
Schreiben Sie ein Skript, das mitteilt, ob es sich bei einem übergebenen Argu-
ment um eine gerade oder ungerade Zahl handelt:
Eingabe: Erfassen Sie die fragliche Zahl interaktiv mit der Funktion read-
line().
Verarbeitung: Der Rest einer Division durch zwei (Modulus-Operator %)
verrät eine grade oder ungerade Zahl.
Ausgabe: Der dreiteilige (ternäre) Operator unterscheidet wahr und falsch.
70
Übungen 2.8
Übung 4
Notieren Sie folgenden Verzeichnisbaum als mehrdimensionales Array in der
Variable $directoryTree.
Hinweis: Jede Verzeichnisebene erzeugt eine neue Array-Dimension.
/home
/max
img1.jpg img2.jpg
/lisa
hausarbeit.doc rechnung.pdf
/system
/programs
firefox word
Übung 5
Wie verhält sich der Wert null in einem String-, Integer- oder Boolean-Kon-
text?
Hinweis: Prüfen Sie durch explizites Casting von null in den String-, Inte-
ger- und Boolean-Datentyp. Visualisieren Sie die Ergebnis-Datentypen mit
var_dump().
71
Programmablauf mit
Kontrollstrukturen
steuern
Die bisherigen Skripte haben ihre Anweisungen linear abgearbeitet, d.h. von
oben nach unten, Zeile für Zeile. Jeder Programmlauf führt dabei jede Anwei-
sung genau einmal aus, die Möglichkeiten zur Problemlösung sind begrenzt.
Anspruchsvollere Aufgaben erfordern Kontrolle über den Programmablauf.
Kontrollstrukturen erlauben es, vom linearen Fluss abzuweichen:
Verzweigungen führen Programmabschnitte nur unter bestimmten Bedin-
gungen aus. Sie werden mit den Schlüsselwörtern if, else und elseif for-
muliert.
Schleifen führen Programmabschnitte wiederholt aus. Sie werden mit den
Schlüsselwörtern foreach, for und while formuliert.
Die Ausführung eines Blocks lässt sich an eine Bedingung knüpfen. Ist die
Bedingung nicht erfüllt, wird der Block nicht ausgeführt. Das erlaubt Abwei-
chungen vom linearen Programmablauf, es kommt zu einer Verzweigung.
73
Kapitel 3 Programmablauf mit Kontrollstrukturen steuern
74
Programmablauf verzweigen 3.1
Quelltext
echo "Geschützter Inhalt!\n";
$password = readline('Passwort bitte: '); 1
if ($password == 'kitty') { 2
echo "(=•́\)=̀•ܫn"; 3
}
Erklärungen
1 Die Funktion readline() unterbricht den Programmlauf und fordert
den Benutzer zur Eingabe des Passworts auf. Das Drücken der Eingabetaste
setzt das Programm fort und weist die Eingabe der Variable $password als
String zu.
2 Prüft mit dem Vergleichsoperator == (»ist gleich«; zwei Gleichheitszei-
chen!), ob das eingegebene Passwort mit dem String-Literal kitty überein-
stimmt. Die Evaluierung des gesamten Ausdrucks $password=='kitty' er-
gibt entweder true oder false.
3 Anweisung zur Ausgabe des Emojis. Sie erfolgt nur, falls die Bedingung
zuvor true ergab.
Falls die Bedingung in runden Klammern zutrifft, kommt der der ersten Code-
Block zur Ausführung, ansonsten der alternative »else«-Block.
75
Kapitel 3 Programmablauf mit Kontrollstrukturen steuern
Quelltext
echo "Willkommen beim Ticketkauf für den Zoo.\n";
$age = (int) readline('Alter des Besuchers: '); 1
if ($age < 10) { 2
$price = 3; 3
} else {
$price = 5; 4
}
echo "Der Eintritt kostet €$price\n"; 5
76
Programmablauf verzweigen 3.1
Erklärungen
1 Die Funktion readline() unterbricht den Programmlauf und fordert
den Benutzer zur Eingabe des Alters auf. Das Drücken der Eingabetaste
setzt das Programm fort und weist die Eingabe der Variable $age als Ganz-
zahl zu.
2 Prüfung mit dem Vergleichsoperators < (»kleiner als«), ob das eingege-
bene Alter kleiner als 10 ist. Die Evaluierung des Ausdrucks $age<10 ergibt
true oder false.
3 Zuweisung des ermäßigten Eintrittspreises an die Variable $price. Die
Anweisung wird nur ausgeführt, falls die Bedingung zuvor true ergab.
4 Zuweisung des normalen Eintrittspreises an die Variable $price. Die An-
weisung wird nur ausgeführt, falls die Bedingung zuvor false ergab.
5 Ausgabe des Eintrittspreises, unabhängig welchen Weg das Programm
zuvor durch die Verzweigung genommen hat.
Trifft die Bedingung zu, wird der gesamte Ausdruck zu Wert1 ausgewertet, an-
sonsten zu Wert2. Betrachten Sie folgende if…else-Verzweigung:
if ($age > 17) {
echo 'Erlaubt';
} else {
echo 'Verboten';
}
Aufgabe 1
Wie verhält sich der Ausdruck »$name ? $name : 'Unbekannt'« wenn $name
einen leeren bzw. nicht-leeren String enthält?
77
Kapitel 3 Programmablauf mit Kontrollstrukturen steuern
if (Bedingung 1) {
Anweisung(en);
} elseif (Bedingung 2) {
Anweisung(en);
} elseif (Bedingung 3) {
Anweisung(en);
} else {
Anweisung(en);
}
Sobald eine Bedingung zutrifft und der zugehörige Block ausgeführt wurde,
werden keine weiteren Bedingungen mehr geprüft und die gesamte Kontroll-
struktur ist beendet.
78
Programmablauf verzweigen 3.1
79
Kapitel 3 Programmablauf mit Kontrollstrukturen steuern
Quelltext
echo "Willkommen am Bankautomat.\n";
$amount = (int) readline('Betrag (€): '); 1
if ($amount < 200) { 2
$percent = 5;
} elseif ($amount < 500) { 3
$percent = 4;
} elseif ($amount < 1000) {
$percent = 2;
} else { 4
$percent = 1;
}
$fee = round($amount * $percent/100); 5
echo "Auszahlungsgebühr: $percent % = $fee €\n"; 6
Erklärungen
1 Die Funktion readline() unterbricht den Programmlauf und fordert
den Benutzer zur Eingabe des Auszahlungsbetrags auf. Das Drücken der
Eingabetaste setzt das Programm fort und weist die Eingabe der Variable
$amount als Ganzzahl zu.
2 Die Fallunterscheidung zur Gebührenstaffelung beginnt. Der erste Fall
mit 5 % Gebühr tritt ein, wenn die Bedingung $amount<200 zutrifft. Die
Variable $percent nimmt den den Wert 5 an und die Kontrollstruktur ist
beendet.
3 Traf die erste Bedingung nicht zu, erfolgt die Prüfung der zweiten Be-
dingung $amount<500. Trifft sie zu, tritt der zweite Fall mit 4 % Gebühr ein,
die Variable $percent nimmt den Wert 4 an und die Kontrollstruktur ist
beendet. Trifft sie nicht zu, werden alle folgenden elseif-Bedingungen in
gleicher Weise geprüft.
4 Traf keine der vorigen Bedingungen zu, handelt es sich um einen Abhe-
bungsbetrag größer gleich 1000 € und die Gebühr beträgt einheitlich 1 %.
Die Variable $percent nimmt den Wert 1 an.
5 Die Auszahlungsgebühr wird berechnet und in der Variable $fee gespei-
chert. Die Funktion round() führt eine Rundung auf null Dezimalstellen
durch.
6 Anzeige der berechneten Gebühren.
80
Bedingungen formulieren 3.2
81
Kapitel 3 Programmablauf mit Kontrollstrukturen steuern
1
https://www.php.net/manual/types.comparisons
82
Bedingungen formulieren 3.2
Das Ergebnis des Ausdrucks ist true, da false&&false zunächst zu false und
dann false||true zu true ausgewertet wird. Klammern verbessern die Les-
barkeit in jedem Fall, auch wenn sie nicht notwendig sein sollten:
(false && false) || true // ergibt true
83
Kapitel 3 Programmablauf mit Kontrollstrukturen steuern
Ein Schaltjahr ist durch vier teilbar: 2016, 2020, 2024 ...
Es ist jedoch kein Schaltjahr, wenn es durch 100 teilbar ist: 1900, 2100, 2200
Ist das Jahr durch 400 teilbar, ist es dennoch ein Schaltjahr: 1600, 2000,
2400
So läuft das fertige Programm
> php leap-year-test.php
Willkommen beim Schaltjahrtest.
Jahreszahl: 2000
2000 ist ein Schaltjahr
Quelltext
echo "Willkommen beim Schaltjahrtest.\n";
$year = (int) readline('Jahreszahl: ');
if ($year % 4 === 0 && ($year % 100 !== 0 || $year % 400 === 0)) {
echo "$year ist ein Schaltjahr";
} else {
echo "$year ist kein Schaltjahr";
}
Erklärungen
Die Erklärungen konzentrieren sich auf die if-Bedingung zur Formulierung
der Schaltjahr-Regeln. Die drei Regeln können zunächst unabhängig in PHP-
Code übersetzt werden:
Durch 4 teilbar, d.h. ohne Rest: $year % 4 === 0
Nicht durch 100 teilbar, d.h. mit Rest: $year % 100 !== 0
Durch 400 teilbar, d.h. ohne Rest: $year % 400 === 0
Die einzelnen Bedingungen müssen nun entsprechend der Regeln logisch
kombiniert werden. Ein Jahr ist ein Schaltjahr, wenn:
es durch 4 und nicht durch 100 teilbar ODER
es durch 4 und auch durch 400 teilbar ist.
Mit Hilfe logischer Operatoren übersetzt in PHP-Code:
($year % 4 === 0 && $year % 100 !== 0) ||
($year % 4 === 0 && $year % 400 === 0)
84
Programmabschnitte mit Schleifen wiederholen 3.3
Die Grundbedingung, dass ein Schaltjahr durch vier teilbar sein muss, lässt
sich für eine kompaktere Schreibweise »ausklammern«:
$year % 4 === 0 && ($year % 100 !== 0 || $year % 400 === 0)
Für die Jahre 2000, 2020, 2022 und 2100 ergeben sich nach Auflösung der
Vergleiche folgende logische Verkettungen:
2000: true && (false || true) => true
2020: true && (true || false) => true
2022: false && (true || false) => false
2100: true && (false || false) => false
Genau genommen wertet PHP logische Ausdrücke nicht weiter aus, sobald
das Ergebnis feststeht. Für das Jahr 2022, welches nicht durch vier teilbar ist,
steht das gesamte Ergebnis bereits unveränderlich nach Auswertung des ers-
ten Operanden zu false fest.
PHP bietet die Schleifentypen foreach, for und while. Oft können Aufgaben
mit verschiedenen Typen gleichermaßen gelöst werden, jeder Typ ist jedoch
auf bestimmte Fälle spezialisiert.
85
Kapitel 3 Programmablauf mit Kontrollstrukturen steuern
Die foreach-Schleife iteriert nach dem folgenden Schema über die Menge der
Array-Elemente.
$array = [Wert1, Wert2, ...]; 1
foreach ($array as $element) { 2
// 1. Lauf mit $element = Wert1
// 2. Lauf mit $element = Wert2 usw.
Anweisung(en);
}
1 $array steht für ein beliebiges Array, dessen Elemente durchlaufen wer-
den sollen.
2 Der Bezeichner $element ist frei wählbar und nimmt in jeder Iteration
den Wert des nächsten Elements aus $array an.
Der Auftrag an PHP lautet: »Solange Elemente im Array sind, führe den An-
weisungsblock aus. Rücke nach jedem Durchlauf ein Element vor. Sind keine
weiteren Elemente mehr im Array, beende die Schleife. Sind gar keine Ele-
mente im Array (leeres Array), führe den Block nie aus«. Folgendes Skript
berechnet für alle Zahlen in einem Array die Quadratwurzel:
86
Programmabschnitte mit Schleifen wiederholen 3.3
Hat das Array keine expliziten Schlüssel, verwendet PHP die intern vergebe-
nen, numerischen Schlüssel (0, 1, 2 …). Folgendes Skript gibt Schlüssel und
Werte eines Arrays aus:
$letters = ['A', 'B', 'C'];
foreach ($letters as $key => $letter) {
echo "$key:$letter ";
}
// => 0:A 1:B 2:C
Schreiben Sie eine foreach-Schleife über das Array ['A', 'B', 'C'], die zur
Ausgabe A-B-C führt (Bindestriche nur zwischen den Buchstaben!).
Tipp: Der Array-Schlüssel sagt Ihnen, in welcher Iteration Sie sich be
finden. Unterscheiden Sie durch eine if-Anweisung.
87
Kapitel 3 Programmablauf mit Kontrollstrukturen steuern
Quelltext
$drinks = [ 1
'Wasser' => 2,
'Cola' => 2.5,
'Kiba' => 3.5,
];
foreach ($drinks as $drink => $price) { 2
echo "$drink: " . number_format($price, 2, ',') . "€\n"; 3
}
Erklärungen
1 Initialisieren einer Getränkeliste als Array $drinks. Jedes Element ordnet
einem Getränkenamen (Schlüssel) einen Preis zu (Wert).
2 Die foreach-Schleife iteriert über die Elemente des Arrays $drinks, der
Block wird für jedes Element einmal ausgeführt. Bei jedem Durchlauf ent-
hält $drink den Schlüssel des aktuellen Elements (Getränkename) und
$price den zugehörigen Wert (Getränkepreis).
3 Für jedes Getränk in der Liste wird derselbe Code zur Ausgabe ausge-
führt. Die Funktion number_format() formatiert die Preise auf zwei Dezi-
malstellen und einem Komma als Dezimaltrenner.
88
Programmabschnitte mit Schleifen wiederholen 3.3
schleife ist sinnvoll, wenn die Anzahl der Iterationen vorher bekannt ist. Ein
Beispiel zur Ausgabe der Ziffern 0 bis 9 verdeutlicht den Ablauf:
for ($i = 0; $i <= 9; $i++) {
echo "$i ";
}
// => 0 1 2 3 4 5 6 7 8 9
Der Kopf der Schleife in der ersten Zeile enthält drei mit Semikolons getrenn-
te Bereiche:
$i=0: Einmalige Anweisung zur Initialisierung der Zählvariablen $i vor
Ausführung der Schleife.
$i<=9: Prüfbedingung vor jedem Schleifendurchlauf; solange sie wahr ist,
erfolgt eine Wiederholung der Schleife.
$i++: Anweisung zur Ausführung nach jedem Schleifendurchlauf; sie er-
höht die Zählvariable um eins.
89
Kapitel 3 Programmablauf mit Kontrollstrukturen steuern
Quelltext
echo "Countdown läuft.\n";
for($i = 10; $i > 0; $i--) { 1
echo "$i "; 2
sleep(1); 3
}
echo "-- START!\n";
Erklärungen
1 Die Zählvariable $i wird mit dem Wert 10 initialisiert. Solange $i>0
wahr ist, soll sich die Schleife wiederholen. Nach jedem Durchlauf wird die
Zählvariable mittels $i-- um eins verringert.
2 Ausgabe des aktuellen Zählerstands.
3 Die Funktion sleep() pausiert das Programm für die übergebene Anzahl
an Sekunden.
90
Programmabschnitte mit Schleifen wiederholen 3.3
Der Anweisungsblock wird solange wiederholt, bis die Bedingung nicht mehr
erfüllt ist.
91
Kapitel 3 Programmablauf mit Kontrollstrukturen steuern
Quelltext
echo "Bitte Namen eingeben.\n";
echo "Auslosung mit leerer Eingabe starten.\n";
$names = []; 1
while($name = readline('Name: ')) { 2
$names[] = $name; 3
}
$randomKey = random_int(0, count($names)-1); 4
echo "Ausgeloster Name: $names[$randomKey]\n"; 5
Erklärungen
1 Initialisierung eines leeren Arrays $names zur Aufnahme der eingegebe-
nen Namen.
2 readline() unterbricht den Programmablauf und wartet auf die Namens
eingabe. Das Drücken der Eingabetaste setzt das Programm fort und weist
die Eingabe als String der Variablen $name zu. Die Auswertung von $name
dient gleichzeitig als Bedingung der while-Schleife: Ein nicht-leerer String
evaluiert zu true, ein leerer String zu false. Solange die Eingabe nicht leer
ist, folgt eine weitere Iteration.
3 Jeder eingegebene Name wird dem Array $names als neues Element am
Ende hinzugefügt. Ohne explizite Schlüssel vergibt PHP automatisch ganz-
zahlige Schlüssel 0, 1, 2 usw. Bei n eingegebenen Namen enthält das Array
damit [0=>Name1, 1=>Name2, ..., n=>NameN].
4 Die Auslosung. Die Funktion random_int() lost einen Zufallsschlüssel
des Arrays $names aus und speichert ihn in der Variable $randomKey. Der
Schlüssel muss zwischen dem ersten Schlüssel 0 und dem höchsten Schlüs-
sel des Arrays liegen. count() ermittelt die Anzahl von Elementen in einem
Array. Da die Schlüssel bei 0 starten, hat der höchste Schlüssel des Arrays
einen um eins geringeren Wert.
92
Programmabschnitte mit Schleifen wiederholen 3.3
3.3.9 Endlosschleifen
Die Bedingung einer Schleife kann (ungewollt) zu einer endlosen Wieder-
holung des Anweisungsblocks führen, das Programm befindet sich in einer
Endlosschleife:
93
Kapitel 3 Programmablauf mit Kontrollstrukturen steuern
Die Notation mit geschweiften Klammern wird leicht unübersichtlich und die
Zuordnung schließender Klammern fällt schwer. Für bessere Lesbarkeit sorgt
eine alternative Syntax:
<?php if ($planet === 'Merkur'): ?>
Der Merkur ist ...
<?php elseif ($planet === 'Venus'): ?>
Die Venus ist ...
<?php elseif ($planet === 'Erde'): ?>
...
<?php else: ?>
94
Übungen 3.5
Unbekannter Planet.
<?php endif ?>
Aufgabe 3
Schreiben Sie eine foreach-Schleife in alternativer Syntax die über ein Ar-
ray $planets mit Planetennamen iteriert und für jeden Namen Willkom-
men auf Planet $planet. ausgibt.
3.5 Übungen
Übung 1
Ermitteln Sie die Wahrheitswerte folgender Ausdrücke:
Vergleich Wahr oder falsch?
0 >= 2
'drei' == 'drei'
'3' === 3
[] === []
true || false
true && false
!false && true
7 > 4 && 7 < 6
7 > 4 && 7 < 6 || 7 < 9
'' == false
'' === false
95
Kapitel 3 Programmablauf mit Kontrollstrukturen steuern
Übung 2
Schreiben Sie ein Skript zur interaktiven Abfrage eines Geburtsjahrs. Akzep-
tieren Sie nur Geburtsjahre zwischen dem aktuellen Jahr und dem Jahr vor
125 Jahren. Teilen Sie dem Benutzer mit, ob seine Eingabe gültig ist oder nicht.
Tipp: Nutzen Sie readline() zur Abfrage des Geburtsjahrs und date('Y') zur
Ermittlung des aktuellen Jahrs.
Übung 3
Schreiben Sie ein Skript, das die Zahlen aus dem Array [2, 6, 8, 19] aufsum-
miert und das Ergebnis ausgibt. Nutzen Sie eine foreach-Schleife.
Übung 4
Schreiben Sie ein Skript, das mit Hilfe von zwei verschachtelten for-Schleifen
folgendes Muster ausgibt:
*
* *
* * *
* * * *
* * * * *
Tipp: Verwenden Sie die Zählvariable der äußeren Schleife zur Bestimmung
der Abbruchbedingung der inneren Schleife.
Übung 5
Schreiben Sie ein Skript, das interaktiv sechs verschiedene Lottozahlen zwi-
schen 1 und 49 vom Benutzer abfragt und am Ende anzeigt.
Tipps:
Sammeln Sie die getippten Zahlen im Array $lottoTip.
Nutzen Sie eine while-Schleife, die sich so lange wiederholt, bis sechs gül-
tige Zahlen eingesammelt wurden. Die Funktion count() ermittelt die An-
zahl an Elementen in einem Array. Bei einer ungültigen Zahl beenden Sie
die aktuelle Iteration mit continue vorzeitig.
Dopplungen können Sie mit der Funktion array_search(Zahl, $lottoTip)
erkennen. Sie liefert false, wenn Zahl noch nicht in $lottoTip existiert.
96
Programmierfehler und
PHP-Konfiguration
Haben Sie bereits versehentlich eine der erlernten Regeln zum Schreiben von
PHP-Skripten verletzt und einen Fehler bei der Programmausführung verur-
sacht? Einen Programmierfehler bezeichnet man als Bug (engl. für »Ungezie-
fer«), die Ursachensuche und Fehlerbeseitigung als Debugging. Bugs können
frustrierend sein, jedoch trägt kaum etwas mehr zum Verständnis bei als die
gewonnenen Erfahrungen bei der Suche nach Fehlerursachen.
Dieses Kapitel stellt unterschiedliche Arten von Programmierfehlern und das
System der Fehlerstufen in PHP vor. Außerdem lernen Sie durch Konfigura-
tion der php.ini-Datei das Verhalten einer PHP-Installation zu beeinflussen.
4.1 Programmierfehler
Es gibt drei Fehlerarten: Syntaxfehler, Laufzeitfehler und logische Fehler.
4.1.1 Syntaxfehler
Im folgenden Skript wurde bei der Verwendung der date()-Funktion verges-
sen, das runde Klammerpaar zu schließen:
echo 'Das aktuelle Datum: ';
echo date('d.m.Y';
Die Ausführung des Skripts bricht mit einem Syntaxfehler (engl. syntax error)
ab. Die Fehlermeldung gibt Aufschluss über das Problem:
> php syntax-error.php
Parse error: syntax error, unexpected token ";", expecting ")"
97
Kapitel 4 Programmierfehler und PHP-Konfiguration
Wie jede Sprache definieren auch Programmiersprachen eine Syntax, d.h. ein
Regelsystem, welche Zeichenfolgen gültig sind. Für PHP besagt eine dieser
Regeln, dass ein Funktionsaufruf aus einem Wort, gefolgt von einem runden
Klammerpaar, bestehen muss, etwa date(). PHP findet den Fehler bereits bei
der Analyse des Quelltexts (dem parsen) und bricht schon vor der Interpre-
tation des Codes ab. Die Ausgabe aus der korrekten ersten Zeile erfolgt daher
nicht. Syntaxfehler sind am leichtesten zu vermeiden, da sie ohne Programm
ausführung bereits im PHP-Quelltext-Editor zu erkennen sind:
4.1.2 Laufzeitfehler
Ist die Syntax eines Skripts korrekt, beginnt der PHP-Interpreter die Anwei-
sungen abzuarbeiten – das Skript »läuft«. Kommt es bei einer Anweisung zu
einem Fehler, d.h. zur Laufzeit (engl. runtime) des Programms, spricht man
von einem Laufzeitfehler (engl. runtime error).
Folgendes Skript ermittelt die anteilige Gewinnsumme für jeden Gewinner
einer Lotterie, die einen Jackpot ausschüttet. Obwohl das Skript syntaktisch
korrekt ist, kann es zu einem Laufzeitfehler kommen:
$jackpot = (int) readline('Jackpot (€): ');
$winners = (int) readline('Anzahl Gewinner: ');
echo '€ je Gewinner: ' . ($jackpot / $winners);
98
PHP konfigurieren: die php.ini-Datei 4.2
Aufgabe 1
Verbessern Sie das Skript jackpot.php, um eine Division durch null auszu-
schließen. Prüfen Sie zuvor die Anzahl der Gewinner.
99
Kapitel 4 Programmierfehler und PHP-Konfiguration
Reicht der Speicher für speicherintensive Aufgaben (z.B. das Verarbeiten sehr
großer Datenmengen) nicht aus, bricht das Skript ab:
Fatal error: Allowed memory size of XXXXX bytes exhausted
Wird ein höherer Speicherverbrauch erwartet und ist genügend Speicher vor-
handen, kann die Direktive angepasst werden (hier auf 256 Megabyte):
memory_limit = 256M
Die php.ini kann mit einem Text-Editor bearbeitet werden, z.B. Visual Studio
Code (Kapitel 1). Der Befehl code öffnet die Datei direkt von der Kommando-
zeile aus in VS Code:
> code /C/Programme/php/php.ini
100
PHP konfigurieren: die php.ini-Datei 4.2
Bestimmte Direktiven in der sehr langen Datei finden Sie schnell mit der
Suchfunktion des Editors ((Strg)+(F)). Gespeicherte Änderungen an der
php.ini greifen sofort bei der nächsten Verwendung des php-Befehls.
101
Kapitel 4 Programmierfehler und PHP-Konfiguration
Unter Linux installieren Sie zusätzliche Erweiterungen wie zuvor PHP selbst
(Abschnitt 1.7.3) mit dem Paketmanager:
> sudo apt install php-Erweiterungsname
Aufgabe 2
4.3 Fehlerstufen
Nicht jeder von PHP erkannte Fehler führt zum Abbruch der Programmaus-
führung. PHP unterscheidet die Schwere von Fehlern in verschiedenen Feh-
lerstufen (engl. error levels). Die wichtigsten Stufen lauten:
Mit der Warnung kennt PHP einen Laufzeitfehler, der nicht zum Skriptab-
bruch führt, sondern lediglich auf ein mögliches Problem aufmerksam ma-
chen soll. Folgendes Skript verwendet eine zuvor nicht deklarierte Variable:
102
Fehlersichtbarkeit einstellen 4.4
echo $myUndefinedVariable;
echo '*** Skript läuft noch ***';
Der PHP-Interpreter gibt eine Warnung aus, sobald er auf die undefinierte
Variable trifft:
> php undefined-variable-warning.php
Warning: Undefined variable $myUndefinedVariable
*** Skript läuft noch ***
103
Kapitel 4 Programmierfehler und PHP-Konfiguration
Aufgabe 3
Wie lautet die Direktive zum generellen Ein- bzw. Ausschalten des Log-
gings?
Tipp: www.php.net/ini.list
4.5 Übungen
Übung 1
Stellen Sie in der php.ini sicher, dass alle Fehler in eine Log-Datei protokolliert
werden und schalten Sie die direkte Fehleranzeige aus. Verursachen Sie Fehler
und beobachten Sie die Logdatei.
Übung 2
Schreiben Sie ein Skript, das den erlaubten Speicherverbrauch anzeigt. Än-
dern Sie den erlaubten Speicherverbrauch zur Laufzeit auf 500MB und prüfen
Sie die veränderte Einstellung erneut. Hinweis: Direktiven mit Angaben zu
Speicherkapazitäten erfolgen in Bytes. Abkürzungen sind mit den Suffixen K
(für Kilobyte), M (für Megabyte) und G (für Gigabyte) möglich.
104
Funktionen
Eine Funktion ist ein hinterlegtes »Rezept« zur Lösung einer Programmierauf-
gabe, das bei Bedarf angewendet werden kann. PHP ist bekannt für die Viel-
falt seiner eingebauten Funktionen, die standardmäßig zur Verfügung stehen.
Darüber hinaus können Sie eigene Funktionen definieren, um selbstgeschrie-
benen Code wiederzuverwenden und zu strukturieren. Ein Codeblock zur
Lösung einer Aufgabe wird dabei als eine Art Unterprogramm in einer Funk-
tion zusammengefasst. Durch den Aufruf der Funktion von einer beliebigen
anderen Stelle im Programm aus führen Sie den Codeblock bei Bedarf aus.
Dieses Kapitel stellt die Verwendung von fest in PHP eingebauten Funktionen
und die Definition eigener Funktionen vor.
105
Kapitel 5 Funktionen
In den vorigen Kapiteln sind Sie bereits der PHP-Funktion date() begegnet,
um das aktuelle Datum bzw. die aktuelle Uhrzeit in einem gewünschten For-
mat zu erhalten. Sie können die Funktion beliebig oft aufrufen und dabei das
erzeugte Datumsformat mit einem Parameter steuern:
echo date('d.m.Y H:i'); // z.B. => 06.05.2022 20:33
echo date('Y-m-d'); // z.B. => 2022-05-06
echo date('l, F jS Y'); // z.B. => Friday, May 6th 2022
Der Funktionsname beschreibt den Zweck der Funktion und dient als Bezeich-
ner, um die Funktion im Programm anzusprechen. Je nach Funktion übergibt
man beim Aufruf in runden Klammern kommasepariert so genannte Argu-
mente. Argumente sind konkrete Werte, die aus dem Programmlauf in die
Funktion übergeben werden und bei jedem Aufruf verschieden sein können.
Die übergebenen Argumente stehen dem Anweisungsblock der Funktion als
Variablen bzw. Parameter zur Verfügung.
Die Begriffe Argument und Parameter werden oft synonym verwen-
det. Genau genommen ist ein Argument der konkrete Übergabewert
aus dem Programmlauf in eine Funktion. Ein Parameter ist die Va-
riable im Kontext der Funktion, die ein übergebenes Argument auf-
nimmt (unabhängig des konkreten Werts).
Funktionsaufrufe sind Ausdrücke, die in einen Wert aufgelöst werden, den
so genannten Rückgabewert der Funktion. Der Rückgabewert kann wie jeder
andere Ausdruck verwendet werden, z.B. in einer Ausgabe, als Zuweisung an
eine Variable, als Bedingung einer Kontrollstruktur oder als Argument für ei-
nen anderen Funktionsaufruf.
Folgender Code rundet die Kreiszahl π (aus der von PHP vordefinierten Kon-
stante M_PI) mit der Funktion round() auf eine zufällige Anzahl an Dezimal-
stellen zwischen 3 und 8. Die Variable $result nimmt den Rückgabewert auf,
der anschließend ausgegeben wird:
106
Native Funktionen aus der PHP-Bibliothek verwenden 5.1
Der zweite Parameter der Funktion round() gibt die Anzahl der Dezimal-
stellen für die Rundung an, die durch die Funktion random_int() zufällig be-
stimmt wird.
Die PHP-Dokumentation beschreibt jede Funktion im Detail und gibt nützli-
che Code-Beispiele.
107
Kapitel 5 Funktionen
108
Native Funktionen aus der PHP-Bibliothek verwenden 5.1
Die Signatur der date()-Funktion gibt eindeutige Hinweise auf die Datenty-
pen ihrer Parameter und des Rückgabewerts:
string $format: Der erste Parameter ist ein String.
int $timestamp: Der zweite Parameter ist eine Ganzzahl.
date(…): string: Der Rückgabewert ist ein String.
Es gibt auch Parameter, denen Werte eines beliebigen Datentyps übergeben
werden können. In einer Signatur sind sie mit dem »unechten« Datentyp
mixed gekennzeichnet. Zum Beispiel prüft isset() unabhängig vom Daten-
typ, ob eine oder mehrere übergebene Variablen im Programm initialisiert
wurden:
isset(mixed $var, mixed ...$vars): bool
Die Übergabe des ersten Arguments ist zwingend. Die drei Punkte vor dem
zweiten Parameter signalisieren, dass optional beliebig viele weitere Argu-
mente folgen dürfen. Dadurch kann isset()auch mehrere Variablen gleich-
zeitig prüfen:
$firstName = 'Erika';
var_dump(isset($firstName)); // => true
var_dump(isset($lastName)); // => false
109
Kapitel 5 Funktionen
5.1.2 Rückgabewerte
Es gibt Funktionen, die:
immer einen Rückgabewert desselben Datentyps liefern, d.h. der Rückga-
bedatentyp ist immer eindeutig, z.B. ein String.
einen Rückgabewert verschiedener Datentypen (»mixed«) liefern können,
d.h. der Rückgabedatentyp ist mehrdeutig, z.B. entweder ein String oder
eine Ganzzahl.
gar keinen Rückgabewert liefern (»void«).
Eindeutiger Rückgabewert
Mit der Funktion date() kennen Sie eine Funktion mit eindeutigem Rück-
gabewert. Die Signatur verrät, dass jeder korrekte Aufruf immer einen String
(ein formatiertes Datum) zurückliefern wird:
date(string $format, int $timestamp = null): string
Mehrdeutiger Rückgabedatentyp
Mehrdeutige Rückgabedatentypen werden genutzt, um mehrere Anwen-
dungsfälle, Sonderfälle oder Fehler auszudrücken. Die Funktion array_
search() durchsucht z.B. ein Array nach einem Wert und liefert bei einem
Treffer den passenden Schlüssel zurück. Der Schlüssel kann eine Ganzzahl
(numerisch indiziertes Array) oder ein String (assoziatives Array) sein. Ist der
Wert gar nicht im Array vorhanden, wird dies mit dem Rückgabewert false
ausgedrückt. Die Signatur zählt die verschiedenen möglichen Rückgabe-
Datentypen auf, getrennt mit einem senkrechten Strich, dem Pipe-Symbol (|):
array_search(mixed $needle, array $haystack): int|string|false
110
Native Funktionen aus der PHP-Bibliothek verwenden 5.1
Der ternäre Operator (Abschnitt 3.1.5) liefert den ersten Ausdruck (Treffer!),
wenn seine Bedingung ($key) wahr ist, ansonsten den zweiten (Niete!).
Auf Grund der dynamischen Typisierung von PHP ist Vorsicht geboten:
$colors = ['rot', 'blau', 'grün'];
$key = array_search('rot', $colors); // $key=0
echo $key ? 'Treffer!' : 'Niete!'; // => Niete!
Was ist passiert? Zur Auswertung der Bedingung ($key) im ternären Operator
führt PHP eine automatische Konvertierung in einen booleschen Wert durch.
Explizit bedeutet dies:
echo ((bool) $key) ? 'Treffer!' : 'Niete!';
Der gefundene Schlüssel 0 für die Farbe rot interpretiert PHP als false, da der
Wahrheitsgehalt der Zahl Null false ist (siehe Abschnitt 2.5):
var_dump((bool) 0); // bool(false)
Die sichere Lösung ist ein strikter Vergleich auf Identität (Abschnitt 3.2.2), die
den Datentyp mit einbezieht:
$colors = ['rot', 'blau', 'grün'];
$key = array_search('rot', $colors); // $key=0
echo ($key !== false) ? 'Treffer!' : 'Niete!'; // => 'Treffer!'
111
Kapitel 5 Funktionen
112
Native Funktionen aus der PHP-Bibliothek verwenden 5.1
Aufgabe 1
Schreiben Sie eine Anweisung, die die Wurzel aus 13 auf zwei Nachkom-
mastellen gerundet berechnet.
113
Kapitel 5 Funktionen
Quelltext
$email = readline('E-Mail: '); 1
$email = strtolower(trim($email)); 2
if (strlen($email) > 50) { 3
exit('E-Mail >50 Zeichen nicht zulässig');
}
114
Native Funktionen aus der PHP-Bibliothek verwenden 5.1
if (!str_contains($email, '@')) { 4
exit('E-Mail muss ein @-Zeichen enthalten.');
}
$emailParts = explode('@', $email); 5
if ($emailParts[1] === 'example.com') { 6
exit('E-Mails von example.com nicht erlaubt.');
}
printf( 7
'E-Mail "%s" wurde registriert.',
str_replace('@', '(at)', $email) 8
);
Erklärungen
1 Abfrage der E-Mail-Adresse und Zuweisung an $email.
2 Normalisierung der Eingabe: Entfernung versehentlich eingegebener
Leerzeichen am Anfang und Ende; einheitliche Umwandlung in Klein-
buchstaben, da die Schreibweise in E-Mail-Adressen keine Rolle spielt.
3 Längenprüfung: Falls die Adresse länger als 50 Zeichen ist, beendet
exit() das Programm mit einem Hinweis.
4 Prüfung, ob die Adresse ein @-Zeichen enthält. Ablehnung, falls kein
@-Zeichen vorhanden ist.
5 Aufsplitten der E-Mail-Adresse an der Stelle des @-Zeichens in ein Array
mit zwei Elementen (Text vor und nach dem @-Zeichen).
6 Prüfung, ob die Adresse die Beispiel-Domain »example.com« verwen-
det. Ablehnung, falls ja.
7 Rückmeldung zur erfolgreichen Registrierung.
8 Ersetzung des @-Zeichens durch (at).
Aufgabe 2
115
Kapitel 5 Funktionen
116
Native Funktionen aus der PHP-Bibliothek verwenden 5.1
Quelltext
$length = (int) readline('Passwortlänge: '); 1
if ($length < 5) {
exit('Passwortlänge muss >= 5 sein.'); 2
}
$characterPool = array_merge( 3
range(0, 9), 4
range('A', 'Z'),
range('a', 'z'),
['*', '#', '?', '+', '_', '-'] 5
);
shuffle($characterPool); 6
$password = ''; 7
while ($length-- > 0) { 8
$randomKey = array_rand($characterPool); 9
$password .= $characterPool[$randomKey]; 1 0
}
echo "Passwort: $password";
Erklärungen
1 Gewünschte Passwortlänge vom Benutzer abfragen und als Ganzzahl an
$length zuweisen.
2 Falls die Passwortlänge unter 5 Zeichen liegt, beendet exit() das Pro-
gramm mit einem Hinweis.
3 In der Array-Variablen $characterPool wird ein Pool möglicher Pass-
wortzeichen aufgebaut. array_merge() vereint den Pool aus einzelnen Teil-
mengen.
4 Neben Arrays mit Zahlenbereichen kann range() auch Buchstabenbe-
reiche erzeugen. So entstehen Arrays mit den Teilmengen 0 bis 9, A bis Z
und a bis z.
5 Eine Teilmenge mit Sonderzeichen wird beigemischt.
117
Kapitel 5 Funktionen
Unixzeit
Für die Programmierung mit Datum und Zeit ist die Unixzeit ein grundle-
gendes Konzept. Die Unixzeit wurde für das Unix-Betriebssystem entwickelt
und zählt die vergangenen Sekunden seit dem 1. Januar 1970 um 00:00 Uhr
UTC (Weltzeit). Die Unixzeit am 25. Mai 2022 um 14:30 lautet zum Beispiel:
1653489000. Eine fixe Unixzeit heißt Zeitstempel (engl. Timestamp).
Ein Aufruf der PHP-Funktion time() liefert den aktuellen Unix-Zeitstempel
nach der Uhr des Betriebssystems:
echo time(); // z.B. => 1653489000
sleep(3); // 3 Sekunden warten
echo time(); // => 1653489003
Datum formatieren
Einem Menschen fällt es schwer, einen Unix-Zeitstempel direkt zu interpre-
tieren. Die date()-Funktion »übersetzt« einen Zeitstempel in ein lesbares
Format und kann auch Dinge wie den Wochentag, den Tag im Monat u.v.m.
daraus bestimmen. Als erstes Argument werden dazu Formatzeichen für das
118
Native Funktionen aus der PHP-Bibliothek verwenden 5.1
Formatzeichen Beschreibung
d Tag des Monats mit führender Null
m Monat des Jahres mit führender Null
Y Jahreszahl, vierstellig
H Stunde im 24h-Format mit führender Null
i Minuten mit führender Null
s Sekunden mit führender Null
y Jahreszahl, zweistellig
n Monat des Jahres, ohne führender Null
w Wochentag als Zahl von 0 (Sonntag, US-Format!) bis Samstag (6)
Rückgaben der Funktion date() können auch für die eigene Programmlogik
genutzt werden. Das Formatzeichen »w« liefert z.B. den Wochentag als Num-
mer zwischen 0 (Sonntag; nach US-Standard der erste Tag der Woche) und 6
(Samstag). Rufen Sie die Funktion an einem Montag auf, wäre das Ergebnis
die Zahl 1:
echo date('w'); // z.B. Aufruf montags => 1
Die Nummer des Wochentags kann weiter genutzt werden, z.B. um den ak-
tuellen Wochentag auf Deutsch auszugeben. Die Wochentags-Nummer wird
dynamisch als Schlüssel eingesetzt, um den passenden Wert aus einem Array
mit den sortierten Namen der deutschen Wochentage zu finden:
$weekdays = ['Sonntag', 'Montag', ... 'Samstag'];
echo $weekdays[date('w')]; // z.B. Aufruf montags => Montag
119
Kapitel 5 Funktionen
Durch explizite Angabe eines Zeitstempels kann ein beliebiges Datum forma-
tiert werden:
$ts = time(); // Zeitstempel zur Laufzeit
date('d.m.y H:i:s', $ts); // aktuelle Zeit
date('d.m.y H:i:s', $ts + 60); // +1 Minute
date('d.m.y H:i:s', $ts + (60*60)); // +1 Stunde
date('d.m.y H:i:s', $ts + (60*60*24)); // +1 Tag
Zeitstempel erzeugen
Die Funktion time() liefert immer den Unix-Zeitstempel für den aktuellen
Zeitpunkt. Mit der Funktion mktime() (make time) können Sie den Zeitstem-
pel für einen beliebigen Zeitpunkt bestimmen. Dazu übergibt man die Be-
standteile des gewünschten Datums in der Reihenfolge: Stunde, Minute, Se-
kunde, Monat, Tag, Jahr:
$ts = mktime(14, 30, 0, 5, 25, 2022); // $ts=1653489000
echo date('d.m.y H:i', $ts); // => 25.05.22 14:30
mktime() hat die praktische Eigenschaft, bei Angaben über die gültigen Berei-
che hinweg automatisch umzurechnen:
// 25. Mai + 14 Tage = "39. Mai" = 8. Juni
$ts = mktime(14, 30, 0, 5, 25 + 14, 2022);
echo date('d.m.y H:i', $ts); // 08.06.22 14:30
// 14:30 Uhr + 12 Stunden = "26:30 Uhr" = 2:30 Uhr
$ts = mktime(14 + 12, 30, 0, 5, 25, 2022);
echo date('d.m.y H:i', $ts); // 26.05.22 02:30
// 1. März 2022 – 1 Tag = letzter Februartag 2022
$ts = mktime(0, 0, 0, 3, 0, 2022);
echo date('d.m.y', $ts); // 28.02.22
// 1. März 2020 – 1 Tag = letzter Februartag 2020
120
Native Funktionen aus der PHP-Bibliothek verwenden 5.1
Beispiele mit relativen Zeitangaben zur Laufzeit am 25. Mai 2022 um 14:30
Uhr:
$ts = strtotime('now');
echo date('d.m.y H:i', $ts); // 25.05.22 14:30
$ts = strtotime('now +3hours');
echo date('d.m.y H:i', $ts); // 25.05.22 17:30
$ts = strtotime('Third Sunday of June next year');
echo date('d.m.y H:i', $ts); // 20.06.22 00:00
$ts = strtotime('Yesterday noon');
echo date('d.m.y H:i', $ts); // 24.05.22 12:00
Zeitzone
Die Unixzeit entspricht immer der Weltzeit UTC (+00:00). Die mitteleuro-
päische Winterzeit ist eine Stunde (+01:00), die Sommerzeit zwei Stunden
(+02:00) voraus.
Ausgaben der Funktion date() richten sich nach der Zeitzone aus der php.
ini-Einstellung date.timezone (Vorgabewert UTC). PHP rechnet einen Unix-
121
Kapitel 5 Funktionen
Zur Laufzeit eines Skripts kann die Zeitzone auch mit der Funktion date_
default_timezone_set() eingestellt werden. Die Zeitzone gilt bis zu einem
weiteren Aufruf der Funktion oder dem Ende des Skripts für alle Datums-
funktionen. Das Pendant date_default_timezone_get() liest die aktuell ein-
gestellte Zeitzone aus.
$timezone = date_default_timezone_get();
echo $timezone.': '.date('H:i'); // z.B. => UTC: 14:30
date_default_timezone_set('Europe/Berlin');
$timezone = date_default_timezone_get();
echo $timezone.': '.date('H:i'); // => Europe/Berlin: 16:30
122
Eigene Funktionen definieren 5.2
Bemerken Sie den Unterschied bei der Formatierung eines Strings mit
Platzhaltern (%s)? Im Programmkontext wird printf() verwendet, im
Kontext der Funktion aber sprintf(). printf() gibt den String wie
echo nach Ersetzung der Platzhalter direkt aus, während sprintf()
ihn als Rückgabewert liefert.
Zur Formatierung eines Datums ist nur die Übergabe des Datums an die
Funktion formatDate() erforderlich:
echo formatDate('2022-05-25'); // => Mittwoch, 25.05.22
echo formatDate('2022-06-08'); // => Samstag, 06.08.22
123
Kapitel 5 Funktionen
Soll die Funktion keinen Wert zurückgeben, kann return ohne Rückgabewert
aufgerufen oder weggelassen werden:
function hello($name) {
if (trim($name) === '') { // nur Leerzeichen?
return;
}
echo "Hallo $name!";
}
hello(' '); // Keine Ausgabe
hello('Karla'); // => Hallo Karla!
Der Aufruf einer Funktion ist bereits vor der Definition möglich, da PHP
Skripte bereits vor der Ausführung komplett einliest:
124
Eigene Funktionen definieren 5.2
Mit Hinweisen auf die Datentypen – so genannten Type Hints – kann eine
Funktion explizit bestimmte Datentypen einfordern und auch den Datentyp
des Rückgabewerts klarstellen:
function sum(int $value1, int $value2): int {
return $value1 + $value2;
}
sum('www', 3);
Die Type Hints machen deutlich, dass beide Parameter und der Rückgabewert
vom Datentyp Integer (int) sein müssen. Der Anweisungsblock der Funktion
ist gegen falsche Datentypen geschützt, der Aufrufer kann sich sicher sein,
eine Ganzzahl als Rückgabewert zu erhalten. Ein falscher Aufruf kommuni-
ziert den Fehler deutlicher:
Fatal error: Uncaught TypeError: sum(): Argument #1 ($value1) must
be of type int, string given
125
Kapitel 5 Funktionen
Mit Type Hints können Code-Editoren falsche Aufrufe bereits beim Schrei-
ben des Codes melden. Um Fehlerquellen zu reduzieren und das Debugging
zu vereinfachen, sollten wann immer möglich Type Hints verwendet werden.
Aufgabe 3
Definieren Sie die Funktion formatDate() vom Beginn des Abschnitts 5.2
mit Type Hints und machen Sie einige Testaufrufe.
Umgekehrt gilt das Gleiche: In folgendem Skript ist die Variable $price aus
dem Geltungsbereich der Funktion setPrice() nicht im globalen Geltungs-
bereich verfügbar:
function setPrice() {
$price = 99;
}
setPrice();
echo $price; // Warning: Undefined variable $price
126
Übungen 5.3
5.3 Übungen
Übung 1
Schreiben Sie ein Skript, das die Bestimmung eines Schaltjahrs (siehe Kapi-
tel 3) in einer Funktion isLeapYear() definiert.
Verwenden Sie Type Hints: Das Eingabejahr muss eine Ganzzahl sein, der
Rückgabewert ein Wahrheitswert.
Listen Sie mit Hilfe der Funktion und einer Schleife alle Schaltjahre zwi-
schen 1900 und dem aktuellen Jahr auf.
Übung 2
Schreiben Sie ein Skript, das das aktuelle Datum im Format Mittwoch, 25. Mai
2022 ausgibt.
Tipp: Nutzen Sie die date()-Funktion mit den Formatzeichen »w« (numeri-
scher Wochentag 0-6) bzw. »n« (numerischer Monat 1-12) zur Übersetzung in
deutsche Wochentags- und Monatsnamen.
Übung 3
Weltuhr: Schreiben Sie ein Skript, das die aktuelle Uhrzeit in allen Zeitzonen
der Welt anzeigt.
Tipps:
Die Funktion timezone_identifiers_list() liefert die Namen aller Zeitzo-
nen (America/New_York, Europe/Berlin usw.) in einem Array.
Die Funktion date_default_timezone_set() stellt eine Zeitzone anhand
ihres Namens ein. Sie gilt für alle folgenden date()-Aufrufe.
127
Webseiten entwickeln
und veröffentlichen
In den vorigen Kapiteln haben Sie die Grundlagen von PHP anhand von
Kommandozeilen-Skripten kennengelernt. Dieses Kapitel wendet sich dem
wichtigsten Einsatzgebiet von PHP zu: der Generierung dynamischer Websei-
ten mit Hilfe eines Webservers.
Das Kapitel erklärt, was beim Abruf einer Webseite im Hintergrund geschieht
und stellt den Einsatz des in PHP eingebauten Webservers für die Entwicklung
von Webseiten auf dem eigenen Computer vor. Sie erlernen die Grundlagen
der HTTP-Kommunikation und sehen an einem Beispiel, wie ein Webspace
zur Veröffentlichung einer Webseite im Internet eingerichtet wird.
129
Kapitel 6 Webseiten entwickeln und veröffentlichen
bar mit einer Telefonnummer, die weltweit genau einem Telefon zugeordnet
ist. Ohne die Telefonnummer und Zuordnung zum Gerät kann das Telefon
nicht angerufen werden. Ein an das Internet angeschlossener Computer mit
zugeordneter IP-Adresse kann von anderen Computern unter dieser Adres-
se »angerufen« werden und ist online. IP-Adressen bestehen aus vier Zah-
len zwischen 0 und 255, die mit einem Punkt getrennt notiert werden, z.B.
134.119.24.29.
130
Was geschieht beim Abruf einer Webseite? 6.1
Ändert sich die IP-Adresse zu einer Domain, etwa weil eine Webseite auf ei-
nen anderen Computer umzieht, ändert sich nichts am Namen der Domain.
Lediglich die Zuordnung im DNS-Register muss aktualisiert werden.
131
Kapitel 6 Webseiten entwickeln und veröffentlichen
ren) Pendant HTTPS. Ein HTTP(S) -Webserver bietet seinen Dienst auf dem
fest definierten Port 80 bzw. 443 an. Der Aufruf von https://wikipedia.de
entspricht daher im Hintergrund einem Aufruf an den HTTPS-Webserver-
Dienst unter (z.B.) 134.119.24.29:443. Für den Abruf öffentlicher Webseiten
in einem Browser ist die Angabe des Ports nicht erforderlich. Der Port ergibt
sich aus dem Kontext der Internetadresse (HTTP = 80, HTTPS = 443).
Aufgabe 1
132
Webserver auf dem eigenen Computer betreiben 6.2
der Client-Rolle können Sie Anfragen an localhost stellen. Ihr Computer hat
für diesen speziellen Domainnamen eine feste Auflösung in die reservierte
IP-Adresse 127.0.0.1 gespeichert. Diese IP-Adresse ist die Adresse desselben
Computers, der die Anfrage gestellt hat (engl. loopback: Sender und Empfän-
ger sind identisch). Auf diese Weise kann ein Computer Anfragen an sich
selbst stellen. Durch den Start einer lokalen Server-Software können Sie in die
Server-Rolle schlüpfen und solche Anfragen beantworten.
Versuchen Sie durch Eingabe der Internetadresse http://localhost in Ihrem
Browser einen Webdienst auf Ihrem lokalen Computer anzusprechen. Eine
HTTP-Anfrage im Browser ohne weitere Port-Angabe verwendet automa-
tisch den Port 80. Es wird eine Fehlermeldung erscheinen, dass die Webseite
nicht verfügbar ist. Der Grund ist einfach: Auf Port 80 Ihres Computers läuft
noch kein Dienst zur Bedienung der Anfrage. Der nächste Abschnitt zeigt die
Bereitstellung eines passenden Diensts.
133
Kapitel 6 Webseiten entwickeln und veröffentlichen
Stellen Sie dem lokalen Webserver durch Eingabe der Adresse http://
localhost:8000 im Browser die erste Anfrage. Beobachten Sie die Log-Nach-
richten auf der Kommandozeile und die Anzeige im Browser. Der Webserver
reagiert und spielt eine Not Found Fehlermeldung aus. Logisch – bislang sind
noch keine Dateien verfügbar.
134
Webserver auf dem eigenen Computer betreiben 6.2
Statische Dateien liefert der Webserver direkt aus. Legen Sie eine HTML-Da-
tei hello.html in die Document-Root ~/www:
<h1>Hallo!</h1>
Aufgabe 2
Fällt Ihnen an der Ausgabe des PHP-Skripts etwas auf? Achten Sie auf die
Zeilenumbrüche.
Werfen Sie einen Blick in die Logs des Webservers auf der Kommandozeile.
Jede Anfrage wird dort protokolliert, u.a. mit
Datum
HTTP Status-Code: z.B. 200 für erfolgreichen Abruf oder 404 für eine nicht
gefundene Datei
HTTP-Verb: bisher nur GET
angefragter URL
135
Kapitel 6 Webseiten entwickeln und veröffentlichen
Aufgabe 3
Legen Sie in der Document-Root die Dateien index.php und index.html an.
Auf welchen verschiedenen Wegen können Sie die beiden Dateien abrufen?
136
Webserver auf dem eigenen Computer betreiben 6.2
137
Kapitel 6 Webseiten entwickeln und veröffentlichen
Aufgabe 4
6.3 HTML-Grundgerüst
Webseiten bestehen aus HTML. Für den Browser spielt es keine Rolle, ob
es sich um statische HTML-Dateien oder durch PHP dynamisch generierte
Inhalte handelt. Ein PHP-Skript gibt zur Erzeugung einer Webseite, z.B. per
echo-Anweisung, HTML aus. Browser sind sehr tolerant bei der Interpretation
von HTML. Im Vergleich zu einem PHP-Programm kommt es bei Syntaxver-
stößen nicht zu einem Abbruch. Nach eigenem Ermessen gleicht der Browser
Dinge wie vergessene HTML-Tags oder unvollständige Seitenstrukturen aus.
Um die beabsichtigte Darstellung in allen Browsern zu erreichen, sollte man
sich aber nicht auf die Fehlertoleranz verlassen und sauberes HTML schrei-
ben. Gewisse Strukturen sind auch nötig, um HTML in Verbindung mit CSS
und JavaScript nutzen zu können. Eine vollständige HTML-Webseite hat fol-
gende Grundstruktur:
<!DOCTYPE html>
<html>
<head>
<title>Titel der Webseite</title>
</head>
<body>
<!-- Das ist ein unsichtbarer Kommentar -->
138
HTML-Grundgerüst 6.3
<p>...</p>
Paragraph: Ein Absatz.
139
Kapitel 6 Webseiten entwickeln und veröffentlichen
<a href="http://localhost">Linkttext</a>
Anchor: Klickbarer Link mit dem sichtbaren Linktext zur URL
http://localhost aus dem href-Attribut (Hypertext Reference).
<ul>
<li>Listenpunkt 1</li>
<li>Listenpunkt 2</li>
</ul>
Unordered list: Ungeordnete Liste.
<strong>Betonter Inhalt</strong>
Betont den Inhalt; sorgt üblicherweise für Fettdruck.
Tab. 6.2: Beispiele für HTML-Elemente und deren Funktion
Hinweis
140
Anfragen und Antworten mit dem HTTP-Protokoll 6.4
/phpinfo.php) angefordert wurde. Der Status der Antwort wird per Code an-
gezeigt, die wichtigsten Werte lauten:
200: »OK« – die Datei wurde gefunden und ausgeliefert.
404: »Not Found« – die Datei existiert nicht.
Die erste Zeile signalisiert die HTTP-Methode zum Abholen (GET) einer
gewünschten Datei (/phpinfo.php). Die weiteren Zeilen sind so genannte
HTTP-Kopfzeilen oder geläufiger in English: HTTP-Header bzw. kurz
Header. Jeder Header ist ein Schlüssel-Wert-Paar, getrennt durch Doppel-
punkt:
Name: Wert
141
Kapitel 6 Webseiten entwickeln und veröffentlichen
142
Anfragen und Antworten mit dem HTTP-Protokoll 6.4
Hinweis
In den nächsten Kapiteln lernen Sie mit $_GET, $_POST, $_COOKIE und $_SES-
SION weitere superglobale Arrays kennen. Die Namen aller »Superglobals«
werden großgeschrieben und beginnen mit einem Unterstrich.
6.4.4 HTTP-Antworten
Auf die Anfrage nach http://localhost:8000/phpinfo.php sendet der Web-
server eine HTTP-Antwort (verkürzt dargestellt):
HTTP/1.1 200 OK
Date: Wed, 27 May 2022 10:13:12 GMT
Content-Type: text/html
... Weitere Header ...
<!DOCTYPE html>
143
Kapitel 6 Webseiten entwickeln und veröffentlichen
<html>
<head>
<title>PHP 8.0.3 - phpinfo()</title>
</head>
<body>...</body>
</html>
Die erste Zeile teilt neben der HTTP-Version den Status der Antwort mit, im
Beispiel 200 OK für eine gefundene Datei. Die restliche Antwort teilt sich im-
mer in zwei durch eine Leerzeile getrennte Bereiche:
Die Antwort-Header (Kopfzeilen): Wie in der Anfrage geben Schlüssel-
Wert-Paare wichtige Zusatzinformationen (Metadaten) über den eigentli-
chen Inhalt der Antwort. PHP erzeugt erforderliche Header automatisch,
z.B. das Datum (Header Date) der Antwort oder den Hinweis, von welcher
Art der folgende Inhalt ist (Content-Type). Mit der Funktion header() kön-
nen Sie eigene Header erzeugen. Die gesendeten Header sind nur über die
Entwickler-Konsole im Browser sichtbar.
Der Inhalt: Nach der Leerzeile folgt der im Browser-Fenster sichtbare In-
halt einer Webseite als sogenannte »Nutzlast« (payload oder body). Die
Payload ist alles, was in der Skriptdatei durch PHP ausgegeben wurde (z.B.
per echo oder var_dump()), bzw. außerhalb von PHP-Tags steht (etwa große
Teile des HTML-Codes).
HTTP-Header können das Verhalten des Browsers beeinflussen. Der Content-
Type-Header text/html veranlasst den Browser etwa, den Inhalt als HTML zu
interpretieren.
Mit der Funktion header() schreiben Sie bei Bedarf eigene Header in die Ant-
wort. Durch Setzen des Headers Content-Type können Sie z.B. die Art des
gesendeten Inhalts selbst bestimmen:
header('Content-Type: text/plain'); // Header
echo '<h1>Hallo text/plain</h1>'; // Payload
144
Anfragen und Antworten mit dem HTTP-Protokoll 6.4
Neben HTML (text/html) und reinem Text (text/plain) gibt es für alle Arten
von Inhalt eine offizielle Bezeichnung, den so genannten MIME-Type1. Wei-
tere Beispiele sind application/pdf für PDF-Dateien, image/jpeg für JPEG-
Bilddateien oder application/zip für ZIP-Archive. Alle MIME-Types können
im Content-Type-Header genutzt werden, um Clients die Art der gesendeten
Payload mitzuteilen. Ein Browser kann so z.B. entsprechend reagieren (HTML
interpretieren, PDF darstellen, Bild anzeigen, ZIP-Archiv zum Download an-
bieten usw.). Im Verlauf des Buchs werden Sie sehen, wie PHP neben Text und
HTML auch Bilder und PDFs erzeugen kann.
Aufgabe 5
1
https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/
MIME_types
145
Kapitel 6 Webseiten entwickeln und veröffentlichen
146
Webspace mieten und Webseite veröffentlichen 6.5
147
Kapitel 6 Webseiten entwickeln und veröffentlichen
Der einfachste Weg, bei Hetzner eigene Skripte in den Webspace hochzula-
den, ist »WebFTP«, eine spezielle Weboberfläche.
Sofern Sie eine Datei in die Document-Root hochgeladen haben, ist sie über
die Domain-Adresse öffentlich im Internet erreichbar. Viele Webhoster bieten
auch Zugriff auf eine Verzeichnisebene über der Document-Root, um Dateien
vor öffentlichem Zugriff geschützt abzulegen.
Für den täglichen Gebrauch empfiehlt sich die Verwendung eines speziellen
FTP-Programms, z.B. FileZilla (https://filezilla-project.org) für Win-
dows, macOS und Linux.
6.6 Übungen
Übung 1
Schreiben Sie ein Skript, das die HTTP-Anfrage-Header aus dem supergloba-
len $_SERVER-Array auflistet.
Übung 2
Folgendes Skript erzeugt mit Hilfe von Funktionen aus der »gd«-Erweiterung
(siehe Abschnitt 4.2.4) ein PNG-Bild (MIME-Type: image/png) mit einem ro-
ten Quadrat:
$image = imagecreate(100, 100); // Bild erzeugen
imagecolorallocate($image, 255, 0, 0); // rot färben
imagepng($image); // Bilddaten ausgeben
Der Browser zeigt jedoch nur »Buchstabensalat«. Wie bringen Sie den Brow-
ser zu einer korrekten Interpretation, um das Bild sichtbar zu machen?
148
Dynamische Webseiten
und Formulare
Die Interaktion mit einer Webseite findet über HTML-Elemente im Browser
statt. Die serverseitige Technologie ist dem Betrachter verborgen. Ein server-
seitiges Skript kann nicht den Anfrage-Antwort-Zyklus des HTTP-Protokolls
unterbrechen, um wie auf der Kommandozeile interaktiv Eingaben vom Be-
trachter zu erfragen. Stattdessen transportiert eine HTTP-Anfrage Benutzer
eingaben durch Klicken eines Links oder Abschicken eines Formulars zum
Webserver:
Die GET-Methode schickt Benutzerdaten beim Klicken eines Links als Teil
der Internetadresse einer Webseite (URL) im sogenannten Query-String
zum Webserver. PHP stellt sie im superglobalen $_GET-Array zur Verfü-
gung.
Die POST-Methode schickt Benutzerdaten beim Absenden eines Formulars
als »Nutzlast« (payload) im unsichtbaren Rumpfteil (body) der Anfrage an
den Webserver. PHP stellt sie im superglobalen $_POST-Array zur Verfü-
gung.
PHP-Skripte können auf die Benutzereingaben dynamisch reagieren.
149
Kapitel 7 Dynamische Webseiten und Formulare
Jede Zielseite muss einzeln als statische HTML-Seite angelegt werden – jeweils
für die Anzeige von ein, zwei und drei Quadraten:
<!-- /squares-1.html (Datei mit einem Quadrat) -->
<img src="/square.png" alt="Quadrat 1"/>
Ein Klick auf den Link zur Anzeige von drei Quadraten löst eine GET-Anfrage
auf die Datei squares-3.html aus (Abbildung 7.3).
150
$_GET: Daten aus dem Query-String der URL 7.1
Aufgabe 1
Testen Sie die statische Version des Kunstprojekts auf Ihrem Computer.
Starten Sie dazu den eingebauten PHP-Webserver auf localhost:8000 und
setzen Sie die Document-Root auf das Unterverzeichnis art-project/v1-
static aus den Code-Downloads zu diesem Kapitel (www.mitp.de/0395).
Eine angedachte Ausweitung des Projekts auf mehr als drei Quadrate ist mit
Aufwand verbunden: Jedes zusätzliche Quadrat erfordert die Ergänzung ei-
nes Links auf der Startseite und eine weitere HTML-Datei mit der passenden
Anzahl an Bild-Elementen. Flexibler und pflegeleichter ist eine dynamische
Lösung mit PHP, wie die nächsten Abschnitte zeigen.
151
Kapitel 7 Dynamische Webseiten und Formulare
Ein Aufruf des Skripts squares.php mit dem Anhängsel ?number=12 in der
URL zeigt ohne Anpassung des HTML gleich ein Dutzend Quadrate:
http://localhost:8000/squares.php?number=12
Hinweis
Zum Testen der zweiten, dynamischen Version des Projekts starten Sie den
lokalen Webserver mit dem Verzeichnis art-project/v2-query-string aus
den Code-Downloads als Document-Root.
Mit dem Fragezeichen in der URL (?) beginnt der so genannte Query-String,
der Eingabedaten an serverseitige Skripte übermitteln kann. Der Query-String
enthält Schlüssel-Wert-Paare nach dem allgemeinen Schema:
script.php?key1=wert1&key2=wert2&key3=wert3
152
$_GET: Daten aus dem Query-String der URL 7.1
Die Abbruchbedingung der Zählschleife bestimmt die Anzahl der Links. Mit
$n<=12 generiert das Skript z.B. gleich ein Dutzend Links mit den passenden
Query-Strings:
<a href="/squares.php?number=1">1 Quadrat</a>
<a href="/squares.php?number=2">2 Quadrate</a>
...
<a href="/squares.php?number=12">12 Quadrate</a>
Die dynamische Variante des Projekts hat nun die gleiche Funktionalität wie
die statische, benötigt jedoch weniger Dateien und Code. Um die Anzahl der
Links und damit die mögliche Anzahl an Quadraten zu variieren, ist nur ein
Wert im Schleifenkopf des Skripts index.php anzupassen.
153
Kapitel 7 Dynamische Webseiten und Formulare
154
$_GET: Daten aus dem Query-String der URL 7.1
Nach einer Warnung läuft das Skript jedoch weiter und PHP setzt die Va-
riable $numberOfSquares auf null. Die Abbruchbedingung der Schleife lautet
bei der ersten Iteration 1<=null. Der unerwartete Vergleich zweier unglei-
cher Datentypen ruft das »Type Juggling« von PHP auf den Plan (Abschnitt
2.5.1), d.h. PHP passt die Datentypen für den Vergleich nach seinem internen
(recht undurchsichtigen) Regelwerk automatisch an. In diesem Fall kommt es
zu einem Vergleich des Wahrheitsgehalts beider Operanden: Eine Zahl un-
gleich Null entspricht wahr, null entspricht falsch. Der resultierende Vergleich
true<=false ergibt immer false. Die Schleife wird daher nie ausgeführt und
der Benutzer sieht gar kein Quadrat bzw. je nach Fehlersichtbarkeit (Abschnitt
4.4) die Warnung. Eine vorige Prüfung hilft zum einen die Warnung zu ver-
meiden und zum anderen die Variable $numberOfSquares sinnvoll auf 0 zu
setzen:
$numberOfSquares = isset($_GET['number'])
? $_GET['number']
: 0;
155
Kapitel 7 Dynamische Webseiten und Formulare
Der ternäre Operator liest sich: »Falls $_GET['number'] gesetzt ist (engl. is set),
initialisiere $numberOfSquares mit dem Wert von $_GET['number'], ansonsten
mit 0«. Ist der URL-Parameter nicht gesetzt, kann das Skript mit $numberOf
Squares=0 weiterarbeiten (siehe unten); Kopfzerbrechen über das mögliche
Verhalten ist bei dem resultierenden Vergleich 1<=0 im Gegensatz zu 1<=null
ausgeschlossen.
Die for-Schleife wird zur Endlosschleife (Abschnitt 3.3.9) und hört nicht auf,
immer mehr Quadrate anzuzeigen.
Falls Sie die dynamische Typisierung in den beschriebenen Situationen als
verwirrend empfinden, sind Sie sicher nicht allein. Solche Situationen sollten
besser vermieden werden. Im Kunstprojekt muss dazu der Datentyp für den
Eingabewert number zu Beginn klargestellt werden, anstatt dies später PHP
zu überlassen. Da das Programm ohnehin nur mit einer Ganzzahl als Einga-
be sinnvoll arbeitet, ist dies durch ein explizites Type-Casting in den Integer-
Datentyp mit dem Casting-Operator (int) (Abschnitt 2.5.2) möglich:
$numberOfSquares = isset($_GET['number'])
? (int) $_GET['number'] // Nicht-Zahlen = 0
: 0;
Nach diesem Schritt ist sichergestellt, dass die Variable $numberOfSquares im-
mer vom Typ Integer ist und anschließend nur Vergleiche zwischen Zahlen
stattfinden. Nicht-Zahlen wie abc oder der leere String werden beim Casting
in die Zahl 0 umgewandelt.
156
$_GET: Daten aus dem Query-String der URL 7.1
Auf negative Zahlen und die Null lässt sich passend reagieren:
if ($numberOfSquares < 1) {
echo 'Keine Quadrate.';
}
Hinweis
Die dritte Version des Projekts mit Eingabevalidierung starten Sie mit dem
Verzeichnis art-project/v3-validation als Document-Root.
Zusammenfassung
Programme dürfen Eingabewerte niemals ungeprüft verwenden. Die Einga-
bevalidierung von squares.php für den URL-Parameter number sorgt für eine
sichere Ausführung des Skripts ohne Überraschungen:
$numberOfSquares = isset($_GET['number'])
? (int) $_GET['number']
: 0; // Variable enthält sicher eine Ganzzahl!
if ($numberOfSquares > 100) { // nicht zu groß
$numberOfSquares = 100;
}
if ($numberOfSquares < 1) { // nicht zu klein
echo 'Keine Quadrate.';
}
for($n = 1; $n <= $numberOfSquares; $n++) {
157
Kapitel 7 Dynamische Webseiten und Formulare
Die Startseite index.php wird auf den unterstützten Bereich der Eingabevali-
dierung mit bis zu 100 Quadraten angepasst:
<p>Quadrate - Wieviele möchten Sie sehen?</p>
<?php for($n = 1; $n <= 100; $n++): ?>
<a href="/squares.php?number=<?= $n ?>">
<?= $n ?> Quadrat<?= $n > 1 ? 'e' : '' ?>
</a><br/>
<?php endfor; ?>
158
Formulardaten im Query-String der URL übermitteln 7.2
Das button-Element vom Typ submit erzeugt eine Schaltfläche zum Absen-
den des Formulars.
Das Absenden des Formulars löst eine neue HTTP-Anfrage mit der GET-Me-
thode an die URL aus dem action-Attribut des form-Elements aus: squares.
php. Ohne Angabe einer Domain komplettiert der Browser die URL automa-
tisch mit derselben Domain, von der das Formular geladen wurde. Die Ziel-
URL lautet daher http://localhost:8000/squares.php. Außerdem wandelt
der Browser die Daten aller Formularfelder in einen Query-String um und
hängt diesen an die Ziel-URL. Jedes Eingabefeld erzeugt einen URL-Parame-
ter mit dem Namen des Felds als Schlüssel und dem eingegebenen Inhalt als
Wert. Mit Eingabe des Werts 12 in das input-Feld namens number lautet die
vollständige Ziel-URL beim Absenden des Formulars:
http://localhost:8000/squares.php?number=12
Das Skript squares.php bedarf keiner Anpassung. Die Eingabe der Quadrate-
Anzahl wurde von den Links in das Formular verlagert.
Hinweis
Die vierte Version des Projekts mit Eingabevalidierung starten Sie mit dem
Verzeichnis art-project/v4-form als Document-Root.
159
Kapitel 7 Dynamische Webseiten und Formulare
Das Absenden eines Formulars mit leerem action-Attribut sendet das For-
mular an dieselbe URL zurück, von der es geladen wurde. Die Eingabevalidie-
rung kann daher (in abgewandelter Form) im selben Skript über dem Formu-
lar platziert werden, die Anzeige der Quadrate darunter:
<?php
$numberOfSquares = 0; 1
$error = false; 2
if (isset($_GET['number'])) { 3
$number = (int) $_GET['number']; 4
if ($number > 0 && $number <= 100) { 5
$numberOfSquares = $number;
} else {
$error = true; 6
}
}
?>
<form action="">...</form>
<?php
for($n = 1; $n <= $numberOfSquares; $n++) { 7
echo '<img src="/square.png"/>';
}
160
Formulardaten im Query-String der URL übermitteln 7.2
161
Kapitel 7 Dynamische Webseiten und Formulare
Bei der erneuten Anzeige des Formulars im Falle eines Eingabefehlers soll das
Attribut hingegen vorbelegt sein, z.B.:
<input name="number" value="Fünf"/>
Ob das Formular abgeschickt und damit auf Grund eines Eingabefehlers er-
neut angezeigt wird, lässt sich am gesetzten URL-Parameter number erkennen.
Nur in diesem Fall soll das Feld mit der bisherigen Eingabe vorbelegt werden:
<input name="number" value="<?php if (isset($_GET['number'])) {
echo $_GET['number']; } ?>"/>
Hinweis
Die fünfte Version des Projekts mit nur einem Skript starten Sie mit dem
Verzeichnis art-project/v5-single-file als Document-Root.
162
Formulardaten im Query-String der URL übermitteln 7.2
Neben der erwarteten Eingabe einer Zahl kann ein böswilliger Benutzer auf
geschickte Weise HTML und damit auch JavaScript zur clientseitigen Pro-
grammierung in die Webseite einschleusen. Betrachten Sie folgende Formu-
lareingabe:
3" onclick="alert('Sie wurden gehackt!')"
Mit der 3 ist zunächst wie gewünscht eine Zahl enthalten. Im Anschluss been-
det jedoch das doppelte Anführungszeichen das value-Attribut und es kann
beliebiger HTML-Code in die Seite eingebracht werden. Nach Abschicken des
Formulars offenbart ein Blick in den Seitenquelltext (Extras|Browserwerkz
euge|Seitequelltext) das Ergebnis:
<input name="number" value="3" onclick="alert('Sie wurden ge-
hackt!')"/>
Das onclick-Attribut führt das enthaltene JavaScript beim Anklicken des Ein-
gabefelds aus. Die JavaScript-Funktion alert() zeigt daraufhin ein Hinweis-
fenster mit dem Text Sie wurden gehackt! an. Wird der Link zur Ergebnisseite
des Formulars an einen unbedarften Benutzer weitergegeben, erlebt dieser
beim Klick in das Eingabefeld eine Überraschung.
Sobald das Einschmuggeln von HTML und JavaScript in eine Webseite mög-
lich ist, können Benutzer Opfer eines solchen Cross-Site-Scripting (XSS) An-
griffs werden. Dabei wird bösartiger Code in einen vertrauenswürdigen Kon-
163
Kapitel 7 Dynamische Webseiten und Formulare
Das Kleiner-Zeichen soll hier kein HTML-Tag öffnen, sondern als solches an-
gezeigt werden. Das gelingt mit der HTML-Entität <:
<strong>7 < 10</strong>
164
Einsatzgebiete der GET-Methode 7.3
Die böswillige Beispiel-Eingabe von oben kann keinen Schaden mehr anrich-
ten, der HTML-Quellcode mit maskierten Anführungszeichen lautet:
<input name="number" value="3" onclick="alert('Sie wur-
den gehackt!')""/>
Vorteile
Die GET-Methode eignet sich hauptsächlich, um Inhalte einer Webseite mit
Hilfe von Parametern an individuelle Bedürfnisse anzupassen, z.B. durch
Sucheingaben, Filter oder Sortierungen. Aufrufe mit der GET-Methode haben
normalerweise keine Seiteneffekte, d.h. sie erzeugen oder ändern keine Daten,
sondern rufen sie lediglich ab. So ändert eine Suche mit einer Suchmaschine
nicht den Datenbestand, sondern filtert mittels URL-Parametern gewünschte
Ergebnisse aus dem Datenbestand heraus.
Eine URL inklusive Query-String kann als Lesezeichen gespeichert oder wei-
tergegeben werden. Mit den Vor- und Zurück-Schaltflächen des Browsers
kann man durch den Verlauf von GET-Anfragen navigieren. Der Aufruf einer
URL mit Parametern führt später für gewöhnlich zur gleichen Ansicht.
Aufgabe 2
Suchen Sie mit Google nach dem Begriff PHP. Bearbeiten Sie die URL der
Ergebnisseite, so dass im Query-String nur noch der GET-Parameter mit
dem Suchbegriff enthalten ist. Passen Sie den Suchbegriff in der URL an,
um ohne Formulareingabe direkt auf die Ergebnisseite für den Suchbegriff
MySQL zu gelangen.
165
Kapitel 7 Dynamische Webseiten und Formulare
Nachteile
Da URL-Parameter offen einsehbar sind, ist die GET-Methode nicht zur Über-
tragung sensibler Daten geeignet. Eine URL wie login.php?password=s3cr3t
offenbart Zugangsdaten leicht an Unbefugte.
Eine URL ist in der Länge limitiert; eine Übertragung von größeren Daten-
mengen, z.B. langer Texte oder Dateiuploads, ist daher nicht möglich. Das
Limit kann je nach Browser variieren, etwa 2000 Zeichen sollten nicht über-
schritten werden.
Bei der Erzeugung oder Änderung von Inhalten aus Formulardaten (Blog-
Einträge, Kommentare, Bild-Uploads usw.) handelt es sich um einmalige
Aktionen. Der nochmalige Aufruf dieser Aktionen durch Vor- und Zurück-
Navigieren oder einen Aufruf aus den Lesezeichen ist nicht gewollt, weshalb
auch in diesen Fällen die GET-Methode nicht geeignet ist.
Eine Datenübertragung ohne URL-Parameter und Größenbeschränkung er-
laubt die POST-Methode, die Sie im nächsten Abschnitt kennenlernen.
166
$_POST: Formulardaten unsichtbar übermitteln 7.4
Wert post zu setzen. Statt in der URL transportiert HTTP die Formulardaten
dann verborgen im Rumpf der Anfrage als »Nutzlast« (Payload) in Richtung
Server. Der Inhalt folgt mit einer Leerzeile getrennt auf die Anfrage-Header.
Allgemein lautet das Schema einer POST-Anfrage:
POST /script.php HTTP/1.1
Host: localhost:8000
User-Agent: ...
Content-Type: application/x-www-form-urlencoded
...
formularfeld1=eingabe1&formularfeld2=eingabe2
Der Inhalt ist wie ein Query-String kodiert – die Formulardaten sind eben-
falls Schlüssel-Wert-Paare und mit Et-Zeichen (&) voneinander getrennt. Die
Browserkonsole gibt nach dem Absenden eines Formulars Aufschluss über
die HTTP-Anfrage:
In PHP erfolgt der Zugriff auf POST-Daten über das superglobale $_POST-
Array. Bislang reagiert das Skript zur Newsletter-Registrierung noch nicht
auf das abgesendete Formular. Eine if-Anweisung kann feststellen, ob POST-
Daten übermittelt wurden:
<?php if (isset($_POST['email'])): ?>
<!-- Todo: Abspeichern der E-Mail-Addresse -->
Danke, <?= htmlspecialchars($_POST['email']) ?>
wurde registriert.
<?php else: ?>
167
Kapitel 7 Dynamische Webseiten und Formulare
Aufgabe 3
Der Benutzer wird darauf hingewiesen, dass das neu Laden dem wiederholten
Absenden des Formulars entspricht und entsprechende Folgen haben könn-
te – bei einem Bestellformular etwa die nochmalige Aufgabe der gleichen Be-
stellung.
Ein eleganter Weg zur Vermeidung dieser möglicherweise verwirrenden Mel-
dung ist es, den Benutzer nach erfolgreicher Verarbeitung des Formulars di-
rekt auf eine neue Seite weiterzuleiten (engl. redirect). Das gelingt durch Set-
zen eines Location-Antwort-Headers mit der Funktion header():
168
Vergleich zwischen GET und POST 7.5
<?php
if (isset($_POST['email'])) {
/* Todo: Abspeichern der E-Mail-Addresse */
header('Location: /thanks.php');
exit();
}
?>
<form action="" method="post">...</form>
Der Location-Header weist den Browser beim Empfang der Antwort an, so-
fort auf die angegebene URL /thanks.php weiterzuleiten. Der Aufruf von
exit() stellt das Ende der Skriptausführung sicher, da die Verarbeitung des
Formulars abgeschlossen ist und der Benutzer auf das neue Skript weitergelei-
tet werden wird. Nach Erhalt der Antwort lädt der Browser aufgrund der per
Location-Header angewiesenen Weiterleitung direkt die neue Seite thanks.
php (per GET-Methode). Auf dieser Seite würde ein Neu-Laden das Skript
thanks.php wiederholt abrufen statt das Formular der nunmehr vorletzten
Seite erneut zu übermitteln.
Hinweis
Starten Sie zum Test und Vergleich der Registrierungs-Beispiele (mit und
ohne Redirect) den Webserver mit dem Unterverzeichnis subscription/
aus den Code-Downloads zum Kapitel als Document-Root.
169
Kapitel 7 Dynamische Webseiten und Formulare
7.6 Übungen
Übung 1
Erstellen Sie ein Formular zur Eingabe von Vor- und Nachname. Begrüßen Sie
den Besucher nach Abschicken des Formulars per GET-Methode an dasselbe
Skript mit dem eingegebenen Namen.
Übung 2
Folgendes Skript erzeugt ein PNG-Bild mit dem schwarzen Text TEST auf hel-
lem Grund (erfordert aktivierte gd-Erweiterung, siehe Abschnitt 4.2.4):
header('Content-Type: image/png');
$image = imagecreate(500, 75); // Bildgröße 500x75px
imagecolorallocate($image, 200, 200, 200); // Hintergrund
$textcolor = imagecolorallocate($image, 0, 0, 0);
imagestring($image, 30, 25, 25, 'TEST', $textcolor);
imagepng($image); // Bilddaten ausgeben
170
Übungen 7.6
Übung 3
Erweitern Sie die finale Version des fiktiven Kunstprojekts aus Abschnitt 7.2
(Verzeichnis art-project/v5-single-file in den Code-Downloads zum Ka-
pitel) mit einem select-Element um die Auswahl einer Form: Quadrat oder
Kreis.
<select name="shape">
<option value="square">Quadrat</option>
<option value="circle" selected>Kreis</option>
</select>
Hinweis: Ergänzen Sie ein Bild circle.png von einem Kreis und machen Sie
den Bildpfad des img-Tags vom Eingabewert des neuen Formularfelds ab
hängig.
Übung 4
Ändern Sie das Skript aus Übung 1 von der GET- auf die POST-Methode.
171
Mit Dateien arbeiten
Jedes Skript bestand bislang aus einer einzelnen Datei. Größere Skripte wer-
den dabei unübersichtlich und Code aus einem Skript kann nicht in einem
anderen wiederverwendet werden. Zur besseren Strukturierung und Wieder-
verwendung lässt sich Quelltext auf mehrere Dateien aufteilen.
Andere Dateien können auch als Datenquelle bzw. -speicher dienen. Ein
Skript liest dabei Daten aus einer Datei ein oder speichert sie dort. So kön-
nen z.B. Benutzereingaben in einer Datei abgelegt und in einem späteren Pro-
grammlauf wieder eingelesen werden – eine einfache Art, Daten dauerhaft zu
speichern.
In diesem Kapitel lernen Sie den Umgang mit Dateien zur Strukturierung von
Quelltexten sowie zum Lesen und Speichern von Daten kennen.
173
Kapitel 8 Mit Dateien arbeiten
<body>
<header>
<img src="/logo.png"/>
<nav>
<a href="/index.php">Startseite</a> -
<a href="/pictures.php">Bilder</a> -
<a href="/guestbook.php">Gästebuch</a>
</nav>
<h1>Startseite</h1>
</header>
<main>
<h2>Willkommen auf meiner Homepage!</h2> ...
</main>
<footer>
<a href="/imprint.php">Impressum</a>
</footer>
</body>
</html>
Jede einzelne Webseite entspricht einem Skript. Auf dem Host-Computer lie-
gen alle Skripte z.B. im Projektverzeichnis ~/website:
~/website
guestbook.php
index.php
imprint.php
pictures.php
Die Webseiten sind erreichbar, sobald der Webserver mit dem Verzeichnis
~/website als Document-Root startet:
Die Skripte haben viele Bereiche gemeinsam. Das heißt, jede Datei wiederholt
viel gleichen HTML-Code, unterscheidet sich eigentlich jedoch nur im Titel
und im Inhalt des main-Elements. Hier das (gekürzte) Skript pictures.php mit
den hervorgehobenen, individuellen Bereichen, an denen es sich von index.
php unterscheidet:
<html>
<head>
174
Quelltext in mehreren Dateien strukturieren 8.1
<title>Bilder</title>
</head>
<body>
<header>
<img src="logo.png"/>
<nav>...</nav>
<h1>Bilder</h1>
</header>
<main>
<h2>Meine schönsten Bilder</h2> ...
</main>
<footer>...</footer>
</body>
</html>
Hinweis
Die beschriebene erste Version der Website finden Sie in den Code-Down-
loads zum Kapitel (www.mitp.de/0395) unter website/version-1, die in den
nächsten Abschnitten verbesserten Versionen entsprechend unter versi-
on-2 und version-3.
175
Kapitel 8 Mit Dateien arbeiten
<nav>...</nav>
<h1>Startseite</h1>
</header>
<main>
Die Dateien _header.php und _footer.php sind nicht als eigenständige Skripte
gedacht, sondern werden von den Hauptskripten (index.php, pictures.php
usw.) mit der require-Anweisung eingebunden.
Der Unterstrich als Präfix in den Dateinamen _header.php und _foot
er.php ist eine Konvention. Sie drückt aus, dass diese Dateien keine
eigenständigen Skripte sind, sondern von anderen Skripten eingebun-
den werden.
In den Hauptskripten ersetzen die Einbindungen mit require die gemeinsa-
men Kopf- und Fußbereiche, wie hier in der Startseite index.php.
<?php require __DIR__.'/_header.php'; ?>
<h2>Willkommen auf meiner Homepage</h2> ...
<?php require __DIR__.'/_footer.php'; ?>
176
Quelltext in mehreren Dateien strukturieren 8.1
Der Einsatz einer Variablen ($title) sorgt für einen dynamischen Seitentitel,
so dass jede Hauptseite einen eigenen Titel verwenden kann:
<html>
<head>
<title><?= $title ?></title>
</head>
<body>
<header>
<img src="logo.png"/>
<nav>…</nav>
<h1><?= $title ?></h1>
</header>
<main>
177
Kapitel 8 Mit Dateien arbeiten
Datei URL
~/website/index.php localhost:8000/
~/website/pictures.php localhost:8000/pictures.php
~/website/guestbook.php localhost:8000/guestbook.php
178
Quelltext in mehreren Dateien strukturieren 8.1
Datei URL
~/website/_header.php localhost:8000/_header.php
~/website/_footer.php localhost:8000/_footer.php
179
Kapitel 8 Mit Dateien arbeiten
Hinweis
if (isset($_POST['email'])) {
file_put_contents(__DIR__.'/emails.txt', $_POST['email']);
header('Location: /thanks.php');
exit();
}
180
Dateien schreiben und lesen 8.2
file_put_contents(
__DIR__ . '/emails.txt',
$_POST['email'] . "\n", // mit Zeilenumbruch!
FILE_APPEND
);
Mit jeder Registrierung erweitert sich die Datei nun um eine Zeile:
lukas@me.com
lina@gmx.net
lea@gmail.com ...
Aufgabe 1
Aufgabe 2
Folgendes Skript liest die Datei emails.txt ein und listet die gesammelten
E-Mail-Adressen zeilenweise auf:
$contents = file_get_contents(__DIR__.'/emails.txt'); 1
$emails = explode("\n", $contents); 2
181
Kapitel 8 Mit Dateien arbeiten
Das Laden fremder Inhalte ermöglicht das sogenannte »Web Scraping« (engl.
etwa: »das Web schürfen«). Mit entsprechenden String-Funktionen können
automatisiert Informationen aus anderen Webseiten extrahiert und weiter-
verarbeitet werden, z.B. aus Nachrichtenseiten, Wetterberichten, Fahrplänen,
Sporttickern usw.
Die Weiterverarbeitung fremder Inhalte ist rechtlich bedenklich. Für viele In-
formationen gibt es jedoch offizielle Alternativen in Form von Web-Schnitt-
stellen. Der Anbieter eines bestimmten Diensts (z.B. für den Wetterbericht)
erlaubt es durch eine solche Schnittstelle anderen Programmen, sich über das
182
Dateien über das Internet laden 8.3
Die JSON-Daten sind reiner Text und unabhängig von PHP. Jede Program-
miersprache kann JSON-Daten einlesen und in eigene interne Datenstruk-
turen übersetzen. Sie können erkennen, dass die zurückgelieferte Struktur
einem assoziativen Array (d.h. mit String-Schlüsseln) in PHP sehr ähnlich
ist. Es gibt Schlüssel-Wert-Paare und die Verschachtelung mit geschweiften
Klammern bildet zwei Dimensionen.
183
Kapitel 8 Mit Dateien arbeiten
Als ob die Daten in einer lokalen Datei vorlägen, kann PHP die Wetterdaten
mit file_get_contents() von der URL abrufen:
$weatherUrl = 'https://api.openweathermap.org/data/2.5/weather?q=B
erlin&lang=de&units=metric&appid=XXXXX';
$data = file_get_contents($weatherUrl);
1 Das erste Argument für json_decode() ist der reine JSON-String aus der
Variablen $data. Das zweite Argument (true) bestimmt, dass das Ergebnis
der Übersetzung ein assoziatives Array sein soll. Das Ergebnis-Array wird
der Variablen $weather zugewiesen.
2 Vergleichen Sie den Array-Zugriff mit den reinen JSON-Daten. Sie er-
kennen ein Element main und darunter die Temperatur im Element temp.
Die genaue Struktur und Benennung der JSON-Daten bestimmt der An-
bieter der Web-API (hier: OpenWeather) und muss bei Unklarheiten in der
Dokumentation nachgeschlagen werden.
184
Datei-Uploads: $_FILES 8.4
Es ist zu beachten:
Datei-Uploads sind nur mit der POST-Methode möglich.
Das Formular muss im Attribut enctype den speziellen Kodierungstyp
(engl. encoding type) multipart/form-data angeben. Ohne diese Angabe
werden alle Formulardaten außer den Dateien übertragen.
185
Kapitel 8 Mit Dateien arbeiten
PHP generiert für jede hochgeladene Datei einen zufälligen Dateinamen (z.B.
phpAAB2nV) und legt die Datei mit diesem Namen für die Laufzeit des Skripts
in einem Verzeichnis für temporäre Dateien ab, z.B. /tmp unter Linux oder
~\AppData\Local\Temp unter Windows. Am Ende der Skript-Laufzeit wird die
Datei automatisch wieder gelöscht. Zur dauerhaften Speicherung muss das
Skript daher zur Laufzeit die Datei mit der Funktion move_uploaded_file() an
einen anderen Ort verschieben:
move_uploaded_file(Quellpfad, Zielpfad);
186
Datei-Uploads: $_FILES 8.4
Folgender Code speichert die hochgeladene Datei aus dem Dateifeld picture
unter dem Original-Dateinamen in das Verzeichnis uploads/ relativ zum
Skript-Verzeichnis:
if (isset($_FILES['picture'])) {
move_uploaded_file(
$_FILES['picture']['tmp_name'],
__DIR__.'/uploads/'.$_FILES['picture']['name']
);
}
Das Verzeichnis uploads/ muss existieren und der Webserver benötigt darin
Schreibrechte (siehe Abschnitt 8.5).
Der Original-Dateiname stammt vom Client. Ein späterer Upload einer ande-
ren Datei mit gleichem Namen würde eine bestehende Datei überschreiben.
Die serverseitige Vergabe eines eindeutigen Namens vermeidet eine mögliche
Namenskollision:
$extension = pathinfo( 1
$_FILES['picture']['name'],
PATHINFO_EXTENSION // Dateiendung extrahieren
);
$filename = sprintf('%s.%s', uniqid(), $extension); 2
move_uploaded_file(
$_FILES['picture']['tmp_name'],
__DIR__.'/uploads/'.$filename // z.b. 60af75f8dc3c8.png
);
8.4.3 Upload-Fehler
Ein Dateiupload kann fehlschlagen, z.B. wenn die maximal zugelassene Da-
teigröße (Abschnitt 8.4.4) überschritten ist. Upload-Fehler meldet PHP als
ganzzahligen Fehlercode ungleich Null im Feld error des Datei-Arrays aus
$_FILES. Für das Upload-Feld mit dem Namen picture findet sich der Feh-
187
Kapitel 8 Mit Dateien arbeiten
8.4.4 php.ini-Einstellungen
Einige php.ini-Einstellungen beeinflussen Datei-Uploads, u.a.:
Aufgabe 3
Ein Formular soll den Upload von bis zu drei Fotos zu maximal je 15MB
plus ein Textfeld für eine Beschreibung erlauben. Welche Einstellungen für
upload_max_filesize und post_max_size erscheinen sinnvoll?
188
Datei-Uploads: $_FILES 8.4
Eine Liste gängiger MIME-Types finden Sie z.B. in den Mozilla Web Docs1.
Das Datei-Array in $_FILES enthält eine Angabe zum MIME-Type für jedes
Upload-Feld:
$_FILES['picture']['type']; // z.B. image/jpeg
Dieser Wert wird jedoch vom Browser übermittelt und ist daher wie alle Cli-
ent-Daten nicht fälschungssicher. Serverseitig kann der MIME-Type mit der
Funktion mime_content_type() aus dem Dateiinhalt selbst bestimmt werden:
$mimeType = mime_content_type($_FILES['picture']['tmp_name']);
if ($mimeType !== 'image/jpeg') {
exit('Nur JPEG Dateien erlaubt.');
}
move_uploaded_file(...);
1
https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/
MIME_types/Common_types
189
Kapitel 8 Mit Dateien arbeiten
Aufgabe 4
Wie lautet der MIME-Type einer MP3-Datei? Nutzen Sie die Funktion
mime_content_type() mit dem Pfad zu einer mp3-Datei auf Ihrem Compu-
ter, um es herauszufinden.
8.5 Datei-Zugriffsrechte
Bei der Arbeit mit Dateien und Verzeichnissen kommt jeder Programmie-
rer früher oder später mit dem Thema Datei-Zugriffsrechte (engl. permissions)
in Berührung. Etwa wenn das Schreiben einer Datei wegen fehlender Rechte
misslingt:
Warning: file_put_contents(data.txt): Failed to open stream: Per-
mission denied
190
Datei-Zugriffsrechte 8.5
Für jeden der drei Bereiche (Benutzer, Gruppe, Andere) gibt es drei Zugriffs-
rechte zum Lesen, Schreiben und Ausführen. Die Rechte haben für eine Datei
oder ein Verzeichnis unterschiedliche Bedeutungen.
191
Kapitel 8 Mit Dateien arbeiten
8.6 Übungen
Übung 1
Auch die include-Anweisung kann Dateien einbinden. Sie unterscheidet sich
in ihrer Reaktion von require, falls eine eingebundene Datei nicht existiert.
Probieren Sie mit folgendem Skript beide Anweisungen aus und finden Sie
den Unterschied.
192
Übungen 8.6
Übung 2
Ein beliebtes, einfaches Dateiformat zur Datenspeicherung ist das CSV-For-
mat (»comma-separated values«). Folgende CSV-Datei users.csv speichert
Personendaten mit Name, Alter und Hobbies:
Name,Alter,Hobbies
Max Becker,29,"Schwimmen, Laufen"
Lisa Fischer,33,"Lesen, Wandern"
Moritz Bender,41,"Computer, Games, Kochen"
Die erste Zeile enthält die Spalten-Überschriften. Jede weitere Zeile entspricht
einem Datensatz. Jeder Datensatz besteht aus durch Kommas getrennten Fel-
dern für Name, Alter und Hobbies.
Schreiben Sie ein Skript, das die Datei einliest und die Daten in einer HTML-
Tabelle ausgibt:
Tipps:
Lesen Sie die Zeilen der CSV-Datei mit file() in ein Array.
Zerlegen Sie jede Zeile mit str_getcsv() in die Felder, PHP übernimmt die
Interpretation des CSV-Formats je Zeile.
Übung 3
Registrieren Sie einen Account auf OpenWeather (www.openweathermap.org).
Erstellen Sie ein Formular, das die Abfrage der Temperatur und der gefühlten
Temperatur für eine eingegebene Stadt ermöglicht.
193
Kapitel 8 Mit Dateien arbeiten
Übung 4
Erstellen Sie ein Formular zum Upload von bis zu drei JPEG-Fotos. Speichern
Sie die Bilder serverseitig ab. Prüfen Sie Uploads auf Fehlercodes und den
korrekten MIME-Type.
194
Cookies und Sessions
Aufgrund der Zustandslosigkeit des HTTP-Protokolls (Abschnitt 6.4.5) haben
Webseiten kein eigenes Gedächtnis. Jeder Seitenaufruf ist isoliert von vorigen
Aufrufen. Ein Besucher, der sich von Seite zu Seite bewegt, wird immer als
neuer Besucher wahrgenommen.
Cookies und Sessions ermöglichen die Wiedererkennung von Besuchern über
mehrere Seiten hinweg und damit die Personalisierung von Webseiten.
Mit einem Cookie legt eine Webseite ein kleines Datenpaket clientseitig im
Browser des Besuchers ab. Der Browser schickt das Datenpaket bei späte-
ren Besuchen an den Webserver zurück.
Mit einer Session (engl. für Sitzung) speichert eine Webseite Daten server-
seitig unter einem eindeutigen Schlüssel. Der Schlüssel wird als Cookie im
Browser des Besuchers hinterlegt und bei erneuten Besuchen an den Web-
server zurückgeschickt.
Cookies und Sessions bilden die Grundlage für Funktionalitäten wie Logins,
Warenkörbe, die Verwaltung persönlicher Daten und vieles mehr.
9.1 Cookies
Ein Cookie (engl. für »Keks«) ist ein kleines Datenpaket in Textform, das cli-
entseitig im Browser eines Website-Besuchers gespeichert wird. Im Kern han-
delt es sich um ein Schlüssel-Wert-Paar, z.B. language=de zur Speicherung der
bevorzugten Sprache eines Besuchers. Der Name des Cookies lautet in diesem
Fall language, sein Wert de.
195
Kapitel 9 Cookies und Sessions
HTTP/1.1 200 OK
Date: Wed, 27 May 2022 06:38:19 GMT
Content-Type: text/html
<html>...</html>
Über der Leerzeile befinden sich die für gewöhnliche Besucher der Websei-
te unsichtbaren HTTP-Header mit Metainformationen über die Antwort,
die das Verhalten des Browsers beeinflussen können. Eigene Header können
mit der Funktion header() erzeugt werden. Unter der Leerzeile folgt der im
Browserfenster sichtbare Inhalt, d.h. alle Ausgaben eines PHP-Skripts (echo,
var_dump() etc.) bzw. alles, was außerhalb von PHP-Tags steht.
Zurück zur Entstehung eines Cookies: In der Antwort kann der Webserver
den Browser mit dem HTTP-Header Set-Cookie zur Speicherung eines Coo-
kies auffordern:
HTTP/1.1 200 OK
Date: Wed, 27 May 2022 06:38:19 GMT
Content-Type: text/html
Set-Cookie: language=de
<html>...</html>
Die Erzeugung eines Cookies wird also durch einen HTTP-Header in der Ant-
wort ausgelöst und kann daher mit der Funktion header() veranlasst werden:
header('Set-Cookie: language=de');
echo 'Cookie "language" gesetzt!';
196
Cookies 9.1
Nach Abruf des Skripts im Browser ist das Cookie in der Browser-Konsole
unter Web-Speicher|Cookies und der Domain http://localhost:8000
sichtbar:
Sobald in einem Skript die erste Ausgabe erfolgt (z.B. per echo), beginnt
der Webserver eventuell bereits mit dem Senden der Antwort an den
Browser. Ab diesem Zeitpunkt können der Antwort keine Header mehr
hinzugefügt werden. Das Setzen eines Cookies bzw. jeglicher Header soll-
te daher im Code immer vor der ersten Ausgabe stattfinden.
Aufgabe 1
197
Kapitel 9 Cookies und Sessions
Mit dem passenden Cookie-Namen als Array-Schlüssel erfolgt der Zugriff auf
den Wert eines bestimmten Cookies:
echo $_COOKIE['language']; // => de
Beachten Sie, dass ein neu gesetztes Cookie erst ab der nächsten Anfrage des
Clients im $_COOKIE-Array sichtbar ist:
setcookie('language', 'de'); 1
if (isset($_COOKIE['language'])) { 2
echo $_COOKIE['language'];
} else {
echo 'Noch kein Cookie gesetzt';
}
Jeder Browser pflegt seine eigenen Cookies, d.h. Cookies sind auf den
Browser beschränkt, in dem sie gesetzt wurden.
Aufgabe 2
198
Cookies 9.1
Die Website hat eine Navigation mit den zwei Unterseiten Startseite/Home-
page und Gästebuch/Guestbook sowie Links zur Einstellung der Anzeige-
sprache Deutsch oder Englisch. Nach Auswahl der Sprache kann beliebig zwi-
schen den Unterseiten gewechselt werden, die Auswahl bleibt erhalten. Die
Sprachauswahl ist als Cookie auf dem Rechner des Besuchers hinterlegt.
Hinweis
Zum Test des Sprachwechslers starten Sie den Webserver mit dem Verzeich-
nis language-switcher/ aus den Code-Downloads als Document-Root.
Quelltext
Die beiden Unterseiten index.php und guestbook.php binden beide zunächst
die Datei _header.php ein. Abhängig von der Variablen $lang ist die Ausgabe-
sprache Englisch oder Deutsch.
<?php require __DIR__ . '/_header.php'; ?>
<h1><?= $lang === 'en' ? 'Welcome' : 'Willkommen'; ?></h1>
Das Skript _header.php setzt die Variable $lang in Abhängigkeit des Cookies
namens lang:
199
Kapitel 9 Cookies und Sessions
<?php
$lang = $_COOKIE['lang'] ?? 'de'; 1
if (isset($_GET['lang'])) { 2
setcookie('lang', $_GET['lang']); 3
header('Location: ' . $_SERVER['PHP_SELF']); exit(); 4
}
?>
<p><a href="?lang=de">DE</a>|<a href="?lang=en">EN</a></p> 5
<ul> 6
<li><a href="index.php">
<?= $lang === 'en' ? 'Homepage' : 'Startseite' ?>
</a></li>
<li><a href="guestbook.php">
<?= $lang === 'en' ? 'Guestbook' : 'Gästebuch' ?>
</a></li>
</ul>
Erklärungen
1 Mit Hilfe des Null Coalescing Operators (?? – siehe unten) wird die Vari-
able $lang mit dem Wert aus dem Cookie lang initialisiert, falls es existiert,
ansonsten mit de.
2 Falls ein URL-Parameter lang empfangen wurde …
3 … wird mit dessen Wert das Cookie lang gesetzt …
4 … und zum selben Skript weitergleitet (= neu laden der Seite). Bei der
erneuten Ausführung wird der Sprachwechsel durch 1 aktiv.
5 Menü zum Sprachwechsel: Jeder Link setzt den passenden URL-Parame-
ter, der den Sprachwechsel auslöst.
6 Website-Menü mit Links zu zwei Unterseiten.
$_SERVER['PHP_SELF'] enthält den aktuellen Skriptnamen und kann verwen-
det werden, um dynamisch Links auf dasselbe Skript zu erzeugen, ohne den
Dateinamen explizit zu nennen.
Der Null coalescing operator (??) ist eine Kurzform für eine häufige, bestimmte
Verwendung des ternären Operators (siehe auch Abschnitt 3.1.5):
$lang = $_COOKIE['lang'] ?? 'de';
200
Cookies 9.1
Der Operator liest sich in Gedanken: »Weise $lang den Wert von $_
COOKIE['lang'] zu, wenn das Element existiert, ansonsten den String de«. Die
gleichwertige Langform lautet:
$lang = isset($_COOKIE['lang']) ? $_COOKIE['lang'] : 'de';
Ab der nächsten Anfrage sendet der Browser das Cookie nicht mehr.
202
Sessions: Benutzersitzungen 9.2
Nach dem Start einer Session können Daten in das superglobale $_SESSION-
Array geschrieben werden:
$_SESSION['lang'] = 'de'; // Spracheinstellung
$_SESSION['cart'] = [ // "Einkaufswagen"
'apples' => 3,
'bananas' => 2,
];
Mit Ende der Skriptausführung speichert PHP die Daten des $_SESSION-Ar-
rays automatisch in die zugehörige Session-Datei auf dem Server. Von dort
liest sie PHP bei einer späteren Anfrage wieder ein.
203
Kapitel 9 Cookies und Sessions
session_start();
print_r($_SESSION);
Die Ausgabe:
Array(
[lang] => de
[cart] => Array (
[apples] => 3
[bananas] => 2
)
)
Aufgabe 3
Quelltext
Die Datei users.php speichert die Benutzer mit individuellen Passwörtern in
einem Array:
204
Sessions: Benutzersitzungen 9.2
return [
'alisa84' => 's3cr3t',
'limo02' => 'pa$$w0rd', // ...
];
Durch die return-Anweisung kann das Array bei Einbindung der Datei einer
Variablen zugewiesen werden:
$users = require __DIR__.'/users.php';
print_r($users);
// Array([alisa84] => s3cr3t [limo02] => pa$$w0rd)
Die Website besteht aus zwei Unterseiten. Beim Wechsel zwischen den Seiten
muss der Anmeldestatus aufrechterhalten werden:
<?php require __DIR__.'/_header.php' ?>
<h1>Willkommen</h1>
Die Unterseiten teilen sich den Kopfbereich aus der Datei _header.php. Sie
enthält den An- und Abmeldebereich sowie die Navigation der Website:
<?php
session_start(); 1
$error = null; 2
if (isset($_POST['username'], $_POST['password'])) { 3
$users = require __DIR__.'/users.php'; 4
$username = $_POST['username'];
if (isset($users[$username]) &&
$users[$username] === $_POST['password']) { 5
$_SESSION['username'] = $_POST['username']; 6
header('Location: ' . $_SERVER['PHP_SELF']); exit();
}
$error = 'Ungültige Anmeldedaten'; 7
205
Kapitel 9 Cookies und Sessions
} elseif (isset($_POST['logout'])) { 8
unset($_SESSION['username']); 9
header('Location: ' . $_SERVER['PHP_SELF']); exit();
}
?>
<?php if ($error !== null): ?> 10
<p style="color:red; >"><?= $error ?></p>
<?php endif; ?>
<?php if (isset($_SESSION['username'])): ?> 11
<p>Hallo <strong><?= $_SESSION['username'] ?></strong>,
Sie sind eingeloggt.</p>
<form method="post">
<button type="submit" name="logout">Ausloggen</button>
</form>
<?php else: ?> 12
<form method="post">
<input name="username" placeholder="Benutzername"/><br/>
<input name="password" placeholder="Passwort"/><br/>
<button type="submit">Einloggen</button>
</form>
<?php endif; ?>
<ul> 13
<li><a href="index.php">Startseite</a></li>
<li><a href="guestbook.php">Gästebuch</a></li>
</ul>
Erklärungen
1 Start bzw. Wiederaufnahme der Session.
2 $error zur Speicherung möglicher Fehlermeldungen.
3 Wurde das Anmeldeformular abgeschickt?
4 Array mit Benutzern und deren Passwörter in die Variable $users laden.
5 Wenn eingegebener Benutzername in $users als Schlüssel existiert und
das Passwort übereinstimmt, ist die Anmeldung erfolgreich.
6 Bei erfolgreicher Anmeldung wird der Benutzernamen in $_SES
SION['username'] gespeichert und die Seite durch eine Weiterleitung auf
sich selbst neu geladen. Der Benutzername in der Session dient als sicheres,
206
Sessions: Benutzersitzungen 9.2
Hinweis
Zum Test des Logins starten Sie den Webserver mit dem Verzeichnis
login/ aus den Code-Downloads als Document-Root.
207
Kapitel 9 Cookies und Sessions
Die Technik zur einmaligen Anzeige einer Nachricht wird mit einem
Blitz (engl. flash) verglichen, da sie nur einmalig »aufblitzt« und mit
dem nächsten Seitenwechsel wieder verschwindet.
Wie kann ein Skript jedoch von einer Aktion aus einem vorherigen Skript wis-
sen und eine passende Meldung dazu anzeigen?
Quelltext
Die Lösung erweitert den Quellcode des Login-Beispiels aus Abschnitt 9.2.3 an
wenigen Stellen. Zur Umsetzung einer Flash-Nachricht wird die gewünschte
Nachricht nur kurzzeitig zwischen zwei Anfragen in der Session gespeichert:
Nach einer erfolgreichen Aktion wie dem Login bzw. Logout und vor der
Weiterleitung auf eine neue Seite wird eine passende Nachricht unter dem
Schlüssel flash_message in das $_SESSION-Array geschrieben.
Im allgemeinen Kopfbereich der Webseite wird bei jeder Anfrage geprüft,
ob eine Flash-Nachricht in der Session vorliegt. Falls ja, wird sie zur An-
zeige gebracht und anschließend gelöscht, um eine einmalige Anzeige der
Nachricht sicherzustellen.
Während eines erfolgreichen Logins bzw. Logouts schreibt das Skript kurz
vor der Weiterleitung zusätzlich die passende Flash-Nachricht unter $_
SESSION['flash_message'] in die Session:
...
if (isset($users[$username]) &&
$users[$username] === $_POST['password']) {
$_SESSION['username'] = $_POST['username'];
208
Sessions: Benutzersitzungen 9.2
Nach dem neu Laden der Seite durch die Weiterleitung per Location-Header
baut sich die Seite neu auf, um sich dem neuen Anmeldestatus anpassen zu
können. Der Code im Kopfbereich in der Datei _header.php wird erweitert,
um eine Flash-Nachricht anzuzeigen, falls das $_SESSION-Array unter dem
Schlüssel flash_message eine bereithält. Unmittelbar nach der Anzeige wird
die Flash-Nachricht aus der Session entfernt, um eine nochmalige Anzeige
beim nächsten Laden der Seite zu vermeiden.
...
<?php if (isset($_SESSION['flash_message'])): ?>
<p style="color:green; font-weight: bold;>">
<?= htmlspecialchars($_SESSION['flash_message']) ?>
</p>
<?php unset($_SESSION['flash_message']); ?>
<?php endif; ?>
...
Die Anzeige der Flash-Nachricht ist unabhängig von ihrem Ursprung und
kann daher ohne weitere Anpassung für Rückmeldungen weiterer Anwen-
dungsfälle genutzt werden, sofern diese eine Flash-Nachricht in die Session
schreiben.
209
Kapitel 9 Cookies und Sessions
Hinweis
Zum Test des Logins mit Flash-Nachrichten starten Sie den Webserver mit
dem Verzeichnis login-with-flash-messages/ aus den Code-Downloads als
Document-Root.
9.3 Übungen
Übung 1
Erzeugen Sie eine Webseite mit einem »Cookie-Banner«, das Besucher einma-
lig fragt, ob sie Werbe-Cookies zustimmen.
210
Einstieg in die
objektorientierte
Programmierung (OOP)
Für die Strukturierung von Computerprogrammen haben sich verschiedene
Grundkonzepte entwickelt, so genannte Programmierparadigmen. Ein Pro-
grammierparadigma ist eine »Denkwelt« zur Lösung von Programmieraufga-
ben. Eine Programmiersprache legt durch die bereitgestellten Sprachelemente
die Verwendung bestimmter Paradigmen nahe. PHP ist eine Hybridsprache
mit zwei etablierten Paradigmen:
Prozedurale Programmierung: Hauptmerkmale sind eine genau bestimmte
Abfolge an Programmanweisungen und die Strukturierung durch Funktio
nen (»Prozeduren«). Die bisherigen Beispiele im Buch verwenden diesen
Stil.
Objektorientierte Programmierung (OOP): Die Objektorientierung bietet
mächtige Werkzeuge, um Programme in sinnvolle Einheiten, die Objekte,
zu zerlegen. Ziel ist eine höhere Flexibilität, Stabilität und Wartbarkeit.
Kenntnisse der objektorientierten Programmierung sind nicht nur zur Gestal-
tung eigener Programme nützlich – PHP selbst stellt viele native Funktiona-
litäten im objektorientierten Stil bereit. In diesem Kapitel lernen Sie Grund-
konzepte der objektorientierten Programmierung kennen: Klassen, Objekte,
Eigenschaften, Methoden, Konstruktoren, Kapselung, Vererbung und Aus-
nahmen.
211
Kapitel 10 Einstieg in die objektorientierte Programmierung (OOP)
212
Grundbegriffe der »OOP« 10.2
Der Code zur Definition der Klasse hat wie die Definition einer Funktion kei-
ne direkte Auswirkung; sie macht PHP lediglich mit dem Bauplan für Objekte
vom Typ Employee bekannt. Auf Grund des leeren Rumpfs hat die Klasse noch
keine Funktionalität.
213
Kapitel 10 Einstieg in die objektorientierte Programmierung (OOP)
Neue Objekte erzeugt der new-Operator. Darauf folgt der Name der Klasse,
von der ein neues Objekt erzeugt werden soll und ein Paar runde Klammern.
Folgendes Skript instanziiert Objekte für zwei Angestellte:
class Employee {}
$employee1 = new Employee(); // ein Angestellter
$employee2 = new Employee(); // ein anderer Angestellter
Noch haben die Objekte keine Funktionalitäten. Erst Eigenschaften und Me-
thoden hauchen den Objekten Leben ein.
214
Grundbegriffe der »OOP« 10.2
Die Klasse Employee legt in ihrem Rumpf fest, mit welchen Eigenschaften jedes
konkrete Objekt ausgestattet sein soll:
class Employee {
public string $firstName;
public string $lastName;
}
Eigenschaften kann man sich als Variablen im Kontext eines Objekts vor-
stellen. Jedes erzeugte Objekt vom Typ Employee verfügt über seine eigenen
Variablen für Vor- und Nachnamen. Der Datentyp schränkt ihren Wert auf
einen bestimmten Datentyp ein. Mit der Angabe string ist sichergestellt, dass
Vor- und Nachname eines Angestellten sinnvollerweise nur Strings sein kön-
nen. Die Sichtbarkeit bestimmt, von welchen Bereichen des Programms ein
Zugriff auf eine Eigenschaft erlaubt sein soll – dazu mehr in Abschnitt 10.2.7.
Nach der Instanziierung eines Objekts vom Typ Employee können die Eigen-
schaften wie Variablen genutzt werden. Die Zugehörigkeit zum Objekt wird
mit dem Zugriff über den speziellen Objekt-Operator »->« deutlich:
215
Kapitel 10 Einstieg in die objektorientierte Programmierung (OOP)
Hinweis
216
Grundbegriffe der »OOP« 10.2
}
}
Nach der Erzeugung eines Objekts der Klasse Employee kann der Aufruf der
Methode mit dem Objekt-Operator »->« erfolgen:
$employee = new Employee();
$employee->payBonus(1000); // => Danke für 1000 €!
217
Kapitel 10 Einstieg in die objektorientierte Programmierung (OOP)
Der Konstruktor ist nützlich, um ein Objekt vor der weiteren Verwendung
in einen gewünschten Ausgangszustand zu versetzen, z.B. durch Methoden-
Parameter:
class Employee {
public int $vacationDays;
public function __construct(int $vacationDays) {
$this->vacationDays = $vacationDays; // initiale Urlaubstage
}
}
Der Konstruktor ist eine Methode ohne Rückgabewert! Die Signatur des
Konstruktors besitzt daher weder einen Typ-Hinweis auf den Rückgabe-
wert, noch kann der Rumpf einen Wert zurückgeben.
218
Grundbegriffe der »OOP« 10.2
class Employee {
public int $vacationDays;
}
$employee = new Employee();
$employee->vacationDays = 30; // Zugriff von außen
echo $employee->vacationDays; // => 30
Durch Anpassung auf eine private (private) Sichtbarkeit kann ein Objekt sei-
ne Daten vor dem Zugriff von außen schützen:
class Employee {
private int $vacationDays;
}
$employee = new Employee();
$employee->vacationDays = 30; // Zugriff verboten!
// Fatal error: Uncaught Error: Cannot access
// private property Employee::$vacationDays
Das Schreiben und Lesen einer privaten Eigenschaft innerhalb des Objekts
mittels $this ist weiterhin möglich. Methoden können daher die Aufgabe
übernehmen, der Eigenschaft Werte zuzuweisen:
class Employee {
private int $vacationDays;
public function setVacationDays(int $days): void {
$this->vacationDays = $days; // Zugriff möglich!
}
public function vacationDays(): int {
return $this->vacationDays; // Zugriff möglich!
}
}
$employee = new Employee();
$employee->setVacationDays(25); // Aufruf von außen
echo $employee->vacationDays(); // => 25
219
Kapitel 10 Einstieg in die objektorientierte Programmierung (OOP)
Das Zuweisen eines Werts an die private Eigenschaft mit dem Umweg über
eine Methode ergibt bis hierhin noch keinen Vorteil gegenüber einer Ei-
genschaft, die selbst öffentlich ist. Eine Methode kann jedoch beliebige Pro-
grammlogik enthalten und eröffnet dadurch alle Möglichkeiten zur Überprü-
fung eingehender Daten, die für die Eigenschaft bestimmt sind.
class Employee {
private int $vacationDays;
public function setVacationDays(int $days): void {
if ($days < 20) {
exit('Mindesturlaub unterschritten!');
}
$this->vacationDays = $days;
}
}
$employee = new Employee();
$employee->setVacationDays(0);
// => Mindesturlaub unterschritten!
220
Vererbung 10.3
Eine Garantie für einen gültigen Zustand entsteht, indem bereits der Kon
struktor zur Übergabe der Urlaubstage verpflichtet:
class Employee {
private int $vacationDays;
public function __construct(int $vacationDays) {
if ($vacationDays < 20) {
exit('Mindesturlaub unterschritten!');
}
$this->vacationDays = $vacationDays;
}
public function vacationDays(): int {
return $this->vacationDays;
}
}
$employee = new Employee(27);
echo $employee->vacationDays(); // => 27
10.3 Vererbung
Ein weiteres grundlegendes Strukturierungselement der objektorientierten
Programmierung ist die Vererbung (engl. inheritance). Die Vererbung erlaubt
es, eine Klasse zu definieren, die auf einer bereits existierenden Klasse auf-
221
Kapitel 10 Einstieg in die objektorientierte Programmierung (OOP)
baut. Die neue Klasse »erbt« die Fähigkeiten der Basisklasse und kann neue
hinzufügen.
Die beiden Klassen Manager und Worker erweitern (engl. to extend) die Klasse
Employee:
class Employee {}
class Manager extends Employee {}
class Worker extends Employee {}
Eine Klasse, von der geerbt wird, bezeichnet man als Elternklasse, die
erbende Klasse als Kindklasse.
222
Vererbung 10.3
}
public function name(): string {
return $this->name;
}
}
Der Type Hint Worker für den Parameter $worker in der Methode addWorker-
ToTeam() stellt sicher, dass nur Objekte der Klasse Worker übergeben werden
dürfen. Einem Manager können dadurch nur Arbeiter als Team-Mitglieder
zugeordnet werden, aber keine anderen Manager. Dadurch können Anforde-
rungen an eine Software sicher abgebildet werden.
$worker1 = new Worker('Arbeiter Max');
$worker2 = new Worker('Arbeiter Jan');
$manager = new Manager('Manager Hans');
$manager->addWorkerToTeam($worker1);
$manager->addWorkerToTeam($worker2);
foreach($manager->team() as $worker) {
echo $worker->name() . "<br/>";
}
223
Kapitel 10 Einstieg in die objektorientierte Programmierung (OOP)
Die Beendigung des Skripts am Ort des Fehlers verhindert die weitere Verar-
beitung eines ungültigen Werts, ist jedoch recht unflexibel. Eine Web-Anwen-
dung könnte z.B. mitten in der Zusammenstellung einer HTML-Seite unter-
brochen werden:
<html>
<head>…</head>
<body>
<?php $employee = new Employee(3); ?>
Urlaubstage: <?= $employee->vacationDays() ?>
</body>
</html>
224
Ausnahmen (Exceptions) 10.4
Auch diese Variante hat Nachteile: Der Code zur Fehlerbehandlung kann
leicht vergessen werden, die Kenntnis verschiedener Rückgabewerte ist not-
wendig. Darüber hinaus erhält der Aufrufer keine Detailinformationen über
den Fehler, lediglich den Wert null.
Die objektorientierte Programmierung bietet mit dem Konzept der Ausnahme
(engl. exception) eine flexiblere Handhabung von Fehlern. Entsteht eine Feh-
lersituation, verkündet der Code diese Tatsache mit dem »Werfen« (engl. to
throw) einer Ausnahme. Eine Ausnahme wird durch ein Objekt der in PHP
eingebauten Klasse Exception (oder einer ihrer Kindklassen) repräsentiert
und die passende Fehlermeldung dem Konstruktor übergeben:
class Employee {
private int $vacationDays;
public function __construct(int $vacationDays) {
if ($vacationDays < 20) {
throw new Exception('Mindesturlaub unterschritten!');
}
$this->vacationDays = $vacationDays;
}
225
Kapitel 10 Einstieg in die objektorientierte Programmierung (OOP)
// ...
}
Das Auftreten einer Ausnahme führt zu einem fatalen Fehler mit Abbruch des
Skripts:
$employee = new Employee(3);
// Fatal error: Uncaught Exception: Mindesturlaub
// unterschritten.
Neben der Fehlermeldung berichtet PHP, dass die Ausnahme nicht »gefan-
gen« (engl. uncaught) wurde. Tatsächlich hat das Werfen einer Ausnahme kei-
nen konkreten Adressaten: Solange sie niemand »fängt«, kommt es zu einem
fatalen Fehler. Mit dem try-catch-Konstrukt erhält der aufrufende Code je-
doch die Möglichkeit, geworfene Ausnahmen aufzufangen:
try {
$employee = new Employee(3); // wirft Ausnahme!
echo $employee->vacationDays();
} catch (Exception $e) { // fängt Ausnahme!
echo 'Fehler: ' . $e->getMessage();
} // => Fehler: Mindesturlaub unterschritten.
226
Native Objektorientierung in PHP 10.5
}
?>
</body>
</html>
Aufgabe 1
Als viertes Argument kann der Funktion json_decode() ein »Flag« über-
geben werden, um das Verhalten im Fehlerfall umzuschalten: Statt null
zurückzugeben, wirft die Funktion dann eine Ausnahme. Finden Sie das
passende Flag (eine vordefinierte Konstante) in der PHP-Dokumentation?
227
Kapitel 10 Einstieg in die objektorientierte Programmierung (OOP)
228
Übungen 10.6
Aufgabe 2
Welches Datum enthält ein Objekt der DateTime-Klasse, wenn es ohne Kon-
struktor-Argument erzeugt wird?
10.6 Übungen
Übung 1
Schreiben Sie ein Skript, das eine Klasse Product definiert.
Statten Sie die Klasse mit drei öffentlichen Eigenschaften für Name, Be-
schreibung und Preis aus.
Instanziieren Sie zwei verschiedene Objekte der Klassen.
Setzen Sie Werte für die Eigenschaften.
Geben Sie eine Produktliste mit allen Eigenschaften aus. Formatieren Sie
den Preis dabei im deutschen Format.
229
Kapitel 10 Einstieg in die objektorientierte Programmierung (OOP)
Übung 2
Erweitern Sie die Product-Klasse aus der vorigen Übung.
Kapseln Sie die Objektdaten in privaten Eigenschaften.
Setzen Sie die Eigenschaften durch die Konstruktor-Methode mit Hilfe der
Sondervariablen $this.
Führen Sie Validierungen ein, um nur Objekte mit sinnvollen Daten zu-
zulassen, d.h. kein leerer Name, keine leere Beschreibung, kein Preis unter
Null. Werfen Sie ansonsten Ausnahmen vom Typ Exception mit Hilfe des
Schlüsselworts throw.
Ergänzen Sie öffentliche Methoden zum Zugriff auf die Objektdaten. Ge-
ben Sie dabei den Preis bereits formatiert zurück.
Passen Sie die Produktliste entsprechend an.
Übung 3
Instanziieren Sie ein DateTime-Objekt mit dem ersten Tag des nächsten Mo-
nats mittags deutscher Zeit. Stellen Sie das Datum um sechs Wochen vor. Än-
dern Sie die Zeitzone auf New York. Geben Sie das eingestellte Datum nach
jeder Änderung formatiert aus.
Tipps:
https://www.php.net/datetime.construct
https://www.php.net/datetimezone.construct
230
Datenverwaltung
mit MySQL
Wichtige Aspekte bei der Datenverarbeitung sind die dauerhafte Speicherung
und der spätere Wiederabruf von Daten. Gewöhnliche Dateien eigenen sich
zwar grundsätzlich zur Datenhaltung (Abschnitt 8.2), fortgeschrittene An-
forderungen können sie aber nicht erfüllen. Lese- und Schreiboperationen
wachsender Dateien sind träge, gleichzeitige Zugriffe verschiedener Prozesse
können sich gegenseitig blockieren oder zu widersprüchlichen Daten führen,
das Auslesen nur von Teilen der Daten ist kaum möglich. Die Mittel für Da-
tenstrukturierung und Zugriffsbeschränkungen sind gering.
Zur professionellen Datenverwaltung kommen daher spezielle Datenbankma-
nagementsysteme (DBMS) zum Einsatz, die eine strukturierte, effiziente und
»konsistente«, d.h. widerspruchsfreie, Datenhaltung ermöglichen. Dieses Ka-
pitel zeigt Grundlagen zu Datenbanken und Tabellen und stellt MySQL als
relationales Datenbankmanagementsystem vor. Sie lernen MySQL zu instal-
lieren, SQL als Abfragesprache einzusetzen, eine Datenbank mit Tabellen an-
zulegen sowie Datensätze in Tabellen einzufügen, abzufragen, zu verändern
und zu löschen.
231
Kapitel 11 Datenverwaltung mit MySQL
Die Datenbank selbst ist ein benannter Container, der mehrere Tabellen zu
einer Einheit zusammenfasst.
232
Was ist SQL? 11.3
233
Kapitel 11 Datenverwaltung mit MySQL
Das Semikolon (;) schließt einen SQL-Befehl ab. Folgender Befehl fügt einen
Datensatz in die Tabelle products der Datenbank shop ein. Ein Datensatz be-
steht aus Werten für die Spalten name und price:
INSERT INTO shop.products (name, price)
VALUES ('Notebook', 1499);
234
Erste Schritte mit MySQL 11.4
235
Kapitel 11 Datenverwaltung mit MySQL
Windows
Laden Sie den MSI-Installer unter https://dev.mysql.com/downloads/
installer herunter. Je nach Versionsnummer erhalten Sie eine Datei mit
einem Namen ähnlich zu mysql-installer-community-8.0.27.0.msi. Für
den Download müssen Sie keinen Benutzeraccount auf mysql.com anlegen,
klicken Sie bei der Aufforderung das unscheinbare »No thanks, just start
my download«. Starten Sie den Installer und wählen Sie im ersten Schritt der
Installation Server Only.
236
Erste Schritte mit MySQL 11.4
Der Haken bei »Start the MySQL Server at System Startup« sorgt für einen
automatischen MySQL-Start nach einem Computer-Neustart. Schließen Sie
die Installation ab.
Zur bequemen Nutzung des Kommandozeilen-Clients mysql ohne lange Pfad
angabe ergänzen Sie analog zur PHP-Installation (Abschnitt 1.7.1) das Ver-
zeichnis C:\Program Files\MySQL\MySQL Server 8.0\bin in der Path-Umge-
bungsvariable.
Damit der mysql-Befehl in der Git Bash (Abschnitt 1.6.1) funktioniert, muss
ein Problem bei der Verwendung interaktiver Funktionen (z.B. Passwortabfra-
gen) behoben werden. Öffnen Sie die Datei ~/.bashrc, d.h. die Datei .bashrc
im Heimatverzeichnis des eingeloggten Benutzers, in einem Texteditor (z.B.
VS Code oder Notepad) und ergänzen Sie folgende Zeile:
alias mysql="winpty mysql"
Starten Sie nach dem Speichern die Git Bash neu. Bei der Ausführung des
Befehls mysql führen Sie fortan in Wirklichkeit den »Alias«-Befehl winpty
mysql aus, ohne sich jedes Mal daran erinnern zu müssen. Das Voranstellen
des Befehls winpty behebt das Problem mit interaktiven Abfragen. Der My
SQL-Client ist bereit:
> mysql --version
mysql Ver 8.0.27 for Win64 ...
237
Kapitel 11 Datenverwaltung mit MySQL
macOS
Installieren Sie MySQL mit Hilfe von Homebrew:
> brew install mysql
Linux
Diese Anleitung beschreibt die MySQL-Installation unter Ubuntu-Linux und
sollte auf andere Linux-Distributionen übertragbar sein, die ebenfalls den
APT-Paketmanager verwenden (Debian, Mint u.a.). Unter Ubuntu können
Sie MySQL mit dem Befehl apt installieren (wie zuvor PHP, siehe Abschnitt
1.7.3):
238
Erste Schritte mit MySQL 11.4
Führen Sie anschließend zur Absicherung der Installation diesen Befehl aus:
> sudo mysql_secure_installation
> php -m
... mysqli ... pdo_mysql ...
239
Kapitel 11 Datenverwaltung mit MySQL
240
Datenbanken 11.6
mysql> quit
Bye
Aufgabe 1
Wie verbinden Sie sich mit dem mysql-Befehl mit einem MySQL-Server auf
einem anderen Computer (Host)?
Tipp: Sie benötigen zusätzlich eine Option für den Host.
11.5 Kommentare
Wie Programmiersprachen unterstützt SQL Kommentare, die nicht Teil eines
Befehls sind, sondern als Verständnishilfe dienen. Kommentare bis zum Zei-
lenende werden in MySQL mit zwei Bindestrichen (--) oder einer Raute (#)
notiert:
CREATE DATABASE shop; -- Kommentar bis Zeilenende
CREATE DATABASE shop; # Kommentar bis Zeilenende
Hinweis
11.6 Datenbanken
Datenbanken sind Container für Tabellen. Vor dem Erstellen einer Tabelle ist
folglich eine Datenbank erforderlich.
241
Kapitel 11 Datenverwaltung mit MySQL
Um Befehle innerhalb der neuen Datenbank auszuführen, wählt man sie zu-
nächst mit dem Befehl USE aus:
mysql> USE company;
Database changed
Dabei gehen alle enthaltenen Tabellen und deren Daten ohne Rückfrage ver-
loren!
242
Tabellen 11.7
11.7 Tabellen
Dieser Abschnitt setzt das Beispiel einer Datenbank company für eine fiktive
Personal-Software zur Verwaltung von Firmenangestellten aus dem vorigen
Abschnitt fort:
mysql> CREATE DATABASE company;
mysql> USE company;
Ein Befehl kann sich über mehrere Zeilen erstrecken, erst nach Eingabe ei-
nes Semikolons wird der Befehl abgeschickt. Die Definition einer Tabelle folgt
dem allgemeinen Schema:
CREATE TABLE Tabellenname (
Spaltename1 Spaltentyp Optionen,
Spaltename2 Spaltentyp Optionen,
...
);
11.7.2 Spaltentypen
Neben dem Spaltennamen muss für jede Spalte ein Spaltentyp festgelegt wer-
den, dem die später eingefügten Daten entsprechen müssen. Einige gängige
Spaltentypen lauten:
243
Kapitel 11 Datenverwaltung mit MySQL
Spaltentyp Beschreibung
CHAR(N) Zeichenkette fester Länge N (bis 255 Zeichen)
VARCHAR(N) Zeichenkette variabler Länge N (bis 65.535 Zeichen bzw. 64KB)
TEXT Zeichenkette bis max. 64KB, ohne Längenangabe
LONGTEXT Zeichenkette bis max. 4GB, ohne Längenangabe
TINYINT Ganzzahl zwischen -128 bis 127 oder vorzeichenlos (»unsigned«)
von 0 bis 255
INT Ganzzahl zwischen -2147483648 bis 2147483647 oder vorzei-
chenlos von 0 bis 4294967295
FLOAT(M, D) Fließkommazahl mit M Ziffern, davon D Dezimalstellen. Für wis-
senschaftliche Daten geeignet
DECIMAL(M, D) Festkommazahl mit M Ziffern, davon D Dezimalstellen. Geeignet
zur Speicherung exakter Werte, z.B. Geldbeträge
DATE Datum im Format YYYY-MM-DD, z.B. 2023-05-27
11.7.3 Spaltenoptionen
Abhängig vom Spaltentyp können verschiedene Optionen eingestellt werden.
244
Tabellen 11.7
Vorgabewerte: DEFAULT
Die Option DEFAULT definiert einen Vorgabewert für eine Spalte. Falls beim
Einfügen eines Datensatzes keine explizite Angabe eines Werts für diese Spal-
te erfolgt, wird der Vorgabewert verwendet. Die Wochenarbeitszeit könnte
mit den üblichen 40 Stunden vorbelegt sein:
mysql> CREATE TABLE employee (
...,
245
Kapitel 11 Datenverwaltung mit MySQL
Eine Primärschlüssel-Spalte schließt den Wert NULL automatisch aus. Der Ver-
such, einen vorhandenen Wert erneut einzufügen, führt zu einem Fehler.
246
Bezeichner 11.8
Beginnend bei eins wird der Wert der Spalte mit jedem neu eingefügten Da-
tensatz automatisch um eins hochgezählt (1, 2, 3, …).
Abbildung 11.7 zeigt die Erstellung und Beschreibung der bisher im Kapitel
entwickelten employee-Tabelle.
11.8 Bezeichner
Bezeichner sind die selbstgewählten Namen für Datenstrukturen und deren
Komponenten, d.h. die Namen für Datenbanken, Tabellen oder Spalten.
247
Kapitel 11 Datenverwaltung mit MySQL
11.8.2 Punkt-Notation
Die Punkt-Notation drückt die Zugehörigkeit einer Tabelle zu einer Daten-
bank aus und ermöglicht den direkten Zugriff auf eine Tabelle ohne vorherige
Auswahl der Datenbank mit dem USE-Befehl. Anstelle ...
USE company; DESCRIBE employee;
248
Daten schreiben, lesen, ändern und löschen 11.9
Für alle Spalten, die nicht »nullable« oder mit einem Vorgabewert belegt sind,
müssen zwingend Werte angegeben werden.
In der employee-Tabelle nummeriert MySQL die Primärschlüsselspalte em
ployee_id automatisch (auto increment). Die Spalte contract_end erlaubt
NULL, weekly_hours hat den Vorgabewert 40 – beide sind daher optional. Fol-
gende Befehle fügen zwei Datensätze ein:
INSERT INTO employee (name, salary, contract_start)
VALUES ('Max Becker', 55000, '2018-03-15');
INSERT INTO employee (name, salary, contract_start)
VALUES ('Lea Klein', 59000, '2019-04-01');
249
Kapitel 11 Datenverwaltung mit MySQL
Der Befehl zum Abruf der IDs und Namen aller Angestellten aus der Tabelle
employee lautet:
250
Daten schreiben, lesen, ändern und löschen 11.9
Ergebnis sortieren
Die angehängte ORDER BY-Klausel sortiert Datensätze nach einer gewünschten
Spalte und Reihenfolge:
Ergebnis filtern
Die WHERE-Klausel schränkt die abgefragten Datensätze eines SELECT-Befehls
auf bestimmte Datensätze ein:
SELECT Spalte(n) FROM Tabelle WHERE Bedingung;
251
Kapitel 11 Datenverwaltung mit MySQL
Die Ausführung des Befehls ähnelt der Schleife eines Programms, sie iteriert
über alle Datensätze und aktualisiert jeweils die Spalte salary. Der zugewiese-
ne Wert salary+1000 verwendet den Spaltennamen wie eine Variable, die bis
zum Abschluss der Aktualisierung noch den unveränderten, aktuellen Wert
des Datensatzes enthält. Für einen Datensatz mit zuvor salary=60000 löst sich
die SET-Zuweisung auf zu: salary=61000.
Eine WHERE-Klausel schränkt Änderungen auf bestimmte Datensätze ein. Die
Kündigung des Angestellten mit der ID 3 wird durch Setzen eines Datums für
das Vertragsende erfasst:
UPDATE employee
SET contract_end = '2024-12-31' WHERE id = 3;
Mit WHERE-Klausel werden Datensätze selektiv gelöscht, wie hier der Angestell-
te mit einer bestimmten ID:
DELETE FROM employee WHERE employee_id = 4;
Oder alle Angestellten deren Vertrag vor einem bestimmten Datum endete:
DELETE FROM employee
WHERE contract_end < '2020-01-01';
252
Übungen 11.10
Aufgabe 2
11.10 Übungen
Übung 1
Erweitern Sie die Definition der Tabelle company.employee mit sinnvoll de-
finierten Spalten zur Speicherung von Geburtsdatum, Postleitzahl und Ge-
schlecht.
Legen Sie die Tabelle auf Ihrem lokalen MySQL-Server an.
Fügen Sie einige Beispiel-Datensätze ein.
Kontrollieren Sie durch Abfrage aller Datensätze.
Übung 2
Erweitern Sie die Datenabfrage der Tabelle aus Übung 1:
Sortieren Sie absteigend nach Gehalt.
Schränken Sie auf ein Gehalt >= 60000 ein.
Kombinieren Sie die Sortierung mit der Einschränkung. Finden Sie die Rei-
henfolge der Klauseln heraus.
Übung 3
Erhöhen Sie alle Gehälter in der Tabelle aus Übung 1 um 10 %. Prüfen Sie
durch Abfrage.
253
Fortgeschrittene Daten
bankabfragen mit MySQL
Im vorigen Kapitel haben Sie die Grundlagen des relationalen Datenbankma-
nagementsystems MySQL und der Datenbanksprache SQL kennengelernt.
Die Eingabe von SQL-Befehlen erfolgte etwas mühsam über die Konsole und
die Möglichkeiten zur Filterung von Datensätzen waren begrenzt. Dieses Ka-
pitel beschäftigt sich mit fortgeschrittenen Themen und zeigt:
die Datenbankverwaltung mit Hilfe einer grafischen Benutzeroberfläche
am Beispiel von phpMyAdmin
den Zugriff auf eine Datenbank beim Webhoster
fortgeschrittene Filtermöglichkeiten zur Datenabfrage
Einsatz von SQL-Funktionen
Erstellung von Indizes für schnellere Abfragen
255
Kapitel 12 Fortgeschrittene Datenbankabfragen mit MySQL
Laden Sie für die lokale Verwendung die aktuellste Version von phpMyAdmin
als ZIP-Archiv von www.phpmyadmin.net/downloads herunter. Abhängig von
der Version lautet der Dateiname etwa phpMyAdmin-5.1.1-all-languages.zip.
Entpacken Sie das Archiv z.B. in Ihr Benutzerverzeichnis und benennen Sie
es der Einfachheit halber in phpMyAdmin um. Öffnen Sie das Verzeichnis in der
Kommandozeile und starten Sie einen Webserver.
256
Grafische Datenbankverwaltung mit phpMyAdmin 12.1
Im Anschluss ist die neue Datenbank vorausgewählt und Sie können die erste
Tabelle darin erzeugen:
Nach dem Speichern fügen Sie über den Reiter Einfügen neue Datensätze
ein:
Über den Reiter Anzeigen erhalten Sie eine Übersicht aller Datensätze (ggf.
über mehrere Seiten verteilt) und einige Funktionen wie Sortierung oder Da-
tenexport:
257
Kapitel 12 Fortgeschrittene Datenbankabfragen mit MySQL
258
MySQL beim Webhoster 12.2
259
Kapitel 12 Fortgeschrittene Datenbankabfragen mit MySQL
260
Fortgeschrittene Datenabfragen 12.3
12.3.1 Vergleichsoperatoren
Bei der Abfrage mit einer WHERE-Klausel gleicht MySQL Datensatz für Daten-
satz ab, ob die Bedingungen erfüllt sind und der Datensatz Teil der Ergebnis-
menge wird. Tabelle 12.1 zeigt Vergleichsoperatoren zur Formulierung von
Bedingungen.
Anführungszeichen
Zeichenketten und Datumsangaben werden in einfachen Anführungszeichen
eingeschlossen, für Zahlen ist dies nicht erforderlich:
... WHERE genre = 'action';
... WHERE id = 3;
Zur Notation von Zeichenketten unterstützt MySQL sowohl einfache als auch
doppelte Anführungszeichen:
... WHERE genre = 'action'; -- SQL-Standard
... WHERE genre = "action"; -- MySQL spezifisch
261
Kapitel 12 Fortgeschrittene Datenbankabfragen mit MySQL
Zur Prüfung auf NULL kommen die speziellen Operatoren IS NULL bzw. IS NOT
NULL zum Einsatz. Folgende Vergleiche finden Datensätze mit bzw. ohne dem
Wert NULL in der Spalte website:
... WHERE website IS NULL;
... WHERE website IS NOT NULL;
262
Fortgeschrittene Datenabfragen 12.3
Bei der Kombination mehrerer Operatoren ist die Bedeutung der gesamten
Bedingung auf den ersten Blick nicht offensichtlich:
... WHERE rating > 7 OR genre = 'thriller' AND length < 90;
Wie in der Programmierung folgt die Auflösung einer Bedingung mit mehre-
ren Operatoren nach einer festen Reihenfolge, der Operator-Präzedenz (engl.
precedence). Im Beispiel bindet AND stärker als OR, zusätzliche Klammern ver-
deutlichen dies:
... WHERE rating > 7 OR (genre = 'thriller' AND length < 90);
In Gedanken: »Filme mit einer Bewertung über 7 oder – unabhängig von der
Bewertung – Filme des Thriller-Genres mit weniger als 90 Minuten Laufzeit«.
Eine Änderung der Klammersetzung ändert das Verhalten:
... WHERE (rating > 7 OR genre = 'thriller') AND length < 90;
In Gedanken: »Filme mit weniger als 90 Minuten Laufzeit, die zusätzlich ent-
weder eine Bewertung über 7 aufweisen oder unabhängig von der Bewertung
Filme des Thriller-Genres sind«.
Um Fehlern vorzubeugen und die Lesbarkeit zu verbessern, sollten bei
der Kombination mehrerer SQL-Bedingungen immer Klammern einge-
setzt werden.
12.3.3 LIMIT: Abfrageergebnisse begrenzen
Die LIMIT-Klausel begrenzt die Anzahl der in einer Abfrage zurückgelieferten
Datensätze. Klassisches Beispiel ist die seitenweise Darstellung von Datensät-
zen aus einer großen Tabelle. Folgende Abfrage selektiert alle Datensätze der
movie-Tabelle in alphabetischer Reihenfolge:
263
Kapitel 12 Fortgeschrittene Datenbankabfragen mit MySQL
Enthält die Tabelle hunderte Datensätze, kann LIMIT die abgefragten Daten-
sätze z.B. auf zunächst 50 begrenzen:
SELECT * FROM movies ORDER BY title LIMIT 50;
Zur Abfrage der nächsten 50 Datensätze werden die ersten 50 mit Hilfe der
zusätzlichen OFFSET-Klausel (engl. für Versatz, Verschiebung) übersprungen.
Die Selektion von weiteren 50 Datensätzen beginnt nun beim 51sten Daten-
satz:
SELECT * FROM movies ORDER BY title LIMIT 50 OFFSET 50;
Aufgabe 1
Formulieren Sie einen SQL-Befehl zur Abfrage der fünf längsten Filme der
Tabelle movie.
Das Ergebnis:
+-------------------------+----------+
| Filmtitel | Länge |
+-------------------------+----------+
| Pulp Fiction | 02:34:00 |
| Matrix | 02:16:00 |
| James Bond 007: Skyfall | 02:23:00 | ...
Aliase sind besonders bei der Arbeit mit SQL-Funktionen (nächster Ab-
schnitt) nützlich, um temporär berechneten Daten einen Namen zu geben.
264
SQL-Funktionen 12.5
12.5 SQL-Funktionen
Jeder Datensatz speichert statische Werte wie Zahlen, Zeichenketten oder
Datumsangaben. Eingebaute SQL-Funktionen können während einer Abfrage
auf diese Werte angewendet werden und dynamisch weitere Werte berechnen.
Das Prinzip erinnert an PHP-Funktionen: Die SQL-Funktion nimmt Argu-
mente entgegen, führt eine Berechnung durch und liefert einen Rückgabe-
wert:
FUNKTIONSNAME(Argument1, Argument2, ...)
Bei der Abfrage von Datensätzen können Spaltennamen wie Variablen als Ar-
gumente an eine Funktion übergeben werden. Die Funktion wird auf jeden
Datensatz des Abfrageergebnisses angewendet. Folgende Abfrage liefert ge-
rundete Geldwechselkurse in einer »virtuellen« Ergebnisspalte:
> SELECT currency, rate, ROUND(rate)
> FROM exchange_rates;
+----------+--------+----------------+
| currency | rate | ROUND(rate, 2) |
+----------+--------+----------------+
| USD | 1.1951 | 1.20 |
| GBP | 0.8595 | 0.86 |
| CHF | 1.0956 | 1.10 |
265
Kapitel 12 Fortgeschrittene Datenbankabfragen mit MySQL
266
SQL-Funktionen 12.5
Datumsfunktionen
267
Kapitel 12 Fortgeschrittene Datenbankabfragen mit MySQL
Aufgabe 2
Formulieren Sie eine SELECT-Abfrage (ohne Tabelle), die das aktuelle Da-
tum zurückliefert.
Funktionsaufruf Beschreibung
COUNT() Anzahl der Datensätze
AVG() Durchschnittswert einer numerischen Spalte
SUM() Summe einer numerischen Spalte
Tab. 12.7: Beispiele für SQL-Aggregatfunktionen
268
Performance und Indizes 12.6
Formulieren Sie eine Abfrage, die alle Zeilen einer Tabelle user mit einem
Wert in der optionalen Spalte phone zählt.
269
Kapitel 12 Fortgeschrittene Datenbankabfragen mit MySQL
stimmten Worts absuchen müssen. Je länger das Buch, desto mehr Aufwand.
Ein Index nennt Ihnen die passenden Seitenzahlen mit geringem Suchauf-
wand.
Zur schnelleren Filterung von Datensätzen können Sie MySQL ebenfalls
durch Anlage eines Index auf bestimmte Tabellenspalten, in denen häufig ge-
sucht wird, helfen. Es gibt unterschiedliche Index-Arten:
Index-Art Bedeutung
PRIMARY KEY »Primärschlüssel« zur eindeutigen Identifizierung eines Datensat-
zes. Je Tabelle ist nur ein Primärschlüssel möglich, jeder Wert darf
nur einmal vorkommen, NULL-Werte sind nicht erlaubt.
UNIQUE »Eindeutiger Index«, jeder Wert darf nur einmal vorkommen. Ist
die Spalte »nullable«, darf der Wert NULL als einziger mehrfach
vorkommen.
INDEX Normaler »Index«, Werte können mehrfach vorkommen.
FULLTEXT »Volltext-Index«, ermöglicht eine Volltextsuche für Spalten mit
längeren Texten. Wörter werden einzeln indiziert.
Tab. 12.8: Verschiedene Index-Typen für Tabellenspalten
Indizes können bei Anlage einer Tabelle oder nachträglich definiert werden.
Für eine Tabelle mit Angestellten-Daten könnten folgende Überlegungen
plausibel sein:
Jeder Angestellte soll durch eine eindeutige ID identifizierbar sein. Jede ID
darf nur einmal vergeben sein und sich nie ändern. Häufige Abfragen per
ID sind zu erwarten. Ein »Primary Key« erfüllt die Anforderungen.
Für jeden Angestellten soll eine E-Mail gespeichert werden, die eindeutig
unter allen Angestellten ist. Sie kann sich später auch ändern. Eine häufige
Filterung nach E-Mail ist zu erwarten. Ein »Unique Key« erfüllt die Anfor-
derungen.
Eine häufige Filterung von Angestellten nach Vertragsbeginn ist zu erwar-
ten. Ein gewöhnlicher »Index« erfüllt die Anforderungen.
Die Adresse eines Angestellten dient Informationszwecken, eine Suche ist
nicht geplant. Ein Index ist nicht erforderlich.
Die passende Tabellendefinition lautet:
270
Performance und Indizes 12.6
1
https://dev.mysql.com/doc/refman/en/fulltext-search.html
271
Kapitel 12 Fortgeschrittene Datenbankabfragen mit MySQL
12.7 Übungen
Übung 1
Arbeiten Sie mit phpMyAdmin:
Legen Sie die Tabelle movie aus Abschnitt 12.3 in einer Datenbank book mit
Hilfe der Datei movie.sql aus den Buchdownloads (www.mitp.de/0395) an.
Tipp: Kopieren Sie das SQL oder nutzen Sie den Datei-Import.
Selektieren Sie Filme aus den Genres Action oder Drama mit einer höheren
Bewertung als 7, neueste zuerst.
Exportieren Sie das Ergebnis als PDF.
Übung 2
Formulieren Sie weitere Abfragen auf die Tabelle movie aus Übung 1:
Geben Sie die Durchschnittsbewertung aller Filme auf eine Stelle gerundet
aus.
Listen Sie alle Filme im Format »Titel (Jahr, Länge)« auf. Formatieren Sie
die Filmlänge mit DATE_FORMAT().
Geben Sie die Anzahl der Filme aus, die vor 2012 erschienen sind. Reduzie-
ren Sie anschließend auf Filme mit Website-Link.
Finden Sie alle Filme mit dem Wort Bond im Titel.
272
PHP und MySQL
kombinieren
In den letzten beiden Kapiteln haben Sie die Verwaltung einer MySQL-Da-
tenbank mit der Datenbanksprache SQL kennengelernt. SQL-Befehle wurden
manuell oder mit phpMyAdmin erstellt und zur Ausführung an den Daten-
bankserver gesendet.
Für ein Computer-Programm ist eine Datenbank die effizienteste Option
zur Datenspeicherung. Jede Programmiersprache ermöglicht die Anbindung
verschiedener Datenbanksysteme. Dieses Kapitel erklärt die Grundlagen zur
»programmatischen« Anbindung einer MySQL-Datenbank aus einem PHP-
Skript:
Verbindung mit MySQL herstellen
SQL-Befehle ausführen
Ergebnisse von SQL-Abfragen verarbeiten
Sie lernen außerdem die sichere Speicherung von Passwörtern und eine be-
kannte Sicherheitsproblematik kennen, die »SQL-Injection«.
273
Kapitel 13 PHP und MySQL kombinieren
den. Für die meisten Anwendungsfälle ist der Einsatz der modernen PDO-
Erweiterung zu empfehlen. Der Umgang ist intuitiv, mit dem einmal erlernten
Wissen können neben MySQL auch andere Datenbanksysteme angebunden
werden.
Die Herstellung der Verbindung kann fehlschlagen, etwa bei inkorrekten Ver-
bindungsdaten, unzureichenden Zugriffsrechten oder einem nicht erreichba-
ren Datenbankserver. In einem solchen Fehlerfall wirft der Konstruktor der
PDO-Klasse eine Ausnahme vom Typ PDOException, die unbehandelt direkt
zum Abbruch des Skripts führt. Durch Fangen der Ausnahme in einem try-
catch-Konstrukt kann sinnvoll auf einen Verbindungsfehler reagiert werden.
try
$pdo = new PDO(...)
} catch (PDOException $e) {
// z.B. Log-Eintrag mit Details aus $e->getMessage()
// z.B. den Administrator per E-Mail/SMS benachrichten
// z.B. Besucher freundlich informieren und Skript beenden:
require 'friendly-error-page.php';
exit();
}
// Ab hier: Verbindung zur Datenbank ist hergestellt
274
PHP mit MySQL verbinden 13.1
werden als Zeichenkette in einem speziellen Format, dem Data Source Name
(DSN), zusammengefasst:
Datenbanktyp:host=Domain;port=Port;dbname=Datenbankname
Für MySQL lautet der Datenbanktyp mysql. Standardmäßig stellt ein MySQL-
Server seinen Dienst auf dem Port 3306 zur Verfügung. Der DSN zur Ver-
bindung mit einer MySQL-Datenbank namens book auf dem lokalen Host-
Computer localhost lautet somit:
mysql:host=localhost;port=3306;dbname=book
275
Kapitel 13 PHP und MySQL kombinieren
Wie in Abschnitt 11.9 beschrieben, kann INSERT auch mehrere Datensätze auf
einmal einfügen und UPDATE bzw. DELETE können sich je nach Einschränkung
durch eine WHERE-Klausel auf viele Datenätze auswirken. Entsprechend liefert
PDO::exec() die Anzahl der eingefügten, aktualisierten oder gelöschten Da-
tensätze zurück.
Datensätze mit der Methode PDO::query() abfragen
Die Methode PDO::query() führt einen SQL-Befehl aus und gibt die Ergeb-
nismenge der gefundenen Datensätze gekapselt in einem Objekt vom Typ
PDOStatement zurück. Dies ist geeignet, um SELECT-Befehle auszuführen und
auf die zurückgelieferten Datensätze zuzugreifen. Folgendes Skript listet alle
Benutzernamen aus der Tabelle user auf:
require __DIR__ . '/_mysql-connect.php';
// $stmt ist Objekt vom Typ "PDOStatement"
$stmt = $pdo->query('SELECT username FROM user');
// Ergebnismenge als Array durchlaufen
foreach ($stmt->fetchAll() as $user) {
echo $user['username']. '<br/>';
}
276
PHP mit MySQL verbinden 13.1
277
Kapitel 13 PHP und MySQL kombinieren
Aufgabe 1
278
Beispiel: Benutzer-Accounts 13.3
Hinweis
Starten Sie zum Testen der Account-Verwaltung den Webserver mit dem
Unterverzeichnis user-accounts/ aus den Code-Downloads zum Kapitel
als Document-Root.
279
Kapitel 13 PHP und MySQL kombinieren
try {
$pdo->exec($sql); 3
echo 'Tabelle <code>user</code> angelegt!';
} catch (PDOException $e) {
echo 'Datenbank-Fehler: ' . $e->getMessage();
}
1 Datenbankverbindung herstellen.
2 SQL-Befehl zur Erstellung der Tabelle user.
3 PDO::exec() führt den SQL-Befehl in der Datenbank aus.
Die Ausführung von SQL-Befehlen der Kategorie »Data-Definition-Lan
guage« (DDL; siehe Tabelle 11.1) zur Erstellung von Datenstrukturen ist na-
türlich nur einmal sinnvoll. Ein erneutes Ausführen des Skripts führt zu ei-
nem Fehler, da die Tabelle user bereits existiert. DDL-Befehle sind häufig Teil
von Installations-Assistenten zur initialen Einrichtung von Datenstrukturen.
280
Beispiel: Benutzer-Accounts 13.3
13.3.3 Login
Das Skript login.php verarbeitet ein Login-Formular mit Eingaben für Be-
nutzername und Passwort. Existiert in der user-Tabelle ein zu den Eingaben
passender Datensatz, ist der Benutzer authentifiziert. Der Status wird in der
Benutzer-Session vermerkt und eine Weiterleitung zur Seite secret.php ange-
stoßen, die eingeloggten Benutzern vorbehalten ist.
if (isset($_POST['username'], $_POST['password'])) { 1
require __DIR__ . '/_mysql-connect.php';
try {
$stmt = $pdo->prepare( 2
'SELECT * FROM user
WHERE username = ? AND password = ?'
)
$stmt->execute ([$_POST['username'], $_POST['password']]); 3
if ($stmt->rowCount() === 1) { 4
$user = $stmt->fetch(); 5
281
Kapitel 13 PHP und MySQL kombinieren
session_start();
$_SESSION['username'] = $user['username']; 6
header('Location: secret.php'); exit(); 7
}
echo 'Benutzername/Passwort ungültig.'; 8
} catch (PDOException $e) {
echo 'Datenbankfehler: '. $e->getMessage();
}
}
?>
<form method="POST"> 9
<input name="username" placeholder="Benutzername"/><br/>
<input type="password" name="password" placeholder="Passwort"/>
<button type="submit">Login</button>
</form>
282
Beispiel: Benutzer-Accounts 13.3
13.3.4 Login-Bereich
Der Inhalt der Seite secret.php ist nur für eingeloggte Benutzer zugänglich.
Das Skript leitet Zugriffe von nicht authentifizierten Benutzern zum Login auf
login.php weiter.
session_start();
if (!isset($_SESSION['username'])) { 1
header('Location: login.php'); exit();
}
if (isset($_GET['logout'])) { 2
unset($_SESSION['username']); 3
header('Location: login.php'); exit();
}
?>
<p> 4
Hallo <?= $_SESSION['username'] ?>,
Sie sind eingeloggt. <br/><img src="kitty.png"/>
<br/><a href="?logout">Logout</a> 5
</p>
1 Falls der Indikator für einen eingeloggten Benutzer das Feld username im
$_SESSION-Array nicht gesetzt ist, erfolgt eine Weiterleitung auf login.php.
2 Ein Logout wird durch Klick auf einen Link mit gesetztem URL-Parame-
ter logout signalisiert.
3 Beim Logout wird der Indikator für einen eingeloggten Benutzer, das
Feld username im $_SESSION-Array, gelöscht und der Benutzer auf login.
php zurückgeleitet.
4 Der exklusive Inhalt für authentifizierte Benutzer.
5 Logout-Link zum selben Skript secret.php mit gesetztem logout-Flag
als URL-Parameter (ein Wert ist nicht nötig).
Aufgabe 2
283
Kapitel 13 PHP und MySQL kombinieren
284
Sicherheitslücke: SQL-Injection 13.4
Wie erkennt PHP den Algorithmus, der zu einem früheren Zeitpunkt zur Ver-
schlüsselung verwendet wurde? PHP bettet diese Information praktischerwei-
se im Passwort-Hash ein und hat diese Information damit automatisch zur
Verfügung. Detaillierte Informationen finden Sie in der PHP-Dokumentation
zum Thema »Password Hashing«1.
1
https://www.php.net/manual/faq.passwords
285
Kapitel 13 PHP und MySQL kombinieren
Der SQL-Befehl für den Benutzer-Login aus Abschnitt 13.3.3 fragt die Daten-
bank, ob ein passender Benutzer mit entsprechendem Password in der user-
Tabelle existiert. Dies könnte auf den ersten Blick auch mit einer einfachen
Code-Variante funktionieren, in der die Benutzereingaben aus dem POST-
Formular (Benutzername und Passwort) direkt in das SQL eingebaut werden,
hier mit Hilfe der sprintf()-Funktion:
$sql = sprintf(
"SELECT * FROM user
WHERE username = '%s' AND password = '%s'",
$_POST['username'],
$_POST['password']
);
$stmt = $pdo->query($sql);
if ($stmt->rowCount() === 1) { // falls ein Benutzer gefunden
// Benutzer eingeloggt!
}
Dieser Code ist anfällig für eine SQL-Injection. Über die Formulareingaben
können auch Zeichen mit SQL-Sonderfunktion eingeschleust werden, z.B. das
einfache Anführungszeichen. In Kenntnis eines gültigen Benutzernamens,
z.B. jan99, kann ein Angreifer die Passwortsicherung aushebeln und den
Account übernehmen.
286
Sicherheitslücke: SQL-Injection 13.4
In Kenntnis eines Benutzernamens kann sich ein Angreifer ohne das passende
Passwort in jeden Account einloggen.
Sichtbare technische Fehlermeldungen können einem Angreifer beim
Versuch helfen, die passende Eingabe für eine SQL-Injection zu finden.
Eine produktive Anwendung muss Fehlermeldungen daher immer in
eine Log-Datei schreiben und nie direkt anzeigen.
Folgende Eingabe schleust sogar einen vollständigen SQL-Befehl ein und
löscht alle Daten aus der user-Tabelle:
287
Kapitel 13 PHP und MySQL kombinieren
13.6 Übungen
Übung 1
Erstellen Sie ein Skript list-users.php zur Auflistung der registrierten Benut-
zer des Beispiels aus Abschnitt 13.3 in einer HTML-Tabelle.
Übung 2
Verbessern Sie das Beispiel aus Abschnitt 13.3 durch Ersetzung des Klartext-
Passworts mit einem Passwort-Hash. Verschlüsseln Sie das Passwort bei der
Registrierung vor dem Speichern in der Datenbank mit password_hash().
Prüfen Sie das Passwort beim Login mit password_verify().
Übung 3
Ergänzen Sie das Beispiel aus Abschnitt 13.3 um die Speicherung des letz-
ten Login-Datums. Ergänzen Sie dazu eine DATETIME-Spalte last_login in der
user-Tabelle. Aktualisieren Sie das Datum an der Stelle eines erfolgreichen
Logins für den passenden Benutzer mit dem UPDATE SQL-Befehl.
288
Abschlussprojekt: Ein
Blog programmieren
Das letzte Kapitel vereint Gelerntes aus dem gesamten Buch zu einem größe-
ren Projekt, der Programmierung eines Blogs mit diesen Features:
Startseite mit Übersicht aller Blog-Artikel und Kategorie-Filter
Artikel-Detailansicht mit komplettem Artikelinhalt und:
Download des Artikels als PDF
Feedback-Formular mit Übermittlung per E-Mail
Login/Logout für Administratoren
Zusätzliche Möglichkeiten für eingeloggte Administratoren:
Erstellung neuer Artikel
Bearbeitung von Artikeln
Löschung von Artikeln
Das Projekt rundet das Buch mit Tipps und Tricks, nützlichen Techniken
und der Einbindung externer Bibliotheken für die PDF-Erstellung sowie zum
E-Mail-Versand ab. Zum Abschluss erhalten Sie einen Ausblick auf fortge-
schrittene Themen.
14.1 Installation
Der Quelltext des Blogs befindet sich in den Code-Downloads zu diesem Ka-
pitel (www.mitp.de/0395) im Unterverzeichnis blog/. Beim Start des Webser-
vers muss die Document-Root auf das Unterverzeichnis blog/public/ einge-
stellt sein. Haben Sie das Projektverzeichnis z.B. in Ihr Benutzerverzeichnis
(~) nach ~/blog verschoben, erfolgt der Start des Entwicklungs-Webservers
mit:
289
Kapitel 14 Abschlussprojekt: Ein Blog programmieren
> cd ~/blog
> php -S localhost:8000 -t public/
Starten Sie phpMyAdmin (Kapitel 12) zur Verwaltung der Datenbank parallel
auf einem anderen Port:
> cd ~/phpMyAdmin
> php -S localhost:8001
290
Verwendete Techniken 14.3
291
Kapitel 14 Abschlussprojekt: Ein Blog programmieren
Setzt man die Erzeugung des Objekts in Klammern, lassen sich beide Schritte
in eine Anweisung kombinieren:
echo (new DateTime('now'))->format('d.m.Y');
Liefert eine Methode ein Objekt zurück, können beliebig viele weitere Verket-
tungen entstehen:
echo (new DateTime('now'))
->modify('+1 month')
->format('d.m.Y');
Nach dem Einfügen eines neuen Artikels kann damit direkt die URL zur Wei-
terleitung auf die Artikelansicht gebildet werden.
header('Location: /article.php?id=.' . $id);
292
Verwendete Techniken 14.3
Alternativ zeigt das Feld REQUEST_METHOD (engl. für Anfrage-Methode) des su-
perglobalen $_SERVER-Arrays an, ob das Skript mit der POST-Methode aufge-
rufen und daher ein Formular abgesendet wurde:
<?php
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
// Formular wurde abgesendet..
} else {
// Formular wurde nicht abgesendet ...
}
?>
<form method="POST">...</form>
Der Wert des Formularfelds wird wie jedes andere Feld an den Server über-
mittelt, das Feld ist für Betrachter jedoch unsichtbar. Versteckte Felder ent-
halten bei Bedarf Zusatzinformation für die Verarbeitung, z.B. die ID eines
Artikels, den ein Administrator löschen möchte:
<form action="/article-delete.php" method="POST">
<input name="id" type="hidden" value="3"/>
<button type="submit">Löschen</button>
</form>
14.3.6 Composer
Bei vielen wiederkehrenden Programmieraufgaben können Sie auf fertige,
kostenlose Lösungen zurückgreifen, z.B. für die Erzeugung von PDF-Dateien
oder den Versand von E-Mails.
293
Kapitel 14 Abschlussprojekt: Ein Blog programmieren
1
https://getcomposer.org/Composer-Setup.exe
2
https://getcomposer.org/installer
294
Verwendete Techniken 14.3
Composer lädt das Paket (ggf. mit weiteren abhängigen Paketen) herunter
und installiert es in das Verzeichnis vendor/ (engl. für Anbieter). Ein Skript,
das die Klassen und Funktionen der installierten Pakete nutzen möchte, muss
zunächst die Datei vendor/autoload.php einbinden. Nach der Installation von
dompdf/dompdf kann z.B. eine Instanz der Klasse Dompdf\Dompdf erzeugt wer-
den, die ein PDF-Dokument repräsentiert:
require __DIR__ . '/vendor/autoload.php';
$pdf = new Dompdf\Dompdf();
Die Verwendung und Möglichkeiten der Pakete beschreiben die über Pa-
ckagist verlinkten Dokumentationen.
3
https://dompdf.github.io
4
https://github.com/symfony/mailer
5
https://getcomposer.org/doc
295
Kapitel 14 Abschlussprojekt: Ein Blog programmieren
Aufgabe 1
14.4.1 Verzeichnisstruktur
Abbildung 14.5 zeigt die Verzeichnisstruktur des Projekts und gibt Hinweise
auf den Zweck der Dateien bzw. Verzeichnisse.
296
So funktioniert das Blog 14.4
<?php
// Hier: PHP-Anweisungen je nach Anwendungsfall ...
$pageTitle = 'Titel der Seite';
require __DIR__.'/../_header.php'; // Kopfbereich
?>
Hier ist der Hauptbereich zwischen Kopf- und Fußbereich:
Enthält HTML und PHP je nach Anwendungsfall.
<?php
require __DIR__.'/../_footer.php'; // Fußbereich
14.4.3 Initialisierungsaufgaben
Jedes öffentliche Skript aus der Document Root bindet zunächst die allgemei-
ne Datei _initialize.php ein. Sie führt Aufgaben durch, die für jede Seite des
Blogs relevant sind, und »initialisiert« damit die Web-Anwendung. Dazu zählt
z.B. die Herstellung der Datenbankverbindung, der Start der Session oder die
Einbindung der Datei vendor/autoload.php, um Composer-Pakete nutzen zu
können. Dieser Abschnitt erläutert einige der Initialisierungsaufgaben.
297
Kapitel 14 Abschlussprojekt: Ein Blog programmieren
define('DATABASE_DSN', 'mysql:host=localhost;dbname=blog');
define('DATABASE_USER', 'root');
define('DATABASE_PASSWORD', 's3cr3t');
define(
'MAILER_DSN', // z.B. Versand via Google Gmails SMTP-Server
'smtp://mein.name@gmail.com:PASSWORD@smtp.gmail.com:587'
);
define('FEEDBACK_RECIPIENT', mein.name@example.com');
define('BLOG_CATEGORIES', [ // Verfügbare Themen-Kategorien
'php' => 'PHP',
'javascript' => 'JavaScript',
'mysql' => 'MySQL',
]);
298
So funktioniert das Blog 14.4
Nach der Definition des Exception-Handlers ist für eine saubere Fehlerbe-
handlung nicht überall ein try-catch-Block nötig, z.B. bei der Herstellung der
Datenbankverbindung:
$pdo = new PDO(DATABASE_DSN, ...);
Schlägt die Datenbankverbindung fehl und wirft eine Ausnahme, tritt der zen-
trale Exception-Handler in Aktion und bindet die eigene Fehlerseite ein.
Eigene Funktionen
Häufig benötigte Aufgaben sind in eigene Funktionen ausgelagert, z.B. zur
Formatierung eines Datums:
299
Kapitel 14 Abschlussprojekt: Ein Blog programmieren
Der Login-Status eines Benutzers ist in der Session gespeichert (siehe auch
Abschnitt 9.2.3):
function isLoggedIn(): bool {
return isset($_SESSION['user']);
}
300
Anwendungsbeispiele 14.5
14.5 Anwendungsbeispiele
Dieser Abschnitt beschreibt einige Anwendungsfälle des Blogs. Alle Fälle sind
ausführlich in den Quelltext-Dateien kommentiert.
Zwischen Kopf- und Fußbereich (_header.php bzw. _footer.php) mit dem al-
len Seiten gemeinsamen HTML-Gerüst erfolgt die Ausgabe des individuellen
HTML für die Startseite. Dort werden die Kategorie-Links und eine Kurz-
Vorschau je Artikel mit Links zur jeweiligen Detailansicht gebildet:
$pageTitle = 'meinBlog!';
require '../_header.php'; // HTML für Kopfbereich
?>
<p>Willkommen in meinem Blog.</p> ...
301
Kapitel 14 Abschlussprojekt: Ein Blog programmieren
<p>
<?php
foreach(BLOG_CATEGORIES as $id => $category) {
printf('<a href="?category=%s">%s</a> ', $id, $category);
}
?>
</p>
<?php foreach($articles as $article): ?>
<h2><?= htmlspecialchars($article['title']); ?></h2> ...
<p>
<?= htmlspecialchars(
substr($article['content'], 0, 150)) ?> ...
<a href="article.php?id=<?= $article['id'] ?>">mehr</a>
</p>
<?php endforeach ?>
<?php
require '../_footer.php'; // HTML für Fußbereich
Links zur Anzeige der Detailansicht eines Artikels mit dem Skript article.
php enthalten die Artikel-ID als URL-Parameter:
302
Anwendungsbeispiele 14.5
303
Kapitel 14 Abschlussprojekt: Ein Blog programmieren
Liegt ein Validierungsfehler für das Feld im Array $formErrors vor, wird
eine CSS-Klasse ergänzt, um das Feld mit Hilfe von Bootstrap visuell als
fehlerhaft zu markieren (roter Rahmen). Die Fehlermeldung wird unter
dem Feld ausgegeben.
Das Feld wird mit dem Wert der Variable $title vorbelegt; liegt ein Va-
lidierungsfehler vor, gehen dem Benutzer dadurch seine bisherigen Ein-
gaben nicht verloren. Bei Nutzung des Formulars zur Bearbeitung eines
Artikels kommt es dadurch auch zur Vorbelegung mit dem bisher gespei-
cherten Titel.
304
Anwendungsbeispiele 14.5
Aufgabe 2
305
Kapitel 14 Abschlussprojekt: Ein Blog programmieren
Falls der zur ID passende Artikel existiert, wird ein Objekt vom Typ Dompdf\
Dompdf erzeugt, das ein zunächst leeres PDF repräsentiert. Dompdf::loadHtml()
lädt den gewünschten Inhalt als HTML, Dompdf::render() konvertiert das
HTML in das PDF-Format. Schließlich bietet Dompdf::stream() das fertige
PDF dem Besucher unter dem angegebenen Dateinamen zum Download an.
Ist Ihnen der Backslash (\) im Klassennamen Dompdf\Dompdf aufge-
fallen, der in einem Bezeichner eigentlich nicht erlaubt ist? Er hat mit
dem Konzept der Namespaces (»Namensräume«) zu tun, siehe dazu
Abschnitt 14.6.1.
306
Anwendungsbeispiele 14.5
307
Kapitel 14 Abschlussprojekt: Ein Blog programmieren
Aufgabe 3
Der Grund ist plausibel: der Klassename DateTime wird bereits von der gleich-
namigen, nativen PHP-Klasse verwendet (Abschnitt 10.5.2).
Namespaces (»Namensräume«) sind ein Konzept, um Namenskonflikte bei
Klassen (und Funktionen) zu vermeiden. Ohne die Verwendung von Name-
spaces – wie in den Kapiteln zuvor – befinden sich alle Klassen im selben,
»globalen« Namensraum. Dies ist vergleichbar mit Dateien, die sich ein einzi-
ges Verzeichnis teilen müssen und jeder Dateiname nur einmal vorkommen
kann. Ähnlich wie die Einführung eines Verzeichnisbaums mit Unterver-
zeichnissen funktioniert das Konzept der Namensräume:
namespace Blog; // Wechsel in den Namespace "Blog"
class DateTime {} // Klasse liegt im Namespace "Blog"
Die Definition der Klasse DateTime befindet sich nun unterhalb des Name-
spaces Blog und wird mit Blog\DateTime referenziert, um sie von DateTime
aus dem globalen Namespace zu unterscheiden. Der Backslash fungiert wie
308
Ausblick: Was kommt als Nächstes? 14.6
Die Klasse Dompdf ist unterhalb des gleichnamigen Namespace Dompdf defi-
niert, der Backslash trennt Namespace und Klassenname.
Eine kompakte (englischsprachige) Video-Einführung in Namespaces gibt es
auf SymfonyCasts6.
Zur Prüfung von Zeichenketten auf komplexe Muster gibt es eine Art eigene
Sprache, die regulären Ausdrücke. Folgender Funktionsaufruf prüft z.B. mit
dem regulären Ausdruck ^[0-9]{5}$, ob die Variable $zip eine syntaktisch
gültige deutsche Postleitzahl enthält, d.h. genau fünf aufeinanderfolgende Zif-
fern zwischen 0 und 9:
if (preg_match('/^[0-9]{5}$/', $zip)) {
// Ja, $zip enthält syntaktisch korrekte Postleitzahl
}
309
Kapitel 14 Abschlussprojekt: Ein Blog programmieren
14.6.4 Frameworks
Das Blog-Projekt zeigt, dass Teilaufgaben wie eine praktische Verzeichnis-
struktur, eine Datenbankverbindung, die Definition von Konfigurationspara-
metern, ein Login, Techniken zur Formularvalidierung oder Weiterleitungen,
die Behandlung von Fehlern u.v.m. eigentlich unabhängig vom Projektinhalt
sind. Das heißt, nicht nur ein Blog benötigt diese Funktionalitäten, sondern
auch ein Online-Shop, ein Browser-Spiel, eine Nachrichten-Website usw.
Aus diesem Grund haben sich so genannte Frameworks (»Rahmenwerke«)
etabliert, die einen vorgefertigten Rahmen zur Verfügung stellen, innerhalb
dessen individuelle Web-Anwendungen mit erprobten Lösungen schnell und
sicher erstellt werden können. Populäre PHP-Frameworks sind etwa Sym-
fony (https://symfony.com), Laravel (https://laravel.com) oder Laminas
(https://getlaminas.org).
310
Übungen 14.7
14.7 Übungen
Übung 1
Untersuchen Sie im Blog-Projekt dieses Kapitels den Anwendungsfall zur
Bearbeitung eines Artikels im Skript article-edit.php. Wie funktioniert die
Logik?
Übung 2
Schreiben Sie ein Skript, das ein PDF mit beliebigem Inhalt im Landschafts-
bzw. Querformat (»landscape«) zum Download erstellt. Installieren Sie dazu
mit Composer das Paket dompdf/dompdf in einem leeren Verzeichnis und
konsultieren Sie die Paket-Dokumentation.
Übung 3
Senden Sie mit dem Symfony Mailer eine E-Mail mit HTML-Inhalt und ei-
nem zusätzlichen CC-Empfänger. Installieren Sie dazu mit Composer das
Paket symfony/mailer in einem leeren Verzeichnis und konsultieren Sie die
Paket-Dokumentation.
311
Stichwortverzeichnis
Stichwortverzeichnis
Symbole Benutzereingabe ....................................... 45
$_COOKIE .............................................. 197 Benutzerklassen ...................................... 191
$_FILES ................................................... 185 Benutzer-Registrierung ......................... 280
$_GET ...................................................... 153 Benutzersitzung
$_POST .................................................... 167 Siehe Session
$_SERVER ...................................... 142, 200 Bezeichner (Datenbank) ........................ 247
$_SESSION .............................................. 203 Bibliothek ................................................ 105
$this .......................................................... 217 Block
127.0.0.1 ................................................... 133 Siehe Anweisungsblock
200 OK ..................................................... 141 Blog ........................................................... 289
404 Not Found ........................................ 141 Boolean ...................................................... 57
Bootstrap ................................................. 292
A break ........................................................... 93
Aggregatfunktion (SQL) ............... 265, 268 Browser-Konsole .................................... 140
Alias (SQL) .............................................. 264 Bug .............................................................. 97
AND ......................................................... 262 C
Anführungszeichen
doppelte .............................................. 52 Camel Case ................................................ 47
einfache ............................................... 51 Casting
Anführungszeichen (SQL) .................... 261 Siehe Type Casting
Anweisung ................................................. 66 CLI
Anweisungsblock ...................................... 73 Siehe Kommandozeile
API ............................................................ 183 Client .................................................. 14, 131
Argument clientseitig .................................................. 20
Funktion ........................................... 106 Compiler .................................................... 26
Kommandozeile ................................. 29 Composer .......................................... 22, 293
Array .......................................................... 59 composer.json ......................................... 295
assoziatives ......................................... 61 composer.lock ......................................... 295
mehrdimensionales ........................... 62 continue ..................................................... 93
AS ............................................................. 264 Cookie ...................................................... 195
Ausdruck ................................................... 66 Ablaufdatum ..................................... 201
Ausgabe-Maskierung ............................. 164 lesen ................................................... 197
Ausnahmen ............................................. 224 löschen .............................................. 202
AUTO_INCREMENT ........................... 246 setzen ................................................. 196
Cookie-Banner ....................................... 210
B CREATE TABLE ..................................... 243
Backend ..................................................... 19 Cronjob ...................................................... 21
Bedingte Anweisung ................................ 74 Cross-Site-Scripting (XSS) .................... 163
Bedingte Wiederholung ........................... 91 CSS ............................................................. 16
Bedingungen ............................................. 81 CSV .......................................................... 193
Benutzer-Accounts verwalten ............... 278
313
Stichwortverzeichnis
314
Stichwortverzeichnis
315
Stichwortverzeichnis
316
Stichwortverzeichnis
317
Stichwortverzeichnis
W X
Wahrheitswert XAMPP .................................................... 309
Siehe Boolean XSS
Web-API ............................................ 20, 183 Siehe Cross-Site-Scripting
Webhoster ................................................ 146
Webhosting .............................................. 259 Z
Web Scraping .......................................... 182 Zählschleife ............................................... 88
Webseite Zeichenkette
dynamische ......................................... 14 Siehe String
statische ............................................... 14 Zeitstempel .............................................. 118
Webserver ......................... 14, 131, 133, 137 Zeitzone ................................................... 121
Webservice ................................................ 18 Zugriffsrechte .......................................... 190
Webspace ................................................. 146 Unix ................................................... 191
WHERE-Klausel ............................ 251, 260 Zuweisung ................................................. 44
while ........................................................... 91
Wildcard .................................................. 262
318
Philipp Hasper
C++
Schnelleinstieg
Programmieren lernen in
14 Tagen
Einfach und ohne Vorkenntnisse
Zahlreiche
Praxisbeispiele
und Übungen
Mit diesem Buch gelingt Ihnen der einfache Einstieg in die C++-Programmierung.
Alle Grundlagen werden in 14 Kapiteln anschaulich und leicht nachvollziehbar
anhand von Codebeispielen erläutert. Übungsaufgaben am Ende der Kapitel
helfen Ihnen, das neu gewonnene Wissen schnell praktisch anzuwenden und
zu vertiefen.
Der Autor führt Sie Schritt für Schritt in die Welt der Programmierung ein: von
den Grundlagen über Objektorientierung bis zur Entwicklung von Anwendungen
mit grafischer Benutzungsoberfläche. Dabei lernen Sie ebenfalls, was guten Pro-
grammierstil ausmacht und wie man Fehler in Programmtexten finden und von
vornherein vermeiden kann.
So sind Sie perfekt auf den Einsatz von C++ im professionellen Umfeld vorbe-
reitet.
PYTHON 3
Schnelleinstieg
Programmieren lernen in
14 Tagen
Einfach und ohne
Vorkenntnisse zum Profi
Zahlreiche
Praxisbeispiele
und Übungen
Mit diesem Buch gelingt Ihnen der Einstieg in die Python-Programmierung ohne
Mühe. Sie benötigen keinerlei Vorkenntnisse.
Alle Grundlagen werden anschaulich und einfach nachvollziehbar anhand von
Codebeispielen erklärt. Übungsaufgaben in unterschiedlichen Schwierigkeits-
stufen am Ende der Kapitel helfen Ihnen, das neu gewonnene Wissen praktisch
anzuwenden und zu vertiefen.
Der Autor führt Sie Schritt für Schritt in die Welt der Programmierung ein: von
den Grundlagen über Objektorientierung bis zur Entwicklung von Anwendungen
mit grafischer Benutzungsoberfläche. Dabei lernen Sie ebenfalls, was guten Pro-
grammierstil ausmacht und wie man Fehler in Programmtexten finden und von
vornherein vermeiden kann.
So gelingt es Ihnen in Kürze, Python effektiv in der Praxis einzusetzen.