This content was uploaded by our users and we assume good faith they have the permission to share this book. If you own the copyright to this book and it is wrongfully on our website, we offer a simple DMCA procedure to remove your content from our site. Start by pressing the button below!
... aktuelles Fachwissen rund um die Uhr – zum Probelesen, Downloaden oder auch auf Papier.
www.InformIT.de
PHP & MySQL Dynamik für Ihre Webseiten! GIESBERT DAMASCHKE
Ü leicht
Ü
klar
eBook Die nicht autorisierte Weitergabe dieses eBooks ist eine Verletzung des Urheberrechts!
Ü
sofort
Bibliografische Information Der Deutschen Bibliothek Die Deutsche Bibliothek verzeichnet diese Publikation in der Deutschen Nationalbibliografie; detaillierte bibliografische Daten sind im Internet über http://dnb.ddb.de abrufbar.
Die Informationen in diesem Produkt werden ohne Rücksicht auf einen eventuellen Patentschutz veröffentlicht. Warennamen werden ohne Gewährleistung der freien Verwendbarkeit benutzt. Bei der Zusammenstellung von Texten und Abbildungen wurde mit größter Sorgfalt vorgegangen. Trotzdem können Fehler nicht vollständig ausgeschlossen werden. Verlag, Herausgeber und Autoren können für fehlerhafte Angaben und deren Folgen weder eine juristische Verantwortung noch irgendeine Haftung übernehmen. Für Verbesserungsvorschläge und Hinweise auf Fehler sind Verlag und Herausgeber dankbar. Alle Rechte vorbehalten, auch die der fotomechanischen Wiedergabe und der Speicherung in elektronischen Medien. Die gewerbliche Nutzung der in diesem Produkt gezeigten Modelle und Arbeiten ist nicht zulässig. Fast alle Hardware- und Softwarebezeichnungen, die in diesem Buch erwähnt werden, sind gleichzeitig auch eingetragene Warenzeichen oder sollten als solche betrachtet werden. Umwelthinweis: Dieses Buch wurde auf chlorfrei gebleichtem Papier gedruckt.
Dynamische Webseiten mit PHP ................... 14 Datenbankbasiertes Webpublishing ...............15 Xampp!.......................................................... 16 Xampp installieren .........................................18 Der erste PHP-Test .........................................21 HTML und PHP .............................................23 Kommentare in PHP ......................................25 Textausgaben mit »echo«...............................26 Variablen & Konstanten ................................. 28 Der Einsatz von Variablen..............................31 Rechnen und Verknüpfen in PHP................... 34 Abkürzungen und Zuweisungen ....................38 Kleine Typenlehre .......................................... 39 Menschen, nicht Maschinen: Rasmus Lerdorf ..............................................41
2
Entscheidungen, Schleifen und Funktionen
42
Logische Vergleiche und Verknüpfungen .......44 Wenn ... dann ... andernfalls!.........................46 Auf Inhalt überprüfen .....................................49 Alternative Abfragen ......................................50 Datumsangaben in PHP .................................51 Programmschleifen ........................................55 Das kleine Einmaleins ....................................59 Funktionen.....................................................61 Variablentypen überprüfen ............................64 Menschen, nicht Maschinen: Brian Behlendorf ............................................65
5
3
Ein Besucherzähler und anderes
66
Drei Projekte für die Homepage.....................68 Grundlegende Dateioperationen mit PHP ......68 Den Besucherzähler als Grafik ausgeben .......72 Wiederholungen ausfiltern mit Cookies .........75 Ein Kennwortschutz für Webseiten................. 77 Eingaben überprüfen ......................................79 Externe Dateien einbinden .............................80 Ein Kontaktformular auf der Webseite ............83 Die Auswertung .............................................85 Die Ausgabe .................................................. 88 Menschen, nicht Maschinen: David Axmark, Allan Larsson und Michael »Monty« Widenius ...........................91
4
Daten strukturieren mit Arrays Ein Umfrageformular mit PHP ........................94 Array: Ein Name, viele Werte.........................95 Ein universales Formular ................................98 Die Auswahl als Drop-Down-Menü ...............99 Das Formular als Tabelle..............................101 Die Ergebnisdatei anlegen und testweise auslesen ........................................102 Assoziative Arrays: Namen statt Nummern...105 Die Umfrage auswerten ...............................107 Das Ergebnis ausgeben ................................110 Datumsangaben mit Arrays ..........................112 Ein intelligentes Menüsystem .......................114 Menschen, nicht Maschinen: Bruce Perens ..119
6
92
Inhaltsverzeichnis
5
Datenbanken mit MySQL und PHPMyAdmin
120
Warum eigentlich eine Datenbank? .............122 PHPMyAdmin ..............................................123 Kopfüber in die Datenwelt ...........................128 Mit PHP auf MySQL-Daten zugreifen...........133 Datensätze ändern .......................................137 Tabellenstruktur ändern ...............................141 Tabellen sichern, löschen und importieren ..145 Menschen, nicht Maschinen: Eric S. Raymond...........................................149
6
Eine Logdatei mit MySQL und PHP
150
Kurzer Rückblick und neue Aussichten ........152 Woher des Wegs, Webwanderer? ................153 Datentypen in MySQL .................................155 Datentypen für Zeichenketten ......................155 Numerische Datentypen ..............................157 Datums- und Zeittypen ................................159 Die Tabelle der Logdatei ..............................161 Daten via PHP in eine Tabelle schreiben .....162 Die Logdaten in die Logdatei schreiben .......164 Die Logdatei vollständig ausgeben ...............167 Die Einträge einer Tabelle zählen.................171 Die Logdatei bereichsweise ausgeben ..........175 TIMESTAMP-Einträge einfügen.....................177 TIMESTAMP-Einträge formatiert auslesen .....180 Das komplette Script ....................................182 Menschen, nicht Maschinen: Richard M. Stallman ....................................183
7
7
Eine Mottomaschine für die Homepage 184 Öfter mal was Neues: Die Mottomaschine ...186 Die Motto-Tabelle........................................186 Das Eingabeformular....................................187 Die Auswertung ...........................................189 Berechneter Zufall .......................................191 Ein Abstecher zu den Lottozahlen ................193 Die Motto-Auswahl und -Ausgabe ...............194 Das Bearbeitungsmodul ...............................196 Ausgewählte Mottos anzeigen......................200 Das ausgewählte Motto bearbeiten und speichern ..............................................201 Der Maschinenraum ....................................204 Einträge aus einer MySQL-Tabelle löschen ..208 Eine neue Funktion für die Mottomaschine ..208 Jede Menge Formulare .................................209 Das Auswertungsscript anpassen..................211 Die Ausgaberoutine anpassen ......................213 Zufallszugriffe mit MySQL ...........................216 Die Bildermaschine: Dateiverzeichnisse mit PHP lesen ..............................................218 Menschen, nicht Maschinen: Linus Torvalds..............................................221
8
Fauler Zauber und andere Fallgruben Fehler gibt es immer wieder ... .....................224 Fauler Zauber mit »Magic Quotes« ..............224 Magic Quotes ausgetrickst ...........................227 Sichere Variablenübernahme .......................228 Die fehlerbereinigte Mottomaschine ............231 Die Sollbruchstellen die() und exit() .............233 Datei- und Datenbankfehler abfangen..........234 Fehlermeldungen bei fehlgeschlagenem Lese- oder Schreibzugriff..............................238 Fehlermeldungen protokollieren ..................241 Die Protokolldatei auslesen und löschen......244 Typische Fehler............................................246 Menschen, nicht Maschinen: Kai Oswald Seidler und Kay Vogelgesang ....249
8
222
Inhaltsverzeichnis
9
Ein Gästebuch
250
Konzept eines Gästebuches .........................252 Eine Tabelle in Handarbeit...........................252 Das Grundgerüst ..........................................256 Die Vorschauroutine ....................................259 Inhalte und Formate .....................................262 Einen Beitrag speichern................................264 Gästebuch ausgeben ....................................266 Der Gästebuch-Prototyp ..............................268 Fehleingaben abfangen ................................269 Umbrüche einfügen .....................................272 Das Gästebuch komplett ..............................274 Menschen, nicht Maschinen: Larry Ewing ....277
10
Ein Weblog
278
Was ist ein »Weblog«? .................................280 Die Zielvorgabe ...........................................280 Das Grundgerüst ..........................................282 Die Tabellen ................................................286 Das Admin-Interface ....................................287 Noch einmal: Datums- und Zeitfunktionen ..291 Menüeinträge auslesen und anzeigen...........293 Das Blog anzeigen .......................................294 Zwischenstand .............................................298 Einen Kennwortschutz einfügen ...................298 Die Formatierung der Eingabe......................302 Schönheitsreparatur beim Menü...................303 Menschen, nicht Maschinen: Sie, ich, wir alle ...........................................304
Internetlexikon
305
Stichwortverzeichnis
311
9
Liebe Leserin, lieber Leser, warum interessiert man sich für PHP und MySQL und greift zu einem Buch zu diesem Thema? Aus Neugier, allgemeinem technischen Interesse oder weil man Programmiersprachen und Datenbanken als solche so ungemein spannend findet? Mag sein. Doch vor allem wohl deshalb, weil einem die immer gleichen Webseiten aus reinem HTML nicht mehr genügen. Weil man sich die Arbeit erleichtern will. Weil man es leid ist, unzählige Dokumente zu öffnen, zu bearbeiten und zu speichern, nur weil sich ein Eintrag geändert hat. Weil man seine Homepage flexibler und leistungsfähiger gestalten möchte. Weil man endlich die Vorteile dynamischer Websites nutzen möchte. Wenn Sie das wollen, dann sind Sie bei diesem Buch genau richtig. Es wird Sie Schritt für Schritt mit ausführlichen Erklärungen von den ersten zögerlichen Anfängen in PHP und MySQL bis zur Erstellung eines Weblogs begleiten und Sie mit den erstaunlichen Möglichkeiten dieses dynamischen Duos vertraut machen. Wenn Sie bislang nur mit HTML gearbeitet haben, dann halten Sie sich gut fest – mit PHP und MySQL revolutionieren Sie Ihre Homepage und stoßen in bislang völlig ungeahnte Bereiche vor. Dieses Buch setzt auf die motivierende Kraft des schnellen Erfolgserlebnisses, auf den Praxiskick, der einem dabei hilft, den Spaßfaktor einer nur scheinbar so trockenen Sache wie dem Programmieren zu entdecken. Die Funktionen von PHP und MySQL werden Ihnen nicht um ihrer selbst willen erklärt, sondern immer mit Blick auf ihren möglichen und nützlichen Einsatz in der Praxis. An zahlreichen praxisnahen Beispielen lernen Sie, wie Sie schon mit wenigen Code-Zeilen in PHP die erstaunlichsten Dinge realisieren können. Schließlich müssen Sie kein Informatikstudium absolviert haben, um PHP und MySQL gewinnbringend einzusetzen. Alles, was Sie tun müssen, ist: anfangen. Wenn Sie Anregungen, Kritik oder Fragen zu diesem Buch haben, mailen Sie diese bitte an [email protected]. P.S.: Die in diesem Buch vorgestellten Beispiele und Scripts finden Sie unter der Adresse http://www.damaschke.de/scripts/ zum Download.
11
Kapitel 1
Erste Schritte in PHP
Mit der serverbasierten Scriptsprache PHP und einer MySQLDatenbank sind dynamische Webseiten kein Problem. In diesem Kapitel bekommen Sie einen ersten Einblick in die erstaunlichen Möglichkeiten, die Ihnen mit PHP & MySQL offen stehen.
Ihr Erfolgsbarometer
Das lernen Sie neu: Dynamische Webseiten mit PHP
14
Xampp!
16
Xampp installieren
18
HTML und PHP
23
Textausgaben mit »echo«
26
Variablen & Konstanten
28
Rechnen und Verknüpfen in PHP
34
Kleine Typenlehre
39
13
Dynamische Webseiten mit PHP PHP ist eine serverbasierte Scriptsprache, die aus statischen HTML-Dateien dynamische, interaktive und flexible Webseiten macht. Mit PHP ist es möglich, Webseiten in Abhängigkeit von individuellen Vorgaben des Benutzers zu erzeugen. Man kann Formular-Eingaben verarbeiten, in einer MySQLDatenbank speichern, zu einem späteren Zeitpunkt wieder auslesen und erneut anzeigen. Script- vs. Programmiersprache
Bei einer Programmiersprache wird der Programmcode durch einen so genannten Compiler in Maschinencode umgesetzt und als direkt ausführbare Programmdatei gespeichert. Die Anweisungen eines Scripts werden dagegen bei jedem Aufruf erneut sequentiell abgearbeitet. Scripts sind normalerweise rechenintensiver und langsamer als Programme, was bei heutigen Computern nicht mehr so stark ins Gewicht fällt.
Eine traditionelle Webseite liegt als HTML-Code auf der Festplatte des Webservers vor. Fordert ein Besucher diese Seite an, so schickt der Webserver eine exakte Kopie der Datei an den Webbrowser des Besuchers, der die gesendeten Daten analysiert und schließlich die Webseite anzeigt. Bei PHP ist das prinzipiell anders. Hier ist eine Webseite kein statisches HTML-Dokument, sondern diese Seite wird erst in dem Moment erzeugt, in dem ein Besucher sie anfordert. Auf dem Server steht gewissermaßen nur die Rohfassung oder Konstruktionsanweisung der angeforderten Seite parat. Diese Rohfassung besteht aus mehr oder weniger viel normalem HTML-Code, in den PHP-Anweisungen eingebettet sind. Diese Anweisungen können sehr einfacher Natur sein – zum Beispiel: »Füge am Kopf jeder angezeigten Seite das aktuelle Datum ein« –, aber auch beliebig komplex werden. Der Besucher einer Webseite merkt davon jedoch nichts. Er fordert unter einer bestimmten Webadresse ein bestimmtes Dokument von einem Webserver an. Der Webserver führt die PHP-Anweisungen in diesem Dokument aus und setzt das gewünschte HTML-Dokument zusammen, das dem Besucher schließlich übermittelt wird. Der Besucher bekommt die PHP-Anweisungen also nicht zu Gesicht, sondern nur das fertige Ergebnis und wird sich allenfalls wundern, warum eine Webseite, die er immer mit der gleichen Adresse aufruft, immer wieder anders aussieht. Selbst ein Blick in den Quelltext der
14
Datenbankbasiertes Webpublishing
Webseite verrät – anders als bei clientbasierten Scriptsprachen wie etwa Javascript, die erst im Browser ausgeführt werden – nichts über ihre Entstehung. Lediglich die Dateiendung, etwa »index.php« statt »index.html«, zeigt, dass es sich hier um eine dynamisch erzeugte Webseite und nicht um eine statische HTML-Datei handelt.
Datenbankbasiertes Webpublishing Durch den Einsatz von PHP wird also eine HTML-Seite flexibel, doch erst in Kombination mit einer MySQL-Datenbank entfaltet sich das volle Potenzial dynamischer Websites in Form eines datenbankbasierten Webpublishings. MySQL
SQL ist die Abkürzung für Standard Query Language. Ein SQL-Server ist ein Datenbankserver, der mittels SQL-Kommandos gesteuert wird. MySQL ist eine sehr leistungsfähige Open-Source-Variante von SQL.
Das klingt jetzt vielleicht etwas rätselhaft, daher dazu rasch ein einfaches Beispiel. Sie möchten, dass beim Aufruf der Startseite »index.php« Ihrer Website ein wechselndes Motto zur Begrüßung angezeigt wird. Beim klassischen HTML-Design würden Sie dieses Motto direkt in den HTML-Code der Startseite integrieren. Möchten Sie das Motto ändern, müssen Sie die Datei index.php im Editor öffnen, das Motto austauschen und die geänderte Datei schließlich wieder auf den Webserver laden. Beim Einsatz von PHP und MySQL gehen Sie dagegen grundlegend anders vor. Die verschiedenen Mottos, die beim Aufruf von index.php angezeigt werden sollen, liegen als Einträge in einer MySQL-Tabelle vor, die zum Beispiel »meine_mottos« heißt. Der Code von index.php enthält dagegen keine direkt anzuzeigenden Texte mehr, sondern nur noch einige HTML-Codes zur Formatierung der Seite und verschiedene PHP-Anweisungen. Wird die Seite aufgerufen, so wird das nächste Motto aus »meine_mottos« ausgelesen, in die Seite eingefügt und die so erzeugte HTML-Datei an den Browser geschickt. Möchten Sie ein Motto hinzufügen, löschen oder korrigieren, so verändern Sie die Daten in der MySQL-Tabelle – die Datei index.php bleibt davon völlig unberührt. Idealerweise enthält die Datei nur die Formatierungen der angezeigten Seite, während die Inhalte aus einer Datenbank ausgelesen werden, die wiederum von Ihnen jederzeit problemlos verändert werden kann.
15
Denkt man dieses Beispiel etwas weiter, gelangt man schnell zu Content Management Systemen, bei denen der Webautor sich nicht mehr mit der Formatierung und HTML-Umsetzung seiner Texte herumschlägt, sondern diese Texte über ein Formular in eine Datenbank eingibt und die webtaugliche Aufbereitung PHP und MySQL überlässt.
Xampp! PHP-Code schreiben ist nicht schwer, ihn auszuführen dagegen sehr: Wie bei HTML benötigen Sie zum Schreiben von PHP-Code keine besonderen Werkzeuge, sondern nur einen einfachen Texteditor, zur Not reicht selbst Notepad, das zum Lieferumfang von Windows gehört. Doch anders als bei HTML können Sie Ihre PHP-Scripte nicht dadurch testen, dass Sie sie lokal in einem Browser öffnen. Schließlich muss PHP-Code von einem PHP-tauglichen Webserver abgerufen werden, damit er ausgeführt wird.
Mit Xampp für Windows können Sie auf Ihrem Windows-Computer einen vollwertigen Webserver mit PHP, MySQL und mehr installieren.
16
Xampp!
Inzwischen gehören PHP und MySQL glücklicherweise zum Standardangebot bei praktisch allen Webhostern, so dass Sie keine Schwierigkeit haben werden, hier einen passenden Anbieter zu finden. Problematisch aber bleibt, dass Sie zum Testen Ihrer Scripts jedes PHPDokument zuerst in ein Testverzeichnis auf dem Webserver hochladen und anschließend mit Ihrem Browser abrufen müssen. Dazu müssen Sie nicht nur permanent online sein (was, falls Sie keine Flatrate oder Standleitung haben, ziemlich ins Geld geht), das kostet auch Zeit und Nerven. Das muss doch einfacher gehen. Die benötigte Serversoftware stammt aus der Open-Source-Szene und kann kostenlos aus dem Internet geladen werden. Nun müssen Sie also nur noch einen lokalen Apache-Webserver mit allen benötigten Modulen installieren und konfigurieren, einen MySQL-Server aufsetzen, und schon – das ist Ihnen zu kompliziert? Ach, wissen Sie was? Mir auch. Apache-Webserver
Wer bei dem Namen des wohl wichtigsten Webservers im Internet an Karl May, Winnetou und edle Indianer denkt, liegt gar nicht mal so falsch. Der Name des Webservers, so sein Entwickler Brian Behlendorf in einem Interview aus dem Jahr 2000, verdankt sich dem Wunsch, ein fantastisches, abenteuerliches Bild zu beschwören. Erst nach der Namensfindung fiel ihm auf, dass »Apache« auch ein hübsches Wortspiel ist: »a patchy Server«, ein geflickter, gepatchter Server. Schließlich bestehe Serversoftware aus einm Haufen Software-Flicken und -Modulen und wird ständig weiterentwickelt und gepatcht.
Glücklicherweise müssen wir uns auch nicht in die ganz und gar nicht trivialen Untiefen der Webserverinstallation und -konfiguration einarbeiten, um mit PHP und MySQL spannende Dinge anstellen zu können. Denn da gibt es lobenswerterweise die Apachefriends, die uns sehr viel Arbeit abgenommen haben und eine lokale Serverinstallation auf Mausklick bereit halten. Kostenlos, versteht sich. Die Lösung des Problems lautet Xampp für Windows. Dabei ist »ampp« die Abkürzung für Apache, MySQL, PHP und Perl, das X steht als Platzhalter für verschiedene Betriebssysteme. Xampp für Windows wird mitunter auch als Wampp bezeichnet. Aber das klingt nicht so hübsch, also lassen wir das. Xampp für Windows läuft unter allen Windows-Installationen ab Version Windows 98 und bietet ein fix und fertig konfiguriertes und sofort einsatzbe-
17
reites Programmpaket, in dem sich alles findet, was Sie zum Betrieb eines Webservers benötigen. Neben den Bestandteilen, die bereits im Namen genannt werden, sind dies zum Beispiel auch FTP-Server, Mailserver und verschiedene Hilfsprogramme wie das unverzichtbare Tool PHPMyAdmin, das im Rahmen dieses Buches noch eine große Rolle spielen wird.
Xampp installieren Die jeweils aktuelle Version von Xampp für Windows finden Sie unter www.apachefriends.org. Alle Scripts in diesem Buch wurden mit der zum Zeitpunkt der Manuskripterstellung aktuellen Version 1.4.5 von Xampp getestet. Die Installation und Inbetriebnahme von Xampp wird auf den Webseiten der Apachefriends ausführlich beschrieben und im Folgenden exemplarisch vorgestellt.
Wenn Sie die EXE-Datei der Installationsdatei laden, beschränkt sich die Xampp-Installation auf wenige Mausklicks.
1 Laden Sie die gewünschte Installationsdatei von Xampp für Windows von den
Webseiten der ApacheFriends und entpacken Sie diese Datei im Hauptverzeichnis Ihrer Festplatte, d. h. normalerweise auf Laufwerk C:\. Am einfachsten geht dies, indem Sie die EXE-Version der Installationsdatei laden und starten. Anschließend finden Sie das Verzeichnis »xampp« im Hauptverzeichnis, also etwa C:\xampp\.
2
Wechseln Sie nun in das neu angelegte Xampp-Verzeichnis auf Laufwerk C:\ und starten Sie die Datei »xampp_start.exe«. Es öffnet sich ein DOS-Fenster, das Sie über den Start von Apache und MySQL informiert. Dieses Fenster dürfen Sie nicht schließen, aber Sie können es natürlich minimieren.
18
Xampp installieren
Ein Klick und schon läuft auf Ihrem lokalen Windows-Computer ein Web- und ein MySQL-Server.
3 Rufen Sie nun in Ihrem Webbrowser die Adresse http://localhost/ auf. Wenn
alles geklappt hat – und es gibt eigentlich keinen Grund, warum es das nicht getan haben sollte –, sehen Sie nun die Xampp-Begrüßungsseite.
Na, wer sagt's denn: Xampp stellt Ihnen alles zur Verfügung, was Sie zur PHP- und MySQL-Entwicklung benötigen.
19
4
Um die Arbeit mit Xampp zu beenden und alle laufenden Server wieder zu stoppen, rufen Sie im Xampp-Verzeichnis einfach die Datei »xampp_stop.exe« auf.
Und tschüss – so einfach, wie Sie die verschiedenen Server starten, so einfach beenden Sie sie auch wieder.
WICHTIGE DURCHSAGE!
Sobald Xampp gestartet ist, läuft auf Ihrem Computer unter anderem ein vollwertiger Webserver und ein Datenbankserver. Sollten Sie zu diesem Zeitpunkt online sein, sind diese Server – und damit Ihr Computer – via Internet zu erreichen und angreifbar. Die Absicherung der verschiedenen Serverdienste auf Ihrem Computer ist zwar möglich, aber nicht ganz trivial und ihre Beschreibung würde den Rahmen dieses Buches sprengen. Am einfachsten und sichersten ist es, wenn Sie während der Zeit, in der Sie Xampp laufen lassen, einfach offline bleiben.
20
Der erste PHP-Test
Sobald Sie via Xampp den Apache-Webserver gestartet haben, ist Ihr Computer im Internet erreichbar. Falls Sie während der Arbeit mit Xampp online sind, sollten Sie den Zugriff von außen auf Ihren Computer möglichst unterbinden. Allerdings ist nicht jede Personal Firewall (hier: Sygate) in der Lage, bei Zugriffen auf den Server zwischen denen, die von der lokalen Maschine erfolgen (und also harmlos sind) und denen, die von außen kommen (und die ein potentielles Sicherheitsrisiko darstellen) zu unterscheiden.
Der erste PHP-Test Sobald Sie Xampp installiert und probeweise gestartet haben, müssen Sie nur noch das Webverzeichnis für Ihre Tests vorbereiten und schon steht Ihrer PHP- und MySQL-Entwicklung nichts mehr im Weg.
1
Im Xampp-Verzeichnis finden Sie einen Ordner namens »htdocs«. Auf dieses Verzeichnis greift der Apache-Webserver standardmäßig als Webverzeichnis zu. Heißt Ihr Xampp-Verzeichnis »C:\xampp« und rufen Sie im Browser die Adresse http://localhost/index.php auf, dann schickt Apache die Datei C:\xampp\htdocs\ index.php an den Browser. Nach der Installation von Xampp finden sich im Webverzeichnis zahlreiche Beispiele, Demos und Dokumente.
2
Benennen Sie das Verzeichnis »htdocs« um, etwa in »htdocs_xampp«, und legen Sie ein neues Verzeichnis »htdocs« an. Dieses neue, leere Verzeichnis entspricht einem neuen und leeWren Verzeichnis bei einem Webhoster.
Sichern Sie das originale Xampp-Webverzeichnis, indem Sie es einfach umbenennen und legen Sie ein neues htdocs-Verzeichnis für Ihre Tests an.
21
Wenn Sie jetzt Xampp starten und Ihren lokalen Webserver mit http://localhost/ aufrufen, erhalten Sie eine Fehlermeldung. Kein Wunder, das Webverzeichnis ist ja leer und das Verzeichnis, auf das Apache in der XamppKonfiguration standardmäßig zugreifen will, existiert nicht mehr. Aber das ändern wir jetzt und setzen dabei sofort eine Prise PHP ein.
3
Öffnen Sie Ihren Editor, notieren Sie in einem neuen, leeren Textdokument das folgende Kommando
4
und speichern Sie die Datei im neu angelegten »htdocs«-Verzeichnis auf Ihrer Festplatte unter dem Namen »index.php«.
Kleine Ursache, große Wirkung: Die unscheinbare Code-Zeile führt zu einer kompletten Konfigurations-Anzeige der installierten PHP-Version.
5 Starten Sie Xampp und rufen Sie in Ihrem Browser die Adresse http://localhost/
index.php auf. Sie sehen nun nicht den kurzen Textschnipsel, den Sie gespeichert haben, sondern eine umfangreiche Tabelle mit Informationen über die laufende PHPInstallation. Wenn Sie einen Blick in den Quelltext der Seite werfen, sehen Sie, dass der unscheinbare Einzeiler offensichtlich eine vollständige HTML-Seite erzeugt hat.
22
HTML und PHP
Was ist da passiert? Nun, ganz einfach: Wir haben vom Webserver eine Datei mit der Endung ».php« angefordert. Anhand dieser Endung erkennt der Server, dass es sich hier nicht um eine normale HTML-Datei handelt, die er unbesehen durchreichen kann, sondern dass sich in der Datei ein Script befindet, das er ausführen muss, bevor die Datei versandfertig ist. Der Webserver öffnet die Datei und stößt sofort auf eine spitze Klammer, gefolgt von einem Fragezeichen: , womit ihm das Ende der PHP-Anweisung signalisiert wird. Alles, was jetzt folgt, ist wieder normaler HTML-Code. Da aber nichts mehr folgt, wird die Datei abgeschlossen und an den Browser geschickt, der die Datei index.php angefordert hat. Der Browser bekommt eine aus seiner Perspektive völlig normale HTML-Seite und stellt sie wie gewohnt dar.
HTML und PHP Das kleine Beispiel zeigt zwar recht eindrucksvoll, wie aus einer unscheinbaren PHP-Anweisung eine ausgewachsene Webseite wird, ist aber, zugegeben, auch ein wenig untypisch. Zum einen kommt es in der Praxis so gut wie nie vor, dass Sie bei Ihren Scripts auf eigenes HTML völlig verzichten, zum anderen werden Sie eigentlich immer mehr als nur eine Zeile PHP ausführen wollen. Eines allerdings zeigt das Beispiel sehr schön: PHP-Code kann nicht nur an jeder beliebigen Stelle in einem HTML-Dokument eingefügt werden, er benötigt noch nicht einmal HTML. Man muss nur darauf achten, dass der PHP-Code korrektes HTML erzeugt, das in einem Webbrowser dargestellt werden kann. Der PHP-Code selbst besteht aus beliebig vielen Anweisungen, die durch ein Semikolon voneinander getrennt werden (das Semikolon darf fehlen, wenn es sich um die letzte Anweisung eines Scripts handelt). Damit der Interpreter den Code eindeutig von der HTML-Umgebung, in die er einge-
23
bettet ist, trennen kann, wird er normalerweise durch ein abgeschlossen. Die Einleitung können Sie auch als arbeiten können. Ein typisches Grundgerüst einer HTML-Datei mit PHP-Code sieht also beispielsweise so aus: Hier steht irgendwas in HTML Hier ist nochmal HTML
Der Vollständigkeit halber sei angemerkt, dass PHP-Scripte innerhalb einer HTML-Datei nicht nur einmal und an einer Stelle, sondern beliebig oft an beliebigen Stellen eingefügt werden können. Die verschiedenen Scripte werden dabei als zusammengehörig aufgefasst. So können Sie in dem einen Script auf Informationen und Daten zugreifen, die Sie in einem anderen Script innerhalb der Datei benutzen. Frei platzierbar
Im Gegensatz zu anderen Scriptsprachen wie etwa Javascript können PHP-Anweisungen an beliebigen Stellen auftauchen – auch außerhalb des HTML-Bereichs. So ist es zum Beispiel möglich, die HEADERDaten einer HTML-Datei über ein PHP-Script zu gestalten, bevor die Datei angezeigt wird.
Wir werden in späteren Beispielen verschiedene praktische Anwendungen kennen lernen. Der typische Einsatz dieser Eigenheit besteht etwa darin, dass Sie in einem Script bestimmte Berechnungen durchführen, die Ergebnisse dieser Berechnungen ausgeben und anschließend weitere Berechnungen erstellen. Die Ergebnisausgabe erfolgt in solchen Fällen typischerweise der Einfachheit halber in HTML, anschließend wechselt man wieder zum Script.
24
Kommentare in PHP
Ausgabe und Formatierung der Ergebnisse in HTML
Kommentare in PHP Wenn Sie ein PHP-Script schreiben, dann wissen Sie natürlich, was die einzelnen Anweisungen bewirken sollen. Das wissen Sie vermutlich auch noch am nächsten Tag. Oder in der nächsten Woche. Aber wissen Sie das auch noch im nächsten Monat oder gar im nächsten Jahr? Aus diesem Grund sollten Sie sich angewöhnen, Ihren Code zu kommentieren. Das mag zur Zeit noch reichlich übertrieben anmuten, schließlich sind die einzelnen Beispiele bislang praktisch selbst erklärend, doch Sie wissen ja – früh übt sich ...
1
Wenn Sie nur kurze Kommentare und Hinweise einfügen, dann setzen Sie einen doppelten Schrägstrich // vor den Kommentar, PHP ignoriert (fast) alles, was nach dieser Markierung kommt bis zum Zeilenende. Das könnte etwa so aussehen: "; echo "Dies ist noch eine PHP-Zeile. "; // Das war's schon ?>
Wie gesagt: Der Interpreter ignoriert die Kommentarzeichen und – fast – alles, was ihnen folgt. Einzige Ausnahme: das abschließende PHP-Tag ?>, das immer, ganz gleich, wo es auftaucht, das Ende des aktuellen PHP-Blocks bezeichnet.
2
Mehrzeilige Erläuterungen werden mit einem /* eingeleitet und mit einem */ beendet. Der Server wird den gesamten Kommentarblock bei der Abarbeitung des Scripts ignorieren:
25
Textausgaben mit »echo« Wie oben schon erwähnt, geben Sie mit echo beliebigen Text aus, den der Webserver genau an der Stelle im HTML-Dokument platziert, an der die echo-Anweisung steht. Die generelle Syntax der echo-Anweisung lautet dabei echo "text";, wobei der Text in Anführungszeichen an Stelle der echo-Anweisung in das HTML-Dokument eingetragen wird. Geben Sie also innerhalb des body-Abschnitts einer HTML-Datei den PHP-Code-Schnipsel Test"; ?> ein, so führt das zum gleichen Ergebnis, als würden Sie direkt Test notieren. Nun werden Sie vielleicht denken, dass das ein etwas umständlicher Weg ist, um Text in einem Browser auszugeben – das kann man mit HTML schließlich auch einfacher haben. Damit haben Sie natürlich Recht – und auch wieder nicht, wie ein einfaches Beispiel zeigt. Wenn Sie auf einer Webseite Text ausgeben, müssen Sie die Sonderzeichen kodieren, also Buchstaben wie ä, ö oder ü durch die so genannten HTMLEntities ä, ö und ü ersetzen. Bei einer Textausgabe mit echo können Sie diese Umsetzung der Sonderzeichen in die korrekten Entities einfach PHP überlassen, dafür steht die Funktion htmlentities() zur Verfügung.
1
Wir kümmern uns später darum, was genau eigentlich Funktionen sind und wie man mit ihnen umgeht, in diesem Kapitel geht es nur darum, ein paar Ergebnisse zu sehen. Geben Sie diesen (oder vergleichbaren) Code im -Teil Ihrer PHP-Testdatei ein:
htmlentities("München"); " "; htmlentities("Fröhliche Grüße"); " "; htmlentities("Jürgen");
?>
2
Wenn Sie diese Datei im Browser aufrufen, werden die Texte »München«, »Fröhliche Grüße« und »Jürgen« untereinander dargestellt, was noch nicht weiter bemerkenswert ist. Werfen Sie jedoch einen Blick in den Quelltext, werden Sie feststellen, dass die Umlaute korrekt kodiert wurden, ohne dass Sie sich darum kümmern mussten.
3
Sollen mehrere Texte mit echo ausgegeben werden, kann man sie einfach mit einem Komma getrennt nacheinander notieren. So lassen sich etwa die fünf Anweisungen zu einer einzigen zusammenziehen:
So weit, so gut. Problematisch wird es jedoch, wenn Sie ein Anführungszeichen ausgeben möchten – denn das ist für echo ja das Signal für den Anfang bzw. das Ende eines auszugebenden Textes. Wenn Sie etwa die Anweisung
ausführen lassen möchten, wird PHP bei der Interpretation dieser Anweisung ins Stolpern geraten.
1
Zuerst wird der Teil echo "Dies ist ein " als abgeschlossene Anweisung zur Textausgabe interpretiert. Das sich anschließende Zitat"-Test" ist für PHP der Beginn einer neuen Anweisung – die in diesem Fall aber für das System völlig unverständlich ist, weshalb die Analyse des Scripts an dieser Stelle abgebrochen und eine Fehlermeldung ausgegeben wird.
2 Um Anführungszeichen (und auch alle anderen kritischen Zeichen) mit einer
echo-Anweisung ausgeben zu können, muss PHP signalisiert werden, dass dieses Zeichen in diesem besondern Fall nicht das Ende des auszugebenden Textes markiert, sondern im Gegenteil noch dazugehört.
3
Hierzu dient der Backslash, also der Schrägstrich von links oben nach rechts unten: \. Das direkt nach dem Backslash folgende Zeichen wird von PHP als einfacher Text und nicht als Steuerzeichen oder Kommando betrachtet. Der Vollständigkeit halber sei noch die eine Ausnahme erwähnt, bei der es genau anders herum ist. Bei der Zeichenkombination \n wird aus dem Buchstaben »n« ein Zeilenumbruch im Quelltext (was wir aber getrost ignorieren können).
Fluchthelfer
Da man mit dem Backslash gewissermaßen den strengen Regeln von PHP für einen kurzen Moment entkommt, nennt man das Zeichen auch »Escape-«, also »Flucht-Zeichen«, mit dem man die Sonderzeichen auf gut Denglisch »escapet« oder »maskiert«. Da durch den Backslash ein Steuerzeichen zu einem normalen Schriftzeichen wird, findet man gelegentlich auch die Formulierung, die Steuerzeichen würden »entwertet«.
27
4
Um das obige Beispiel also auszugeben und eine Fehlermeldung zu vermeiden, muss man die Anweisung als
5 formulieren. Wenn Sie nun noch htmlentities() einsetzen –
6
– werden die Anführungszeichen auch noch korrekt in " aufgelöst und alles ist in schönster HTML-Ordnung.
Dank Escape-Zeichen und htmlentities() wird der auszugebende Text in korrekten HTML-Code umgesetzt.
Variablen & Konstanten Nun gut, werden Sie jetzt vielleicht einwenden, das ist ja alles ganz nett, aber immer noch nicht sonderlich aufregend. Und überhaupt – wo bleibt eigentlich die versprochene Dynamik? Gemach, gemach, wir stehen ja noch ganz am Anfang. Bislang haben wir es nur mit festen Inhalten zu tun gehabt. Zwar hat PHP mehr oder weniger stark in die Anzeige eingegriffen, aber wirklich flexibler oder gar dynamischer als normales HTML ist das noch nicht. Doch durch den Einsatz von Variablen wird alles anders.
28
Variablen & Konstanten
Variablen sind symbolische Bezeichner für Speicherbereiche, die vom Programmierer mit beliebigen Werten gefüllt werden und die im Programmablauf ihren Wert verändern können. Um die konkrete Verwaltung des Arbeitsspeichers kümmert sich der Computer, wir deklarieren nur einen symbolischen Bezeichner als Variable und weisen der Variable einen Wert zu. Wie eine Variable benannt wird, bleibt dem Programmierer überlassen, man muss nur daran denken, dem Namen ein führendes Dollarzeichen zu geben, an dem PHP erkennt, dass es sich hier um eine Variable handelt. Bei der Namenswahl setzt Ihnen PHP kaum Grenzen, Sie können Buchstaben, Ziffern und den Unterstrich _ benutzen. Nicht erlaubt sind Anführungsund andere Steuerzeichen, Leerzeichen und Ziffern am Anfang des Variablennamens. Tabu sind natürlich auch die Wörter und Begriffe, mit denen PHP selbst arbeitet. Zwar könnten Sie eine Variable namens $echo benutzen, aber das ist keine gute Idee, führt dergleichen doch sehr schnell zu Tippfehlern, missverständlichem Code und ähnlich unerfreulichen Dingen. Außerdem unterscheidet PHP zwischen Groß- und Kleinschreibung.
•
Gültige Variablennamen sind zum Beispiel $ergebnis, $Ergebnis und $erGEBnis. Das ist für unser Ohr zwar drei Mal der gleiche Name, für PHP sind es aber drei völlig verschiedene Werte (Tippfehler bei Variablen sind eine der häufigsten Fehlerquellen in PHP-Scripts).
•
Ungültige Variablennamen sind dagegen $12_Uhr_Mittags (Ziffer am Anfang des Namens), $High Noon (Leerzeichen im Namen) oder $HighNoon (das Minus-Zeichen ist als Sonderzeichen in einem Variablennamen nicht erlaubt). Namensgebung
Auch wenn Umlaute in Variablennamen erlaubt sind, sollten Sie darauf ebenso verzichten wie auf andere Sonderzeichen. Stellen Sie sich vor, Sie müssten Ihren PHP-Code eines Tages mit einer amerikanischen Tastatur korrigieren, auf der es die deutschen Sonderzeichen nicht gibt. Schon deshalb ist es eine gute Idee, wann immer möglich beim kleinsten gemeinsamen Nenner aller Computersysteme, dem Standard-ASCII-Code, zu bleiben. Um Verwirrungen und Fehlerquellen in umfangreicheren Scripten zu vermeiden, sollten Sie sich auf Buchstaben und Ziffern beschränken und versuchen, im Laufe der Zeit ein festes Schema zur Benennung von Variablen zu entwickeln.
29
Bevor Sie mit einer Variablen arbeiten können, müssen Sie diese im Programm bekannt machen, bzw. Sie müssen sie »deklarieren«. Das ist in manchen Programmiersprachen eine recht aufwändige Sache, in PHP ist das glücklicherweise sehr einfach. Sie deklarieren eine Variable dadurch, dass Sie ihr einen Wert zuweisen. Das geschieht durch eine simple Gleichung: $Name = Wert:
Jede Wertzuweisung ist eine abgeschlossene, gültige PHP-Anweisung und muss folglich von den anderen durch ein Semikolon getrennt werden. Wie Sie sehen, kann eine Variable unterschiedliche Inhalte haben: Die Variable $Sinn_des_Lebens ist eine ganze Zahl; $Benutzer_Name ist normaler Text, oder, wie das im Programmierjargon heißt, eine Zeichenkette bzw. ein »String« und bei $Die_Zahl_Pi handelt es sich um eine Fließkommazahl. Hinweis
Bei Fließkommazahlen wird ein Punkt an Stelle eines Kommas gesetzt, also 3.14 statt 3,14.
Die Wertzuweisung an eine Variable kann an beliebiger Stelle in Ihrem PHP-Script erfolgen. Dort, wo Sie eine Variable benötigen, führen Sie diese einfach durch eine Wertzuweisung ein, um den Rest kümmert sich PHP. Neben den Variablen gibt es in PHP natürlich auch noch Konstanten, die in der Praxis allerdings nur eine eher untergeordnete Rolle spielen. Wenn man sie benötigt, ist es gut, dass sie zur Verfügung stehen – aber man benötigt sie sehr selten. Konstanten sind, wie die Variablen, symbolische Namen für Speicherzellen, in denen Sie beliebige Werte ablegen können. Doch anders als bei Variablen können Sie diesen Wert nach der Initialisierung der Konstante im Programmablauf nicht mehr verändern. Konstanten werden auch nicht über eine einfache Wertzuweisung definiert, sondern über die Funktion define(Name, Wert). Für Name tragen Sie den Namen der zu definierenden Konstanten ein, für Wert den Wert, den Sie ihr geben möchten: define(PI, 3.14159265);
30
Der Einsatz von Variablen
Anders als Variablen besitzen Konstanten kein führendes Dollarzeichen. Damit man sie besser vom übrigen Code unterscheiden kann, hat es sich eingebürgert, sie durchgehend groß zu schreiben, also BENUTZER statt Benutzer oder benutzer. Da Konstanten kein eindeutiges Erkennungszeichen besitzen, kann man sie auch, anders als Variablen, nicht so ohne weiteres mit anderem Text mischen und über echo ausgeben. Die Variable $name kann zum Beispiel mit
ausgegeben werden, bei der Konstanten BENUTZER funktioniert das nicht, da PHP sie bei
nicht als Konstante erkennt, sondern als auszugebenden Text interpretiert. Hier muss man zum Beispiel zu zwei echo-Anweisungen greifen: "; ?>
Wenn Sie, so wie in diesem Beispiel, mit echo-Anweisungen mehrere Zeichenketten oder Werte nacheinander ausgeben, dann können Sie daraus auch eine echo-Anweisung machen, der Sie die auszugebenden Werte mit einem Komma getrennt übergeben: "; ?>
Der Einsatz von Variablen Variablen dienen dazu, einen Wert, der sich im Laufe des Programms verändert – etwa durch eine Berechnung oder Benutzereingabe – zu verwalten. Hierzu ein kleines Beispiel, das gleich zeigt, in welche Bereiche Sie mit PHP vorstoßen und etwas ausführt, was mit HTML nicht geht.
31
Wie Sie vielleicht wissen, kann man (unabhängig von der eingesetzten Scriptsprache) auf zwei Arten mit dem Browser Werte an den Webserver übermitteln, mit get und mit post. Um post kümmern wir uns später im Zusammenhang mit der Auswertung von Formularen, bei get wird eine Wertzuweisung einfach mit einem Fragezeichen an die Adresse einer Webseite als URL-Parameter gehängt. So wird etwa mit
http://localhost/index.php?t=test zum Beispiel die Datei index.php aufgerufen und dabei der Variablen t der Wert test zugewiesen. Damit der Webserver mit dieser Zuweisung überhaupt etwas anfangen kann, muss »index.php« ein Script enthalten, das die übergebene Variable verarbeitet. Und genau das machen wir jetzt. Wir basteln eine Webseite namens »test.php«, deren Titelzeile und Text in Abhängigkeit eines mit get übergebenen Wertes verändert wird.
1 PHP speichert alle mit get übergebenen Werte in einem so genannten »Array«
namens $_GET[] (in einem Array werden mehrere Werte unter einem Variablennamen gespeichert – aber auch hier gilt: um die Details kümmern wir uns später). Um auf einen bestimmten übergebenen Wert zuzugreifen, setzt man seinen Namen (in einfachen Anführungszeichen) in die eckigen Klammern und weist einer Variablen in PHP diesen Wert zu. Die erste Zeile von »test.php« lautet also:
2
Hiermit deklarieren wir die Variable $titel, indem wir ihr den mit get übergebenen Wert für t zuweisen. Als Nächstes folgt der übliche HTML-Code, mit , und . Nur dass wir statt eines fest vorgegebenen Titels die übergebene Variable einsetzen: =$titel?>
3
Sie erinnern sich – die echo-Anweisung darf direkt nach Beginn eines PHP-Scripts durch ein Gleichheitszeichen abgekürzt werden. Der eingefügte PHP-Schnipsel wird beim Abruf der Seite also durch genau den Wert ersetzt werden, der mit get übergeben wurde.
32
Der Einsatz von Variablen
4
Nun folgt der -Teil des HTML-Codes, in dem wir erneut auf die Variable zugreifen und sie mit echo ausgeben:
Guten Tag,
der Titel dieser Webseite lautet
5
Wie Sie sehen, können Sie HTML und PHP lustig durcheinander mischen, Sie müssen nur darauf achten, dass das PHP-Script sinnvollen HTML-Code erzeugt. In diesem Fall wird der übergebene Wert noch einmal zur Kontrolle kursiv ausgegeben.
6
Und da das ganze eine korrekte HTML-Datei ergeben soll, setzen wir nun noch den üblichen Abschluss einer HTML-Datei:
An diesem Beispiel sehen Sie nicht nur den Einsatz von Variablen, sondern können auch erkennen, dass PHP-Code an beliebigen Stellen und beliebig oft in den HTML-Code eingefügt werden kann.
Wenn Sie die Datei »test.php« nun speichern, können Sie über den getParameter bestimmen, was in der Titelzeile der Webseite stehen soll, indem Sie den gewünschten Namen mit ?t= an den Dateinamen anhängen:
http://localhost/test.php?t=Firlefanz http://localhost/test.php?t=Irgendwas http://localhost/test.php?t=Ein Test Falls Sie bei der Eingabe Leerzeichen benutzen, werden diese vom Browser automatisch als %20 kodiert, bevor der Wert an den Webserver übergeben wird, aus Ein Test wird also Ein%20Test. Diese Kodierung wird lediglich für die Verarbeitung der Leerzeichen benötigt und erscheint in der Adresse-
33
zeile des Browser, aber natürlich nicht in der Titelzeile oder im Text der Webseite.
Der Beginn einer wundervollen Freundschaft: PHP verarbeitet einen übergebenen Wert und macht den ersten Schritt zu einer dynamischen Webseite. In diesem Beispiel kann der Benutzer durch die Änderung des übergebenen Parameters Titel und Text der Webseite ändern.
Rechnen und Verknüpfen in PHP Bislang haben wir uns mit Variablen beschäftigt, die als Wert einen String enthielten, also eine Zeichenkette bzw. Text. Das klassische Einsatzgebiet von Variablen sind aber Zahlenwerte und Ziffern. Es ist kein Problem, mit PHP beliebige Rechenoperationen durchzuführen. Dazu müssen Sie den Variablen lediglich die gewünschten Werte zuweisen und mit den üblichen arithmetischen Operatoren verknüpfen. Die vier Grundrechenarten werden wie gewohnt notiert, Variablen können mit festen Zahlen kombiniert werden und auch die üblichen Klammerregeln gelten bei Berechnungen mit PHP. Damit auch die Rechenanweisungen nicht gar zu trocken daher kommen, setzen wir sie in einem kleinen dynamischen Beispiel ein. Diesmal werden via get zwei Werte übergeben, die von PHP auf verschiedene Weise verrechnet werden. Die Berechnung samt Ergebnis wird als HTML-Seite im Browser angezeigt. Um mit get mehr als einen Wert zu übergeben, müssen Sie die Zuweisungen lediglich mit einem Ampersand, dem so genannten »kaufmännischen Und« & verketten, etwa so: test.php?a=5&b=7.
34
Rechnen und Verknüpfen in PHP
Bei diesem Scriptbeispiel werden zwei Werte eingelesen, auf verschiedene Weise miteinander verrechnet und die Ergebnisse anschließend ausgegeben.
1
Das PHP-Script zur Berechnung und Ausgabe der beiden Zahlen wird im body der Datei notiert. Das Script zerfällt dabei in drei Teile. Zuerst werden die beiden Rechenwerte über $_GET[] zwei Variablen zugewiesen. Das sieht zum Beispiel so aus:
2
Anschließend führt PHP die Berechnungen durch und speichert die Ergebnisse in vier weiteren Variablen. Dieser Teil kann dann so aussehen (natürlich können Sie auch andere Berechnungen durchführen und andere Variablennamen wählen):
35
3
Schließlich müssen die Ergebnisse noch mit echo ausgegeben werden. Hier ist eine Eigenheit bemerkenswert: Innerhalb einer Zeichenkette in Anführungszeichen werden zwar die Variablen erkannt und durch ihre aktuellen Werte ersetzt, ein echo "$a" gibt also den aktuellen Wert der Variablen $a aus, nicht den Text »$a«. Das gilt jedoch nicht für die Rechenanweisungen, die zu einfachem, auszugebenden Text werden. Mit echo "3 + 2" führen Sie also keine Berechnung durch, sondern geben den Text »3 + 2« aus.
Am Ende jeder Zeile fügen wir noch ein -Tag für den Zeilenumbruch ein, ansonsten würden die vier Zeilen ohne Leerzeichen aneinander gehängt werden.
Hier werden mit get die beiden Werte a=5 und b=10 an das Script in test.php übergeben, das sie auf verschiedene Weisen verrechnet und das Ergebnis ausgibt.
Bei sehr vielen Berechnungen in PHP werden Sie ein und denselben Variablennamen sowohl auf der linken als auch der rechten Seite des Zuweisungsoperators = finden, wie zum Beispiel hier:
Diese Notierung sieht auf den ersten Blick vielleicht seltsam aus, erklärt sich aber ganz einfach. PHP führt nämlich zuerst die Rechenoperationen auf der rechten Seite aus, addiert den Wert 4 zum aktuellen Wert von $variable. Dieses Ergebnis wird danach $variable als neuer Wert zugewiesen.
36
Rechnen und Verknüpfen in PHP
Im folgenden Beispiel wird $variable mit dem Wert 5 initialisiert. In der nächsten Codezeile wird zum aktuellen Wert von $variable 4 addiert und das Ergebnis $variable zugewiesen. Damit wird der ursprüngliche Wert von $variable überschrieben und $variable hat nun den Wert 9:
Die mit weitem Abstand wohl häufigste arithmetische Operation, die in PHP vorkommt, ist die kontinuierliche Erhöhung bzw. Verminderung einer Variablen um den Wert 1. Normalerweise würde man dies als
oder als
notieren. Doch da speziell diese Operationen sehr häufig benötigt werden, gibt es dafür auch eine Abkürzung. Mit $counter++ wird der Wert der Variablen $counter um eins erhöht, mit $counter-- entsprechend um eins vermindert. In beiden Fällen handelt es sich um abgeschlossene Anweisungen, die mit einem Semikolon von anderen Anweisungen in einem PHP-Script getrennt werden müssen:
Hier wird der Variablen $a der Wert 10 zugewiesen und anschließend um eins erhöht, $a hat also nun den Wert 11. Ähnliches passiert mit der Variablen $b, die mit dem Wert 5 initialisiert wird und danach um eins vermindert wird, also den Wert 4 besitzt. Wie Sie hier sehen, können Sie mehrere Anweisungen in einer Zeile notieren. Sie müssen nur darauf achten, alle Anweisungen mit einem Semikolon ; voneinander zu trennen. Neben den vier Grundrechenarten Addition, Subtraktion, Multiplikation und Division kennt PHP noch den so genannten »Modulo«-Operator, mit dem der ganzzahlige Rest einer Division ermittelt wird. Das kennen Sie vielleicht
37
noch aus der Grundschule, bevor die Kommarechnung dran kam: »10 geteilt durch 3 ist 3, Rest 1«, »12 geteilt durch 5 ist 2, Rest 2«. Mit der Einführung von »modulo« lässt sich das auch als »10 modulo 3 = 1« bzw. als »12 modulo 5 = 2« formulieren. Das Zeichen für Modulo ist in PHP das Prozentzeichen %, die genannten Beispiele könnte man dann folgendermaßen in PHP notieren:
Benötigt werden Modulo-Operationen zum Beispiel dann, wenn man wissen möchte, ob eine Zahl durch eine andere Zahl restlos teilbar ist. Wenn zum Beispiel $a % 2 den Wert 0 ergibt, dann ist $a restlos durch 2 teilbar, also eine gerade Zahl. Außer den arithmetischen Operatoren +, –, *, /, % und dem Zuweisungsoperator = kennt PHP schließlich noch den so genannten Verkettungsoperator, mit dem Sie beliebige Zeichenketten verknüpfen können. Dieser Operator besteht in einem einfachen Punkt und hängt den rechten Operanden an den linken an. Nach der Ausführung dieses Codefragments:
hat die Variable $gruss demnach den Wert Guten Abend.
Abkürzungen und Zuweisungen Programmierer sind faule Menschen und tippen ungern auch nur ein Zeichen zu viel ein. Das klingt Ihnen jetzt zu negativ? Dann formulieren wir das einfach um: Programmierer sind vorsichtige Menschen, die wissen, dass jeder Tippfehler ein Script ruinieren kann und die daher möglichst wenig Zeichen eintippen. So oder so – es kann nicht überraschen, dass es für verschiedene häufig vorkommende Operationen Abkürzungen gibt, die Ihnen Tipparbeit ersparen und gleichzeitig die Tippfehlergefahr verringern. Einige davon haben Sie schon kennen gelernt.
38
Kleine Typenlehre
So kann die echo-Anweisung direkt zu Beginn eines Scripts mit einem Gleichheitszeichen abgekürzt werden, die folgenden zwei Anweisungen führen zum gleichen Ergebnis:
Ebenfalls bekannt sind die Erhöhung oder Verminderung einer Variablen um den Wert eins mit einem nachgestellten doppelten Plus- bzw. Minus-Zeichen:
Darüber hinaus können Sie immer dann, wenn Sie auf beiden Seiten des Gleichheitszeichens dieselbe Variable notieren – etwa in $a = $a + 27 oder $string = $string.$text –, die Notation durch spezielle Zuweisungsoperatoren abkürzen: Operator
Beispiel
Erläuterung
+=
$a += 27
Identisch mit: $a = $a + 27
–=
$a –= 3
Identisch mit: $a = $a – 3
*=
$a *= 19
Identisch mit: $a = $a * 19
/=
$a /= 61
Identisch mit: $a = $a / 61
%=
$a %= 42
Identisch mit: $a = $a % 42
.=
$a .= $b
Identisch mit: $a = $a.$b
Kleine Typenlehre Eine Variable kann unterschiedliche Inhalte haben: ganze Zahlen, Fließkommazahlen und Texte. Je nach ihrem Inhalt ist sie von einem bestimmten »Typ«. Die unterschiedlichen Typen werden mit englischen Begriffen benannt.
•
Eine ganze Zahl heißt auf Englisch »integer«; wenn $a = 1961, dann ist $a also vom Typ integer.
•
Besitzt eine Variable einen gebrochenen bzw. Fließkommawert wie beispielsweise $euro_kurs = 1.95583, dann ist diese Variable vom Typ double.
39
•
Enthält die Variable eine Zeichenkette (englisch: »string«) wie etwa in $text = "Hallo Welt!", dann ist diese Variable vom Typ string.
•
Außerdem kann eine Variable das Ergebnis eines logischen Vergleiches repräsentieren und die Werte »wahr« oder »falsch« annehmen, bzw. true oder false. In diesem Fall ist der Datentyp boolean (benannt nach dem englischen Logiker George Boole).
Jeder Datentyp stellt andere Anforderungen an den Arbeitsspeicher, was bei vielen Programmiersprachen dazu führt, dass Sie zum Beispiel einer einmal als Integer angelegten Variablen im Programmablauf keinen Fließkommawert zuweisen können und einer einmal als Fließkommazahl deklarierten Variablen keinen Text. PHP nimmt es da nicht so genau und macht es Ihnen damit einfacher und schwieriger zugleich. Der Datentyp einer Variablen wird dem Wert angepasst, der der Variablen zugewiesen wird. So kann im Laufe eines Scripts eine Variable zuerst als string eingeführt und später als integer oder double weiterverarbeitet und am Schluss als boolean benutzt werden. Es ist zwar angenehm, dass Sie sich als PHP-Programmierer nicht sonderlich um die Datentypen kümmern müssen, doch es gibt auch einen Haken: PHP führt auch unsinnige Anweisungen ohne Fehlermeldung aus und addiert zum Beispiel klaglos eine Fließkommazahl und einen Text:
Diese Zeilen werden anstandslos verarbeitet. Da sich ein Text nicht zu einer Zahl addieren lässt, versucht PHP zuerst, den Text als Zahl zu interpretieren, was mit Hallo Welt aber nicht gelingt. Daher wird aus der String-Variablen $text mit dem Wert Hallo Welt intern eine Variable vom Typ double mit dem Wert 0 und zur Double-Variablen $zahl addiert. Als Ergebnis wird dann 42.42 ausgegeben werden. Etwas anders sieht die Sache aus, wenn eine string-Variable eindeutig als Zahl zu interpretieren ist. In diesem Fall gelingt die interne Umwandlung und das Rechenergebnis ist korrekt. Genau das passiert übrigens bei unserem weiter oben gezeigten Script, dem Werte als URL-Parameter übergeben werden. Jede mit get übergebene Variable ist für PHP vom Typ string. Doch solange ihr Wert aber auch eindeutig als Zahl gelesen werden kann, kann PHP damit auch richtig rechnen.
40
Menschen, nicht Maschinen
Diese automatische Konvertierung und Anpassung der Datentypen müssen Sie immer im Hinterkopf behalten und bei Ihren Variablen-Operationen berücksichtigen. Sollte eine Berechnung in einem Script einfach mal nicht das tun, was sie tun soll und Sie den Fehler nicht finden, dann kontrollieren Sie die Datentypen Ihrer Variablen – vielleicht hat sich ja irgendwo ein kleiner Fehler mit großen Folgen eingeschlichen.
Menschen, nicht Maschinen: Rasmus Lerdorf
In diesem Buch geht es um eine Programmiersprache und um Computer, also um Maschinendinge. Doch Maschinen sind nur Mittel zum Zweck, am Anfang und am Ende steht immer der Mensch. Ohne die Kreativitiät und das Engagement von Menschen gäbe es weder PHP noch Computer, ohne den Wunsch, mit anderen Menschen zu kommunzieren, gäbe es kein Internet und keine Webseiten. Da es in diesem Buch mitunter reichlich trocken und technisch zugehen wird, soll wenigstens am Abschluss jedes Kapitels kurz auf die Menschen hingewiesen werden, denen wir PHP, MySQL & Co. verdanken. Die Reihenfolge der Nennung ist dabei mehr oder weniger ein Zufallsprodukt und drückt keine Wertung aus. Den Anfang macht Rasmus Lerdorf. Lerdorf wurde 22. November 1968 in Qeqertarsuaq, Grönland, geboren. Mit 17 sammelte er seine ersten Unix-Erfahrungen und hat seither zahlreiche Beiträge zur Open Source Software geleistet. Sein wohl folgenreichstes und wichtigstes Projekt begann er 1994/1995: Lerdorf ist der Erfinder von PHP und bis heute einer der wichtigsten Köpfe im PHP-Team. Das Kürzel stand ursprünglich für »Personal Homepage Tools«, eine Name, der spätestens ab der Version 3 (die maßgeblich von Zeev Suraski and Andi Gutmans entwickelt wurde) nicht mehr passend schien. Im April 1998 stimmte man in der PHP-Community über die Bedeutung des Akronyms ab. Das Rennen machte »PHP: Hypertext Preprocessor«. Die Homepage von Rasmus Lerdorf finden Sie unter der Adresse http://lerdorf.com/.
41
Kapitel 2
Entscheidungen, Schleifen und Funktionen
In diesem Kapitel lernen Sie, wie Sie in PHP Entscheidungen fällen, Befehlsfolgen mehrfach abarbeiten und eigene Anweisungen erzeugen können. Damit sind wir bereits bestens gerüstet, um Formulareingaben zu verwalten.
Ihr Erfolgsbarometer
Das können Sie schon: Sie haben Ihren lokalen Computer mit Xampp in einen Webserver mit PHP verwandelt und Ihre ersten Erfahrungen mit der Sprache gemacht.
16
Das lernen Sie neu: Logische Vergleiche und Verknüpfungen
44
Wenn ... dann ... andernfalls!
46
Datumsangaben in PHP
51
Programmschleifen
55
Funktionen
61
Variablentypen überprüfen
64
43
Logische Vergleiche und Verknüpfungen Bevor wir uns mit den verschiedenen Möglichkeiten beschäftigen, in PHP Entscheidungen zu fällen, müssen wir einen kleinen Abstecher in die Logik machen. Denn die Basis aller Entscheidungen in einem Programm oder Script ist der Vergleich zweier Werte. Dieser Vergleich wird durch so genannte Vergleichsoperatoren ausgedrückt. Wenn Sie zwei Zahlen oder Variablen miteinander vergleichen, dann kann dieser Vergleich zu einem von drei möglichen Ergebnissen führen. Entweder ist der eine Wert kleiner als der andere, oder er ist größer oder beide Werte sind gleich. Um diese Verhältnisse zwischen zwei Werten zu beschreiben, gibt es drei verschiedene Operatoren, mit denen die Werte zu einem Ausdruck verbunden werden.
• • •
$a < $b: Der Wert der Variablen $a ist kleiner als der Wert der Variablen $b. $a > $b: Der Wert der Variablen $a ist größer als der Wert der Variablen $b. $a == $b: Der Wert der Variablen $a ist gleich dem Wert der Variablen $b (da das Gleichheitszeichen in PHP bereits als Zuweisungsoperator
benutzt wird, wird die Gleichheit zweier Werte durch ein doppeltes Gleichheitszeichen dargestellt). Man kann diese drei Grundformen auch kombinieren und erhält so folgende Ausdrücke:
•
$x <= $y: Der Wert der Variablen $x ist kleiner oder gleich dem Wert der Variablen $y.
•
$x >= $y: Der Wert der Variablen $x ist größer oder gleich dem Wert der Variablen $y.
Schließlich besteht noch die Möglichkeit, die Ungleichheit zweier Werte zu formulieren:
44
•
$x != $y: Der Wert der Variablen $x ist ungleich dem Wert der Variablen $y.
•
In Abhängigkeit vom Wert der auf diese Art verknüpften Variablen ist ein so formulierter Ausdruck entweder wahr oder falsch.
•
In PHP lassen sich diese Ausdrücke auswerten und je nach Ergebnis (true oder false) der weitere Verlauf über Wenn-dann-Strukturen des Scripts steuern: Wenn ein bestimmter Ausdruck true ist, dann mache dieses, andernfalls tue jenes.
Logische Vergleiche und Verknüpfungen
Für $a = 1 und $b = 2 gilt: Ausdruck
Wert
Erläuterung
$a < $b
true
Der Ausdruck ist wahr, weil 1 kleiner als 2 ist.
$a > $b
false
Der Ausdruck ist falsch, weil 1 nicht größer als 2 ist.
$a == $b
false
Der Ausdruck ist falsch, weil 1 nicht gleich 2 ist.
$a != $b
true
Der Ausdruck ist wahr, weil 1 ungleich 2 ist.
$a <= $b
true
Der Ausdruck ist wahr, weil 1 kleiner oder gleich 2 ist.
$a >= $b
false
Der Ausdruck ist falsch, weil 1 weder kleiner noch größer als 2 ist.
Die einfachen Vergleiche erlauben auch nur einfache Abfragen. Mitunter möchte man aber etwas komplexere Bedingungen formulieren und die Ausführung eines Programmcodes von mehr als nur einem Ausdruck abhängig machen, etwa: »Wenn die Variable $a kleiner als $b ist und die Variable $c kleiner als $d, dann ...«. In diesem Fall müssen Sie die unterschiedlichen Ausdrücke mit einem logischen and (»und«) bzw. einem logischen or (»oder«) verknüpfen. Der so gebildete neue Ausdruck erzeugt in Abhängigkeit von den Wahrheitswerten der verknüpften Ausdrücke einen neuen Wahrheitswert.
1
Eine and-Verknüpfung ist dann (und nur dann) wahr, wenn alle verknüpften Ausdrücke wahr sind. Eine and-Verknüpfung lässt sich mit dem doppelten Ampersand && abkürzen: $d) ($a < $b) && ($c > $d) ?>
2
Eine or-Verknüpfung ist dann wahr, wenn mindestens einer der verknüpften Ausdrücke wahr ist. Eine or-Verknüpfung lässt sich mit dem doppelten Pipesymbol || abkürzen: $d) ($a < $b) || ($c > $d) ?>
45
3 Eine xor-Verknüpfung ist eine Verschärfung der or-Verknüpfung. Sie ist dann
(und nur dann) wahr, wenn entweder der eine oder der andere verknüpfte Ausdruck wahr ist. Wenn beide wahr sind, ist eine xor-Verknüpfung falsch, wenn beide verknüpften Aussagen falsch sind, natürlich auch. Für xor gibt es keine Abkürzung:
$d) ?>
4
Schließlich können Sie jeden Wahrheitswert durch ein vorangestelltes ! negieren. Ein negierter Ausdruck ist dann wahr, wenn der Ausdruck falsch ist und umgekehrt:
Wenn ... dann ... andernfalls! Mit der Möglichkeit, Verhältnisse zwischen zwei (oder mehr) Variablen bzw. Aussagen zu beschreiben, sind wir in PHP in der Lage, Entscheidungen zu treffen. Die klassische »Wenn-dann«-Verknüpfung wird in PHP mit einer if-Anweisung realisiert. Der umgangssprachliche Satz »Wenn eine bestimmte Bedingung zutrifft, dann tue dieses«, ließe sich in PHP abstrakt so formulieren: if (Bedingung) Anweisung;
Wenn Sie mehr als nur eine Anweisung ausführen wollen, dann müssen Sie die folgenden Anweisungen wie gewohnt mit einem Semikolon voneinander trennen und mit einer Mengenklammer zusammenfassen: if (Bedingung) { Anweisung 1; Anweisung 2; Anweisung 3; }
Die in der Mengenklammer zusammengefassten Anweisungen werden dann – und nur dann! – ausgeführt, wenn die Bedingung den Wert true besitzt, ansonsten ignoriert PHP den gesamten Block.
46
Wenn ... dann ... andernfalls!
Die Mengenklammer
Mit der Mengenklammer werden bei bestimmten Konstruktionen mehrere Anweisungen zusammengefasst. Die verschiedenen Anweisungen innerhalb der Mengenklammer werden wie gewohnt durch ein Semikolon getrennt. Nach der Mengenklammer steht jedoch kein Semikolon, auch wenn noch andere Anweisungen folgen sollten.
Jetzt sind wir in der Lage, ein kleines Script zu schreiben, das entscheiden kann, ob zwei übergebene Werte gleich sind, oder ob der erste kleiner bzw. größer als der zweite Wert ist. Dazu werden zuerst zwei mit get übergebene Werte in Variablen abgelegt. Anschließend überprüfen drei aufeinanderfolgende if-Abfragen die möglichen Beziehungen der beiden Werte und geben, falls sie zutreffen, einen kurzen Text aus.
= $_GET['a']; = $_GET['b']; ($a < $b) echo "A ist kleiner als B"; ($a > $b) echo "A ist größer als B"; ($a == $b) echo "A ist gleich B";
Speichern Sie das kleine Script im -Teil von z. B. »test.php« und rufen Sie es mit zwei Werten auf, etwa als
http://localhost/test.php?a=5&b=1 Das funktioniert schon ganz gut, hat aber noch einen Schönheitsfehler. Bei jedem Aufruf werden alle if-Abfragen abgearbeitet, auch dann, wenn dies gar nicht nötig ist. Wenn etwa die erste Abfrage zutrifft und die echo-Anweisung ausgeführt wird, können die übrigen beiden if-Abfragen übersprungen werden, weil sie garantiert nicht mehr zutreffen können. Für diesen Fall gibt es die else- Anweisung. Das englische Wort bedeutet so viel wie »sonst, anders, anderenfalls«. In Kombination mit if sind damit Konstruktionen der Art »Wenn die Bedingung zutrifft, tue jenes, andernfalls unternehme dieses« formulierbar. Trifft die Bedingung in der if-Abfrage zu, wird die damit verbundene Anweisung ausgeführt und der else-Teil ignoriert. Im umgekehrten Fall – die Bedingung ist falsch – wird der if-Teil ignoriert und die mit else verbundene Anweisung ausgeführt.
47
Die Konstruktion hat folgende Grundstruktur: if (Bedingung) Anweisung; else Anweisung;
Auch bei else können Sie mehrere, mit einem Semikolon getrennte Anweisungen mit einer Mengenklammer zusammenfassen (nach der, wie bei if, dann kein Semikolon mehr folgt): if (Bedingung) { Anweisung 1; Anweisung 2; } else { Anweisung 1; Anweisung 2; }
Mit der elseif-Anweisung lässt sich diese Abfrage noch weiter ausbauen. Hiermit lassen sich mehrere Bedingungen nacheinander überprüfen. Am Schluss steht schließlich die else-Anweisung, die ausgeführt wird, wenn keine der Bedingungen erfüllt wurde: if (Bedingung 1) Anweisung; elseif (Bedingung 2) Anweisung; else Anweisung;
Dabei können Sie auch mehrere elsif-Anweisungen aufeinander folgen und so verschiedene Bedingungen überprüfen lassen: if (Bedingung 1) Anweisung; elseif (Bedingung 2) Anweisung; elseif (Bedingung 3) Anweisung; elseif (Bedingung 4) Anweisung; elseif (Bedingung 5) Anweisung; else Anweisung;
Natürlich gibt es auch bei der if-elseif-else-Struktur die Möglichkeit, mit Mengenklammern mehrere Anweisungen zu bündeln. Hier gelten die gleichen Regeln wie bei if oder else: if (Bedingung 1) { Anweisung 1; Anweisung 2; } elseif (Bedingung 2) { Anweisung 1; Anweisung 2; } else { Anweisung 1; Anweisung 2; }
48
Auf Inhalt überprüfen
Damit können wir unser kleines Beispiel schon etwas eleganter formulieren und die überflüssigen if-Abfragen durch elseif und else ersetzen. Trifft die if-Abfrage zu, wird der entsprechende Text ausgegeben und das Script beendet. Andernfalls wird die elseif-Abfrage bearbeitet und erst, wenn diese ebenfalls nicht zutrifft, gelangt das Script zur else-Anweisung: $b) echo "A ist größer als B"; else echo "A ist gleich B"; ?>
Auf Inhalt überprüfen Nun führt das Script zwar keine überflüssigen Abfragen mehr durch, aber einen Haken hat die Sache doch noch. Es erkennt nicht, wenn keine Werte für $a und $b übergeben wurden und führt anschließend eher unsinnige Vergleiche aus. Das mag in diesem Beispiel noch ein akzeptabler Fehler ohne große Konsequenzen sein, aber wenn wir bei einer Formularauswertung nicht überprüfen können, ob das Formular korrekt ausgefüllt wurde, kann das fatale Folgen haben. Hier hilft die Funktion isset(), der man in Klammern die Variable übergibt, die überprüft werden soll. Existiert die Variable, dann liefert isset() den Wert true zurück, andernfalls false. So lässt sich diese Funktion sehr schön in eine if-Abfrage integrieren:
Häufig wird isset() in Verbindung mit der Negation ! benutzt, um eine Konstruktion der Art »Wenn die Variable $a nicht existiert, dann ...« zu bilden, was in PHP so aussieht:
Unser Beispielscript kann nun so umgebaut werden, dass es nur ausgeführt wird, wenn für $a und $b Werte übergeben wurden, andernfalls wird ein kurzer Hinweis ausgegeben.
49
Die if-Abfragen des bisherigen Scripts rutschen dabei komplett in den Anweisungsteil einer weiteren if-Abfrage und werden dann (und nur dann) ausgeführt, wenn sowohl $a also auch $b einen Wert besitzen, die Funktion isset($a) und isset($b) den Wert true liefern: $b) echo "A ist größer als B"; else echo "A ist gleich B"; } else echo "Geben Sie Werte für A und B ein !"; ?>
Durch den Einsatz von isset() lässt sich überprüfen, ob eine Variable einen Wert besitzt und eine Weiterverarbeitung überhaupt sinnvoll ist.
Neben isset(), mit der man die Existenz einer Variablen überprüft, gibt es in PHP noch die Funktion empty(), die ähnlich arbeitet, aber mitunter seltsame Nebeneffekte produziert. Mit dieser Funktion wird überprüft, ob eine Variable einen Inhalt besitzt oder nicht. Fatalerweise wird allerdings der Wert 0 als »leer« gewertet, und zwar sowohl als numerischer Wert ($a=0), als auch als Zeichenkette ($a="0"). Der Einsatz dieser Funktion will also gut überlegt sein.
Alternative Abfragen Solange Sie nur zwei Werte vergleichen, werden Sie mit if, elseif und else keine Probleme bekommen. Sobald es aber darum geht, mehr als nur zwei oder drei Möglichkeiten zu beachten, tendieren if-Abfragen dazu, eher unübersichtlich zu werden. Hier greift man zur switch-Anweisung, mit der sich gewissermaßen beliebig viele if-Abfragen zusammenfassen lassen. Die switch-Anweisung wertet einen Ausdruck aus und vergleicht anschließend beliebig viele Varianten mit dem Ergebnis. Sollte eine Variante (case)
50
Datumsangaben in PHP
zutreffen, wird der dazugehörige Programmcode ausgeführt und die Anweisung über das Kommando break verlassen. Ein frei definierbarer default-Block enthält überdies Anweisungen, die ausgeführt werden, wenn keine der Vorgaben zutrifft. Die Struktur der switchAnweisung hat folgenden Aufbau: switch (Ausdruck) { case Ergebnis1: Anweisung1; break; case Ergebnis2: Anweisung2; break; // beliebig viele weitere case-Einträge default: Anweisung_default; }
Das Ergebnis des Ausdrucks wird mit den case-Vorgaben verglichen und im Falle einer Übereinstimmung der dazugehörige Code ausgeführt. Über das break-Kommando wird die switch-Anweisung verlassen und das Programm mit dem Code nach der abschließenden geschweiften Klammer fortgesetzt. Falls keine der gemachten Vorgaben mit dem Ergebnis des Ausdrucks überein stimmt, wird der default-Code ausgeführt (falls ein solcher Code vorhanden ist, diese Anweisung ist nicht zwingend erforderlich). Da dieser Code immer zuletzt steht, entfällt das break-Kommando. Achten Sie darauf, dass die case- und default-Zeilen mit einem Doppelpunkt, nicht mit einem Semikolon beendet werden! Wenn Sie das break-Kommando vergessen, dann erhalten Sie zwar keine Fehlermeldung, aber unter Umständen ein unerwünschtes Ergebnis. Sobald eine case-Anweisung zutrifft, werden sämtliche folgenden Anweisungen ausgeführt, auch die anderen case-Anweisungen. Obendrein wird die defaultAnweisung am Ende auf jeden Fall ausgeführt, was wohl kaum im Sinne des Erfinders ist.
Datumsangaben in PHP Ein einfaches, praxisnahes Einsatzgebiet für switch liefert die Datumsabfrage. Auch dafür bietet PHP – Sie ahnen es – eine eigene Funktion. Streng genommen gibt es sogar mehrere Funktionen, die sich mit Daten und Zeiten beschäftigen, wir beschränken uns hier aber nur auf die griffigste: date().
51
Der Einsatz der date()-Funktion ist recht einfach: Sie übergeben der Funktion einen oder mehrere bestimmte Parameter und die Funktion gibt Ihnen dafür das gewünschte Datum oder die gewünschte Uhrzeit zurück. Kompliziert wird die Sache nur dadurch, dass es für date() erstaunlich viele Parameter gibt, was für ein gewisses Durcheinander sorgt. Die folgende Tabelle stellt die wichtigsten date()-Parameter zusammen. Parameter für Datumsangaben mit date(): d
Tag im Monat als Zahl mit führender Null
j
Tag im Monat als Zahl ohne führende Null
w
Wochentag als Zahl von 0 – 6
m
aktueller Monat als Zahl mit führender Null (01-12)
n
aktueller Monat als Zahl ohne führende Null (1-12)
D
Wochentag, englischer Begriff, abgekürzt mit 3 Buchstaben
l
Wochentag, englischer Begriff, ausgeschrieben (Achtung: »l« ist ein kleines »L«, kein großes »i«)
F
Monat, englischer Begriff, ausgeschrieben
M
Monat, englischer Begriff, abgekürzt mit 3 Buchstaben
y
Das Jahr als zweistellige Zahl
Y
Das Jahr als vierstellige Zahl
Parameter für Zeitangaben mit date(): s
Sekunden, Zahl mit führender Null
i
Minuten, Zahl mit führender Null
H
Stunden im 24-Stunden-Format mit führender Null
G
Stunden im 24-Stunden-Format ohne führende Null
Die Parameter können bei date() auch als Bestandteile einer auszugebenden Zeichenkette benutzt werden, in der die übergebenen Parameter durch die entsprechenden Angaben ersetzt und alle anderen Zeichen unverändert ausgegeben werden. So lassen sich Datumsabfragen als kompakter Code formulieren.
52
Datumsangaben in PHP
1
Benötigt man etwa das aktuelle Datum in Form von »17. 6. 2002«, dann geht das ein wenig umständlich so:
2
Diese vier Anweisungen lassen sich jedoch zu einer einzigen einschmelzen, indem man date() die benötigten Parameter zusammen mit den Punkten und Leerzeichen nach Tag und Monat als Zeichenkette übergibt (date("j. n. Y")) und diesen Ausdruck einfach mit einem Komma an den auszugebenden Text hängt:
3 Auf die gleiche Weise können wir das aktuelle Datum und die Uhrzeit mit
date() ermitteln. Die Ausgabe soll nach dem Muster Heute ist WOCHENTAG,
der DATUM. Es ist jetzt UHRZEIT Uhr erfolgen. "; echo "Es ist jetzt $uhrzeit Uhr."; ?>
4
Allerdings ist das Ergebnis nicht so ganz das, was wir uns vielleicht vorgestellt haben – schließlich wird die Ausgabe in einem Mischmasch aus Deutsch und Englisch erfolgen.
Die date()-Funktion liefert das aktuelle Datum und Uhrzeit – allerdings auf Englisch.
53
5
Hier können wir nun durch eine switch-Abfrage die englischen Tages- und Monatsbezeichnungen durch die deutschen Begriffe austauschen.
Wie Sie sehen, können Sie die verschiedenen case-Einträge auch in einer Zeile notieren.
6
Bei der Ermittlung des Monatsnamens geht man ähnlich vor. Die acht Anweisungen – nein, nicht zwölf, die Monatsnamen »April«, »August«, »September« und »November« werden im Englischen wie im Deutschen geschrieben, hier muss das Script also nichts ersetzen – werden nach dem gleichen Muster notiert:
7
Wenn in $wochentag und $monat nun die deutschen Bezeichnungen vorliegen, ist der Rest des Scripts rasch angepasst. Die Datumsangabe mit date("d. F Y") müssen wir nur noch durch ersetzen, die echo-Anweisungen bleiben unverändert.
54
Programmschleifen
Mit einer einfachen switch-Anweisung lassen sich die englischen Begriffe der date()Funktion durch die entsprechenden deutschen Bezeichnungen austauschen.
Das Datum auf der Homepage
Mit dem vorgestellten Script können Sie Besucher Ihrer Homepage mit dem aktuellen Datum und der Uhrzeit begrüßen. Setzen Sie dafür das Script (ohne die echo-Anweisungen versteht sich) an den Anfang des Codes Ihrer Webseite. Innerhalb des HTML-Teils können Sie dann jederzeit mit und Datum und Uhrzeit einfügen und die Ausgabe mit den üblichen HTML-Möglichkeiten formatieren.
Programmschleifen Bislang werden die Anweisungen in den Beispielscripten genau einmal durchlaufen. Doch ein Computer ist endlos geduldig und entfaltet seine wahre Stärke erst dann, wenn er einen bestimmten Anweisungsblock so lange wiederholt, wie Sie das wollen. Diese so genannten Schleifen sind das Kernstück eines jeden Programms und machen es flexibler und leistungsfähiger. Die einfachste Form einer Schleife in PHP ist die while-Konstruktion. »While« ist das englische Wort für »während, solange« und genauso funktioniert die Schleife auch. Solange eine bestimmte Abbruchbedingung nicht eintritt, solange werden die Anweisungen innerhalb der Schleife durchlaufen. Die Abbruchbedingung wird dabei als logischer Ausdruck notiert. In der allgemeinen Form sieht das so aus: while (Ausdruck) { // Beliebige Anweisungen }
55
Solange der Ausdruck den Wert true besitzt, werden die Anweisungen in den geschweiften Klammern ausgeführt. Mindestens eine dieser Anweisungen muss also den Wert des Ausdrucks so verändern, dass er irgendwann false ergibt, ansonsten wird die Abbruchbedingung nie erfüllt und die Schleife nie verlassen. Hinweis
Fehlende oder fehlerhaft formulierte Abbruchbedingungen sind eine der häufigsten Ursachen für einen Programmabsturz.
Das klingt jetzt vielleicht etwas abstrakt und trocken, also probieren wir das rasch an einem einfachen Beispiel aus.
1
Einem Script werden mit get zwei Zahlen übergeben, die als Anfangs- und Endwert gespeichert werden. Das Script zählt dann in Einserschritten von der einen bis zur anderen Zahl und zeigt das Ergebnis am Bildschirm an:
2
Da die Variable $anfang innerhalb der while-Schleife verändert wird, verändert sich auch der Wahrheitswert der Abbruchbedingung. Sobald der Wert von $anfang größer als $ende ist, wird die Schleife verlassen.
Streng genommen müssten wir noch einige Sicherheitsabfragen für den Fall einfügen, dass keine Werte übergeben werden oder dass der Endwert kleiner als der Anfangswert ist. Aber wirklich nötig sind sie in diesem Fall nicht, denn die Schleife wird dann (und nur dann) durchlaufen, solange $anfang kleiner oder gleich $ende ist. In den anderen Fällen passiert gar nichts. While ist ein Beispiel für eine so genannte »abweisende Schleife«, bei der
noch vor dem ersten Durchlauf die Abbruchbedingung überprüft wird. Das Gegenstück ist eine »annehmende Schleife«, bei der erst nach den Anweisungen überprüft wird, ob die Abbruchbedingung eingetreten ist. Eine solche Schleife wird also mindestens einmal, eine abweisende Schleife unter Umständen gar nicht durchlaufen.
56
Programmschleifen
Eine annehmende Schleife in PHP wird mit do/while konstruiert: do { // Beliebige Anweisungen } while (Ausdruck);
Neben der while- kennt PHP noch die for-Schleife, die in vielen Fällen das gleiche Ergebnis liefert, aber einen etwas kompakteren und übersichtlicheren Code ermöglicht. Bei einer while-Konstruktion müssen Sie dafür sorgen, dass die Abbruchbedingung der Schleife erreicht wird, indem etwa innerhalb der Schleife ein Zähler mitgeführt oder durch kontinuierliche Akkumulation ein Grenzwert erreicht wird. Bei einer for-Konstruktion wird die Ausführungsbedingung und die kontinuierliche Erhöhung eines Zählers dagegen außerhalb und vor dem Start der eigentlichen Schleife definiert. Die allgemeine Syntax einer for-Schleife sieht so aus: for (Initialisierung; Bedingung; Veränderung) { // Beliebige Anweisungen }
Einzeilig
Besteht die Schleife nur aus einer Anweisung, kann man die for-Konstruktion in einer Zeile schreiben und auf die Mengenklammern verzichten.
Kernstück der for-Schleife sind die drei durch ein Semikolon getrennten Anweisungen in Klammern. Zuerst wird üblicherweise eine Variable als Zähler initialisiert, danach wird die Bedingung angegeben, die erfüllt sein muss, damit die Schleife durchlaufen wird, und schließlich wird der Zähler erhöht (oder verringert). Um die Zahlen von 1 bis 10 auszugeben, benötigt man zum Beispiel diese Schleife:
Das kleine while-Beispiel ließe sich also in einer for-Schleife folgendermaßen notieren:
57
Ein typischer Einsatz für die for-Schleife ist das Abzählen von Werten. Will man etwa die ASCII-Codes von 32 bis 255 ausgeben, so benötigt man dafür gerade mal eine Zeile PHP-Code. HTML- und numerische Entities
In HTML können Zeichen durch so genannte Entities dargestellt werden. Eine Entity wird mit einem Ampersand & eingeleitet und einem Semikolon ; beendet. Das auszugebende Zeichen wird entweder mit seinem ISO-Namen angegeben (z. B. »auml« für »a-Umlaut«, also »ä«) oder mit seinem numerischen Zeichencode (»ä« hat den Code 228, notiert als #228). Ein »ä« lässt sich so in HTML entweder als »ä« oder als »ä« darstellen.
Man lässt in einer Schleife eine Variable von 32 bis 255 hochzählen und setzt diese Variable in einer echo-Anweisung als Wert für die numerische Entity ein: ASCII-Codes 32 bis 255
Dies sind die ASCII-Codes von 32 bis 255:
Eine einzige Zeile in PHP genügt, um sich die darstellbaren ASCII-Codes ausgeben zu lassen.
58
Das kleine Einmaleins
Das kleine Einmaleins Ihre wahre Stärke erreichen Schleifen dann, wenn man sie verschachtelt, d. h. innerhalb einer Schleife eine weitere Schleife ausführt. Verschachtelte Schleifen sind nicht immer auf Anhieb verständlich und tendieren dazu, sehr komplex zu werden und zu eher unerwarteten Ergebnissen zu führen. Gehen wir also das Verfahren an einem Beispiel etwas ausführlicher durch. Aufgabe ist es, das kleine Einmaleins zeilenweise über eine PHP-Anweisung auszugeben.
1
Wir benötigen zwei Schleifen, eine für die Reihen, die von eins bis zehn zählt und eine für die Spalten, die ebenfalls von eins bis zehn zählt und die eigentliche Multiplikation enthält. Das Grundgerüst könnte so aussehen: "; } ?>
2
Die erste Schleife benutzt die Variable $r (für »Reihe«) als Zähler von 1 bis 10. Die erste Anweisung ist eine weitere Schleife, die die Variable $s (für »Spalte«) von 1 bis 10 zählt und das Ergebnis der Multiplikation von Reihen- und Spaltenzähler ausgibt. Abschließend sorgt ein -Tag dafür, dass eine neue Zeile begonnen wird.
3
Was passiert nun genau in dieser Schleife? Gehen wir sie im Kopf einmal kurz durch. Zu Beginn wird der Variablen $r der Wert 1 zugewiesen. Danach beginnt die zweite Schleife, in der die Variable $s die Werte 1 bis 10 durchläuft, während $r immer noch den Wert 1 besitzt. Innerhalb der zweiten Schleife werden $r und $s miteinander multipliziert und das Ergebnis ausgegeben. Insgesamt bekommt man also dieses Ergebnis:
1 2 3 4 5 6 7 8 9 10
4
Damit ist die innere Schleife beendet, die äußere wird fortgeführt. Es wird ein Zeilenumbruch erzwungen, danach wird der Wert für $r um eins erhöht. Da die Abbruchbedingung der äußeren Schleife noch nicht erreicht ist, beginnt nun alles von vorn, diesmal mit dem Wert 2 für die Variable $r, die Anzeige sieht nun so aus:
1 2 3 4 5 6 7 8 9 10 2 4 6 8 10 12 14 16 18 20
59
5
Wieder wird die innere Schleife beendet und die äußere fortgeführt. Dies wird so lange wiederholt, bis die Variable $r den Wert 11 erreicht hat und die äußere Schleife verlassen wird.
6
Damit die Ausgabe etwas ansprechender und übersichtlicher gerät, setzen wir den gesamten Code in ein
-Tag. Die äußere Schleife gibt die Reihen aus, muss also die innere Schleife mit einem
-Element umgeben. Dort werden nun die einzelnen Werte pro Reihe ausgegeben, die jeweils von einem
umrahmt werden müssen. Zusammen ergibt sich dieser HTML-Code mit PHP-Anteil:
"; for ($s = 1; $s <= 10; $s++) { echo "
"; echo ($r * $s); echo "
"; } echo ""; } ?>
7 Die innere Schleife könnte mit einem Komma zu einer einzigen Anweisung
zusammengefasst und so in einer Zeile notiert werden. Allerdings wird's dann ein wenig unübersichtlich:
",($r * $s),"
"; ?>
Für den Anfang empfiehlt es sich, auf solche Verkürzungen zu verzichten und jeden Schritt in einer einzelnen Zeile zu schreiben. Damit ist der PHP-Teil der Aufgabe erledigt, nun kann man sich daran machen, die Ausgabe durch Optimierung des Codes noch ein wenig gefälliger zu gestalten, etwa durch Stylesheets den Zellen Hintergrundfarben zu geben und die Zelleninhalte rechtsbündig auszurichten. Natürlich können Sie mit dieser Schleife nicht nur das kleine Einmaleins, sondern praktisch jede gewünschte Multiplikationstabelle erzeugen. Dafür müssen Sie lediglich die Schleifenwerte entsprechend anpassen. Dabei können Sie nicht nur die Start- und Endwerte der Schleife verändern, sondern auch die Schrittweite und etwa nur jeden zweiten Wert berechnen lassen:
60
Funktionen
Selbstverständlich können Sie für die Schrittweite $s = $s + 2 auch die verkürzte Darstellung benutzen:
Durch Anpassung der Schleifenwerte können Sie beliebige Multiplikationstabellen erzeugen. Dabei ist PHP für die Inhalte der Tabelle zuständig, während ihre Gestaltung wie gewohnt in HTML erfolgt.
Funktionen Eine Funktion bezeichnet in PHP gewissermaßen ein Programm innerhalb des Programms zur Lösung häufig wiederkehrender Aufgaben oder Anforderungen. PHP besitzt bereits von Haus aus mehr als 1.000 Funktionen zur
61
Erledigung der unterschiedlichsten Aufgaben, ein paar davon wie isset(), htmlentities() oder date() haben wir bereits kennen gelernt. Außerdem können Sie beliebige Funktionen definieren, die auf Ihre individuellen Programmerfordernisse zugeschnitten sind. Eine Funktion wird durch ihren Namen und normalerweise mit einem Parameter in Klammern aufgerufen, der innerhalb der Funktion verarbeitet wird. Das Ergebnis wird anschließend von der Funktion an das aufrufende Script zurückgegeben. Dort wird es einer Variablen zugewiesen und kann so im Script weiter verarbeitet werden. Das klingt jetzt vielleicht etwas umständlich, aber die Beschreibung ist länger als der PHP-Code. So liefert die Funktion sqrt() die Wurzel eines übergebenen Wertes zurück, sqrt(4) ergibt also den Wert 2. Damit mit diesem Ergebnis aber weiter gearbeitet werden kann, muss man es einer Variablen zuweisen, als Text ausgeben oder als Bestandteil einer weiteren Berechnung benutzen:
Funktionen können natürlich auch mehr als einen Parameter besitzen, die man mit Komma getrennt an die Funktion übergibt. So ersetzt etwa die Funktion str_replace() in einer Zeichenkette (einem so genannten »String«) beliebige Zeichen durch andere Zeichen. Dabei werden der Funktion folgende Parameter übergeben: das (oder die) Zeichen, die ersetzt, das (oder die) Zeichen, die eingefügt und schließlich der String, in dem die Zeichen ausgetauscht werden sollen. Mit str_replace("e", "x", "Internet")werden folglich alle Buchstaben »e« im Wort »Internet« durch ein »x« ersetzt. Zugegeben, das ist jetzt kein sehr sinnvolles Beispiel, aber diese Funktion wird uns später noch oft und in sinnvolleren Kontexten begegnen. Möchten Sie zur Lösung einer bestimmten Aufgabe eine Funktion selbst definieren, so können Sie dies über die Anweisung function tun. Sie definieren die Funktion, indem Sie ihr einen Namen geben, die benötigten Parameter nennen und, natürlich, die Anweisungen definieren, die innerhalb der Funktion ausgeführt werden sollen. Diese Anweisungen stehen immer in Mengenklammern. So ist es problemlos möglich, den arithmetischen Befehlsvorrat von PHP durch eine Quadrat-Funktion zu ergänzen (PHP besitzt zwar eine Funktion,
62
Funktionen
um die Quadratwurzel eines Wertes zu ermitteln, aber keine, um eine Zahl zu quadrieren). Die Funktion soll »square()« heißen, mit einem Wert aufgerufen werden und dessen Quadrat zurückgeben:
Mit der Anweisung return gibt man einen Wert von der Funktion an das aufrufende Script zurück. Ein einfaches Beispiel soll den Einsatz selbstgemachter Funktionen verdeutlichen. Gültigkeit von Variablen
Variablen, die innerhalb einer Funktion benutzt werden, sind auch nur innerhalb der Funktion gültig. Eine Variable $zahl, die im Script benutzt wird, und eine Variable $zahl innerhalb einer Funktion sind für PHP zwei grundsätzlich verschiedene Werte.
Die Funktions-Definition wird üblicherweise an den Kopf des Dokuments gesetzt, im Script selbst kann die Funktion dann so benutzt werden wie jede andere Funktion auch. Das Beispielscript macht nun nichts anderes, als via get einen Wert entgegenzunehmen, ihn mit der Funktion square() zu quadrieren und die Berechnung auszugeben. Dabei wird die numerische Entity × benutzt, mit der sich ein Multiplikationszeichen darstellen lässt (was deutlich besser lesbar ist als der Einsatz von x oder *): Quadratfunktion
63
Wenn Sie eine Fließkommazahl übergeben möchten, müssen Sie statt des gewohnten Kommas einen Punkt notieren, also »12.1« statt »12,1«. Andernfalls wird der übergebene Wert als Zeichenkette, nicht als Zahl erkannt.
Variablentypen überprüfen Die selbstgeschriebene Funktion square() arbeitet wie erwartet, aber es gibt noch einen Schönheitsfehler: Wenn die mit get übergebene Variable $a kein numerischer Wert, sondern ein Text ist – etwa bei einem Aufruf mit
http://localhost/funktion.php?a=test dann wird das Quadrat von »test« gebildet. Das Script verarbeitet diese Eingabe zwar klaglos und wird als Ergebnis den Text »test × test = 0« ausgeben, aber sonderlich sinnvoll ist das nicht. Wir sollten also vor dem Funktionsaufruf überprüfen, ob ein numerischer Wert vorliegt.
1
Hier hilft uns die Funktion is_numeric(), die den Wert true zurückgibt, wenn die zu überprüfende Variable ein numerischer Wert ist, und false ergibt, wenn dies nicht der Fall ist. Damit können wir die Funktion als Bedingung in einer if-Konstruktion einsetzen, deren Anweisung ausgeführt wird, wenn die Variable numerisch ist, andernfalls – else – wird ein kurzer Hinweis angezeigt:
2
Wenn wir schon dabei sind, mögliche Eingabefehler abzufangen, dann können wir auch gleich mit isset($a)überprüfen, ob überhaupt ein Wert übergeben wurde. Wenn ja, dann wird die numerische Prüfung durchgeführt, wenn nicht, wird zur Eingabe eines Wertes aufgefordert. Das könnte dann so aussehen:
64
Menschen, nicht Maschinen
if (is_numeric($a)) echo "$a × $a = ",square($a); else echo "$a ist kein numerische Wert."; } else echo "Bitte einen numerischen Wert für a angeben."; ?> Die wichtigsten Variablen-Funktionen Funktion
Erläuterung
empty($a)
true, falls $a leer ist. Vorsicht, »0« gilt als »leer«!
isset($a)
true, falls $a existiert, wobei $a auch leer sein kann.
is_numeric($a)
true, falls $a ein numerischer Wert ist.
is_int($a)
true, falls $a ganzzahlig ist.
is_bool($a)
true, falls $a ein logischer Wert (boolean) ist.
is_float($a)
true, falls $a eine Fließkommazahl ist.
gettype($a)
Ermittelt den Typ der Variablen $a. Mögliche Rückgabewerte sind u. a.: boolean, integer, double und string.
settype($a,Typ)
Setzt den Typ der Variablen $a. Mit $a="1 Dutzend" ist $a vom Typ string. Nach settype($a,"integer") wird $a zu einer Integer-Variable mit dem Wert 1. Mögliche Werte für Typ sind u. a.: boolean, integer, double und string.
Menschen, nicht Maschinen: Brian Behlendorf
Brian Behlendorf aus dem sonnigen Südkalifornien schuf mit »Apache« den einflussreichsten und wichtigsten Webserver im Internet. Behlendorf studierte Anfang der neunziger Jahre an der Universität von Berkeley, Kalifornien, und gründete bereits 1993 – zwei Jahre vor dem großen Internetboom – zusammen mit Jonathan Nelson eine Webdesign-Firma. 1994 entwickelte er »Hotwired«, die Website für das Kult-Magazin »Wired«. Bei der Arbeit an Hotwired stellte man fest, dass die bisherigen Webserver nicht leistungsfähig genug waren und begann mit der Arbeit an einem eigenen Server, der auf den Namen Apache getauft und zu dessen professionellen Entwicklung im Februar 1995 die Apache Group gegründet wurde. Brian Behlendorfs private Homepage finden Sie hier: http://brian.behlendorf.com/
65
Kapitel 3
Ein Besucherzähler und anderes
In diesem Kapitel werden wir die bisher vorgestellten Verfahren im Praxiseinsatz testen, wobei Sie zusätzlich erfahren, wie Sie Formulare auswerten, Cookies einsetzen oder mit PHP Dateioperationen durchführen.
Ihr Erfolgsbarometer
Das können Sie schon: Sie haben Ihren lokalen Computer mit Xampp in einen Webserver mit PHP verwandelt und Ihre ersten Erfahrungen mit der Sprache gemacht.
16
Sie können in Ihren Programmen logische Entscheidungen treffen, Schleifen einsetzen und Funktionen definieren.
42
Das lernen Sie neu: Grundlegende Dateioperationen mit PHP
68
Den Besucherzähler als Grafik ausgeben
72
Wiederholungen ausfiltern mit Cookies
75
Ein Kennwortschutz für Webseiten
77
Externe Dateien einbinden
80
Ein Kontaktformular auf der Webseite
83
67
Drei Projekte für die Homepage Jetzt, wo wir den grundlegenden Einsatz von und den Umgang mit PHP kennen gelernt haben, wird es Zeit, PHP nicht nur in mehr oder weniger abstrakten Beispielen zu erproben, sondern im handfesten Praxiseinsatz an drei konkreten Projekten, die Ihnen etwas über die Besucher Ihrer Webseiten verraten.
•
Ein Besucherzähler: Wir schreiben ein kleines Script, das mitzählt, wie häufig eine Webseite aufgerufen wurde.
•
Passwortschutz: Ein einfaches Script sorgt dafür, dass erst nach Eingabe des richtigen Kennwortes eine Webseite dargestellt wird und Unbefugten der Zugriff verweigert wird.
•
Kontaktformular: Bieten Sie den Besuchern Ihrer Website die Möglichkeit, Ihnen über ein Formular eine Nachricht zu schicken.
Die wichtigsten Grundlagen zur Realisation dieser Projekte haben wir bereits kennen gelernt. Was wir allerdings noch nicht wissen, aber wissen müssen: Wie kann man mit PHP Daten in einer Datei speichern und bei Bedarf wieder auslesen?
Grundlegende Dateioperationen mit PHP Die Idee für den Besucherzähler ist denkbar einfach. In einer externen Datei »counter.txt« wird die Zahl der Besucherzugriffe gespeichert. Bei jedem Aufruf der Webseite lädt ein Script diese Zahl aus »counter.txt« und zeigt sie an. Anschließend wird sie um eins erhöht und wieder gespeichert. Bevor PHP auf eine Datei zugreifen kann, muss es die Datei öffnen. Dabei wird unterschieden, ob es sich dabei um einen Lese- oder Schreibzugriff handelt. Anschließend muss die geöffnete Datei wieder geschlossen werden. Die Arbeitsschritte, die unser Script erledigen muss, sehen also folgendermaßen aus:
1
Überprüfen, ob die Datei »counter.txt« existiert. Wenn nicht, dann muss diese Datei erzeugt und mit dem Wert 0 (oder einem anderen Startwert) initialisiert werden.
2
Die Datei »counter.txt« wird für den Lesezugriff geöffnet und der Wert ausgelesen. Der Wert wird der Variablen $counter zur späteren Verarbeitung übergeben. Anschließend wird die Datei geschlossen.
3
Der Wert wird um eins erhöht und die Datei »counter.txt« für den Schreibzugriff geöffnet. Die alte Zahl wird mit der neuen Zahl überschrieben, die Datei gespeichert und schließlich geschlossen.
68
Grundlegende Dateioperationen mit PHP
4 In der Variablen $counter und in der Datei »counter.txt« befindet sich nun der aktuelle Zählerstand.
Zum Öffnen einer Datei stellt PHP die Funktion fopen() zur Verfügung. Die Funktion erwartet zwei Parameter: Den Namen der zu öffnenden Datei und den Modus, in dem die Datei geöffnet werden soll. Dabei unterscheidet PHP drei unterschiedliche Zustände: Daten lesen (Parameter "r"), Daten schreiben (Parameter "w") und neue Daten anhängen (Parameter "a"). Die Funktion fopen()gibt nach dem Aufruf als Wert den so genannten Dateizeiger oder file-pointer zurück. Diesen Wert müssen wir beim Aufruf einer Variablen zuweisen, etwa $dz für Dateizeiger oder $fp für file-pointer. Alle anderen Dateioperationen benötigen anschließend diese Variable.
1
Widmen wir uns nun dem ersten Schritt, den unser Script abarbeiten muss. Um zu überprüfen, ob eine Datei existiert, gibt es die Funktion file_exists(), der man den Namen der zu prüfenden Datei übergibt.
2 Wenn die Datei bereits vorhanden ist, gibt die Funktion den Wert true zurück,
andernfalls den Wert false. Wir können diese Funktion also in einer if-Abfrage einsetzen und für den Fall, dass »counter.txt« nicht existiert, innerhalb der ifAbfrage die Datei anlegen und initialisieren: if (!file_exists("counter.txt")) { // Datei existiert nicht, neu anlegen und // initialisieren }
3
Für den Fall, dass »counter.txt« nicht existiert, muss sie neu angelegt werden. Dafür öffnen wir die Datei mit Schreibzugriff. PHP bemerkt, dass die Datei nicht existiert, in die geschrieben werden soll, und legt sie automatisch an: $dz = fopen("counter.txt","w");
Vorsicht!
Öffnen Sie eine existierende Datei mit dem Parameter "w", wird der Inhalt der Datei gelöscht und durch den neuen Inhalt ersetzt!
4
Um einen Wert in eine zum Schreiben geöffnete Datei zu schreiben, wird die Funktion fwrite() eingesetzt, der man den Dateizeiger und die zu schreibenden Daten übergibt. Um also in die neu angelegte Datei den Wert 0 zu schreiben, benötigen wir folgende Anweisung: fwrite($dz, "0");
69
5
Schließlich muss die immer noch geöffnete, neu angelegte Datei wieder geschlossen werden, wofür die Funktion fclose() benutzt wird, der man den Dateizeiger der zu schließenden Datei übergibt.
6
Setzen wir die einzelnen Schritte zusammen und benutzen, damit das Script etwas flexibler wird, für den Dateinamen eine Variable, so erhalten wir den folgenden Programmcode:
Dieser Einstieg sorgt dafür, dass die Datei $datei_name auf jeden Fall existiert und wir beim Lesezugriff keine Fehlermeldung erhalten.
7
Um die Datei für den Lesezugriff zu öffnen, benutzten wir fopen() mit dem Parameter "r". Nach dem Öffnen können Sie über verschiedene Funktionen den Inhalt der Datei auslesen. Für uns genügt vorerst die Funktion fread(), mit der Sie eine bestimmte Zeichenanzahl aus einer geöffneten Datei auslesen. Dazu übergibt man der Funktion den aktuellen Dateizeiger und die Anzahl der zu lesenden Zeichen.
8
Da wir wohl kaum in die Verlegenheit geraten werden, einen Zähler mit mehr als zehn Stellen auszulesen, können wir uns darauf beschränken, die ersten zehn Zeichen zu lesen und diesen Wert der Variablen $counter zuzuweisen. Zum Abschluss schließen wir die Datei wieder mit fclose():
9
Nun enthält die Variable $counter den letzten, aktuellen Stand des Besucherzählers. Um den aktuellen Aufruf mit zu zählen, wird sie mit $counter++; um eins erhöht und mit fwrite() in »counter.txt« gespeichert. Dazu öffnen wir die Datei erneut für den Schreibzugriff, speichern den neuen Wert und schließen die Datei.
70
Grundlegende Dateioperationen mit PHP
10 Setzen wir alle Teile des Scripts zusammen, so erhalten wir diesen ScriptBlock, den wir an den Anfang der HTML-Datei setzen, deren Aufrufe gezählt werden sollen:
11 Den Wert der Variablen $counter können wir nun an beliebiger Stelle im HTML-Code der Webseite über einfügen. Etwa so:
Guten Tag,
diese Seite wurde jetzt zum . Mal aufgerufen.
Mit einer Hand voll PHP-Code lässt sich schnell und unkompliziert ermitteln, wie oft eine Datei aufgerufen wurde.
71
Den Besucherzähler als Grafik ausgeben Der Besucherzähler funktioniert zwar tadellos, ist jedoch noch ein wenig langweilig. Wir können ihn aber problemlos aufpeppen, indem wir den Zählerstand nicht als einfachen Text, sondern als Grafik ausgeben. Dafür wird der Inhalt der Variablen $counter als Zeichenkette interpretiert und die Ziffern von links nach rechts der Reihe nach ausgelesen. Für jede Ziffer wird eine entsprechende Zahlengrafik eingefügt, die wir als Dateien »0.gif« bis »9.gif« im gleichen Verzeichnis wie das Script ablegen. Derartige Grafiken finden Sie im Internet auf unzähligen Seiten zum freien Download, Sie können sich Ihre Zahlengrafiken natürlich auch selbst anlegen. Alles, was wir für dieses Vorhaben benötigen, ist eine Funktion, mit der man eine String-Variable Zeichen für Zeichen untersuchen kann. Eine solche Funktion steht mit substr() zur Verfügung, die dazu dient, beliebige Teilstücke aus einer Zeichenkette zu lesen. Sie arbeitet mit drei Parametern: der Zeichenkette, der Startposition des Teilstücks und schließlich der Länge des Teilstücks. Wird der letzte Parameter nicht angegeben, so gibt substr() den Rest der Zeichenkette ab der Startposition zurück. Zu beachten ist hier nur, dass substr() – wie praktisch alle Funktionen in PHP – mit dem Zählen bei 0 beginnt. Mit
bekommt die Variable $dummy also drei Zeichen ab dem zweiten Zeichen von »Zeichenkette« zugewiesen. Nach dieser Anweisung besitzt die Variable den Wert »eic«, mit
wird $dummy der Wert »kette« zugewiesen.
1 Um den Inhalt von $counter zu analysieren, benötigen wir eine Schleife, in der die Variable $pos von 0 bis zum Ende der Zeichenkette gezählt wird und mit der wir über substr($counter, $pos, 1) jeweils ein Zeichen auslesen.
2 Die Länge von $counter ermitteln wir mit der Funktion strlen(). Der Funktion wird einfach der String übergeben, als Ergebnis erhält man die Anzahl der Zeichen in diesem String.
72
Den Besucherzähler als Grafik ausgeben
3 Mit dem folgenden Testscript ermittelt strlen() die Länge der Zeichenkette
$counter, die zur Kontrolle mit echo ausgegeben wird. Danach folgt eine forSchleife, in der mittels substr() jeweils ein Zeichen ausgelesen und mit Zeilenumbruch ( ) ausgegeben wird:
Nach diesem Test können wir uns an die Umsetzung der ursprünglichen Idee machen. Dabei wird eine switch-Anweisung benutzt, die in Abhängigkeit von der aktuellen Ziffer über das -Element die benötigte Grafik einbindet. Achten Sie darauf, dass die für die Pfadangabe zur Grafik benötigten Anführungszeichen innerhalb der echo-Anweisung mit dem Backslash \ maskiert werden müssen: "; case "1" : echo ""; case "2" : echo ""; case "3" : echo ""; case "4" : echo ""; case "5" : echo ""; case "6" : echo ""; case "7" : echo ""; case "8" : echo ""; case "9" : echo ""; } } ?>
Dieses Script löst zwar unsere Aufgabe, tut dies aber auf eine etwas plumpe Weise. So lässt sich die zehnzeilige switch-Anweisung stark vereinfachen, wenn wir uns klar machen, dass der aktuelle Wert von $ziffer auch als Teil des Dateinamens der benötigten Zifferngrafik interpretiert werden kann.
73
5 Wenn etwa der Wert von $ziffer »4« beträgt, dann wird die Grafik »4.gif« eingebunden, die wir in diesem Fall aber auch als echo "$ziffer.gif" notieren können. Damit lässt sich die Ziffernausgabe von zehn auf eine Zeile reduzieren:
"; }? >
6
Doch das Script hat immer noch einen kleinen Haken – der Zählerwert liegt nun nicht mehr als griffige Variable vor, sondern als mehrzeiliges Script, was den Einsatz in einem HTML-Code etwas umständlich macht.
7
Statt den Zähler also innerhalb der Schleife sofort auszugeben, setzen wir in der Schleife eine neue Zeichenkette $counter_grafik zusammen, die aus den benötigten -Elementen besteht und die dann an beliebiger Stelle im HTML-Code über ausgegeben werden kann.
8 Dazu muss $counter_grafik vor Beginn der Schleife initialisiert werden. Inner-
halb der Schleife wird dann mit dem Verkettungsoperator . die jeweilige Anweisung angehängt. Und wenn wir schon beim Vereinfachen der Anweisungen sind, setzen wir auch gleich den in Kapitel 1 erläuterten Zuweisungsoperator .= ein: "; } ?>
9
Diesen Teil können wir nun ebenfalls an den Anfang der HTML-Datei schieben, etwa im Anschluss an die Dateizugriffe, und innerhalb des eigentlichen HTMLCodes mit einem den Zähler als Grafik ausgeben:
Diese Seite wurde nun mal abgerufen
74
Wiederholungen ausfiltern mit Cookies
Mit einer Hand voll Zeilen mehr können Sie den Abrufzähler auch als Grafik darstellen.
Wiederholungen ausfiltern mit Cookies Es ist schon erstaunlich, welche Ergebnisse man mit ein paar PHP-Zeilen erzielen kann. Eines haben wir bei der bisherigen Arbeit allerdings kurzerhand unterschlagen: unser Besucherzähler – ist überhaupt kein Besucherzähler. Vielmehr handelt es sich um einen so genannten »Hitcounter«, also um einen Zähler, der angibt, wie oft eine Seite abgerufen wurde. Nun kann es aber sein, dass ein Besucher eine Seite mehrfach abruft, was den Zähler natürlich nach oben treibt, ohne dass es tatsächlich einen neuen Besucher gibt. Um das zu unterbinden, setzen wir einen so genannten temporären Cookie ein. Ein Cookie ist ein kleiner Datenschnipsel, den ein Webserver an den Browser schickt, um dort eine Markierung zu hinterlassen, an der der Server den Browser wieder erkennt. So ist es zum Beispiel möglich, wiederholte Zugriffe von der gleichen Person auszufiltern. Ein normaler Cookie wird vom Browser gespeichert, ein temporärer Cookie existiert dagegen nur so lange, wie das Browserfenster geöffnet ist und wird nicht gespeichert. Die Überlegung, um aus unserem Hitcounter einen echten Besucherzähler zu machen, ist folgende: Bei jedem Aufruf der Webseite wird, wie bisher auch, der aktuelle Zählerstand ausgelesen. Anschließend wird überprüft, ob ein Cookie vorhanden ist. Falls dies nicht der Fall ist, wird ein Cookie gesetzt, der Counter um eins erhöht und gespeichert. Doch falls ein Cookie vorliegt, handelt es sich um einen wiederholten Besuch. Der Counter muss nicht erhöht und auch nicht wieder gespeichert werden.
75
1
Ein Cookie ist im Prinzip eine Variable, der Sie mit der Funktion setcookie() einen Namen und einen Wert zuweisen. Um den Cookie »besucher« mit dem Wert »ja« zu setzen, benötigen Sie demnach folgende Anweisung:
2 PHP speichert alle Cookies in der Systemvariablen $_COOKIE. Ähnlich wie bei
$_GET handelt es sich dabei um ein so genanntes Array (zur Erinnerung: ein Array
bietet die Möglichkeit, verschiedene Variablen unter einem Namen zu speichern, wir werden uns später auführlich mit Arrays beschäftigen). Um auf einen Cookie zuzugreifen, lesen wir seinen Wert aus diesem Array aus, in dem wir den Namen des Cookies in einfachen Anführungszeichen und eckigen Klammern einsetzen: $besucher = $_COOKIE['besucher']
3 Um zu überprüfen, ob eine Variable existiert, benutzen wir wieder die Funktion
isset(), die ein false zurückgibt, wenn die Variable nicht gesetzt ist. Andernfalls, also wenn der Cookie $besucher existiert, liefert die Funktion isset($besucher) den Wert true.
4
Wenn wir das Funktionsergebnis negieren und in einer if-Abfrage einsetzen, können wir für den Fall, dass der Cookie $besucher nicht existiert (!isset($besucher)), den Zähler erhöhen.
5
Der komplette PHP- und HTML-Code des Besucherzählers sieht im Ganzen jetzt so aus:
76
Ein Kennwortschutz für Webseiten Jede Webseite, die Sie auf Ihren Webserver laden, kann in der Regel von jedem Websurfer im Internet eingesehen werden, das ist schließlich Sinn und Zweck einer Website. Doch nicht immer möchte man, dass jedermann auf alles zugreifen kann. Manche Informationen sind vertraulich oder nur für einen bestimmten Nutzerkreis bestimmt. In diesem Fall muss man dafür sorgen, dass die Daten nicht von unbefugten Zeitgenossen gelesen werden können. Die Lösung des Problems ist ein Kennwortschutz. Die Idee: Bevor die Informationen angezeigt werden, muss sich der Besucher mit Benutzernamen und Kennwort legitimieren. Ein PHP-Script überprüft die Eingaben und gibt erst dann den Weg frei, wenn die Daten korrekt sind. Damit der Besucher die Möglichkeit hat, Name und Kennwort einzugeben, benötigen wir ein einfaches Formular mit zwei Eingabefeldern.
1
Standardmäßig werden bei einem Formular die Daten mit get an den Server übertragen, also im Klartext in der Adresszeile des Browser angezeigt. Das ist für ein Kennwort natürlich nicht zu empfehlen. Setzen wir stattdessen post ein, werden die Daten unsichtbar übermittelt. Deklarieren wir außerdem noch das Eingabefeld für das Kennwort als type="password", hat ein neugieriger Zeitgenosse keine Chance mehr, einen zufälligen Blick auf das Kennwort zu werfen.
77
2 Ein schmuckloses Formular zur Abfrage von Name und Kennwort sieht also so aus:
3
Natürlich können Sie dieses Formular mit den üblichen HTML-Codes noch deutlich ansprechender gestalten, aber für unsere Zwecke soll das genügen.
4
Wenn Sie in dieses Formular Daten eintragen und mit einem Klick auf »OK« abschicken, passiert gar nichts. Zwar übermittelt das Formular die eingegebenen Daten an den Scriptteil der Formulardatei zur Auswertung zurück, aber da es noch kein Script zur Auswertung gibt, gibt es auch keine Reaktion. Aber das kann man ja ändern.
5 Bei älteren Browsern wie etwa Netscape 4.7 müssen Sie im "; if (isset($pass)) echo "Kennwort = $pass "; ?>
Das Auswertungsscript des Formulars macht noch nicht mehr, als die eingegebenen Daten zur Kontrolle auszugeben; aber für den Anfang ist das ja schon mal nicht schlecht.
Eingaben überprüfen Der erfolgreiche Testdurchlauf zeigt uns, dass die Datenübertragung vom Formular zum Script funktioniert, wir können uns nun daran machen, die eingegebenen Daten zu überprüfen. Die richtigen Werte für $user und $pass können wir einfach im Script deklarieren. Da der PHP-Code auf dem Server ausgeführt und nicht an den Webbrowser übermittelt wird, bekommt der Besucher diese Deklaration auch dann nicht zu Gesicht, wenn er sich den Quelltext der Seite anzeigen lässt. Über eine if-Abfrage vergleicht man die eingegebenen mit den korrekten Daten. Nur wenn sowohl die Eingabe für den Benutzernamen als auch das Kennwort korrekt sind, die logische Verknüpfung mit AND bzw. in der Kurzform mit && also den Wert true ergibt, werden die Anweisungen in der ifAbfrage ausgeführt.
79
In der Grundform zum Testen könnte das zum Beispiel so aussehen:
Nun sollten die Zugangsdaten zu einer Webseite regelmäßig geändert werden. In diesem Fall müssten wir die Variablen $user_ok und $pass_ok im Script ändern, was auf Dauer aber ein wenig umständlich ist. Angenehmer wäre es doch, wenn wir die Zugangsdaten in einer externen Datei, deklarieren und die Formularseite einfach in Ruhe lassen könnten. Obendrein gilt es ein potentielles Sicherheitsrisiko zu bedenken: Es ist denkbar, dass auf dem Webserver der PHP-Interpreter ausfällt und der Server das Script nicht interpretiert, sondern als Klartext direkt an den Browser schickt. Zugegeben, das kommt praktisch nicht vor, aber es ist möglich. In diesem Fall könnte der Besucher die korrekten Eingaben einfach im Script nachlesen, was nun nicht gerade Sinn und Zweck eines Kennwortschutzes ist. Auch hier empfiehlt es sich folglich, die korrekten Daten außerhalb des Formulars und der Auswertungsroutine zu definieren.
Externe Dateien einbinden Externe Dateien lassen sich mit PHP über die Anweisung include() einbinden. Dabei wird der Inhalt der angegebenen Datei vollständig an die Stelle des include()-Kommandos gesetzt. Vor der Ausführung der Anweisung wird der aktuelle PHP-Code vorübergehend beendet, der Inhalt der angegebenen Datei geladen und anschließend PHP wieder aktiviert und das Script an der Stelle fortgeführt, an der es mit include() unterbrochen wurde. Das bedeutet in der Praxis: Möchten Sie im eingefügten Teil PHP-Kommandos benutzen, dann müssen Sie diese wie gewohnt mit beenden. Andernfalls wird der Dateiinhalt als normales HTML betrachtet. Wenn wir so in einer externen Daten namens »zugang.php« die Zugangsdaten definieren –
80
Externe Dateien einbinden
– können wir diese in unserem Script über include("zugang.php") einbinden und sind damit in der Lage, in Zukunft Username und Passwort zu ändern, ohne das komplette Formular oder das Auswertungsscript bearbeiten zu müssen. Doch das Sicherheitsproblem bleibt bestehen: Wer den Namen der Datei mit der Variablendefinition kennt, kann die Datei unabhängig vom Formular oder Script direkt aufrufen und sich im Browser anzeigen lassen. Und wenn dann noch die PHP-Auswertung schief gehen sollte, war die ganze Kennwortmühe für die Katz. So unwahrscheinlich dieses Szenario auch ist – es ist nicht unmöglich, dass jemand einfach durch einen blöden Zufall über die eigentlich geheimen Daten stolpert. Include() und Pfadangaben
Die Funktion include() sucht standardmäßig im aktuellen Verzeichnis nach der einzubindenden Datei. Will man Dateien aus anderen Verzeichnissen einbinden, muss man eine relative Pfadnotierung benutzen. Mit include ("../inc/#_variablen.inc") greift man also auf die Datei #_variablen.inc zu, die, ausgehend vom übergeordneten Verzeichnis, im Verzeichnis »inc« zu finden ist.
2 Die Datei »menue.inc« kann nun in jede der vier Seiten, in denen das Menü
eingeblendet werden soll, mit einer include-Anweisung eingefügt werden; eine rudimentäre Webseite mit Menü sieht also zum Beispiel so aus:
Start
Dies ist die Seite, die über den Menüpunkt "Start" aufgerufen wird.
115
Auf dem Weg zu einem intelligenten Menüsystem – noch erkennt die Menüroutine nicht, in welcher Umgebung sie steht und zeigt auch redundante Links (wie hier zum Menüpunkt »Start«) an.
Bislang werden von der Ausgaberoutine alle Menüeinträge als Link markiert, ganz gleich, ob das notwendig ist oder nicht. Um das zu ändern, muss das Script wissen, in welches Dokument es aktuell eingebunden wurde. Dann kann es den aktuellen Dateinamen mit dem Sprungziel im Menü vergleichen und, sollten die beiden identisch sein, den Menüeintrag ausgeben, ohne ihn zu verlinken.
3 Hier hilft uns die Systemvariable $_SERVER weiter. Dabei handelt es sich um ein assoziatives Array, in dem die verschiedensten Systemwerte abgelegt sind. Über
$_SERVER['PHP_SELF'] erhalten wir etwa den aktuellen Dateinamen inklusive des
Pfades vom Wurzelverzeichnis aus. Wir benötigen allerdings nur den reinen Dateinamen, den uns die Funktion basename() liefert.
4 Wir müssen in der Ausgabeschleife nur den Dateinamen mit base-
name($_SERVER['PHP_SELF']) vergleichen. Stimmen die beiden nicht überein, dann ist die aktuelle Seite nicht identisch mit dem Menüeintrag, der Menüeintrag muss verlinkt werden.
116
Ein intelligentes Menüsystem
5
Andernfalls ist die aktuelle Seite genau die, die über den Menüpunkt erreicht werden soll, hier müssen wir also auf den Link verzichten. Stattdessen ändern wir die Hintergrundfarbe, um den aktuell gewählten Menüeintrag hervorzuheben.
6 Die vollständige Datei »menue.inc« sieht schließlich so aus: "start.php", "Texte" => "texte.php", "Bilder" => "bilder.php", "Info" => "info.php" ); ?>
$datei){ if ($datei == basename($_SERVER['PHP_SELF'])) { echo "
7 Wenn Ihnen das zu viele echo-Anweisungen sind, dann können Sie die foreach-Schleife auch auf zwei Zeilen zusammenkürzen, indem Sie den auszugebenden Text zu einer Zeichenkette zusammenfassen und direkt hinter die if- bzw. else-Anweisung ohne Mengenklammer ausgeben. Allerdings ist der Preis für den
kompakten Code eine gewisse Unübersichtlichkeit: $datei){ if ($datei == basename($_SERVER['PHP_SELF'])) echo "
Ergänzt man das Ausgabescript um eine Abfrage des aktuellen Dateinamens, so erkennt die Menüroutine nun automatisch, in welches Dokument sie eingebunden wurde, verzichtet auf redundante Links und hebt den aktuell gewählten Menüpunkt hervor.
118
Menschen, nicht Maschinen
Menschen, nicht Maschinen: Bruce Perens
Bruce Perens ist einer der einflussreichsten und wichtigsten Personen der Open-Source-Bewegung. Mit seinem Artikel »The Open Source Definition« hat er gewissermaßen das Manifest zur Bedeutung der freien Software geschrieben. Sein erstes eigenes freies Programm brachte er 1987 unter dem Namen »Electric Fence« heraus. Übrigens: Wenn Sie sich das nächste mal »A Bug's Life« oder »Toy Story 2« anschauen, dann achten Sie auf den Abspann – Sie werden dort den Namen Bruce Perens als Software Engineer, bzw. als Animation Software Engineer entdecken. Seine Homepage finden Sie unter der Adresse http://perens.com/.
119
Kapitel 5
Datenbanken mit MySQL und PHPMyAdmin
Mit einer Datenbankanbindung an MySQL stoßen Sie in völlig neue Dimensionen vor. Dank PHPMyAdmin ist der Einstieg in den Umgang mit Datenbanken auch für Einsteiger problemlos möglich.
Ihr Erfolgsbarometer
Das können Sie schon: Sie haben Ihren lokalen Computer mit Xampp in einen Webserver mit PHP verwandelt und Ihre ersten Erfahrungen mit der Sprache gemacht.
16
Sie können in Ihren Programmen logische Entscheidungen treffen, Schleifen einsetzen und Funktionen definieren.
42
Am Beispiel von drei Praxisprojekten haben Sie gelernt, wie Sie Daten in Dateien speichern, Cookies einsetzen und Formulare auswerten.
66
Sie haben die mächtigen Einsatzmöglichkeiten von numerischen und assoziativen Arrays kennen gelernt.
92
Das lernen Sie neu: Warum eigentlich eine Datenbank?
122
PHPMyAdmin
123
Kopfüber in die Datenwelt
128
Mit PHP auf MySQL-Daten zugreifen
133
Datensätze ändern
137
Tabellenstruktur ändern
141
Tabellen sichern, löschen und importieren
145
121
Warum eigentlich eine Datenbank? Eine Datenbank erlaubt die strukturierte Speicherung und Verwaltung beliebiger Daten. Dabei werden unterschiedliche Werte – etwa Name, Vorname oder Geburtsdatum einer Person – in einzelnen Feldern gespeichert, zusammengehörige Felder bilden einen Datensatz, mehrere, gleichstrukturierte Datensätze eine Tabelle und mehrere, verschieden strukturierte und inhaltlich voneinander unabhängige Tabellen eine Datenbank. Der Datenbestand wird vom Datenbankprogramm nach bestimmten Regeln so gespeichert und verwaltet, dass ein gezielter Zugriff auf ausgewählte Daten möglichst effizient und schnell möglich ist. Typische Anwendungsgebiete von Datenbanken sind etwa die Speicherung mehr oder weniger umfangreicher Adresssammlungen, die Organisation unterschiedlichster Lagerbestände vom Weinkeller bis zur Bibliothek oder eine Auftrags- und Warenverwaltung. Nun werden Sie sich vielleicht fragen, was Sie mit einer Datenbank oder selbst auch nur einer Tabelle sollen. Ihre Adressen verwalten Sie mit einem lokalen Programm, Sie müssen keinen Warenverkehr überwachen, eine Auftragsverwaltung brauchen Sie vielleicht auch nicht und vermutlich sind auch Ihre Wein-, Buch-, CD-, Video- oder DVD-Bestände nicht so umfangreich, dass Sie sie nun unbedingt mit einer komplizierten Datenbank verwalten müssten. Doch auch für private Webseitenkonstrukteure sind Datenbanken der Schlüssel zur ungeahnt flexiblen und leistungsfähigen Webseite. Denn in einer Datentabelle können Sie natürlich nicht nur Adressen oder Warenbestände organisieren, sondern schlechterdings alles, was sich in irgendeiner Form digitalisieren lässt. Mit einer Datenbank können Sie Ihre Webseite zum Beispiel problemlos um ein Gästebuch erweitern, Sie können eine Logdatei anlegen und den Besucherverkehr statistisch auswerten oder Sie publizieren auf Ihrer Webseite Ihr digitales Tagebuch mit Notizen, Einfällen und Fundstücken aus dem Netz. Bei einem solchen so genannten »Blog« erfassen Sie den zu publizierenden Text in einem Webformular, speichern ihn in einer Tabelle und überlassen es schließlich PHP & HTML, Ihre Einträge sauber formatiert als Ihre Webseite im Internet zu publizieren. Um mit Datenbanken arbeiten zu können, benötigen Sie einen Datenbankserver, der die Datenbank verwaltet. Hier hat sich MySQL als Standardserver in vielen Bereichen durchgesetzt. PHP ist von Haus aus auf die Kooperation mit den Datenbeständen eines MySQL-Servers ausgelegt und bei praktisch allen Webhostern gehört mindestens eine MySQL-Datenbank zum Standardangebot. Da Sie in einer Datenbank praktisch beliebig viele, unterschiedliche
122
PHPMyAdmin
und voneinander unabhängige Tabellen anlegen können, reicht eine Datenbank für die meisten Anwendungen in der Webpraxis aus. Normalerweise sind Datenbanken eine sehr komplexe Angelegenheit, die viel planende Arbeit verlangt, und ihr Einsatz gehört nicht unbedingt zu den Dingen, die man sich freiwillig ans Bein binden sollte. Normalerweise. Mit MySQL sieht das allerdings anders aus. Nicht, dass MySQL nun ein besonders triviales oder anspruchsloses System für den privaten Hausgebrauch wäre, ganz im Gegenteil. MySQL nimmt es mit den Großen der Branche auf und spielt in der gleichen Liga wie die Datenbanken von Oracle, Sybase & Co. Da wirkt der Einsatz von MySQL auf einer privaten Website fast schon so wie das sprichwörtliche Kanonenschießen auf Spatzen – was Ihnen aber völlig egal sein kann. MySQL ist ein sehr gutmütiges System und trotz seiner immensen Fähigkeiten durchaus auch für Einsteiger geeignet. Die Fähigkeiten von MySQL im Umgang mit riesigen Datenmengen und komplizierten Verknüpfungen verbieten es ja nicht, das System auch zur Lösung bescheidenerer Aufgaben einzusetzen. Natürlich sollten Sie einen Datenbankeinsatz planen, aber wenn Sie es nicht tun und einfach frohgemut anfangen, legt Ihnen MySQL auch keine überflüssigen Steine in den Weg. Die Strukturen Ihrer Datentabellen lassen sich jederzeit ändern, anpassen, erweitern und nahezu beliebig manipulieren. Im Grunde benötigen Sie nur eine Hand voll MySQL-Kommandos, um sich Ihre alltägliche Webarbeit drastisch zu erleichtern. Wenn Sie es dann später doch einmal etwas genauer wissen wollen, können Sie sich beliebig tief in die Materie eingraben – aber Sie müssen es nicht, um Ihre Homepage datenbankbasiert zu publizieren.
PHPMyAdmin Der normale Weg beim Aufbau einer Datenbank bzw. einer Tabelle ist dieser: Sie skizzieren die Struktur der benötigten Tabelle und machen sich klar, welche und wie viele Felder mit welchen Eigenschaften Sie genau benötigen. Anders als bei PHP spielen bei MySQL übrigens die Feldtypen eine Rolle, es ist zum Beispiel nicht möglich, in einem Feld, das für Fließkommazahlen gedacht ist, eine Zeichenkette zu speichern. Nachdem die Struktur steht, weisen Sie MySQL durch bestimmte Kommandos an, diese Tabelle zu erstellen. Anschließend können Sie über ein Formular – das Sie natürlich erst einmal in HTML erstellen und mit einem PHP-Script auswerten müssen – Daten in die Tabelle schreiben und über bestimmte Kommandos wieder auslesen.
123
Das Verfahren ist nicht ganz so kompliziert, wie es vielleicht klingen mag, aber immer noch kompliziert genug, um sich nicht immer mit jedem Detail beschäftigen zu wollen. Hier setzt das Programm PHPMyAdmin an. Damit sind Sie in der Lage, in kürzester Zeit eine Datentabelle in Betrieb zu nehmen, ohne sich auch nur einmal mit der Frage beschäftigen zu müssen, wie eine Datenbank angelegt wird oder wie Sie Daten in Ihre Tabellen bekommen. Denn das übernimmt zum größten Teil PHPMyAdmin. Wie der Name schon sagt, handelt es sich dabei um ein Programm zur Administrierung bzw. Verwaltung von MySQL-Datenbanken, das vollständig in PHP geschrieben ist. Mit dem Programm können Sie alle notwendigen Datenbankoperationen vornehmen und es bietet obendrein eine einfache Maske zur Eingabe und Bearbeitung von Daten, so dass Sie zumindest für einfache und überschaubare Datenbestände keine eigenen Formulare schreiben müssen. Das gilt natürlich nur, solange Sie allein Daten eingeben und verändern. Sobald Sie den Besuchern Ihrer Webseite diese Möglichkeit – etwa in einem Gästebuch oder Diskussionsforum – geben möchten, kommen Sie um ein Formular und seine Auswertung nicht mehr herum.
Mit PHPMyAdmin wird die Verwaltung von MySQL-Datenbanken und Tabellen so drastisch vereinfacht, dass auch Einsteiger mit MySQL arbeiten können.
124
PHPMyAdmin
Bei vielen Webhostern ist PHPMyAdmin bereits installiert, darum müssen Sie sich nicht mehr kümmern. Sollte das nicht der Fall sein, können Sie das Programm von den Webseiten unter www.phpmyadmin.net herunterladen und in Ihrem Webverzeichnis installieren (wie fast alle zentralen Tools und Programme aus dem PHP- und MySQL-Umfeld ist auch PHPMyAdmin ein Projekt der Open-Source-Szene und kann kostenlos eingesetzt werden). Die Installation besteht lediglich darin, alle Dateien in einem eigenen Verzeichnis auf dem Server zu entpacken und in der Datei »config.inc.php« ein paar Parameter anzupassen – welche das sind, hängt von Ihrem MySQLServer ab, normalerweise nennt Ihnen Ihr Provider die benötigten Angaben, sobald Sie eine MySQL-Datenbank haben. Bei Xampp ist PHPMyAdmin natürlich vorinstalliert und kann über http://localhost/phpmyadmin/ aufgerufen werden.
PHPMyAdmin liegt in verschiedenen Sprachen vor und kann mit einem Mausklick auf eine deutschsprachige Benutzeroberfläche umgeschaltet werden.
Beim ersten Start begrüßt Sie PHPMyAdmin mit einer großen Warnung und fordert Sie auf, die Passwörter und Benutzerrechte für die Zugriffe auf den MySQL-Server zu kontrollieren. Wenn Sie – wie in Kapitel 1 empfohlen – Xampp nur dann starten, wenn Sie offline sind, dann können Sie diese War-
125
nung zwar getrost ignorieren, aber störend ist sie ja doch. Räumen wir die Zugriffsrechte also ein wenig auf.
Zu Beginn sollten Sie einfach klar Schiff machen und die nicht benötigten MySQLBenutzer löschen.
1
Klicken Sie auf den Link »Rechte«, um in die »Benutzerübersicht« zu gelangen. Von den aufgelisteten Benutzern benötigen Sie nur »pma« und »root« mit dem Host »localhost«.
2
Markieren Sie die nicht benötigen Benutzereinträge. Aktivieren Sie den Punkt »Die Benutzer aus den Benutzertabellen löschen« und klicken Sie auf »OK«.
Damit ist ein ungeschützter Zugriff von außen auf den MySQL-Server nicht mehr möglich, nur noch die Benutzer »pma« und »root« dürfen von der lokalen Maschine aus mit dem MySQL-Server interagieren. Geben Sie dem Benutzer »root« nun noch ein Kennwort, ist der Zugriff so sicher, wie er nur sein kann.
Nach der Aufräumaktion gibt es nur noch den Benutzer »pma« und »root« mit Zugriff vom »localhost« (also Ihrem Computer).
126
PHPMyAdmin
3
In der »Benutzerübersicht« sind nach der vorhergehenden Löschaktion nur noch die Benutzer »pma« und »root« am Host »localhost« eingetragen. Klicken Sie beim Eintrag für den Benutzer »root« nun in der Spalte »Aktion« auf den Link »Bearbeiten«.
Ein Benutzer, der sämtliche Rechte besitzt, sollte niemals ohne Kennwort betrieben werden.
4
Tragen Sie im Formularabschnitt »Kennwort ändern« ein Kennwort für den Benutzer »root« ein und bestätigen Sie es mit einem Klick auf »OK«.
Sobald Sie das Kennwort für »root« geändert haben und in PHPMyAdmin etwas unternehmen wollen, steigt das Programm spätestens beim nächsten Start mit einer Fehlermeldung aus. Doch kein Grund zur Sorge. PHPMyAdmin führt zwar die Benutzerkonfiguration für den MySQL-Server durch, ist aber nicht in der Lage, seine eigene Konfigurationsdatei entsprechend anzupassen. Da müssen wir ein wenig nachhelfen und das geänderte Passwort eintragen.
5
Laden Sie die Datei »config.inc.php« in Ihren Texteditor. Sie finden die Datei in Ihrem Xampp-Verzeichnis im Ordner »phpmyadmin«.
In der Datei config.inc.php definieren Sie die Zugriffsparameter für PHPMyAdmin. Diese Einträge müssen Sie normalerweise auch anpassen, wenn Sie PHPMyAdmin in Ihrem Webverzeichnis bei einem Provider installieren.
127
6 Suchen Sie nach der Zeile $cfg['Servers'][$i]['user'] = 'root';. Diese Zeile leitet drei Variablen-Definitionen ein, in denen der Authentifizierungs-Typ, der Username und das zu dem Usernamen gehörende Kennwort definiert werden.
7 Als Authentifizierungs-Typ ist standardmäßig 'config' eingestellt und als Username 'root' eingetragen. Sie müssen lediglich in der dritten Zeile das von Ihnen gewählte Kennwort eintragen. Lautet das zum Beispiel »test«, dann sehen die drei Zeilen wie folgt aus:
Speichern Sie die geänderte Datei und aktualisieren Sie die Browseranzeige für PHPMyAdmin. Nun ist der Benutzer »root« mit vollem Zugriffsrecht kennwortgeschützt eingetragen, ein ungeschützter Zugriff von außen ist nun nicht mehr möglich und der Warnhinweis ist verschwunden.
Kopfüber in die Datenwelt Im Folgenden soll die Behauptung belegt werden, dass Sie mit MySQL einfach drauflos datenbanken können, ohne so ganz genau zu wissen, was Sie da eigentlich tun. Wir werden mit PHPMyAdmin eine Datenbank anlegen, in dieser Datenbank eine Tabelle erzeugen, ein paar Werte eingeben und sie danach mit einem PHP-Script auslesen und als Webseite anzeigen. Anschließend werden wir die einfache Tabellenstruktur nachträglich erweitern und die gespeicherten Daten mit PHP den geänderten Strukturen anpassen.
1
Der erste Schritt ist nur bei einer lokalen Konfiguration nötig und möglich: Sie müssen eine Datenbank anlegen, in der Sie später die Datentabellen einrichten. Dieser Schritt entfällt natürlich bei einem Webhoster, bei dem Sie eine MySQLDatenbank zur Verfügung gestellt bekommen und nur eingeschränkte Zugriffsrechte auf den MySQL-Server haben.
128
Kopfüber in die Datenwelt
Bei einem Webhoster haben Sie normalerweise keine Zugriffsrechte, um Datenbanken anzulegen oder zu löschen, sondern bekommen ein vorkonfiguriertes System. Bei einer lokalen Xampp-Installation sind Sie dagegen König und haben alle Zugriffsrechte, die es gibt.
2
Geben Sie auf der Startseite von PHPMyAdmin einen neuen Datenbanknamen ein (hier: »test_datenbank«) und klicken Sie auf »Anlegen«. Das war's schon. PHPMyAdmin wechselt automatisch zur neuen Datenbank, in der Sie nun eine Tabelle anlegen können.
Vorsicht beim Löschen von Datenbanken
Xampp legt einige Testdatenbanken an, die Sie eigentlich löschen können. Doch das sollten Sie nicht tun, sonst funktionieren anschließend die Xampp-Beispiele nicht mehr, was schade wäre. Schlimmer noch: Die Datenbanken »mysql« oder »webauth« verwalten wichtige Systemdaten, ohne die gar nichts geht. Am besten ist es, wenn Sie die Xampp-Datenbanken einfach in Ruhe lassen.
Wie gesagt: Eine Tabelle besteht aus mehreren Feldern, die zusammen einen Datensatz ergeben. Bei den folgenden Schritten macht es übrigens keinen Unterschied mehr, ob Sie eine lokale Installation von MySQL benutzen oder eine Datenbank bei einem Webhoster, der Ablauf bleibt gleich.
129
Eine Datenbank besteht aus beliebig vielen, unterschiedlich strukturierten Tabellen. Die Tabellendefinitionen lassen sich jederzeit mit wenigen Mausklicks ändern.
3
Zum Anlegen einer Tabelle müssen Sie PHPMyAdmin einen Namen für die Tabelle und die Anzahl der benutzten Felder angeben. Beide Angaben können später beliebig verändert werden. Wählen Sie einen Tabellennamen (hier: »test_tabelle«), tragen Sie als Feldanzahl eine »2« ein und klicken Sie auf »OK«. Sie sehen nun die Eingabemaske zur Definition der beiden Felder.
Eine Tabelle besteht aus mindestens einem Feld. Anders als bei der Variablen-Definition in PHP müssen Sie sich bei einer Tabelle relativ genau überlegen, welche Art von Daten Sie in den Feldern ablegen möchten.
4
Tragen Sie als Namen für das erste Feld »id« ein. Dies wird unser Index, also eine eindeutige Nummer, an der MySQL den dazugehörigen Datensatz identifizieren kann. Im zweiten Feld sollen beliebige Namen abgelegt werden, wir nennen das Feld der Einfachheit halber »name«.
5
Wie weiter oben schon erwähnt, müssen Sie bei einer Datenbank jedem Feld einen Datentyp zuweisen. Da der Index ein ganzzahliger, numerischer Wert ist, wählen wir unter »Typ« den Eintrag »INT«. Beim zweiten Feld »name« wählen wir »VARCHAR« und legen als »Länge» den Wert »100« fest.
130
Kopfüber in die Datenwelt
INT und VARCHAR
INT und VARCHAR sind wohl die beiden häufigsten Feldtypen bei MySQL. »INT« ist die Abkürzung für »Integer«, also »ganze Zahl«. Ein Feld vom Typ INT kann ganzzahlige Werte von rund -2,1 bis +2,1 Milliarden aufnehmen. Eine Längenangabe ist nicht zwingend erforderlich. »VARCHAR« ist eine Abkürzung für »variable« und »character«. Ein Feld vom Typ VARCHAR kann unterschiedlich viele Zeichen aufnehmen. Wie viele maximal hineinpassen, müssen Sie über die »Länge« angeben. Ein VARCHAR-Feld kann maximal 255 Zeichen enthalten.
Um an alle Einstellungsmöglichkeiten der Felddefinitionen zu gelangen, müssen Sie ein wenig nach rechts scrollen.
6
Legen Sie nun noch für das »id«-Feld unter »Extras« ein »auto_increment« fest. Dann zählt MySQL diesen Wert, beginnend bei 1, mit jedem neuen Eintrag selbst hoch, ohne dass wir uns darum kümmern müssten. Aktivieren Sie abschließend die Option »Primärschlüssel«.
Eine neue Tabelle ist mit PHPMyAdmin im Handumdrehen angelegt. Da praktisch alle Eigenschaften jederzeit geändert und angepasst werden können, kann man ganz klein anfangen und Tabellenstrukturen in MySQL später mitwachsen lassen.
131
7
Klicken Sie auf die Schaltfläche »Speichern«. Die neue Tabelle wird innerhalb der Datenbank »test_datenbank« angelegt und angezeigt. In einem kleinen Fenster wird zur Information noch der MySQL-Code eingeblendet, der ausgeführt wurde, um die Tabelle mit den gewünschten Eigenschaften anzulegen.
Nachdem die Tabelle erzeugt wurde, müssen Sie nun noch ein paar Daten eingeben. In diesem Beispiel werden es Schauspielernamen aus dem Film »Casablanca« sein, Sie können natürlich auch völlig andere Namen benutzen.
8
Klicken Sie auf den Karteireiter »Einfügen«. Es wird nun das Eingabeformular angezeigt. Um das Feld »id« müssen wir uns nicht kümmern, hier sorgt MySQL selbst dafür, dass ein fortlaufender, eindeutiger Indexwert eingetragen wird.
Über die einfachen, aber funktionalen Formulare von PHPMyAdmin lassen sich problemlos Werte in eine Tabelle eintragen.
9
Tragen Sie einen Wert für »name« ein (hier: Humphrey Bogart). Da wir noch mehr Namen eintragen wollen, aktivieren Sie die Option »anschließend einen weiteren Datensatz einfügen« und klicken auf »OK«.
10 Geben Sie auf die beschriebene Weise eine Hand voll Namen ein. Nach
jeder Eingabe wird der ausgeführte MySQL-Code angezeigt. Klicken Sie schließlich auf den Karteireiter »Anzeige«. Nun sehen Sie eine tabellarische Übersicht aller bisher eingegebenen Datensätze. Da die Datensätze derzeit nur aus einer Indexnummer und einem Namen bestehen, sieht das alles noch nicht sehr spektakulär aus, aber das macht ja nichts.
132
Mit PHP auf MySQL-Daten zugreifen
In der Anzeige der Tabelle haben Sie jederzeit Zugriff auf beliebige Datensätze, die Sie mit einem Klick auf das entsprechende Symbol (Notizblock oder Mülleimer) bearbeiten oder löschen können.
11 Damit ist die erste Tabelle bereits angelegt. Gehen wir nun daran, die Daten in einem PHP-Script auszulesen und auszugeben.
Mit PHP auf MySQL-Daten zugreifen Bevor Sie mit PHP auf die Daten in einer Tabelle zugreifen können, müssen Sie zuerst eine Verbindung zum Datenbankserver aufbauen und die Datenbank öffnen, auf deren Tabelle Sie mit den nächsten Kommandos zugreifen möchten. Den Kontakt zur Datenbank nehmen Sie mit der Funktion mysql_connect() auf, der Sie die Werte für den Hostnamen des Servers, Ihren Usernamen und Ihr Passwort übergeben. Die benötigten Angaben erfahren Sie von Ihrem Provider, bei einer lokalen Konfiguration mit Xampp ist der Hostname »localhost«, die übrigen Angaben haben Sie in PHPMyAdmin selbst festgelegt. Ähnlich wie beim Öffnen einer Datei liefert auch diese Funktion einen Zeiger zurück, der bei den späteren Datenbankzugriffen benötigt wird. Wir speichern diesen Zeiger in der Variablen $dz (für Datenbankzeiger). Sobald die Verbindung zum Server besteht, wählen Sie über die Funktion mysql_select_db() die gewünschte Datenbank aus. Dieser Funktion wird der Name der Datenbank und der Datenbankzeiger übergeben.
133
Für den Fall, dass Sie als Benutzer »root« mit dem Passwort »test« arbeiten, sieht der benötigte PHP-Code zur Kontaktaufnahme mit dem MySQL-Server also so aus:
Da Sie diesen Code-Schnipsel in praktisch jedem PHP-Code benötigen, der auf Tabellen in Ihrer Datenbank zugreift, empfiehlt es sich, ihn als externe Datei wie »mysql.inc« zu speichern und später über
zu Beginn der entsprechenden Datei einzubinden. Sobald eine Verbindung zum Server besteht und die Datenbank geöffnet ist, können wir Anfragen (»queries«) an den Server schicken, mit dem wir bestimmte Daten aus bestimmten Tabellen anfordern (»selektieren«). Als Antwort auf unsere Anfragen stellt der Datenbankserver die gewünschten Daten abholbereit in den Speicher. Bei den Anfragen an den Server wird eine formalisierte Sprache mit bestimmten Regeln und Eigenheiten benutzt. Eines der grundlegenden MySQL-Kommandos ist SELECT, also »wählen, selektieren«, mit dem wir auf Daten einer Tabelle zugreifen können. Diesem Kommando können diverse Parameter und Werte übergeben werden, wir beschränken uns vorerst darauf, alle Felder – symbolisiert durch das Jokerzeichen * – aus (FROM) der Tabelle »test_tabelle« anzufordern. Das Kommando »Wähle alle Felder aus der Tabelle test_tabelle« sieht in MySQL somit folgendermaßen aus: SELECT * FROM test_tabelle
Ein solches Kommando heißt auch Anfrage oder Query und die PHP-Funktion, mit der wir eine Anfrage an einen MySQL-Server schicken, trägt dementsprechend den Namen mysql_query(). Die Funktion liefert einen Zeiger zurück, den wir in einer Variablen $sql speichern und für weitere Zugriffe benötigen. $query = "SELECT * FROM test_tabelle"; $sql = mysql_query($query);
134
Mit PHP auf MySQL-Daten zugreifen
Natürlich können Sie die beiden Zeilen zu einer zusammenfassen und auf die Deklaration von $query verzichten: $sql = mysql_query("SELECT * FROM test_tabelle");
Nun liegen die angeforderten Werte abholbereit im Speicher des Servers, der Zeiger $sql zeigt auf den nächsten Eintrag, wir müssen die Daten nur noch auslesen. Dazu gibt es verschiedene Methoden, in unserem Fall ist mysql_fetch_object() am besten geeignet. Diese Funktion benötigt als Parameter den aktuellen Wert von $sql und liefert den Wert false zurück, wenn das Ende des aktuellen Abfrage-Ergebnisses erreicht ist. Andernfalls weist es den aktuellen Datensatz einer so genannten Objektvariablen zu. Dabei handelt es sich um einen bestimmten Variablentyp, der uns bislang noch nicht begegnet ist und den wir im Rahmen dieses Buches auch nicht allzu ausführlich besprechen werden. Eine Objektvariable können Sie sich ein wenig so wie ein assoziatives Array vorstellen. In dieser Variablen liegen die angeforderten Werte des aktuellen Datensatzes und können über die Anweisung $objekt -> feldbezeichner
einer normalen Variablen zugewiesen werden.
1
Die folgende kleine while-Schleife liest also so lange die bereit gestellten Daten, bis das Ende des Abfrage-Ergebnisses erreicht ist und ordnet den jeweils aktuellen Datensatz der Objektvariablen $ds zu. In der Schleife werden die Werte von id und name zwei Variablen zugewiesen, die anschließend als eine Zeile ausgegeben werden: while ($ds = mysql_fetch_object($sql)){ $id = $ds -> id; $name = $ds -> name; echo $id," ", $name," "; }
2
Nach Abschluss der Schleife wird die Verbindung zum Datenbankserver wieder beendet: mysql_close($dz);
3
Setzen wir nun die Puzzleteile zusammen, so erhalten wir das folgende Script, mit dem wir die Daten aus der Tabelle »test_tabelle« auslesen und zeilenweise ausgeben:
Das Ergebnis ist natürlich noch genauso unspektakulär wie unsere Tabelle selbst, aber eine kleine Änderung der Abfrage deutet bereits an, was nun möglich ist.
4
Wir ändern die SELECT-Anweisung so, dass uns der MySQL-Server die gewünschten Daten bereits nach Namen sortiert liefert. Dafür ergänzen wir die Anweisung lediglich um ORDER BY name. Die Anfrage an den Server lautet also nun »Wähle alle Felder aus der Tabelle test_tabelle aus und sortiere sie nach dem Inhalt im Feld name«. Anders gesagt: $query = "SELECT * FROM test_tabelle ORDER BY name";
MySQL kann Ihnen die Daten auch vorsortiert liefern, so dass Sie sie nur noch auslesen müssen.
136
Datensätze ändern
5
Wenn Sie die kleine Testdatei speichern und aufrufen, werden die Einträge alphabetisch nach dem Feld »name« sortiert angezeigt, ohne dass Sie den PHPCode hätten ändern müssen.
Datensätze ändern Bei der sortierten Ausgabe stellen wir nun allerdings fest, dass wir die Namen doch besser in der Reihenfolge »Nachname, Vorname« hätten speichern sollen. Das können wir nun in PHPMyAdmin manuell bewerkstelligen und Eintrag für Eintrag ändern; wir können es aber auch über ein kleines Script erledigen, das den Namen ausliest, nach dem Muster »Nachname, Vorname« ändert, zurückschreibt und das Ergebnis zur Kontrolle als Webseite ausgibt. In unserem Beispiel enthält die Variable $name den zu ändernden Namen. Der Nachname steht innerhalb von $name nach dem letzten Leerzeichen (»letztes Leerzeichen« deshalb, weil ein Name ja mehrere Vornamen und damit auch mehrere Leerzeichen enthalten kann). Entsprechend ist der Vorname (bzw. sind die Vornamen) alles, was innerhalb von $name vor dem letzten Leerzeichen steht. Bei der Analyse des Namens setzen wir die Funktion strrchr() ein, der man eine Zeichenkette und ein Zeichen übergibt. Als Ergebnis liefert die Funktion den Rest der Zeichenkette nach dem letzten Vorkommen des übergebenen Zeichens.
1
So können wir den Nachnamen – also alles, was in der Variablen $name nach dem letzten Leerzeichen steht – mit einer einzigen Code-Zeile ermitteln. Da dabei das Leerzeichen mit übernommen wird, entfernen wir es mit der Funktion trim(): $nachname = trim(strrchr($name, " "));
2
Für die Ermittlung des Vornamens müssen wir zwei Funktionen kombinieren. Mit strrpos() ermittelt man die numerische Position des letzten Vorkommens eines Zeichens innerhalb einer Zeichenkette. Mit dieser Zeile erfahren wir also die Position des letzten Leerzeichens innerhalb von $name: $letztes_leerzeichen = strrpos($name," ");
137
3 Mit dieser Angabe können wir nun die Funktion substr() füttern, die einen
Teilbereich einer Zeichenkette zurückliefert. Dazu übergibt man ihr die Zeichenkette, die Start- und die Endposition des Teilstücks. Den Vornamen ermitteln wir also folgendermaßen:
$vorname = substr($name,0,$letztes_leerzeichen);
4
Nun können wir den Namen nach dem Muster »Nachname, Vorname« mit dem Verkettungsoperator . neu zusammensetzen: $name_neu = $nachname.", ".$vorname;
Bevor wir die geänderten Daten in die Datenbank zurückschreiben, sollten wir uns testweise einmal ausgeben lassen, ob unsere Manipulation überhaupt das gewünschte Ergebnis bringt.
5 Dafür integrieren wir die vier neuen Zeilen in die while-Schleife und fügen eine entsprechende echo-Anweisung hinzu. Das komplette und nicht sehr umfangreiche Script sieht jetzt so aus:
Der Test verläuft wie erwartet, mit ein paar Zeilen werden die in der Datenbank abgelegten Namen in das gewünschte Format gebracht.
Um die geänderten Daten zurückzuschreiben, setzen wir das MySQL-Kommando UPDATE ein. Diesem Kommando wird zuerst der Name der Tabelle übergeben, in der Daten geändert werden sollen. Anschließend werden mit SET die neuen Werte für bestimmte Felder festgelegt. Mit WHERE wird eine Bedingung formuliert, anhand derer MySQL den zu ändernden Datensatz eindeutig erkennt. Hier setzen wir das Feld id ein. Mit der Anweisung UPDATE test_tabelle SET name = '$name_neu' WHERE id = $id
wird im Datensatz der Tabelle »test_tabelle«, in dessen id-Feld der Wert $id steht, der Inhalt des Feldes name mit dem Inhalt der Variablen $name_neu überschrieben. Auch diese Anfrage wird mit der Funktion mysql_query() an den Datenbankserver übermittelt. Das Ergebnis dieser Funktion weisen wir einer temporären Variablen namens $dummy zu, die in unserem Beispiel nicht weiter benötigt wird. Einzige kleine Stolperfalle: der übergebene Wert für SET ist eine Zeichenkette und muss in einfachen Anführungszeichen stehen. Lange Rede, kurzer Code:
139
Um die Namen in der Tabelle zu korrigieren, genügt der einmalige Durchlauf dieses Scripts. Damit wir nicht versehentlich einen bereits geänderten Namen erneut ändern und damit aus »Nachname, Vorname« ein »Vorname, Nachname,« machen, fügen wir noch eine kleine Sicherheitsabfrage ein. Ein Update wird nur dann vorgenommen, wenn $name kein Komma enthält. Für diese Überprüfung benutzen wir die Funktion strpos(), mit der man die Position des ersten Auftauchens eines bestimmten Zeichens ermittelt. Ist das Zeichen nicht in der zu untersuchenden Zeichenkette enthalten, liefert die Funktion den Wert false. Um überflüssige Leerzeichen zu entfernen, setzen wir schließlich noch die Funktion trim() ein. Da hier keine Ausgaben auf dem Bildschirm stattfinden, benötigen wir auch kein HTML, sondern können den PHP-Code als Datei »update.php« speichern und einmal im Browser aufrufen, um das Script ausführen zu lassen (nach dem Durchlauf sollte man allerdings mit PHPMyAdmin überprüfen, ob die Daten auch wie gewünscht geändert wurden). id; $name = $ds -> name; if (!strpos($name, ",")) { $nachname = trim(strrchr($name, " ")); $letztes_leerzeichen = strrpos($name," "); $vorname = substr($name,0,$letztes_leerzeichen); $name_neu = $nachname.", ".$vorname; $update = "UPDATE test_tabelle SET name = '$name_neu' WHERE id = $id"; $dummy = mysql_query($update); } } mysql_close($dz); ?>
Anschließend liefert das ursprüngliche Script zur zeilenweise Ausgabe der nach Namen geordneten Daten das gewünschte Ergebnis – die nach Nachnamen sortierte Namensliste.
140
Tabellenstruktur ändern
Na also, geht doch. Mit einer Hand voll PHP-Code werden die Namen modifiziert und in die Tabelle geschrieben, so dass die Ausgaberoutine beim nächsten Aufruf die korrekt sortierte Namensliste liefert.
Tabellenstruktur ändern Nachdem die Namenseinträge vorerst so sind, wie sie vernünftigerweise wohl sein sollten, können wir uns daran machen, die Tabelle mit PHPMyAdmin um ein neues Feld zu erweitern.
In eine Tabelle lassen sich jederzeit neue Felder hinzufügen. Dabei ist die Positionierung eines neuen Feldes für die Funktionsfähigkeit der Tabelle nicht weiter wichtig. Bei umfangreichen Tabellen sorgt eine saubere Struktur allerdings für mehr Übersicht.
141
1
Starten Sie PHPMyAdmin, wechseln Sie zu Ihrer Datenbank und zur Testtabelle. Tragen Sie in der Zeile »Neue Felder hinzufügen« den Wert »1« ein und klicken Sie auf »OK«.
Die neuen Felder werden bequem über ein Formular zur Tabelle hinzugefügt.
2
Sie sehen nun ein ähnliches Formular wie beim Anlegen der Tabelle. Geben Sie dem Feld einen passenden Namen, legen Sie den Typ und gegebenenfalls die Länge fest und klicken Sie auf »Speichern«. In diesem Beispiel soll den Schauspielernamen aus Casablanca der Rollenname zugeordnet werden, das Feld heißt daher »rolle«, ist vom Typ varchar und hat eine Länge von 100 Zeichen.
Über die entsprechende Funktion von PHPMyAdmin können Sie jeden Datensatz problemlos bearbeiten, neue Werte eintragen oder korrigieren.
3
Klicken Sie anschließend auf den Karteireiter »Anzeigen«. Nun sehen Sie alle Datensätze mit dem neuen, noch leeren Feld. Mit einem Klick auf das NotizblockSymbol eines Eintrages gelangen Sie zum Bearbeitungsformular des Datensatzes. Hier können Sie die neuen Werte eintragen.
142
Tabellenstruktur ändern
Um nun Schauspieler- und Rollennamen mit unserem Script auszugeben, müssen wir innerhalb der Schleife lediglich einer neuen Variablen den entsprechenden Wert zuweisen: name; $rolle = $ds -> rolle; echo "$name spielt: $rolle "; } ?>
Allerdings ist es jetzt ein wenig unschön, dass die Namen der Schauspieler in der Form »Nachname, Vorname« gespeichert sind, schließlich klingt ein Satz wie »Bergman, Ingrid spielt: Ilsa Lund Laszlo« ein wenig seltsam. Vielleicht war es von Anfang an keine so schlaue Idee, den Namen in nur einem Feld unterzubringen. Doch dank der Flexibilität von MySQL und den Fähigkeiten von PHPMyAdmin stellt uns unsere mangelhafte, ja, schlampige Planung vor kein allzu großes Problem. Wir ergänzen die Tabelle einfach um ein weiteres Feld für den Vornamen, womit wir bei der Ausgabe und Verarbeitung der gespeicherten Daten deutlich flexibler werden. Auch dieses Mal werden wir die Namen mit einem PHP-Script in ihre Bestandteile zerlegen und anschließend speichern. Der Nachname ist im Feld name der Teil, der vor dem Komma steht, der Vorname ist alles nach dem ersten Leerzeichen.
4
Um den Vornamen auszuschneiden, benutzen wir die Funktion strstr(), die ähnlich arbeitet wie strrchr(), nur dass in diesem Fall alles ab dem ersten Auftauchen eines bestimmten Zeichens übergeben wird. Wenn in der Variablen $name der Inhalt des Feldes »name« steht, dann erhalten wir also mit folgender Anweisung den Vornamen (wobei auch dieses Mal die Funktion trim() eingesetzt wird, um das Leerzeichen zu Beginn der Zeichenkette zu entfernen): $vorname = trim(strstr($name," "));
5
Um den Nachnamen zu isolieren, setzen wir wieder strpos() und substr() ein. Mit strpos() ermitteln wir die Position des Kommas und schneiden anschließend mit substr() alles vom Anfang bis zum Komma aus: $komma_position = strpos($name,","); $nachname = substr($name,0,$komma_position);
143
6
Bevor wir nun die so ermittelten Werte in die Tabelle schreiben, geben wir zur Kontrolle das Ergebnis auf dem Bildschirm aus: echo echo echo echo echo
Nachdem dieser Test erfolgreich verlaufen ist und die Bildschirmausgabe unseren Vorstellungen entspricht, können wir das Script durch ein UPDATE-Kommando ergänzen. Da wir dieses Mal mehr als einen Wert verändern wollen, geben wir die entsprechende Zuweisung durch ein Komma getrennt nach SET an. Der Rest der Anweisung bleibt gleich, so dass wir diese Code-Zeile erhalten: $update = "UPDATE test_tabelle SET name = '$nachname', vorname = '$vorname' WHERE id = $id"; $dummy = mysql_query($update);
8
Geben wir abschließend noch eine kurze Update-Bestätigung aus, erhalten wir insgesamt das folgende Script: id; $name = $ds -> name; $vorname = trim(strstr($name," ")); $komma_position = strpos($name,","); $nachname = substr($name,0,$komma_position); echo "
"; echo "Gespeichert: $name "; echo "Vorname: $vorname "; echo "Nachname: $nachname"; $update = "UPDATE test_tabelle SET name = '$nachname', vorname = '$vorname' WHERE id = $id"; $dummy = mysql_query($update); echo "Update durchgeführt!"; echo "
"; } mysql_close($dz); ?>
144
Tabellen sichern, löschen und importieren
Dank PHPMyAdmin und der gutmütigen Flexibilität von MySQL kann eine Tabelle problemlos mitwachsen und den sich ändernden Anforderungen und Umständen angepasst werden.
Tabellen sichern, löschen und importieren Immer dann, wenn Daten in einer Tabelle verändert werden, besteht die Gefahr, dass durch einen Programmfehler oder Unachtsamkeit die falschen Einträge überschrieben werden und wichtige Daten verloren gehen. Wenn sich etwa in einem der obigen Beispiele ein kleiner Fehler in der UPDATE-Anweisung einschleicht, kann es passieren, dass mit einem Mausklick die komplette Tabelle ruiniert wird. Es ist also keine schlechte Idee, von seinen Tabellen regelmäßig Sicherheitskopien anzulegen, mit denen man im Falle eines Falles den Datenbestand wiederherstellt. Glücklicherweise bietet PHPMyAdmin einen sehr einfachen Weg, den Datenbestand einer Tabelle in einer externen Backup-Datei zu sichern und wenn notwendig problemlos wieder zurückzuschreiben. Im Folgenden gehen wir die nötigen Schritte kurz durch. Wir werden unsere Beispieltabelle exportieren, einen Totalverlust simulieren (also die Tabelle kurzerhand löschen) und anschließend die Sicherheitskopie einlesen.
Dank PHPMyAdmin können Sie mit wenigen Mausklicks den Datenbestand sichern.
145
1
Wechseln Sie in PHPMyAdmin zur Anzeige Ihrer Tabellen und markieren Sie die Tabelle, deren Daten Sie exportieren möchten. In unserem Beispiel gibt es nur eine Tabelle namens »test_tabelle« in der »test_datenbank«. Klicken Sie anschließend auf den Karteireiter »Exportieren«.
Lassen Sie sich durch die zahlreichen Export-Optionen nicht abschrecken. Es ist einfacher, als es vielleicht aussieht.
2
Sie sehen nun ein Formular mit verschiedenen Eingabebereichen. Das mag auf den ersten Blick etwas verwirrend wirken, ist aber recht simpel – lassen Sie einfach alles so, wie es ist. Nur im unteren Feld aktivieren Sie das Kästchen »Senden«. Anschließend klicken Sie auf »OK«.
Zip-Export
Bei sehr umfangreichen Tabellen können Sie im »Senden«-Abschnitt ein Kompressionsverfahren wählen. Aktivieren Sie hier »Zip-komprimiert«, um eine möglichst kompakte Archivdatei zu erzeugen.
146
Tabellen sichern, löschen und importieren
Die exportierten SQL-Daten können als lokale Dateikopie auf der Festplatte abgelegt werden.
3
Der MySQL-Server exportiert die gewünschten Daten nun als Datei und schickt sie an den Webbrowser, der Ihnen die Möglichkeit bietet, die empfangenen Daten auf Ihrer Festplatte zu speichern.
Die gespeicherte Datei ist im einfachen ASCII-Format und kann in jedem Texteditor geöffnet werden. Werfen Sie ruhig einen Blick hinein, Sie sehen den MySQL-Code, der benötigt wird, um die exportierte Tabelle erneut anzulegen und mit Daten zu füllen. Außerdem vermerkt PHPMyAdmin im Kopf der Tabelle einige statistische Daten wie etwa die Entstehungszeit. Nachdem das Backup der Tabelle erfolgreich angelegt wurde, können Sie nun die exportierte Tabelle komplett löschen.
Klick und weg. So schnell, wie Sie eine Tabelle anlegen, so schnell können Sie sie auch wieder loswerden.
4
Wechseln Sie in PHPMyAdmin in die Anzeige der zu löschenden Tabelle, indem Sie sie zum Beispiel in der linken Spalte auswählen. Klicken Sie anschließend auf den Karteireiter »Löschen«.
147
Vorsicht!
Achten Sie darauf, dass Sie auch tatsächlich in der Tabellenanzeige sind und löschen Sie nicht versehentlich die ganze Datenbank!
Weg ist weg! Klicken Sie hier also erst dann auf OK, wenn Sie wissen, was Sie da tun (in diesem Fall wird die Tabelle »test_tabelle« unwiderruflich gelöscht).
5
Es erscheint eine Sicherheitsabfrage, die Sie mit einem Klick auf »OK« bejahen. Anschließend wird die gewählte Tabelle gelöscht und ist serverseitig nicht mehr rekonstruierbar.
So, das war der Datengau, die Tabelle ist futsch und mit ihr auch sämtliche Daten. In unserem Beispiel ist das natürlich nicht weiter schlimm, aber stellen Sie sich vor, Sie verlieren, sei es durch eigene Unachtsamkeit, sei es, weil Ihr Provider eine technische Panne hat, alle mühsam erfassten und zusammengetragenen Daten – sehr viel schlimmer kann es gar nicht mehr kommen. Hoffen wir, dass Sie in der Praxis dann, so wie in unserem Testlauf, ebenfalls auf ein Backup zurückgreifen können. Damit können Sie nämlich mit ein paar Mausklicks das Malheur ausbügeln. Und zwar so:
In PHPMyAdmin können Sie mit wenigen Mausklicks komplette MySQL-Datenbestände importieren.
148
Menschen, nicht Maschinen
6
Klicken Sie auf den Karteireiter »SQL«. Sie sehen nun ein Eingabefeld, über das Sie SQL-Kommandos direkt ausführen lassen können und eine Eingabezeile, in der Sie eine Datei für den Import eintragen können. Wählen Sie über den »Browse«Button die soeben exportierte SQL-Datei (in unserem Beispiel »test_datenbank.sql«) und klicken Sie auf »OK«.
In der Kontrollanzeige sehen Sie alle SQL-Befehle, die PHPMyAdmin an den MySQLServer geschickt hat.
7
PHPMyAdmin liest die angegebene Datei ein und übermittelt den darin enthaltenen SQL-Code an den MySQL-Server. Der führt den Code aus und am Ende erhalten wir exakt die Tabelle, die wir gesichert und anschließend gelöscht hatten.
Puh, da haben wir ja noch mal Glück gehabt ;-) Menschen, nicht Maschinen: Eric S. Raymond
Der 1957 geborene Eric S. Raymond ist einer der berühmtesten, umtriebigsten und wichtigsten Personen der Hacker- und Open-Source-Szene. Er ist der Autor zahlreicher Fachbücher und Artikel, hat als Programmierer wichtige Beiträge zu Linux geliefert, ist in vielen Open-Source-Projekten engagiert und gründete 1998 die einflussreiche »Open Source Initiative«. Auf seiner Homepage finden Sie einige seiner Essays und Aufsätze rund um das Thema Open Source: http://www.catb.org/~esr/.
149
Kapitel 6
Eine Logdatei mit MySQL und PHP
Nach dem Sprung ins kalte Wasser im letzten Kapitel schwimmen wir uns in diesem Kapitel warm. Wir basteln uns eine kleine Logdatei zur statistischen Auswertung der Besucher unserer Website.
Ihr Erfolgsbarometer
Das können Sie schon: Sie können in Ihren Programmen logische Entscheidungen treffen, Schleifen einsetzen und Funktionen definieren.
42
Am Beispiel von drei Praxisprojekten haben Sie gelernt, wie Sie Daten in Dateien speichern, Cookies einsetzen und Formulare auswerten.
66
Sie haben die mächtigen Einsatzmöglichkeiten von numerischen und assoziativen Arrays kennen gelernt.
92
Dank PHPMyAdmin war der Einstieg in MySQL nicht schwer und Sie haben gelernt, wie Sie von PHP aus auf MySQL-Daten zugreifen können.
120
Das lernen Sie neu: Kurzer Rückblick und neue Aussichten
152
Woher des Wegs, Webwanderer?
153
Datentypen in MySQL
155
Daten via PHP in eine Tabelle schreiben
162
Die Einträge einer Tabelle zählen
171
Die Logdatei bereichsweise ausgeben
175
TIMESTAMP-Einträge einfügen
177
151
Kurzer Rückblick und neue Aussichten Im letzten Kapitel sind wir in Riesenschritten in die geheimnisvollen Weiten von MySQL vorgedrungen und haben dabei festgestellt, dass sie, zumindest in den Anfangsgründen, so geheimnisvoll gar nicht sind. Wenn auch die Beziehung des dynamischen Duos PHP & MySQL beliebig kompliziert werden kann und sich PHP & MySQL-Experten mit Problemen beschäftigen, die zu beschreiben dieses einführende Buch nicht hinreichen würde, bietet die Kombination aus Script- und Datenbanksprache doch auch eine Fülle an einfachen und auch dem Anfänger zugänglichen Möglichkeiten, die man zum Ausbau seiner Website nutzen kann. Rekapitulieren wir noch einmal rasch die wichtigsten Eckpunkte:
Aus Feldern werden Datensätze, aus Datensätzen Tabellen und aus Tabellen Datenbanken.
1
Daten werden in Feldern gespeichert, mehrere Felder bilden einen Datensatz, mehrere Datensätze ergeben eine Tabelle, mehrere Tabellen addieren sich zu einer Datenbank. Über allem wacht der Datenbankserver, der mehrere Datenbanken verwalten kann.
2
Um mit PHP auf Daten zuzugreifen, die in einer MySQL-Datenbank gespeichert sind, muss zuerst eine Verbindung zum Datenbankserver hergestellt werden. Dazu dient die Funktion mysql_connect, der als Parameter der Hostname, der Username und das Passwort übergeben werden. Die Funktion liefert einen Wert zurück, über den der MySQL-Server die geöffnete Verbindung eindeutig identifizieren kann und der in einer Variablen abgelegt wird: $dz = mysql_connect($host, $user, $pass);
3 Sobald die Verbindung zum Server hergestellt ist, gibt man über die Funktion
mysql_select_db die Datenbank an, auf deren Tabellen man zugreifen möchte. Der Funktion wird der Datenbankname und der Zeigerwert übergeben:
mysql_select_db($database, $dz);
152
Woher des Wegs, Webwanderer?
4
Alle Daten liegen in Feldern innerhalb von Tabellen. Über die SELECT-Anweisung kann man auf bestimmte Einträge zugreifen. Mit UPDATE lassen sich Werte eines Eintrags gezielt verändern: $query = "SELECT * FROM test_tabelle ORDER BY name"; $update = "UPDATE tabelle SET name = '$name' WHERE id = $id";
5
Jedes Kommando, das an den MySQL-Server geschickt wird, ist eine so genannte »Anfrage« oder »Query«. Sie wird via PHP als String mit der Funktion mysql_query() an den Server geschickt. Die Funktion liefert einen Zeigerwert zurück, über den schließlich PHP auf die angeforderten und vom Server bereitgestellten Daten zugreifen kann: $sql = mysql_query($query); $sql = mysql_query($update);
Bislang haben wir für die Erfassung der Daten ausgiebig Gebrauch vom Hilfsprogramm PHPMyAdmin gemacht. Dieses Tool werden wir beim Entwurf und bei der Anpassung unserer Tabellen auch weiterhin einsetzen, doch zur Eingabe von Daten sollten wir nicht zwingend darauf angewiesen sein. Schließlich gibt es in der Praxis genügend Fälle, wo unsere Scripte automatisch erfasste Daten speichern oder ein Besucher über ein Formular Daten erfassen können muss. Nehmen wir zum Beispiel eine Logdatei, in der verzeichnet wird, von wo aus ein Besucher auf unsere Webseiten gekommen ist und mit welchem Browser er darauf zugreift. Diese Daten können wir nicht selbst in eine Tabelle eintragen, sondern müssen das dem Webserver überlassen. Und genau das werden wir nun tun. Wir entwickeln ein kleines Script, das beim Aufruf einer Webseite automatisch einige statistische Daten erfasst und in eine MySQL-Tabelle schreibt, so dass wir nicht nur wissen, wie oft eine Seite abgerufen wurde, sondern auch, von welcher IP-Adresse aus und mit welchem Browser der Zugriff erfolgte.
Woher des Wegs, Webwanderer? Als Betreiber einer Webseite möchte man häufig nicht nur wissen, wie oft eine Seite abgerufen oder wie viele Besucher man gehabt hat, sondern auch, woher diese Besucher kamen, auf welchen Link sie geklickt haben, um die Webseite zu erreichen oder mit welchem Browser sie unterwegs sind. Diese (und andere) Daten werden von PHP bei jedem Zugriff automatisch erfasst und in der schon in früheren Kapiteln kurz gestreiften Variable $_SERVER gespeichert, die als assoziatives Array zahlreiche Elemente enthält. Um den Referer, die Browserkennung und die IP-Adresse des Besuchers auszulesen, greift man einfach auf die entsprechenden Daten von $_SERVER zu.
153
Referer
Referer kommt vom englische Verb »to refer«, das »weiterleiten, übergeben, sich beziehen auf« bedeutet und lässt sich ein wenig holprig mit »Verweiser« übersetzen. Die korrekte Schreibweise lautet eigentlich »referrer«, aber der Schreibfehler hat es bis in die Webprotokolle geschafft und ist damit für PHP & Co. verbindlich. Ein Referer ist die Adresse des Links, den der Benutzer angeklickt hat, um zu einer bestimmten Webseite zu gelangen. Der Referer wird nicht von allen Browsern korrekt übertragen, die Übertragung lässt sich zudem manipulieren und komplett unterdrücken.
Der Referer findet sich in $_SERVER['HTTP_REFERER'], die Browserkennung in $_SERVER['HTTP_USER_AGENT'] und die IP-Adresse in $_SERVER['REMOTE_ADDR']. Kombiniert man diese Werte noch mit dem aktuellen Datum und der Uhrzeit, so erhält man schon eine recht hübsche Datensammlung, die man in einer Logdatei sammeln kann.
1
In einem ersten, einfachen Testlauf werden in der Datei »logfile.php« die entsprechenden Werte der Reihe nach ausgelesen und am Bildschirm angezeigt. Damit der Referer einen Wert enthält, rufen wir die Seite einfach über einen Link zu sich selbst auf: Klick! Datum: Zeit: Referrer: Browser: IP-Adresse:
Mit geringem Aufwand lassen sich in PHP eine Reihe statistischer Daten ermitteln.
154
Datentypen in MySQL
2
Speichern Sie dieses kurze Scriptbeispiel als »logfile.php« und rufen Sie die Datei im Browser auf. Beim ersten Aufruf wird der Eintrag für den Referer noch leer sein, haben Sie die Datei doch durch direkte Eingabe des Dateinamens aufgerufen. Doch sobald Sie auf den Link klicken, ruft die Datei sich selbst auf und es existiert ein Referer.
Wie wir an die Daten für unseren Logfile kommen, wissen wir also jetzt. Nun müssen wir uns nur noch eine Tabelle anlegen, in der diese Daten gespeichert werden sollen. Dabei muss man sich über (mindestens) zwei Dinge Klarheit verschaffen: Wie viele Felder werden benötigt und welche Datentypen müssen die Felder haben? Die Anzahl lässt sich sehr schnell bestimmen. Die Tabelle muss eins plus fünf, also sechs, Felder enthalten: Das mehr oder weniger obligatorische Index-Feld und je ein Feld für Datum, Zeitpunkt, Referer, Browser und IP-Adresse. Mit den Datentypen ist man nicht ganz so schnell fertig, da müssen wir ein wenig weiter ausholen.
Datentypen in MySQL Wie schon im vorherigen Kapitel erwähnt, spielen die Datentypen bei MySQL eine ungleich größere Rolle als bei PHP. Stellen Sie sich ein Regal mit verschiedenen Fächern vor, in die jeweils nur Unterlagen mit einer ganz bestimmten Form abgelegt werden können. In den einen Korb passen nur kreisrund zugeschnittene Formulare, in den anderen nur quadratische und ein dritter nimmt nur sternförmige Papiere auf. Genauso ist es mit den Datentypen bei MySQL. Es gibt Felder, die nehmen nur ganze Zahlen innerhalb eines bestimmten Bereiches auf, andere akzeptieren nur Text und wieder andere sind auf Datums- und Zeitangaben spezialisiert. Von den verschiedenen Datentypen in MySQL sind drei Gruppen besonders wichtig: Datentypen für Zeichenketten, also für Texte, numerische Typen für Zahlen und Typen für Datums- bzw. Zeitangaben. Außerdem gibt es noch binäre Typen (etwa für Grafiken- oder Sound-Daten) und Mengen-Typen, um mehrere Zeichenketten in einem Feld ablegen zu können.
Datentypen für Zeichenketten Zum Speichern von beliebigen Zeichenketten und Texten stellt MySQL sechs verschiedene Typen zur Verfügung, von denen Sie einige schon kennen gelernt haben.
155
CHAR definiert Felder zur Eingabe von Zeichenketten mit fester Länge. Legen
Sie für das Feld »test« als Länge beispielsweise zehn Zeichen fest, dann können Sie in diesem Feld nur Zeichenketten mit bis zu zehn Zeichen Länge ablegen. Ist die Zeichenkette kürzer, wird der Rest mit Leerzeichen aufgefüllt. Die maximale Länge beträgt 255 Zeichen, die Längenangabe bei der Definition des Feldes ist obligatorisch.
Ein Feld vom Typ CHAR kann maximal 255 Zeichen lange Zeichenketten aufnehmen und ist immer exakt so lang, wie Sie es festlegen.
Mit VARCHAR steht ein flexibleres Format zur Verfügung. Ein Feld mit diesem Typ kann zwar ebenfalls nur maximal 255 Zeichen aufnehmen, doch wenn Sie Texte eingeben, die kürzer als die festgelegte Länge sind, wird das Feld nicht mit Leerzeichen aufgefüllt. VARCHAR ist einer der am häufigsten eingesetzten Datentypen. Auch hier ist die Angabe der Feldlänge obligatorisch.
VARCHAR ist der Standardtyp für viele Textfelder und kann maximal 255 Zeichen lang sein.
Neben diesen beiden klassischen Zeichenkettentypen gibt es noch den Typ TEXT, der in vier Varianten vorkommt, die sich in ihrer maximalen Länge unterscheiden:
• • • •
TINYTEXT kann maximal 255 Zeichen enthalten TEXT reicht für 65.535 Zeichen aus MEDIUMTEXT speichert bis zu 16.777.215 Zeichen lange Texte LONGTEXT fasst schließlich sagenhafte 4.294.967.295 Zeichen.
Mit TEXT steht ein Typ zur Verfügung, der bis zu 65 KByte großen Fließtext aufnehmen kann. Zum Vergleich: Eine normale Buchseite umfasst etwa 3 KByte Text.
156
Numerische Datentypen
Bei so vielen Typen hat man ein wenig die Qual der Wahl – welcher Typ ist für Zeichenketten üblicherweise sinnvoll? Die Antwort ist einfach: VARCHAR für Zeichenketten mit überschaubarer Länge bis 255 Zeichen und TEXT für praktisch alles andere. Statt VARCHAR könnte man zwar auch TINYTEXT einsetzen, um sich bei der Definition die Längenangabe zu sparen, doch dafür kann ein solches Feld nicht mehr indiziert werden, was später bei der Suche nach Texten das System ausbremst. MEDIUM- bzw. LONGTEXT-Felder fassen bis zu 16 MByte bzw. 4 GByte große Texte (minus 1 Byte, das MySQL für interne Zwecke abzwackt) – und die Wahrscheinlichkeit, dass Sie mit diesen Datenmengen jonglieren müssen, ist eher gering.
Numerische Datentypen Bei den numerischen Typen, also den Datenfeldern, die zur Speicherung von Zahlen vorgesehen sind, kennt MySQL insgesamt acht verschiedene Varianten, die wiederum zwischen ganzzahligen und Fließkommawerten unterscheiden. Für ganze Zahlen steht generell der Typ INT zur Verfügung, den es in verschiedenen Abstufungen gibt:
•
TINYINT fasst ganze Zahlen zwischen –127 und +128. Wenn nur positive Werte gespeichert werden sollen, liegt der Bereich zwischen 0 und 255.
•
In SMALLINT passen Zahlen von –32.768 bis +32.767. Bleibt man positiv, reicht der Typ für Werte von 0 bis 65.535.
•
Mit MEDIUMINT können Sie Werte zwischen –8.388.608 und +8.388.607 speichern. Auch hier können Sie sich auf den positiven Bereich ohne Vorzeichen beschränken und so Zahlen zwischen 0 bis rund 16 Millionen speichern.
•
INT selbst umfasst Werte von rund –2,1 Milliarden bis zu +2,1 Milliarden. Durch Beschränkung auf den positiven Bereich passen in INT Werte von
0 bis rund 4,3 Milliarden.
•
Mit BIGINT verlieren wir uns endgültig in den ewigen Weiten der ganzen Zahlen. Der Typ fasst alle ganzen Zahlen von –263 bis +263, bzw. von 0 bis 264 –1.
157
Wenn Sie den Wertebereich einer ganzen Zahl auf den positiven Bereich beschränken wollen, müssen Sie bei der Felddefinition das Attribut UNSIGNED – was so viel wie »ohne Vorzeichen« bedeutet – setzen. In PHPMyAdmin gibt es dafür die Spalte »Attribute«. Außerdem können Sie jedem Typ eine Längenvorgabe machen, mit der Sie festlegen, wie viele Stellen der zu speichernde Wert haben darf.
Wenn Sie bei ganzzahligen Werten auf das Vorzeichen verzichten (UNSIGNED), können Sie zwar keine negativen Werte mehr speichern, aber dafür verdoppelt sich die Reichweite der positiven Werte. Die Längenangabe ist nicht zwingend erforderlich.
Für Fließkommazahlen stehen drei verschiedene Typen zur Verfügung: FLOAT, DOUBLE und DECIMAL. Mit FLOAT speichern Sie Fließkommazahlen mit einfacher, bei DOUBLE mit doppelter Genauigkeit. DECIMAL speichert die Zahl als String und verlangt eine Längenangabe für den Vor- und Nachkommabereich. Geben Sie keine an, wird die Länge auf 10,0 festgesetzt, ein solches Feld würde Zahlen mit bis zu zehn Stellen im Vorkomma- und null Stellen im Nachkommabereich aufnehmen. Bei FLOAT und DOUBLE können, müssen Sie aber keine Längenangaben machen. Auch bei den Zahlen stellt sich die Frage, welche Typen man üblicherweise einsetzt. Hier hängt die Antwort stark von der Anwendung ab, ein Mathematiker stellt gänzlich andere Anforderungen als der normale Webseitenbastler. Für diesen gilt die Faustregel: SMALLINT bis INT reicht fast immer bei ganzen Zahlen und genauer als FLOAT muss es auch nicht werden.
Wenn Sie nicht gerade mathematische Spezialanwendungen einsetzen, reicht die einfache Genauigkeit von FLOAT für Fließkommazahlen problemlos aus.
Ein Sonderfall für Fließkommazahlen stellt DECIMAL dar. Dass die Werte intern als String gespeichert werden, kann uns aus PHP-Sicht egal sein, PHP nimmt es mit den Typen ja nicht so genau. Interessant und nützlich ist aller-
158
Datums- und Zeittypen
dings die Längenangabe. So lassen sich typische Fließkommazahlen aus dem Alltag wie Preis- oder Temperaturangaben (18,20 Euro oder 21,4 Grad) in einen DECIMAL-Feld speichern, ohne dass es bei internen Berechnungen zu den bei Fließkommazahlen fast unweigerlich auftretenden Rundungsunschärfen kommt. Punkt statt Komma
Bei der Definition von Fließkommazahlen wird zwar ein Komma eingesetzt (3,2), bei der Eingabe der Werte aber ein Punkt. Der Wert »18,20« muss also als »18.20« angegeben werden.
Der Typ DECIMAL eignet sich sehr gut zur Speicherung alltäglicher Fließkommazahlen mit genau begrenztem Umfang. In diesem Beispiel kann das Feld »preis« alle Werte von –999,99 bis +999,99 aufnehmen und bis zur zweiten Nachkommastelle genau rechnen, ohne über eventuelle Rundungsunschärfen von FLOAT oder DOUBLE zu stolpern.
Datums- und Zeittypen Nach Zeichen und Zahlen bleiben nun noch die Datums- und Zeitfelder übrig. Hier stellt MySQL fünf verschiedene Datentypen zur Auswahl. In einem Feld vom Typ DATE wird das Datum im Format JJJJ-MM-TT gespeichert, der 27. März 1961 würde also als 1961-03-27 abgelegt werden. Das jüngste Datum, das gespeichert werden kann, ist der 1. Januar 1000 (100001-01), das späteste der 31. Dezember 9999 (9999-12-31). Für Gegenwartsund Science-Fiction-Autoren ist der Speicherbereich großzügig bemessen, Historiker bekommen bei MySQL rasch ein Problem. Für Daten außerhalb des Gültigkeitsbereiches von DATE müssen Sie zu selbst gebastelten Lösungen greifen und zum Beispiel Angaben wie »50 v. Chr.« als String ablegen.
Der Standardtyp DATE ist für fast alle üblichen Datumsangaben im Format JJJJ-MM-TT geeignet, bei historischen Daten vor dem 1. Januar 1000 ist allerdings nichts zu machen.
159
Für Zeitangaben steht TIME zur Verfügung, das die Uhrzeit im üblichen Format von HH:MM:SS aufnimmt, etwa 14:32:12 für Vierzehnuhrzweiundreißig und zwölf Sekunden. Der Wertebereich von TIME reicht von -838:59:59 bis +838:59:59, umfasst also den Zeitrahmen von über einem Monat. In einem Feld von DATETIME werden beide Angaben zu einem Wert kombiniert, wobei zwischen Datums- und Zeitangabe ein Leerzeichen gesetzt wird. Die umgangssprachliche Angabe »Am 17. Mai 1731, pünktlich um 3 Uhr und 22 Minuten nachmittags ...« würde bei MySQL also als 1731-05-17 15:22:00 in einem Feld vom Typ DATETIME gespeichert werden können. Zu diesen beiden Zeittypen gesellt sich noch die Angabe YEAR, in der, das wird Sie kaum überraschen, eine Jahresangabe gespeichert werden kann. Dabei gibt der Längenparameter an, ob die Jahreszahl zweistellig (04) oder vierstellig (2004) sein soll. Verzichten Sie auf die Angabe, wird das Jahr (vernünftigerweise) als vierstellige Zahl gespeichert.
Wenn Sie keinen zwingenden guten Grund haben, sollten Sie Jahreszahlen immer unmissverständlich als vierstellige Zahl speichern.
Schließlich kennt MySQL noch den Typ TIMESTAMP, also »Zeitstempel«. Ähnlich wie bei DATETIME werden hier Datum und Uhrzeit als ein Wert abgelegt, allerdings gibt es keinerlei Trennzeichen zwischen den einzelnen Werten, aus der Datums- und Zeitangabe 1731-05-17 15:22:00 wird ein 17310517152200. Das ist nun nicht sonderlich gut lesbar und man könnte sich fragen, was das soll. Ganz einfach: In diesem Feld speichert MySQL automatisch den exakten Zeitpunkt, zu dem ein Datensatz angelegt oder verändert wurde.
Mit dem Datentyp TIMESTAMP können Sie MySQL dafür sorgen lassen, dass jeder Datensatz bei der Anlage oder Veränderungen einen exakten Zeitstempel verpasst bekommt.
160
Die Tabelle der Logdatei
Die Tabelle der Logdatei Nach diesen Vorüberlegungen ist das tabellarische Grundgerüst unserer Logdatei kein Problem mehr und mit Hilfe von PHPMyAdmin rasch erstellt. Weiter oben haben wir festgestellt, dass wir eine Tabelle mit sechs Feldern benötigen: Index, Datum, Zeitpunkt, Referer, Browser und IP-Adresse. Da uns MySQL mit DATETIME eine Kombination aus Datum und Zeitpunkt anbietet, können wir auch mit fünf Feldern auskommen. Denkbar wäre auch der Einsatz von TIMESTAMP, bei dem wir den Eintrag obendrein dem MySQL-Server überlassen könnten. Hier kann es zwar zu leichten Differenzen zwischen dem Zeitpunkt, zu dem eine Webseite abgerufen wird und dem, zu dem die Zugriffsdaten gespeichert werden, kommen; d. h. dass nicht der exakte Zugriffszeitpunkt protokolliert würde, aber der Zeitunterschied dürfte höchstens ein oder zwei Sekunden betragen und kann daher getrost ignoriert werden. Doch ist das in unserem Fall wirklich sinnvoll? Das können wir erst entscheiden, wenn wir wissen, wie wir die gespeicherten Daten verarbeiten wollen. Da wir bei der Ausgabe der Logdatei als Tabelle am Bildschirm die Angaben für Datum und Uhrzeit getrennt ausgeben möchten, scheint es vorerst sinnvoll, die Daten auch in getrennten Feldern zu erfassen. Legen wir also Datum und Zeitpunkt separat in Feldern vom Typ DATE und TIME ab. Da die Neustrukturierung und Ordnung von MySQL-Daten mühelos möglich ist, können wir die beiden Felder später immer noch zu einem Feld vom Typ DATETIME oder TIMESTAMP zusammenfassen.
1
Starten Sie PHPMyAdmin und legen Sie eine neue Tabelle »logdatei« mit 6 Feldern an. Sie sehen nun ein Eingabeformular, in das Sie die folgenden sechs Felder und die entsprechenden Typen und Eigenschaften der Felder definieren.
Die Tabelle für die Logdatei benötigt sechs Felder. Sollten wir uns das später noch einmal anders überlegen, können wir die Tabellenstruktur jederzeit problemlos ändern.
161
2
Für das Index-Feld id nehmen wir den Typ SMALLINT mit dem Attribut UNSIGNED. Damit kann der Index maximal bis 65.535 hochzählen – für unser kleines Testprojekt ist das mehr als ausreichend. Außerdem wählen wir in der Spalte »Extra« den Eintrag auto_increment und erklären das Feld zum »Primärschlüssel«.
3 Für die Felder datum und zeit wählen wir die entsprechenden Typen DATE und TIME.
4 Der Referer-Eintrag stellt uns vor ein kleines Problem. Normalerweise müsste
VARCHAR mit einer Länge von 255 Zeichen problemlos ausreichen. Andererseits kann man nicht sicher ausschließen, dass ein Link nicht doch länger sein kann. Das gilt besonders für die Referer, wie sie von Google, Yahoo und ähnlichen Suchmaschinen erzeugt werden. Nehmen wir für das Feld referer also lieber den Typ TEXT – länger als 64.000 Zeichen wird ein Link nicht sein.
5
Die Browserkennung wird hingegen wohl nie länger als 255 Zeichen werden, das Feld browser ist folglich vom Typ VARCHAR und bekommt als Längenangabe 255.
6
Die IP-Adresse schließlich besteht immer aus vier Gruppen mit höchstens drei Ziffern, die durch einen Punkt getrennt sind, etwa: 62.245.190.21, eine IP-Adresse ist demnach höchstens 4 * 3 + 3 = 15 Zeichen lang. Das Feld ip ist damit vom Typ VARCHAR mit einer Länge von 15.
Dank PHPMyAdmin ist die Logdatei-Tabelle mit wenigen Mausklicks angelegt. Der unterstrichene Feldnamen »id« zeigt an, dass dieses Feld der Primärschlüssel der Tabelle ist.
Daten via PHP in eine Tabelle schreiben So weit, so gut. Kümmern wir uns nun darum, wie wir die Daten, die unser kleines Logscript ermittelt, in die Tabelle bekommen – die manuelle Eingabe über PHPMyAdmin scheidet ja aus. Dazu setzen wir das SQL-Kommando INSERT ein. Die Details – welche Daten sollen in welche Felder von welcher Tabelle eingefügt werden – werden über verschiedene Parameter definiert. So wird mit INTO die Tabelle bestimmt und mit VALUES legt man die Werte fest.
162
Daten via PHP in eine Tabelle schreiben
Dabei gibt es zwei Möglichkeiten. Zum einen können Sie hinter VALUES in Klammern alle Daten eines Datensatzes in der Reihenfolge der Tabellenstruktur durch Komma getrennt angeben. Zeichenketten müssen dabei in einfache Anführungszeichen gesetzt werden. MySQL legt daraufhin einen neuen Datensatz an und trägt die angegebenen Daten in der Reihenfolge ein, in der sie hinter VALUES angeführt werden. Mit dem Befehl INSERT INTO test VALUES (1, 'test', 27)
würde also in der Tabelle »test« ein neuer Datensatz eingefügt, dessen ersten drei Felder die genannten Werte enthalten. Das Verfahren ist zwar einfach, hat aber einen Nachteil. Wenn, wie in unseren Beispielen, die Tabellen ein Index-Feld besitzen, das von MySQL automatisch hochgezählt wird, dann würde dieses Feld durch das INSERTKommando ebenfalls mit einem Wert gefüllt und der automatische Zähler wäre für die Katz. Man kann dies verhindern, in dem man den ersten Eintrag einfach leer lässt, etwa so: INSERT INTO test VALUES (, 'test', 27)
Doch das ist ein relativ fehleranfälliges Verfahren. Daher ist es besser und übersichtlicher, zusätzlich zu den Werten auch die Feldnamen zu nennen, in die die Werte eingefügt werden sollen. Diese Feldnamen werden nach dem Tabellennamen in Klammern angegeben und durch ein Komma voneinander getrennt.
1
Als ein einfaches Beispiel kann unsere Testtabelle aus dem vorherigen Kapitel dienen. Diese Tabelle hat den Namen test_tabelle und die vier Felder id, name, vorname und rolle. Wir möchten nun den Schauspieler Louis Mercier mit seiner Rolle als Schmuggler im Film Casablanca aufnehmen.
2 Der erste Teil des INSERT-Kommandos lautet also: INSERT INTO test_tabelle
3 Als Nächstes müssen wir die Felder nennen, für die wir Werte haben. Da das
Feld id automatisch ausgefüllt wird, muss es nicht aufgeführt werden. Das Kommando sieht also jetzt so aus: INSERT INTO test_tabelle (name, vorname, rolle)
4 Jetzt müssen nur noch die Werte mit VALUES übergeben werden, und das INSERT-Kommando ist fertig:
INSERT INTO test_tabelle (name, vorname, rolle) VALUES ('Mercier', 'Louis', 'Schmuggler')
163
5
Wie schon bei SELECT und UPDATE wird auch dieses Kommando mit mysql_query an den Datenbankserver geschickt. Der vollständige Code zur Eingabe des neuen Datensatzes via PHP in die Beispieltabelle sieht also so aus (das Script zum Aufbau der Verbindung zum Datenbankserver steht dabei wie gehabt in der Datei »mysql.inc«, der Datenbankzeiger wird in der Variablen $dz abgelegt):
Wie schon beim UPDATE-Kommando wird auch hier der Rückgabewert von mysql_query für das INSERT-Kommando ignoriert und nur pro forma in der Variablen $dummy abgelegt. Das ist natürlich ein wenig unverantwortlich und nicht korrekt, kann man über diesen Rückgabewert doch feststellen, ob der Datenbankzugriff erfolgreich war oder nicht. Doch so unter uns und auf unserem lokalen Computer gehen wir der Einfachheit halber kurzerhand davon aus, dass schon nichts schief gehen wird. Wenn die lokal entwickelte Website ins Internet gestellt wird, sieht die Sache natürlich anders aus. Wir werden uns daher später mit der Behandlung von Laufzeitfehlern von PHP oder MySQL beschäftigen und den Wert $dummy dann nicht mehr links liegen lassen.
Die Logdaten in die Logdatei schreiben Nach diesen Vorüberlegungen stellt uns das Script, mit dem wir die erfassten Logdaten in die Tabelle schreiben, vor keine allzu großen Probleme mehr. Zuerst lesen wir die entsprechenden Werte von $_SERVER aus und legen sie in Variablen ab. Anschließend schreiben wir diese Wert mit dem INSERTKommando in die Tabelle »logdatei«. Auch bei diesem Beispiel wird wieder davon ausgegangen, dass die benötigten Scriptzeilen zur Kontaktaufnahme mit dem Datenbankserver in der Datei mysql.inc zu finden sind. Dieses Mal haben wir sie allerdings gleich in ein Verzeichnis namens »inc« abgelegt, das im Hauptverzeichnis der Website zu finden ist, und das noch andere zentrale Dateien – etwa die Stylesheet-Defini-
164
Die Logdaten in die Logdatei schreiben
tionen – enthält. Um auf diese Datei mit include() zuzugreifen, könnte man nun den relativen Pfad angeben, etwa include ("../inc/mysql.inc");
Doch das hat den Nachteil, dass wir diese Pfadangabe immer anpassen müssen, wenn wir die Ordnerstruktur der Site verändern und das Script in einer anderen Verzeichnisebene landen sollte. Da ist es einfacher, sich die Tatsache zunutze zu machen, dass man der Funktion auch komplette Webadressen übergeben kann. Hier müssen Sie nur darauf achten, dass Sie den URL anpassen, sobald Sie die Scripts nicht mehr lokal mit Xampp, sondern im echten Leben auf Ihrem Webserver testen.
Je mehr Werte und Felder Sie mit dem INSERT-Kommando in einen neuen Datensatz schreiben, desto unübersichtlicher – und das heißt bei PHP immer auch: um so fehleranfälliger! – wird die Definition der Variablen $query. Für mehr Übersicht kann hier die Notation mit dem Verkettungsoperator sorgen, wobei wir ausnutzen können, dass Zeilenumbrüche den Code für uns besser lesbar machen und von PHP ignoriert werden. Dieser vierzeilige Block ist für PHP also eine Zeile mit einer Anweisung, in der die einzelnen Teile durch den Verkettungsoperator – den Punkt – zu einer Zeichenkette zusammengesetzt werden: $query = "INSERT INTO logdatei " ."(datum, zeit, referer, browser, ip) " ."VALUES " ."('$datum', '$zeit', '$referer', '$browser', '$ip')";
Setzt man den PHP-Code an den Anfang einer Webseite, so wird jeder Abruf dieser Seite automatisch in der Logdatei eingetragen. Damit wir mit dem Script nicht nur die Zugriffe auf eine Webseite, sondern auf verschiedene Seiten protokollieren können, fügen wir der Tabelle ein Feld
165
webseite hinzu und speichern bei jedem Zugriff zusätzlich den Namen der
aktuell aufgerufenen Webseite.
Die Logdatei wird um ein weiteres Feld ergänzt, um das Script flexibler zu gestalten.
Das neue Feld fügen wir – wie im vorherigen Kapitel erläutert – mit PHPMyAdmin der Tabelle hinzu. Es ist vom Typ VARCHAR und 255 Zeichen lang. Den Namen der jeweils aktuellen Webseite ermitteln wir über den Wert von $_SERVER['PHP_SELF']. Ergänzen wir das Logscript um die entsprechenden Werte, so erhalten wir schließlich diesen Scriptblock (bei dem zu Anfang wieder das Script zur Datenbankverbindung mit include() eingebunden wird):
Wenn Sie nun dieses Script beispielsweise als »#_logdatei.php« speichern, können Sie es am Kopf jeder Webseite mit
einfügen, und so die Zugriffe auf diese Webseite in Ihrer Logdatei protokollieren. Beachten Sie aber, dass das hier entwickelte Script zu Beginn mit include ("http://localhost/inc/mysql.inc");
das externe Script zur Kontaktaufnahme zum MySQL-Server einbindet und am Ende die bestehende Datenbankverbindung mit
166
Die Logdatei vollständig ausgeben
mysql_close($dz);
explizit schließt. Diese Zeilen müssen Sie gegebenenfalls Ihrer Website-Umgebung anpassen. Dabei ist ein eventueller doppelter Aufruf von mysql_connect() nicht weiter problematisch, da PHP doppelte Verbindungsaufrufe zum MySQL-Server einfach ignoriert bzw. auf die bereits vorhandene Verbindung zurückgreift. Allerdings kann das explizite Schließen der Datenbankverbindung Ihre Scripts eventuell durcheinander bringen, diese Zeile müssen Sie unter Umständen also entfernen. Wenn Sie möchten, können Sie auf das explizite Schließen der Datenbankverbindung auch ganz verzichten und es dem Server überlassen, der alle bestehenden Verbindunen kappt, sobald das Script abgearbeitet ist. Das ist zwar stilistisch nicht ganz sauber, aber es funktioniert.
Die Logdatei vollständig ausgeben Mit PHPMyAdmin können Sie nicht nur die Tabelle anlegen und konfigurieren, sondern sich auch die Einträge anzeigen lassen. Dafür müssen Sie nach der Auswahl der Tabelle nur auf die Registerkarte »Ansicht« wechseln. Die Anordnung der einzelnen Einträge lässt sich durch einen Klick auf die Spaltennamen verändern, mit dem großen »T« wechseln Sie zwischen einer umbrochenen und einer umbruchslosen Darstellung.
Möglich, aber etwas unübersichtlich: Die Anzeige einer Tabelle in PHPMyAdmin
167
Allerdings ist es doch ein wenig unhandlich, immer erst PHPMyAdmin starten zu müssen, wenn man einen Blick in die Tabelle werfen möchte. Da schreiben wir uns die Anzeigeroutine doch lieber rasch selbst. Wie das geht, haben wir ja bereits im vorherigen Kapitel gesehen.
1
Diesmal geben wir aber nicht alle Felder aus, sondern interessieren uns nur für das Zugriffsdatum, den Referer und die abgerufene Webseite. Um mit dem SELECTKommando nicht auf alle, sondern nur auf diese drei Felder zuzugreifen, werden die Namen der ausgewählten Felder durch Komma voneinander getrennt hinter das SELECT-Statement gesetzt. Außerdem sollen die Einträge nach Datum sortiert werden. Die benötigte SELECT-Anweisung bekommt also folgende Form: SELECT datum, referer, webseite FROM logdatei ORDER BY datum
2 Diese Anfrage wird wie gehabt mit mysql_query() an den Server geschickt,
das Ergebnis wieder über mysql_fetch_object() ausgelesen und kann dann etwa über eine echo-Anweisung am Bildschirm ausgegeben werden: datum; $referer = $ds->referer; $webseite = $ds->webseite; echo "
$datum $referer $webseite
"; } ?>
3
Das Ergebnis ist in dieser Form natürlich ziemlich chaotisch, doch eine einfache Tabelle in HTML sorgt für rasche Abhilfe:
Eine rasche Ausgabe der Daten in eine HTML-Tabelle ist kein Problem – aber Feintuning für eine bessere Übersicht ist unverzichtbar.
Jetzt werden die Einträge zwar zeilenweise in eine Tabelle geschrieben, aber wirklich übersichtlich ist das noch nicht. Schließlich sorgen besonders lange Referer-Einträge dafür, dass die Tabelle nicht vollständig auf den Bildschirm
169
passt. Dabei gibt es eigentlich keinen Grund, warum wir die vollständige Referer-Adresse angezeigt bekommen sollten. Wenn ein Referer länger als sagen wir mal 50 Zeichen wird, können wir die Anzeige auch einfach abschneiden. Auf das ewig gleiche »http://« am Anfang jedes Referers können wir auch gut verzichten. Um die überlange Anzeige sinnvoll zu kürzen, entfernen wir zuerst die sieben ersten Zeichen und schneiden dann, wenn nötig, einfach alles ab, was danach noch länger als 50 Zeichen ist.
4
PHP bietet zahlreiche Funktionen zur Manipulation und Verarbeitung von Zeichenketten und es gibt verschiedene Möglichkeiten, unser Ziel zu erreichen. Am einfachsten ist es, wenn wir über die Funktion substr() 50 Zeichen ab der Position sieben (die Zählung beginnt bei 0) ausschneiden, zum Beispiel so: $referer = substr($ds->referer,7,50);
5
Und wenn wir schon mal dabei sind, können wir die Referer-Anzeige in der Tabelle auch noch als anklickbaren Link formatieren, so dass man von der LogdateiAnzeige aus gleich mal nachsehen kann, von welcher Seite die Besucher gekommen sind. Dafür müssen wir den – natürlich noch ungekürzten – Referer-Wert als href-Parameter in einem a-Element einsetzen. So ermitteln wir die Werte für die benötigten Variablen: $url = $ds->referer; $referer = substr($url,7,50);
6 Die Ausgabezeile für den Referer passen wir folgendermaßen an: echo "
Mit nur einer PHP-Anweisung lässt sich dafür sorgen, dass die Referer-Einträge in der Anzeige nicht das Maß der Tabelle sprengen.
170
Die Einträge einer Tabelle zählen
Die Einträge einer Tabelle zählen Bislang haben wir die Logdatei einfach »am Stück« ausgegeben, doch ist dieses Vorgehen eigentlich nicht zu empfehlen. Schließlich kann eine Logdatei im Laufe der Zeit sehr umfangreich werden und mehrere hundert wenn nicht gar tausend Einträge enthalten, was eine vollständige Ausgabe wenig sinnvoll erscheinen lässt. Daher setzen wir den Parameter LIMIT ein, mit dem die SELECT-Anweisung nur auf einen bestimmten Bereich der Tabelle zugreift. Dabei werden LIMIT zwei Parameter übergeben, mit denen der Startpunkt (beginnend bei Null) und die Anzahl der auszuwählenden Datensätze festgelegt werden. So werden mit LIMIT 0,15 die Datensätze Nummer 0 bis 14 selektiert, mit LIMIT 15,15 die folgenden Datensätze Nummer 15 bis 29 und so weiter. Übrigens kann man mit LIMIT auch nur einen einzigen Datensatz ausgeben, in diesem Fall lässt man die zweite Zahl einfach fort: LIMIT 1. Um diese Angaben korrekt einsetzen zu können, müssen wir wissen, wie viele Datensätze die Tabelle besitzt, damit wir nicht übers Ziel hinausschießen und mit LIMIT auf Datensätze zugreifen wollen, die es gar nicht gibt. Kein Fehler, aber unsauber
Man könnte die Anzahl der Datensätze auch ignorieren, das Script würde trotzdem funktionieren. Bei Zugriffen auf nicht existierende Datensätze liefert es einfach nur leere Ergebnisse, keine Fehler. Aber das wäre schon eine sehr schlampige und unsaubere Programmierung, die Sie sich besser erst gar nicht angewöhnen sollten.
Die Anzahl aller Zeilen in einer Tabelle liefert die MySQL-Funktion COUNT(), der wir als Argument ein Sternchen übergeben und so sämtliche Zeilen zählen lassen. Die Funktion wird als Teil eines SELECT-Statements über mysql_query() an den Server geschickt: $query = "SELECT COUNT(*) FROM logdatei"; $sql = mysql_query($query);
Die Variable $sql enthält wie gewohnt nicht die Anzahl, sondern nur einen Zeigerwert, über den PHP auf den Speicherbereich zugreifen kann, in dem der SQL-Server die angeforderte Information abgelegt hat. Um sie von dort auszulesen, benötigen wir die Funktion mysql_result(), der wir mindestens zwei Parameter übergeben müssen. Zum einen die Zeigervariable $sql, zum anderen eine ganze Zahl, die angibt, den wievielten Datensatz aus dem
171
Ergebnis wir auslesen möchten. Da die Abfrage genau einen Wert liefert und auch hier bei Null beginnend gezählt wird, können wir also mit $anzahl = mysql_result($sql,0)
auf den ersten – und einzigen – Wert zugreifen, den der MySQL-Server bereitgestellt hat. Um den Einsatz von COUNT zu testen, ermitteln wir mit folgendem Script, wie viele Zeilen die Tabelle logdatei enthält:
Setzt man im SELECT-Statement zusätzlich die WHERE-Klausel ein, so kann man mit COUNT auch ermitteln, wie viele Datensätze vorliegen, auf die bestimmte Bedingungen zutreffen. So lässt sich etwa mit SELECT COUNT(*) FROM logdatei WHERE datum = '2004-07-28'
ermitteln, wie viele Zugriffe am 28. Juli 2004 erfolgten. In diesem Fall wurde das Gleichheitszeichen benutzt, um nur bestimmte Datensätze auszufiltern. Man kann aber auch einen Mustervergleich durchführen. Dazu dient der Operator LIKE und der Platzhalter %, der für eine beliebige Anzahl von Zeichen steht. Mit %google% würden also sämtliche Einträge erfasst, in denen das Wort »google« an beliebiger Stelle auftaucht. Zeichenketten werden dabei wie üblich in einfache Anführungszeichen gesetzt. Die SELECT-Anweisung, die uns die Anzahl aller Datensätze (COUNT(*)) aus der Tabelle »logdatei« (FROM logdatei) liefert, bei denen im Feld »referer« (WHERE referer) an beliebiger Position die Zeichenfolge »google« auftaucht (LIKE '%google%'), sieht also so aus: SELECT COUNT(*) FROM logdatei WHERE referer LIKE '%google%'
Auf ähnliche Weise können Sie auch alle anderen Einträge der Tabelle zählen lassen. Möchten Sie zum Beispiel wissen, wie viele Besucher mit dem Internet
172
Die Einträge einer Tabelle zählen
Explorer 6 auf Ihre Webseiten zugegriffen haben, so lassen Sie alle Einträge zählen, bei denen im Browser-Feld die Zeichenfolge MSIE 6.0 auftaucht: SELECT COUNT(*) FROM logdatei WHERE browser LIKE '%MSIE 6.0%'
Das folgende Script ermittelt der Reihe nach die Anzahl ...
• • • • •
... aller Einträge. ... der Zugriffe an einem bestimmten Tag ... der Zugriffe, die via Google erfolgten ... der Besucher, die mit dem IE 6.0 unterwegs sind ... der Besucher, die einen auf Gecko basierenden Browser benutzen (z. B. Mozilla).
"; echo "Am 28. 7. 2004 kamen $tag Besucher. "; echo "Insgesamt kamen $google Besucher via Google. "; echo "$ie6 Besucher surfen mit dem Internet Explorer 6. "; echo "$gecko Besucher surfen mit einem auf Gecko basierenden Browser "; ?>
173
Die Notation ist in diesem Beispiel sehr ausführlich und lässt sich deutlich verkürzen. So können die jeweils drei Zeilen zur Definition der benötigten Variablen auch jeweils zu einer Zeile zusammengefasst werden. Für die Gesamtzahl sähe das zum Beispiel so aus: $alle = mysql_result(mysql_query("SELECT COUNT(*) FROM logdatei"),0);
Das Script lässt sich noch stärker vereinfachen, wenn wir eine Funktion definieren, der wir nur noch die WHERE-Klausel zur näheren Bestimmung dessen, was gezählt werden soll, übergeben. Wird die Funktion mit dem Parameter 0 aufgerufen, so gibt sie die Gesamtzahl zurück, ansonsten nur den gewünschten Wert.
Dadurch wird der PHP-Code zwar deutlich kürzer, aber ist auch nicht mehr so einfach lesbar, weshalb es nicht nur als Einsteiger nicht ratsam ist, bei der Entwicklung von Scripts sofort mit zusammenfassenden Verkürzungen und Funktionen zu arbeiten, sondern eine Aufgabe zuerst Schritt für Schritt zu lösen und erst dann, wenn alles fehlerfrei läuft, sich daran zu machen, den Code zu optimieren.
Liegen die Daten erst einmal in einer MySQL-Tabelle vor, kann man sie nach Herzenslust mit wenigen Code-Zeilen auswerten.
174
Die Logdatei bereichsweise ausgeben
Die Logdatei bereichsweise ausgeben Damit haben wir alle Bausteine beisammen, um den Inhalt der Tabelle »logdatei« bereichsweise am Bildschirm ausgeben zu können. Unsere AusgabeRoutine soll immer nur einen Abschnitt von 15 Einträgen anzeigen, wobei wir über einen Link die nächsten Einträge abrufen. Stoßen wir dabei an das Ende der Tabelle, beginnt die Anzeige wieder bei Null. Der erforderliche Startparameter für LIMIT wird beim Aufruf der Auswertungsseite als Parameter s übergeben, etwa mit ausgabe.php?s=90, um 15 Einträge ab Eintrag Nummer 90 anzuzeigen.
1
Unser kleines Script muss also zuerst ermitteln, wie viele Datensätze die Tabelle überhaupt besitzt und diesen Wert in einer Variablen, etwa $gesamt, speichern. Anschließend wird das gewünschte Intervall (in unserem Beispiel sind es 15 Einträge) definiert und der Start-Parameter mit $start = $_GET['s'] in einer Variablen abgelegt.
2
Den Parameter für den Link zu Anzeige der nächsten 15 Einträge ermitteln wir durch eine einfache Addition vom Start- und Intervallwert und legen ihn in der Variablen $mehr ab. Sollte die Summe aus dem aktuellen Startwert und dem Intervall die Gesamtanzahl der Einträge übersteigen, muss zum einen das Anzeigeintervall angepasst, zum anderen der Link-Parameter auf Null gesetzt werden. Hier setzen wir eine klassische if-/ else-Abfrage ein.
3
Setzen wir das alles zusammen an den Kopf der Datei »auswertung.php«, so ergibt sich dieses Script, das die benötigten Variablen bereitstellt: $gesamt) { $intervall = $gesamt - $start; $mehr = "0"; } else $mehr = $start + $intervall; ?>
4
Der HTML-Teil der Auswertungs-Datei unterscheidet sich nur geringfügig von dem weiter oben entwickelten Code zur tabellarischen Anzeige der gesamten Logdatei. Zum einen benötigen wird einen Link, über den wird die nächsten Einträge abrufen. Der könnte etwa so aussehen: ">Weiter
175
5
Am besten fügen wir an den Beginn der Tabelle eine dreispaltige Zeile mit Erläuterungen und einem »Weiter«-Link ein:
Die Tabelle enthält Einträge, dies sind Einträge Nummer bis ">Weiter
6 Außerdem müssen wir natürlich die Variable $query entsprechend anpassen: $query = "SELECT datum, referer, webseite FROM logdatei ORDER BY datum LIMIT $start,$intervall";
7 Das restliche Ausgabescript bleibt gleich.
Bei umfangreichen Tabellen empfiehlt sich die bereichsweise Ausgabe der Daten, indem die SELECT-Anweisung um LIMIT ergänzt wird.
176
TIMESTAMP-Einträge einfügen
TIMESTAMP-Einträge einfügen Beim Entwurf der Tabelle wurde bereits erörtert, dass das Logfile statt getrennter Datums- und Zeitfelder auch mit einem einzigen Feld vom Typ DATETIME oder TIMESTAMP auskommen könnte. Das werden wir jetzt ausprobieren. Im Folgenden werden die getrennten Felder aufgelöst und in einem TIMESTAMP-Feld zusammengeführt. Anschließend wird das SELECT-Statement so umgeformt, dass uns MySQL die Zeitangaben im gewünschten Format liefert, ohne dass wir den Zeitstempel in PHP zerlegen und analysieren müssten. Um bei diesem Umbau unsere bisher erfassten Werte nicht zu verlieren, müssen wir einen kleinen Trick anwenden. Normalerweise benutzt MySQL ein TIMESTAMP-Felder automatisch und ignoriert es, wenn wir einen Wert in dieses Feld schreiben möchten. Erweitern wir unsere Logdatei-Tabelle um ein solches Feld, füllt MySQL es auch gleich automatisch aus: Alle bereits vorhandenen Einträge haben in diesem Feld den Zeitpunkt stehen, zu dem das neue Feld eingefügt wurde. Erst bei neuen Einträgen wird hier der gewünschte Zeitstempel eingetragen. Damit würden die bisherigen Datumsund Zeitangaben gelöscht. Fügen wir jedoch anschließend ein weiteres, also zweites, TIMESTAMP-Feld hinzu, so ignoriert der MySQL-Server dieses Feld und füllt es mit Nullen. Dieses zweite Feld können wir über ein kleines PHPScript mit den bisher erfassten Datums- und Zeitwerten füllen. Anschließend löschen wir das erste TIMESTAMP-Feld und behalten so ein Feld zurück, das bei den bereits vorhandenen Einträgen den korrekten Zeitpunkt enthält und das bei neuen Zugriffen automatisch ausgefüllt wird.
Wenn Sie zwei TIMESTAMP-Felder anlegen, wird nur das erste von MySQL selbst verwaltet, das zweite steht zu Ihrer Verfügung.
1
Rufen Sie in PHPMyAdmin die Tabelle der Logdatei auf und fügen Sie auf der Registerkarte »Struktur« zwei neue Felder unterhalb vom Feld id an. Die beiden neuen Felder sind jeweils vom Typ TIMESTAMP, das erste der beiden ist das Dummy-Feld, das später gelöscht werden wird.
177
Die Nullwerte des zweiten Feldes werden später durch ein Script mit den Datums- und Zeitangaben im TIMESTAMP-Format überschrieben werden.
2
Werfen Sie nun einen kurzen Blick in die Anzeige der Tabelle. Wie Sie sehen, enthält das erste Feld den exakten Zeitpunkt, zu dem Sie die Änderung vorgenommen haben, das zweite Feld ist mit Nullen gefüllt – aber das werden wir jetzt ändern.
Da in einem TIMESTAMP-Feld Datum und Uhrzeit als fortlaufender Ziffernstring ohne Trennzeichen gespeichert werden, müssen wir die beiden Werte aus der Tabelle auslesen, zusammenfügen und anschließend die Bindestriche aus dem Datum und die Doppelpunkte aus der Zeitangabe löschen. Das Zusammenfügen erledigen wir wie gehabt durch den Verkettungsoperator (den Punkt), die Zeichen ersetzen wir mit der Funktion str_replace(), die wir bereits in Kapitel 2 kennen gelernt haben. Zur Erinnerung an die etwas verquere Syntax der Funktion, soll ein einfaches Beispiel dienen. Wir verwandeln das Wort »Erdbeereis« in »Erdbeerkuchen«. Mit anschließender Textausgabe sieht der PHP-Code folgendermaßen aus:
Wenn wir mit dieser Funktion Zeichen aus einer Zeichenkette löschen möchten, so müssen wir den zweiten Parameter leer lassen. So wird aus »Erdbeereis« einfach nur »Erdbeer«:
Wenden wird diese Funktion auf unsere Logdatei an, erhalten wir folgendes kleines Script, in dem wir zuerst Datum und Uhrzeit auslesen, die beiden Werte zusammenfügen und anschließend die überflüssigen Zeichen entfernen:
Um den Inhalt der Variablen $stempel in das neue Feld zeitstempel einzufügen, benutzen wir die UPDATE-Anweisung. Damit die Anweisung auch weiß, zu welchem Eintrag der neue Wert gehört, lesen wir zusätzlich das Feld id des jeweiligen Eintrags aus und speichern den Wert in der Variablen $id. Die Anweisung sieht so aus: UPDATE logdatei SET zeitstempel = $stempel WHERE id = $id
Ergänzen wir das SELECT-Statement unseres Scripts um die id-Abfrage und fügen die benötigte UPDATE-Anweisung hinzu, so erhalten wir die folgenden Code-Zeilen: id; $datum = $ds->datum; $zeit = $ds->zeit; $stempel = $datum.$zeit; $stempel = str_replace("-","",$stempel); $stempel = str_replace(":","",$stempel); $query = "UPDATE logdatei SET zeitstempel = $stempel WHERE id = $id"; $dummy = mysql_query($query); } mysql_close($dz); ?>
Beachten Sie, dass hier keine Rückmeldung am Bildschirm erfolgt – wenn das Browserfenster nach dem Aufruf also leer bleibt, war das Script erfolgreich. Sie können sich mit einem Blick in PHPMyAdmin davon überzeugen, dass das Feld zeitstempel nun die gewünschten Werte enthält.
179
Die Felder dummy, datum und zeit werden jetzt nicht mehr benötigt und können via PHPMyAdmin gelöscht werden. Sobald dummy gelöscht wird, wird zeitstempel zum ersten und einzigen Feld vom Typ TIMESTAMP, in dem der MySQL-Server bei jedem neuen Eintrag automatisch Datum und Uhrzeit speichert. Nun müssen wir noch unser Script, mit dem wir die Logdaten in die Tabelle schreiben, überarbeiten – also einfach alles löschen, was mit Zeit und Datum zu tun hat – und die Umwandlung ist abgeschlossen.
TIMESTAMP-Einträge formatiert auslesen Die Umwandlung hat uns zwar ein Tabellenfeld und eine Hand voll PHPCode erspart, aber dafür stehen wir jetzt vor dem Problem, dass wir das Datum und die Uhrzeit nicht mehr mit einem Blick bzw. einer einfachen MySQL-Abfrage ermitteln können. Doch das Problem ist schnell behoben, schließlich stellt MySQL die Funktion DATE_FORMAT zur Verfügung, mit der wir das TIMESTAMP-Feld vom Server auswerten lassen können. Wie bei den Zeit- und Datumsfunktionen in PHP, die in Kapitel 3 erläutert wurden, wird auch bei dieser Funktion zuerst das Datum übergeben und anschließend über verschiedene Parameter definiert, wie das Datum formatiert werden soll. Die wichtigsten Parameter sind dabei:
• •
180
%c für den numerischen Monatswert von 1 für Januar bis 12 für Dezember %d und %e für den numerischen Tageswert; dabei ist %d zweistellig mit führender Null (00 bis 31) und %e einfach (0 bis 31)
•
%H und %h liefern die Stunde mit führender Null im 24- bzw. 12-Stundenformat
•
%i ergibt die Minutenzahl mit führender Null
TIMESTAMP-Einträge formatiert auslesen
• •
%T für die Zeit im 24-Stunden-Format als hh:mm:ss %w für die numerische Angabe des Wochentags, von 0 für Sonntag bis
6 für Samstag
•
%Y für die vierstellige Jahresangabe.
Die Parameter können beliebig kombiniert werden und werden in Hochkommata der Funktion übergeben. Möchte man also aus dem Feld zeitstempel nur das Datum im Format »27.3.1961« genannt bekommen, so erreicht man dies mit SELECT DATE_FORMAT(zeitstempel,'%e.%c.%Y') FROM logdatei
Um das Ergebnis auszulesen und einer Variablen zuzuweisen, muss man MySQL allerdings noch sagen, als welchen Wert es die formatierte Zeitangabe übergeben soll – bislang liegt ja nur ein Wert, aber keine Variable vor, der dieser Wert zugeordnet werden könnte. Dies erreicht man durch die Anweisung AS name (was mit: »als 'name'« übersetzt werden kann). Die umgangssprachliche Anweisung: »Stelle den Inhalt aus dem Feld zeitstempel der Tabelle logdatei formatiert unter dem Namen datum zur Verfügung« sieht also so aus: SELECT DATE_FORMAT(zeitstempel,'%e.%c.%Y') AS datum FROM logdatei
Die DATE_FORMAT-Funktion samt AS-Anweisung gilt als ein Parameter für SELECT, dem weitere, mit Komma getrennt, angefügt werden können. Statt wie bisher datum, referer, webseite anzugeben, heißt es nun DATE_FORMAT(zeitstempel,'%e.%c.%Y') AS datum, referer, webseite
Damit ist es nun möglich, die Variable $query in unserem Ausgabescript entsprechend anzupassen: $query = "SELECT DATE_FORMAT(zeitstempel,'%e.%c.%Y') AS datum, referer, webseite FROM logdatei ORDER BY zeitstempel LIMIT $start,$intervall";
Da das Datum immer noch unter dem Namen datum ermittelt wird, kann das gesamte übrige Script so bleiben, wie es ist. Der Vollständigkeit halber sei noch erwähnt, dass Sie hier nicht zwingend an den Feldnamen der Tabelle gebunden sind. Sie könnten statt AS datum natürlich auch ein AS firlefanz in das SELECT-Statment einfügen und die Zuweisung $datum = $ds->datum;
in $datum = $ds->firlefanz;
ändern – aber warum sollten Sie das tun?
181
MySQL kann uns Datums- und Zeitangaben auch gleich in dem Format liefern, in dem wir sie benutzen möchten und uns die Umwandlung innerhalb von PHP ersparen.
Das komplette Script Nachfolgend nun noch einmal alles im Zusammenhang – das vollständige Script zur bereichsweisen Anzeige der Logdatei mit formatiert ausgelesenem TIMESTAMP, wie es in den letzten Abschnitten nach und nach entwickelt wurde: $gesamt) { $intervall = $gesamt - $start; $mehr = "0"; } else $mehr = $start + $intervall; ?>
182
Menschen, nicht Maschinen
Die Tabelle enthält Einträge, dies sind Einträge Nummer bis ">Weiter
Richard M. Stallman wurde 1953 geboren und ist heute der wohl bekannteste Kämpfer für Freie Software. Er gründete das wichtige GNU Projekt und ist Präsident der 1985 ebenfalls von ihm gegründeten Free Software Foundation, die sich für alle Fragen und Belange der Freien Software einsetzt. Für Stallman hat das Thema nicht nur technische Aspekte, sondern ist von umfassender gesellschaftlicher Bedeutung, was sich in seinem starken poltischen Engagment niederschlägt. Auf Stallmans Homepage finden Sie umfangreiche Artikel und Dokumente zu seiner Arbeit: http://www.stallman.org/.
183
Kapitel 7
Eine Mottomaschine für die Homepage
Inzwischen können wir Daten via PHPMyAdmin und mit einem Script in eine MySQL-Tabelle eingeben und wieder auslesen. Was uns noch fehlt, ist eine ausgefeilte Formularauswertung und anschließende Speicherung der Eingaben. Am Beispiel einer Mottomaschine für die Homepage werden wir unsere MySQL- und PHP-Fähigkeiten weiter ausbauen.
Ihr Erfolgsbarometer
Das können Sie schon: Am Beispiel von drei Praxisprojekten haben Sie gelernt, wie Sie Daten in Dateien speichern, Cookies einsetzen und Formulare auswerten. Sie haben die mächtigen Einsatzmöglichkeiten von numerischen und assoziativen Arrays kennen gelernt. Dank PHPMyAdmin war der Einstieg in MySQL nicht schwer und Sie haben gelernt, wie Sie von PHP aus auf MySQL-Daten zugreifen können. Am Beispiel einer Logdatei haben Sie den Einsatz der Dateitypen von MySQL gelernt und wissen nun, wie Sie Daten via PHP speichern
66 92
120
150
Das lernen Sie neu: Öfter mal was Neues: Die Mottomaschine Berechneter Zufall Ein Abstecher zu den Lottozahlen Die Motto-Auswahl und -Ausgabe Das ausgewählte Motto bearbeiten Einträge aus einer MySQL-Tabelle löschen Jede Menge Formulare Zufallszugriffe mit MySQL Die Bildermaschine: Dateiverzeichnisse mit PHP lesen
186 191 193 194 201 208 209 216 218
185
Öfter mal was Neues: Die Mottomaschine Die Grundidee der Mottomaschine ist recht einfach: Bei jedem Aufruf einer Webseite soll ein zufällig ausgewähltes Motto aus einer Motto-Tabelle einer MySQL-Datenbank ausgelesen und angezeigt werden, so dass Besucher der Seite jedes Mal mit einem anderen Aphorismus, Sinnspruch oder Zitat begrüßt werden. Die Mottomaschine besteht aus verschiedenen Modulen.
•
Eingabe: Über das Eingabeformular erfassen wir die Texte, die in die MottoTabelle eingefügt werden.
•
Auswertung: Eine Auswertungsroutine nimmt die Formulareingaben entgegen und schreibt sie in die Tabelle.
•
Ausgabe: Natürlich benötigen wir auch ein Script, das wir in die mit einem Motto zu schmückende Webseite einfügen und das ein zufälliges Motto aus der Tabelle auswählt und anzeigt.
•
Bearbeitung: Und damit wir nicht immer auf PHPMyAdmin angewiesen sind, brauchen wir eine Webseite, die uns den Inhalt der Motto-Tabelle anzeigt und bearbeiten lässt.
So weit der grobe Überblick, machen wir uns an die Arbeit und entwerfen zuerst die Rohfassung der benötigten Module. Diese Rohfassung nimmt so gut wie keine Rücksicht auf problematische Sonderzeichen, mögliche Fehlerquellen und Ähnliches (darum kümmern wir uns erst in den nächsten Kapiteln); hier geht es nur um das zu Grunde liegende Prinzip.
Die Motto-Tabelle Zuerst legen wir mit PHPMyAdmin die Tabelle an, die unsere Mottosammlung aufnehmen soll. Diese Aufgabe stellt uns inzwischen vor keine nennenswerten Probleme.
1
Starten Sie PHPMyAdmin und wechseln Sie zu Ihrer Test-Datenbank. Legen Sie dort eine neue Tabelle mit dem Namen »motto« und drei Feldern an.
2 Das erste Feld nimmt den obligatorischen Datensatzindex id auf. Das Feld
wird wie gewohnt als SMALLINT mit dem Attribut UNSIGNED und dem Extra auto_increment angelegt. Außerdem definieren wir es als den Primärindex oder -schlüssel der Tabelle. Über diesen eindeutigen, fortlaufenden Index greifen wir später auf einen zufällig ausgewählten Eintrag zu.
186
Das Eingabeformular
Um das id-Feld als »Primärschlüssel« anzulegen, müssen Sie in PHPMyAdmin ganz nach rechts außen scrollen.
3
Das zweite Feld soll unsere Motto-Einträge aufnehmen. Der Name des Feldes ist also motto, als Typ wählen wir TEXT. Mit seinem Fassungsvermögen von 64 KByte bietet dieses Feld mehr als genügend Platz. Eine kleinere Einheit steht nicht zur Verfügung, die nächst kleineren Typen VARCHAR bzw. TINYTEXT nehmen jeweils nur maximal 255 Zeichen auf, was entschieden zu wenig ist.
4
Das dritte und letzte Feld der Tabelle ist für die Quellenhinweise bestimmt. Hier genügen 255 Zeichen, länger wird ein solcher Hinweis nicht werden. Wir nennen das Feld quelle und legen es als VARCHAR mit einer Länge von 255 an.
Die Motto-Tabelle ist sehr einfach strukturiert und besteht nur aus drei Feldern.
Das Eingabeformular Auch das Formular zur Eingabe der Mottos ist kein kompliziertes Hexenwerk, sondern banales Basis-HTML. Wir benötigen lediglich ein Formular mit je einem Eingabefeld für Motto und Quelle, die Datensatznummer wird von MySQL ja automatisch erstellt.
1 Für längere Texteingaben stellt HTML das Formularelement textarea zur Ver-
fügung. Anders als bei input gibt es hier einen öffnenden und einen schließenden Teil, der zwingend angegeben werden muss. Möchte man, dass in dem Formularfeld ein Text angezeigt wird, so wird er als Inhalt des Elementes zwischen Anfangsund Endteil notiert (darauf kommen wir später zurück).
2
Höhe und Breite eines Textfeldes werden normalerweise über die Attribute rows und cols festgelegt, in diesem Beispiel werden stattdessen style-Angaben benutzt, da nur so das Erscheinungsbild des Feldes exakt definiert werden kann. Seinen Inhalt liefert das Feld unter dem Namen motto zurück:
187
3 Die Quelle wird in einem normalen input-Feld erfasst, das mit einer style-
Angabe auf die Breite des Textfeldes gebracht wird und auf den Namen quelle hört:
4
Das Formular selbst schickt die Daten für motto und quelle mit post an das Auswertungsscript »auswertung.php« weiter. Der vollständige HTML-Code des Formulars sieht also so aus:
Motto-Eingabe
Ein einfaches Formular zur Eingabe der Mottos ist in HTML schnell erstellt.
188
Die Auswertung
Die Auswertung So einfach, wie es bisher war, geht es weiter, auch beim Auswertungsformular setzen wir nur bereits bekannte Programmiertechniken ein. Das benötigte Script »auswertung.php« muss gar nicht viel können: Variablen entgegennehmen, in die Tabelle schreiben, den Eintrag zur Kontrolle anzeigen und die Möglichkeit bieten, ein weiteres Motto einzutragen.
1
Damit wir keine überflüssigen Leerzeichen, Tabulatoren und Ähnliches speichern, werden die eingegebenen Daten mit der Funktion trim() behandelt, bevor sie in die Tabelle eingetragen werden. Der PHP-Teil, der die Variablen ausliest und in die Tabelle schreibt, sieht zum Beispiel so aus:
2
Daran schließt sich ein kleiner HTML-Teil an, der die Eingabe zur Kontrolle am Bildschirm anzeigt und einen Link zum Eingabeformular bietet. Auch hier wird, wie beim Eingabeformular, mit wenigen style-Angaben dafür gesorgt, dass die Anzeige nicht gar so trostlos trocken erscheint, wie es beim Standard-HTML üblich ist:
Das über das Formular eingegebene Motto wurde in die Tabelle eingetragen und wird zur Kontrolle noch einmal angezeigt. Über den Link ruft man erneut das Eingabeformular auf.
Damit Sie die nächsten Schritte nachvollziehen können, geben Sie einfach ein paar Mottos in die Tabelle ein. Wenn Sie Zeichen, die für PHP Steuerzeichen sind (wie die normalen Anführungszeichen "..." oder Hochkommata '...') eingeben, werden Sie vermutlich feststellen, dass diese Zeichen automatisch »escaped«, also mit einem Backslash versehen werden. Dieses Phänomen hört auf den Namen »Magic Quotes« und gehört zu den problematischen Sonderfällen, die wir beim Feintuning der Mottomaschine im nächsten Kapitel berücksichtigen werden. Sollte das Phänomen bei Ihrer PHP-Installation nicht auftreten, dann sind Sie dem Grundproblem dieser »Magic Quotes« übrigens bereits auf der Spur.
190
Berechneter Zufall
Hoppla – bei der Eingabe von Anführungszeichen ist das Ergebnis nicht unbedingt das, was wir erwartet haben.
Aber wie gesagt – dazu später mehr. Jetzt geht es vorerst nur darum, die Maschine überhaupt zum Laufen zu bekommen – wie stotternd und spotzend auch immer, Hauptsache, sie läuft.
Berechneter Zufall Bei den bisherigen Modulen unserer Mottomaschine haben wir lediglich Verfahren eingesetzt, die wir bereits in den vorherigen Kapiteln entwickelt und kennen gelernt haben. Für die Auswahl des Mottos in der Ausgaberoutine reicht das aber nicht. Schließlich möchten wir aus der Mottosammlung mit jedem Aufruf ein zufälliges Motto herausgreifen und anzeigen. Damit das geht, müssen wir zuerst wissen, wie man in PHP Zufallszahlen erzeugt. Ein Computer kann vor allem eins: rechnen. Schlimmer noch – er kann nur rechnen. Auch Zufallszahlen müssen vom Computer berechnet werden – und das ist einigermaßen paradox, schließlich ist das, was berechnet werden kann, nicht mehr zufällig. Der Computer erzeugt also immer nur Pseudo-Zufallszahlen. Ganz gleich, wie kompliziert die Berechnungen sind, die der PC ausführt um die pseudozufällige Zahl zu ermitteln: Bei gleichem Ausgangspunkt und gleicher Rechengrundlage ergibt sich immer wieder die gleiche pseudozufällige Zahlenfolge. Bei PHP wird die Funktion zur Berechnung der Zufallszahl daher bei jedem Aufruf mit einem andern Wert initialisiert, der auf dem so genannten Unix-Timestamp basiert. Dieser Zeitstempel zählt die
191
verflossenen Sekunden seit dem 1. Januar 1970, 0:00:00 Uhr (dieses Datum markiert den Beginn der Unix-Epoche).
1
Der praktische Einsatz der pseudozufälligen Zahlen in PHP ist denkbar einfach. Zur Ermittlung von Zufallszahlen innerhalb eines bestimmten, ganzzahligen Intervalls stellt PHP die Funktion rand() zur Verfügung. Als Parameter übergibt man zwei ganzzahlige Grenzwerte des Intervalls, mit $zufall = rand(1,10): wird der Variablen $zufall ein zufälliger Wert zwischen 1 und 10 zugewiesen.
Zufallszahlen initialisieren
Die Funktion rand() liefert erst ab der PHP-Version 4.2.0 mit jedem Aufruf andere Zufallszahlenfolgen, bei früheren PHP-Versionen muss rand() vor dem Einsatz mit srand() einmalig initialisiert werden:
Computergenerierte Zufallszahlen sind nicht wirklich zufällig, aber für die Praxis immer noch zufällig genug.
2
Um sich davon zu überzeugen, dass die Funktion bei jedem Aufruf einen anderen Wert liefert, können Sie das folgende Mini-Testscript einsetzen und mehrfach hintereinander aufrufen. Bei jedem Aufruf werden 100 zufällige Zahlen zwischen 1 und 10 ausgegeben:
192
Ein Abstecher zu den Lottozahlen
Ein Abstecher zu den Lottozahlen Mit der Zufallsfunktion rand() können Sie sich mit PHP übrigens auch die Lottozahlen vorschlagen lassen. Allerdings ist es hier mit einer einfachen Schleife, die sechs Zufallszahlen aus dem Intervall von 1 bis 49 ermittelt, nicht getan. Schließlich kann es hier zu Dopplungen kommen – und mit einem Tipp wie 5 9 9 31 44 49
hat man nun garantiert nicht das große Los gezogen. Spielen wir die Ziehung der Lottozahlen in PHP zur Übung einmal kurz durch.
1
Um Dopplungen zu vermeiden, erfolgt die Ziehung der Lottozahlen gewissermaßen über Bande. Statt die Zahlen direkt zu ermitteln, setzen wir ein numerisches Array $lotto mit 49 Einträgen von $lotto[1] bis $lotto[49] ein. Bei jeder ermittelten Zufallszahl zwischen 1 und 49 wird überprüft, ob das entsprechende Element von $lotto den Wert 1 besitzt. Ist dies der Fall, dann wurde diese Zahl bereits gezogen und wir brauchen eine neue Zufallszahl. Falls der Wert des Array-Eintrags dagegen Null ist, wird er auf eins gesetzt und damit als gezogen markiert.
2
Da wir nicht im Voraus wissen können, wie oft wir eine Zufallszahl ermitteln müssen, bis wir unsere »6 aus 49« zusammen haben, setzen wir eine while-Schleife und eine Zählvariable $ziehung ein, die mit dem Wert 1 initialisiert und nach jeder erfolgreichen Ziehung um eins erhöht wird. Sobald $ziehung den Wert 7 erreicht, haben wir unsere sechs Zahlen beieinander und können sie ausgeben
3
Die Ausgabe erfolgt in einer Schleife. Die Schleifenvariable durchläuft die Werte von 1 bis 49 und wird als Index für $lotto benutzt. Falls der entsprechende Wert von $lotto 1 ist, dann wurde diese Zahl gezogen und wir geben den aktuellen Wert der Schleifenvariablen aus. Durch diesen kleinen Umweg erreichen wir nicht nur, dass wir sechs unterschiedliche Zahlen zwischen 1 und 49 erhalten, sondern auch, dass diese Zahlen numerisch sortiert sind:
193
4 Die if-Abfrage zur Ausgabe der gezogenen Zahlen enthält nur eine Anweisung und passt daher in der Kurznotation ohne Mengenklammern in eine Zeile. Damit besteht auch die for-Schleife aus nur einer Anweisung und auch bei ihr kann auf die Mengenklammern verzichtet und alles in einer Zeile notiert werden. Das spart ein paar Zeilen im Code, aber natürlich erreichen Sie mit der übersichtlicheren Langform ebenfalls Ihr Ziel:
for ($i = 1; $i <= 49; $i++) { if ($lotto[$i] == 1) { echo "$i "; } }
Die Motto-Auswahl und -Ausgabe Nach diesem kurzen Exkurs in die Zufallszahlen mit PHP ist die zufällige Auswahl eines Eintrages in der Tabelle kein Problem mehr.
1 Mit der MySQL-Funktion COUNT() ermitteln wir die Gesamtzahl der Tabellen-
einträge und gleichzeitig die Obergrenze des Intervalls, aus dem wir mit rand() eine Zufallszahl ermitteln: $query = "SELECT COUNT(*) FROM motto"; $sql = mysql_query($query); $max = mysql_result($sql,0); $id = rand(1,$max);
194
Die Motto-Auswahl und -Ausgabe
2
Anschließend wird der entsprechende Datensatz ausgelesen und in zwei Variablen abgelegt, auf die im HTML-Teil der Webseite an beliebiger Stelle zugegriffen werden kann. Damit dies auch problemlos geschehen kann, werden die Werte über die Funktion htmlentities() in korrektes HTML umgewandelt.
3 Da das SELECT-Statement genau einen Datensatz zurückliefert, können wir auf die bisher eingesetzte while-Schleife beim Auslesen der Daten verzichten:
$query = "SELECT motto, quelle FROM motto WHERE id = $id"; $sql = mysql_query($query); $ds = mysql_fetch_object($sql); $motto = htmlentities($ds->motto); $quelle = htmlentities($ds->quelle);
4
Setzt man dieses Script vor den Beginn des HTML-Teils, stehen für die Webseite in den beiden Variablen $motto und $quelle die benötigten Angaben zur Verfügung. Ein einfaches Beispiel für den praktischen Einsatz der Mottomaschine: motto); $quelle = htmlentities($ds->quelle); mysql_close($dz); ?> Testseite <style type="text/css"> p, body, h1 {font-family : Arial}
Willkommen auf meiner Webseite
Schon bemerkt? Das Motto am Kopf der Seite ändert sich mit jedem Aufruf!
195
Liegen Motto und Quelle erst einmal als Variablen vor, kann man sie an beliebiger Stelle auf der Webseite anzeigen lassen.
Das Bearbeitungsmodul Nachdem die Mottomaschine einigermaßen störungsfrei läuft, fehlt uns nur noch ein Script, mit dem wir die Einträge in der Tabelle bearbeiten können, ohne dass wir dazu immer PHPMyAdmin starten müssen. Unser Script soll es uns erlauben, aus einer kleinen Übersicht gezielt auf einen Datensatz zuzugreifen, ihn zu verändern, zurückzuschreiben – und, als radikalste Form der Bearbeitung – ihn gegebenenfalls zu löschen. Die Grundstruktur der Bearbeitungsseite – die im Folgenden unter dem Dateinamen »bearbeiten.php« in mehreren Schritten entwickelt wird – soll im oberen Bereich ein Eingabefenster bieten, in dem das aktuell zu bearbeitende Motto angezeigt wird. Darunter werden die verschiedenen, bereits gespeicherten Mottos in einer kleinen Tabelle aufgelistet. Dabei besitzt jedes Motto einen Link. Klickt man auf diesen Link, so soll das gewählte Motto in das Bearbeitungsformular übernommen, bearbeitet und wieder gespeichert werden können. Damit das funktioniert, bestehen die Links in der Tabelle aus dem Aufruf der Bearbeitungsseite, der als get-Parameter der Index des gewählten Eintrags übergeben wird.
196
Das Bearbeitungsmodul
Die Datei »bearbeiten.php« kann also auf zwei Arten aufgerufen werden: Ohne get-Parameter, also zum Beispiel mit:
http://localhost/bearbeiten.php Dann wird ein leeres Formular am Kopf der Seite gezeigt, darunter stehen tabellarisch aufgelistet die bereits vorhandenen Mottos. Oder aber mit get-Parameter, also zum Beispiel so:
http://localhost/bearbeiten.php?id=17 In diesem Beispiel soll also das Motto mit dem Index 17 aus der MySQLTabelle ausgelesen und sein Inhalt im Formularfeld zur Bearbeitung eingetragen werden. Unterhalb des Formularfeldes folgt wieder die tabellarische Liste aller vorhandenen Mottos. Bevor wir uns um den eigentlichen Script-Teil der Datei kümmern, entwerfen wir schon eine Rohfassung des HTML-Formulars und der Tabelle zur Anzeige der vorhandenen Mottos. In einem späteren Schritt werden wir diese Grobstruktur verfeinern.
1
Der PHP-Teil zu Beginn der Datei besteht vorerst nur aus unserer Standardzeile, mit der wir die Verbindung zum Datenbankserver aufnehmen:
2
Auf diesen Block folgen die üblichen HTML-Header-Daten, in die wir eine kleine CSS-Definition einschieben, um die Tabellenausgabe etwas ansehnlicher zu gestalten, als es mit Standard-HTML möglich ist: <style type="text/css"> body, td {font-family : Arial; font-size: 16px;} small {font-size : 12px;} td {vertical-align: top; border-bottom : 1px solid black; border-right : 1px solid black; padding : 5px; }
197
3
Als ersten Teil des HTML-Bodys setzen wir das Formular zur Bearbeitung von Motto und Quelle. Dieses Formular unterscheidet sich im bisherigen Entwurfszustand kaum von dem Formular, das wir bislang für die Eingabe benutzt haben:
4
Im Anschluss an dieses Formular folgt die Tabelle mit den verschiedenen Mottos. Die einzelnen Tabelleneinträge erzeugen wir innerhalb einer while-Schleife. Die notwendigen SQL-Kommandos zum Auslesen der Einträge sind uns inzwischen wohl vertraut, wir müssen nur darauf achten, bei der Zuweisung von $motto und $quelle über die Funktion htmlentities() für korrekt kodierten HTML-Code zu sorgen.
5
Wir gönnen der Tabelle noch eine Überschrift und kommentieren die Ausgabe der einzelnen Zeilen vorerst einmal aus. Nach der Tabelle folgen noch die abschließenden Tags zum Beenden der HTML-Datei. So erhalten wir folgende Grundstruktur:
Id
Motto
Bearbeiten
id; $motto = htmlentities($ds->motto); $quelle = htmlentities($ds->quelle); /* Hier werden die einzelnen Tabellenzeilen ausgegeben */ } ?>
198
Das Bearbeitungsmodul
6
An die Stelle des Kommentars müssen wir nun nur noch den Code für eine dreispaltige Tabellenzeile setzen. In der erste Spalte steht die Datensatznummer, also die id, in der zweiten Spalte das Motto samt Quellenangabe und in der dritten findet sich der Bearbeitungslink, den wir der Kürze halber lieber »Edit« nennen. Damit wir nicht zu viele Anführungszeichen escapen müssen, verlassen wir für die Ausgabe der Zeile kurz den PHP-Code und wechseln zu HTML.
7 Für den »Edit«-Link wird die id des aktuellen Datensatzes als get-Parameter an
den URL gehängt. Die Notation mischt HTML- und PHP-Code und bietet ein auf den ersten Blick krudes Gemisch aus spitzen Klammern und Zuweisungszeichen, ist aber im Grunde ganz einfach. In reinem HTML sähe ein solcher Link etwa so aus:
8 Wir müssen lediglich den übergebenen Wert (hier die 1) durch die Variable $id
ersetzen, die wir mit echo ausgeben, was in der Kurzform bekanntlich so aussieht: . Setzt man nun diesen Code an die Stelle der Ziffer, so ergibt sich diese Anweisung: ">Edit
9
Setzen wir alles zusammen, so erhalten wir folgendes Code-Segment, mit dem die Mottos jeweils in einer Tabellenzeile ausgegeben werden: ?>
Damit steht das Grundgerüst des Bearbeitungsmoduls, das bislang allerdings nur ein nicht funktionierendes Formular zur Verfügung stellt und die gesamten Mottos anzeigt. Ein Klick auf »Edit« übergibt zwar einen get-Parameter, hat ansonsten aber keine Auswirkungen. Es wird Zeit, das zu ändern.
199
Das Bearbeitungsmodul sieht zwar schon ganz gut aus, funktioniert aber noch nicht. Noch fehlt der entscheidende Script-Teil.
Ausgewählte Mottos anzeigen Widmen wir uns nun der eigentlichen Bearbeitungsroutine unserer Mottomaschine, von der wir derzeit gewissermaßen nur die Karosserie besitzen.
1
Damit unser Bearbeitungsmodul auf Touren kommt, muss unser Script-Teil zu Beginn der Datei einen eventuell übergebenen get-Parameter auswerten. Dazu weisen wir zuerst der Variablen $id den Wert von $_GET['id'] zu und überprüfen anschließend mit einer if-Abfrage, ob der Wert leer ist oder nicht.
2
Sollte die Abfrage if (!empty($id)) zutreffen – $id also nicht leer oder gleich Null sein – dann können wir den gewünschten Datensatz auslesen und in entsprechenden Variablen zur Verfügung stellen.
200
Das ausgewählte Motto bearbeiten und speichern
3
Zusammen mit dem Kommando zur Einbindung der MySQL-Verbindung ergibt sich für den einleitenden Script-Teil also der folgende Code: id; $motto = $ds->motto; $quelle = $ds->quelle; } ?>
4 Nun liegen in den Variablen $id, $motto und $quelle die Werte des aus-
gewählten Datensatzes vor und können im Formular ausgegeben werden. Dazu weisen wir dem input-Feld den Inhalt von $quelle über das Attribut value zu, während wir beim Textfeld die Variable $motto im textarea-Element eintragen:
Mit dieser Erweiterung der Datei sind wir bereits in der Lage, nach einem Klick auf den Edit-Link das gewählte Motto im Bearbeitungsformular anzuzeigen. Bearbeiten können wir es natürlich auch – aber der Klick auf die Schaltfläche bewirkt noch gar nichts, die Bearbeitungen werden einfach ignoriert.
Das ausgewählte Motto bearbeiten und speichern
1
Was genau passiert, wenn wir auf die Schaltfläche klicken? Ganz einfach: Das Formular übermittelt die Daten mit post an die Datei »bearbeiten.php«, also gewissermaßen an sich selbst. Unser Script-Teil muss nun so umgebaut werden, dass die übergebenen Daten des bearbeiteten Datensatzes korrekt in die Tabelle zurück geschrieben werden.
2 Damit das möglich ist, benötigen wir die id des Eintrags, also den Wert von
$id. Das Formular darf nicht nur die Werte für motto und quelle übertragen, sondern muss auch den Wert für id übermitteln. Das erledigen wir wie gewohnt über ein weiteres input-Feld im Formular.
201
3
Damit dieses Feld aber nicht angezeigt und bearbeitet werden kann – sonst wird am Ende noch durch einen dummen Eingabefehler die falsche Datensatznummer übermittelt und damit der falsche Datensatz bearbeitet – ist das zusätzliche inputFeld vom Typ hidden, sein Name ist id und als Wert (value) wird der Inhalt der Variablen $id eingetragen.
4
Das Formular muss also an einer beliebigen Stelle um diesen Eintrag erweitert werden:
Damit haben wir nun alle notwendigen Bauteile zusammen, um unser einleitendes Script der Datei »bearbeiten.php« um den benötigten Code zur Aktualisierung eines bearbeiteten Datensatzes zu erweitern.
5
Wenn beim Aufruf von »bearbeiten.php« eine get-Variable namens id vorliegt, dann wurde die Datei mit einem URL-Parameter aufgerufen und wir müssen den gewünschten Datensatz im Formular anzeigen.
6
Falls jedoch passende post-Werte vorhanden sind, dann wurde ein Datensatz bearbeitet und muss über ein UPDATE-Statement aktualisiert werden.
7
Bislang überprüfen wir beim Aufruf der Seite, ob eine get-Variable übergeben wurde. Diese Abfrage wird nun mit einer else-Verzweigung um eine Abfrage nach dem Vorliegen von post-Variablen erweitert.
8
Dabei gehen wir genauso vor, wie bei der get-Abfrage. Wir weisen den Variablen $id, $motto und $quelle die entsprechenden $_POST-Einträge zu und überprüfen anschließend, ob $id nach dieser Zuweisung einen Inhalt hat oder nicht. Ist dies der Fall, so wird der entsprechende Datensatz aktualisiert. Damit wir beim Aktualisieren der Daten keinen unnötigen Whitespace in die Datenbank schreiben, werden die vom Formular übergebenen Daten außerdem mit trim() bereinigt.
9
Damit das Formular anschließend leer ist und wir kein Durcheinander mit Variablenwerten bekommen, werden die Variablen nach dem Update gelöscht. Das könnte man über eine Zuweisung der Art $motto = ""; erledigen, eleganter und zuverlässiger ist es aber, die Variablen mit der Funktion unset() vollständig aus dem Speicher zu löschen. Will man mehrere nicht mehr benötigte Variablen entfernen, gibt man sie mit Komma getrennt an: unset($id, $motto, $quelle);
202
Das ausgewählte Motto bearbeiten und speichern
10 Alles in allem sieht das einleitende Script jetzt so aus: id; $motto = $ds->motto; $quelle = $ds->quelle; } else { $id = $_POST['id']; $motto = trim($_POST['motto']); $quelle = trim($_POST['quelle']); if (!empty($id)) { $query = "UPDATE motto SET " ."motto = '$motto', quelle = '$quelle'" ."WHERE id = $id"; $dummy = mysql_query($query); unset($motto, $quelle,$id); } } ?>
Nach einer Änderung des Script-Teils der Datei bearbeiten.php können Mottos nicht nur ausgewählt und angezeigt, sondern auch bearbeitet und aktualisiert werden.
203
11 Wenn Sie diesen Script-Teil nun mit dem weiter oben entwickelten HTML-
Teil kombinieren und das ganze als »bearbeiten.php« speichern, dann erhalten Sie das geplante Bearbeitungsmodul. Nun bewirkt ein Klick auf den Edit-Link, dass der ausgewählte Datensatz im Formular angezeigt und nach einem Klick auf die Schaltfläche auch zurück geschrieben wird. Dabei zeigt die Tabelle immer den aktuellen Stand der Mottosammlung an, jede Änderung wird also sofort angezeigt und kann umgehend kontrolliert werden.
Der Maschinenraum Damit haben wir eigentlich im Großen und Ganzen das erreicht, was wir erreichen wollten und könnten uns zufrieden zurücklehnen. Doch nun ist es nur noch ein sehr kleiner Schritt, um Eingabe, Auswertung und Bearbeitung zu einem einzigen Script zusammenzufassen. Wenn wir mit wenig Aufwand aus dem Gefummel mit verschiedenen Dateien einen funktionstüchtigen Maschinenraum machen können – warum sollten wir dann auf halben Weg stehen bleiben? Das Eingabeformular in »bearbeiten.php« kann ja nicht nur die Inhalte für bereits vorhandene Einträge anzeigen und bearbeiten, sondern auch völlig neue Einträge entgegennehmen. Gibt man in das Formular in »bearbeiten.php« neue Daten ein und klickt auf die Schaltfläche, dann unterscheiden sich die übergebenen Daten nur in einem Punkt von denen, die bei einer Bearbeitung übergeben werden: Es fehlt ein Wert für den Index. Der wird ja bei der Bearbeitung als Wert eines versteckten input-Feldes übergeben und ist von uns nicht beeinflussbar. Bei einem Aufruf von »bearbeiten.php« können also folgende Fälle auftreten:
204
•
Es liegen keine get- oder post-Variablen vor. In diesem Fall wird das leere Formular und die Tabelle der bisher eingetragenen Mottos angezeigt.
•
Es liegt eine get-Variable mit dem Namen id vor. Das bedeutet, dass das Motto mit diesem Indexwert bearbeitet werden soll. Die entsprechenden Daten müssen also ausgelesen und im Formular angezeigt werden.
•
Es liegt eine post-Variable mit dem Namen id vor. Das kann nur bedeuten, dass ein bearbeiteter Datensatz gespeichert werden soll. Es muss also das entsprechende UPDATE-Statement ausgeführt werden. Um die Anzeige wieder zu leeren, werden die Variablenwerte anschließend gelöscht.
•
Es liegt eine post-Variable mit dem Namen motto vor, aber keine mit dem Namen id. Dies ist der Fall, wenn ein neues Motto eingetragen wurde. Hier wird mit dem INSERT-Kommando ein neuer Datensatz hinzugefügt. Auch hier werden die Variablen anschließend gelöscht. Da im
Der Maschinenraum
HTML-Teil der Datei »bearbeiten.php« sämtliche Einträge angezeigt werden, sieht man anschließend den neuen Eintrag bereits aufgeführt und ein leeres Eingabeformular, in das man ein weiteres Motto aufnehmen kann: $query = "INSERT INTO motto " ."(motto, quelle)" ."VALUES ('$motto','$quelle')"; $dummy = mysql_query($query); unset($id, $motto, $quelle);
1 Diese vier Varianten lassen sich durch eine Kombination von if-, else- und
elseif-Verzweigungen recht einfach in PHP nachbilden. Es ergibt sich folgender
Script-Block, der am Anfang von »bearbeiten.php« steht: id; $motto = $ds->motto; $quelle = $ds->quelle; } else { $id = $_POST['id']; $motto = trim($_POST['motto']); $quelle = trim($_POST['quelle']); if (!empty($id)) { $query = "UPDATE motto SET " ."motto = '$motto', quelle = '$quelle'" ."WHERE id = $id"; $dummy = mysql_query($query); unset($id, $motto, $quelle); } elseif(!empty($motto)) { $query = "INSERT INTO motto " ."(motto, quelle)" ."VALUES ('$motto','$quelle')"; $dummy = mysql_query($query); unset($id, $motto, $quelle); } } ?>
205
2 Der Code lässt sich noch vereinfachen. So sind die Anweisungsblöcke für das
UPDATE- und das INSERT-Kommando bis auf die Definition der Variablen $query
identisch. Die beiden gleich bleibenden Anweisungen müssen also nicht innerhalb der if- bzw. elseif-Verzweigung stehen, sondern können herausgezogen und im Anschluss ausgeführt werden.
3 Dadurch enthalten die beiden Verzweigungen nur noch eine Anweisung – die
$query-Definition – und können als einzeiliges Kommando ohne Mengenklammern notiert werden. Der gesamte else-Block schrumpft damit zu wenigen Zeilen
zusammen: id; $motto = $ds->motto; $quelle = $ds->quelle; } else { $id = $_POST['id']; $motto = trim($_POST['motto']); $quelle = trim($_POST['quelle']); if (!empty($id)) $query = "UPDATE motto SET motto = '$motto', quelle = '$quelle' WHERE id = $id"; elseif(!empty($motto)) $query = "INSERT INTO motto (motto, quelle) VALUES ('$motto','$quelle')"; $dummy = mysql_query($query); unset($id, $motto, $quelle); } ?>
Da das INSERT-Kommando nur ausgeführt wird, wenn die Variable $motto einen Wert enthält, vermeiden wir es so noch ganz nebenbei, dass wir einen leeren Datensatz in die Tabelle schreiben. Jetzt fehlt nur noch eine Kleinigkeit. Bislang werden die Mottos bei der Ausgabe mit aufsteigender id aufgelistet. Besser wäre es aber, wenn die Liste absteigend sortiert würde, damit neu hinzugekommene Einträge gleich an den Anfang der Liste gesetzt werden und man sofort sieht, wie der Eintrag gespeichert wurde.
206
Der Maschinenraum
4
Um die Sortierreihenfolge in der Anzeige zu ändern, müssen wir im HTML-Teil des Scripts die Definition der Variablen $query ändern. Bislang sieht die Zeile so aus: $query = "SELECT * FROM motto ORDER BY id";
5 Standardmäßig sortiert ORDER BY aufsteigend. Um die Sortierreihenfolge zu ändern, müssen wir im SELECT-Statement die ORDER BY-Anweisung um das Kommando DESC erweitern. Das ist die Abkürzung für »descending« (absteigend, sinkend):
$query = "SELECT * FROM motto ORDER BY id DESC";
6
Passen Sie die Zeile im HTML-Teil der Datei entsprechend an. Nun können Sie über »bearbeiten.php« nicht nur die vorhandenen Mottos bearbeiten, sondern auch neue Mottos hinzufügen. Mit anderen Worten: Die anfangs entwickelten Scripts zur Eingabe und zur Auswertung der Eingabe sind damit obsolet geworden.
Aus der einfachen Bearbeitungsroutine wurde mit wenigen Code-Zeilen ein veritabler Maschinenraum, der verschiedene Funktionen in sich vereinigt.
207
Einträge aus einer MySQL-Tabelle löschen Inzwischen ist unsere Mottomaschine eine recht ausgereifte Sache geworden und wir können uns zufrieden auf die Schulter klopfen. Allerdings fehlt noch eine Funktion, die ganz sinnvoll wäre. Bislang können wir Einträge anzeigen lassen, bearbeiten und neue Einträge hinzufügen, aber die radikalste Form der Bearbeitung beherrscht unsere Mottomaschine noch nicht: das Löschen von Einträgen. Um in MySQL einen Datensatz zu löschen, wird die Anweisung DELETE benutzt. Als Parameter werden ihr mit FROM der Tabellenname übergeben, aus der ein Eintrag gelöscht werden soll, und eine Bedingung, an der MySQL eindeutig entscheiden kann, welche Datensätze betroffen sind. Als eindeutige Bedingung bietet sich in unserem Fall der Index der Tabelle an. Wenn also der Eintrag mit dem Index Nr. 7 aus der Tabelle »motto« gelöscht werden soll, so lautet die entsprechende MySQL-Anweisung: DELETE FROM motto WHERE id = 7
Wie alle anderen Statements wird auch diese Anweisung über die Funktion mysql_query() an den Server übermittelt. Ein einfaches PHP-Script, mit dem man den Datensatz Nummer 7 aus der Tabelle »motto« löscht, könnte also zum Beispiel so aussehen:
Eine neue Funktion für die Mottomaschine Um unsere Mottomaschine um eine Löschfunktion zu erweitern, müssen wir uns ein paar Gedanken machen, wie das ganze funktionieren soll. Bislang übergeben wir bei einem Klick auf den »Edit«-Link den Index des gewählten Datensatzes. Auf eine ähnliche Weise könnten wir einen »Delete«-Link einfügen und die get-Parameter anpassen. Denn nun genügt dem Script ja nicht mehr nur die Angabe der id, sondern es muss ja auch entscheiden können, ob der so ausgewählte Datensatz bearbeitet oder gelöscht werden soll. Daher führen wir einen zweiten Parameter namens aktion ein, der zusätzlich zur id mit get übergeben wird und der dem Script sagt, was mit dem Datensatz geschehen soll.
208
Jede Menge Formulare
Wird das Script dann beispielsweise mit
bearbeiten.php?aktion=Edit&id=7 aufgerufen, dann soll der Datensatz Nummer 7 bearbeitet werden, bei
bearbeiten.php?aktion=Delete&id=5 wird er dagegen aus der Tabelle entfernt. So weit der Plan, schreiten wir zur Ausführung.
Jede Menge Formulare Bislang setzen wir einen normalen HTML-Link ein, um die benötigten getParameter an das Script zu übermitteln. Dabei könnten wir bleiben und neben dem »Edit«- einfach einen »Delete«-Link setzen. Allerdings führt dies dazu, dass die Tabelle ein wenig unübersichtlich wird. Schöner und funktionaler als ein Link ist hier allemal eine Schaltfläche. Da kommt es uns gut zupass, dass man in einem HTML-Script nicht nur beliebig viele Formulare unterbringen kann, sondern sich die Schaltflächen vom Typ submit auch dazu eignen, eigene Werte zu übergeben (und nicht nur dazu dienen, die Werte aus den input-Feldern abzuschicken). So ist es möglich, in dem »Bearbeiten«-Feld der Ausgabetabelle, in dem bislang nur der »Edit«-Link steht, ein Miniformular mit zwei Schaltflächen unterzubringen. Beide Schaltflächen hören auf den Namen »aktion«, die eine bekommt den Wert (value) »Edit«, die andere »Delete«. Dieser Wert wird zum einen als Beschriftung der Schaltflächen angezeigt, zum anderen bei einem Klick als jeweiliger Wert von aktion abgeschickt. Fügen wir als verstecktes (type="hidden") Eingabefeld noch die id des jeweiligen Datensatzes hinzu, so ist der Formularcode für die »Bearbeiten«-Spalte fertig. Das folgende Formular übermittelt nach einem Klick auf eine der beiden Schaltflächen den Wert der Schaltfläche und die id des entsprechenden Eintrags (das Attribut nowrap sorgt dafür, dass die Tabellenzelle nicht unschön umbrochen wird):
209
Nach einem Klick auf eine der beiden Schaltflächen wird die Datei »bearbeiten.php« also wie geplant zum Beispiel mit
bearbeiten.php?aktion=Edit&id=7 oder
bearbeiten.php?aktion=Delete&id=5 aufgerufen. Bevor wir uns daran machen, das Auswertungsscript an die neue Funktion anzupassen, passen wir rasch den HTML-Teil der Datei »bearbeiten.php« an. Setzen Sie an die Stelle des bisherigen und weiter oben entwickelten Codes zur Anzeige der einzelnen Tabellenzeile diese Zeilen: ?>
<small>
210
Das Auswertungsscript anpassen
Schaltflächen statt Links: In jeder Zelle steht nun ein kleines Formular, über dessen Schaltflächen dem Script mitgeteilt werden kann, was mit dem entsprechenden Datensatz geschehen soll.
Das Auswertungsscript anpassen Da die neu hinzugekommenen Formulare die Werte mit get übermitteln, betrifft die Anpassung des Auswertungsscriptes zu Beginn von »bearbeiten.php« lediglich die Analyse der get-Variablen, sobald post-Variablen vorliegen, bleibt alles beim alten.
1
Da wir nun mit aktion über einen zweiten Wert verfügen, den das Script zur Entscheidung dessen, was es tun soll, heranziehen kann, prüfen wir nicht mehr, ob mit get eine Variable namens id übergeben wurde, sondern untersuchen nun, ob eine Variable namens aktion vorliegt, die entweder den Wert »Delete« oder den Wert »Edit« besitzt. Bei »Delete« wird die entsprechende MySQL-Anweisung ausgeführt und der Datensatz gelöscht, bei »Edit« wechseln wir in den schon bekannten Edit-Modus.
2
Eines müssen wir noch beachten: Wenn wir direkt nach dem Löschen eines Datensatzes einen neuen Datensatz hinzufügen wollen, dann besitzt die Variable $id noch den Wert des gelöschten Datensatzes. Das führt dazu, dass die Auswertungsroutine zum Update-Teil des Scripts verzweigt und einen Datensatz aktualisieren will, den es gar nicht mehr gibt. Für Abhilfe sorgt auch hier die unset-Funktion.
211
3
Das vollständige PHP-Script von »bearbeiten.php« steht wie bisher auch vor dem HTML-Code. Inklusive der Datenbankverbindung über die eingebundene Datei »mysql.inc« sieht es nun so aus: id; $motto = $ds->motto; $quelle = $ds->quelle; } else { $id = $_POST['id']; $motto = trim($_POST['motto']); $quelle = trim($_POST['quelle']); if (!empty($id)) $query = "UPDATE motto SET motto = '$motto', quelle = '$quelle' WHERE id = $id"; elseif(!empty($motto)) $query = "INSERT INTO motto (motto, quelle) VALUES ('$motto','$quelle')"; $dummy = mysql_query($query); unset($motto, $quelle,$id); } ?>
Unsere Mottomaschine besteht nun nur noch aus zwei Dateien: Der Ausgaberoutine und dem Maschinenraum »bearbeiten.php«, in dem wir Mottos erfassen, bearbeiten und löschen.
212
Die Ausgaberoutine anpassen
Die Bearbeitungsroutine hat sich zum multifunktionalen Maschinenraum gemausert, in dem Mottos hinzugefügt, bearbeitet und gelöscht werden können.
Die Ausgaberoutine anpassen Die Arbeiten an der Mottomaschine sind fast abgeschlossen, es bleibt nur noch ein kleiner Schönheitsfehler, den wir beheben müssen. Wenn wir einen Eintrag löschen, löschen wir natürlich auch seine id, die von MySQL nicht neu vergeben wird. Hat die Tabelle zum Beispiel zehn Einträge, deren id-Werte lückenlos von 1 bis 10 laufen, so erhält der nächste Eintrag die Nummer 11. Daran ändert sich auch dann nichts, wenn wir die Nummer 10 zuvor löschen und die id mit dem Wert gewissermaßen wieder »frei« ist. Damit funktioniert aber auch unsere Ausgaberoutine nicht mehr wie gewünscht, denn die geht ja von einer lückenlosen Vergabe der id-Werte und davon aus, dass die Gesamtanzahl der Einträge mit dem höchsten id-Wert identisch ist. Dass das nicht unbedingt der Fall sein muss, kann man sich an einem einfachen Beispiel rasch klar machen.
213
Nehmen wir an, der höchste Index-Eintrag der Tabelle ist 24, doch die Einträge 17, 19, 20 und 21 wurden gelöscht. In diesem Fall besitzt die Tabelle nur 20 Einträge. Unsere bisherige Zufallsauswahl sieht ja so aus: $query = "SELECT COUNT(*) FROM motto"; $sql = mysql_query($query); $max = mysql_result($sql,0); $id = rand(1,$max);
Diese Zeilen würden also nun einen zufälligen Wert zwischen 1 und 20 als $id ermitteln, die Einträge 22, 23 und 24 würden also niemals abgerufen werden. Schlimmer noch: Ergibt der Aufruf von rand(1,21) den Wert 17, 19, 20 oder 21, dann würde die Ausgaberoutine vom MySQL-Server einen Datensatz anfordern, den es gar nicht mehr gibt.
Wenn ein Datensatz gelöscht wurde, verschwindet auch sein Indexwert, der von PHP kein zweites Mal vergeben wird.
Keine Frage – so kann das nicht bleiben. Zur Lösung des Problems gibt es zwei Möglichkeiten: eine Lösung in PHP und eine Lösung in MySQL. Sehen wir uns zuerst die Lösung in PHP an. Diese ist zwar deutlich umständlicher als das, was MySQL zu bieten hat, aber eine gute Übung im Umgang mit Schleifen und booleschen Variablen. Und Sie wissen ja: Übung macht den Meister. Da wir mit der Anzahl der Einträge in PHP nicht mehr weiter kommen, lassen wir uns nun vom MySQL-Server den höchsten id-Wert der Tabelle nennen und setzen diesen Wert als obere Grenze für die Funktion rand() ein. Bei der Auswahl der Mottos muss dann noch geprüft werden, ob der gewählte Eintrag überhaupt existiert. Ist dies nicht der Fall, müssen wir so lange eine neue Zufallszahl ermitteln, bis wir auf einen ausgefüllten Datensatz stoßen.
214
Die Ausgaberoutine anpassen
1
Den höchsten id-Wert (und damit die obere Grenze des Intervalls, aus dem wir eine Zufallszahl ermitteln) erfahren wir über die MySQL-Funktion MAX(), die uns den höchsten Wert für einen bestimmten Ausdruck nennt. Der Ausdruck ist in diesem Fall einfach der Name des Feldes: $query = "SELECT MAX(id) FROM motto"; $sql = mysql_query($query); $max = mysql_result($sql,0);
2
Damit steht in der Variablen $max der höchste Indexwert zur Verfügung und der Aufruf von rand(1,$max) berücksichtigt alle möglichen Einträge. Nun müssen wir uns nur noch darum kümmern, dass wir keine nicht-existierenden Datensätze als Motto auslesen wollen. Dazu benötigen wir eine Schleife, in der so lange Datensätze ausgewählt und ausgelesen werden, bis wir auf einen korrekten Eintrag stoßen.
3 Die Schleifenkonstruktion wird wie gewohnt mit while gebildet, als Kontrollvariable definieren wir eine boolesche Variable, der wir den Namen $gefunden geben und die wir mit dem Wahrheitswert false initialisieren.
4
So können wir die while-Schleife mit einer logischen Negation (mit !) fast schon wie eine Klartextanweisung definieren: »Solange nichts gefunden, suche weiter«. Am Code für die Motto-Auswahl hat sich nichts geändert: $gefunden = false; while (!$gefunden) { // Code für die Motto-Auswahl }
5 Wenn wir auf einen nicht-existierenden Datensatz zugreifen wollen, so erhalten wir von MySQL keine direkte Fehlermeldung (wie Sie mit solchen und anderen Fehlermeldungen umgehen, erfahren Sie im nächsten Kapitel). Wir erkennen dies aber daran, dass die zugewiesene Variable $motto leer ist. Sobald also $motto nicht leer ist, haben wir einen Datensatz gefunden und können $gefunden auf true setzen und damit die while-Schleife verlassen: if (!empty($motto)) $gefunden = true;
6
Setzen wir nun alles zusammen und achten wir darauf, dass wir die Datenbankverbindung beenden, so erhalten wir folgenden PHP-Code, den wir an den Anfang der Webseite setzen können, auf der wir das Motto anzeigen lassen wollen:
215
$gefunden = false; while (!$gefunden) { $id = rand(1,$max); $query = "SELECT motto, quelle FROM motto WHERE id = $id"; $sql = mysql_query($query); $ds = mysql_fetch_object($sql); $motto = htmlentities($ds->motto); $quelle = htmlentities($ds->quelle); if (!empty($motto)) $gefunden = true; } mysql_close($dz); ?>
In diesem Beispiel wird innerhalb der while-Schleife zur Kontrolle der Inhalt von $query ausgegeben. Der jeweils letzte Eintrag (hier: id = 1) ist das SELECT-Statement, mit dem das angezeigte Motto ausgewählt wurde. Die vorherigen Einträge sind versuchte Zugriffe auf Datensätze, die nicht existieren (hier: 17, 21 und 11).
Zufallszugriffe mit MySQL So, das war die etwas umständliche Lösung in PHP, bei der wir nicht nur viel tippen müssen, sondern dem MySQL-Server unter Umständen mit mehreren unsinnigen Anforderungen von Datensätzen, die gar nicht existieren, unnötig auf Trab halten.
216
Zufallszugriffe mit MySQL
Doch das muss alles nicht sein, denn auch MySQL kann mit Zufallszahlen umgehen – und bietet einen pfiffigen Einsatz seiner RAND()-Funktion. In Kombination mit LIMIT ist es damit nämlich unter anderem möglich, ein zufällig zusammengewürfeltes Sample aus einer Tabelle abzufragen.
1
Möchte man zum Beispiel 100 zufällig ausgewählte Einträge in zufälliger Reihenfolge aus der Tabelle test, so sieht das SELECT-Statement etwa so aus: SELECT * FROM test ORDER BY RAND() LIMIT 100
2
Diese Funktion lässt sich sehr gut auf unser kleines Problem anwenden. Statt in PHP eine Zufallszahl als Index zu bestimmen und anschließend den zu diesem Index gehörenden Datensatz auszulesen, überlassen wir die Zufallsauswahl einfach dem Server und fordern mit RAND() einen zufällig ausgewählten Datensatz an: SELECT motto, quelle FROM motto ORDER BY RAND() LIMIT 1
3
Damit schrumpft unsere Auswahlroutine zu diesen wenigen Zeilen zusammen, die deutlich übersichtlicher, kompakter, schneller – kurz: besser sind als die bisherige Lösung: motto); $quelle = htmlentities($ds->quelle); mysql_close($dz); ?>
4
Fügen Sie den PHP-Code am Kopf jeder Webseite ein, in der Sie ein zufälliges Motto mit und einfügen wollen.
Damit ist die Arbeit an der Mottomaschine vorläufig beendet, die Maschine ist im Prinzip einsatzbereit. Zur Fertigstellung fehlt allerdings noch eine kleine Routine, die sich um das Problem der anfangs erwähnten »Magic Quotes« kümmert. Dafür müssen wir etwas weiter ausholen (was wir im nächsten Kapitel auch tun werden), doch zuvor bauen wir die Motto- noch rasch in eine Bildermaschine um.
217
Die Bildermaschine: Dateiverzeichnisse mit PHP lesen Vielleicht möchten Sie die Besucher Ihrer Webseite nicht mit einem Motto, sondern mit einem zufällig ausgewählten Bild begrüßen, da ein Bild bekanntlich mehr als 1000 Worte sagt. Kein Problem – der notwendige PHP-Code, der aus der Motto- eine Bildermaschine macht, ist schnell entwickelt und Sie erfahren obendrein noch, wie Sie mit PHP ein Dateiverzeichnis auslesen. So verabschieden wir uns aus diesem Kapitel über zufällig ausgewählte Datensätze und Einträge mit einer kleinen »Bilder-statt-Mottos-Maschine«. Zeitprobleme
Bei der Bildermaschine kann es passieren, dass Sie bei relativ großen Bilder über ein Timingproblem beim Zusammenspiel von Browser und Apache-Webserver stolpern, der Browser zeigt die Bilder dann nur teilweise oder gar nicht an. Verkleinern Sie in diesem Fall die Bildgröße.
Bei der Bildermaschine können wir auf MySQL völlig verzichten, mehr als eine Hand voll PHP-Code wird nicht benötigt. Die Idee: Bei jedem Aufruf einer Webseite soll ein anderes, zufällig ausgewähltes Bild aus dem Verzeichnis »img« angezeigt werden. Dieses Verzeichnis ist völlig unabhängig von irgendwelchen Scripts. Wenn wir ein Bild aus der Zufallsauswahl entfernen wollen, löschen wir es einfach aus dem Verzeichnis; wir erweitern die Auswahl, indem wir neue Bilder in das Verzeichnis kopieren – der HTML-Code der Webseite und das PHP-Script müssen dafür nicht angepasst werden. Alles, was wir zur Realisation dieser Idee benötigen, ist die Funktion readdir(), die uns bei jedem Aufruf den nächsten Dateinamen aus dem aktuellen Verzeichnis angibt. Legen wir diese Dateinamen in einem numerischen Array $bilder ab, so können wir über eine einfache Zufallsauswahl einen Dateinamen herausgreifen und als Parameter für ein img-Element benutzen. Das Verfahren im Einzelnen:
1
Bei Verzeichnissen ist es nicht anders als bei Dateien oder Datenbanken – bevor wir darauf zugreifen können, müssen wir es öffnen. Dazu dient die Funktion opendir(), die einen Zeiger zurückliefert, über den readdir() dann weiß, welches
218
Die Bildermaschine: Dateiverzeichnisse mit PHP lesen
Verzeichnis gelesen werden soll. Mit den folgenden beiden Beispielzeilen öffnen wir das Verzeichnis »img« und lesen den ersten Dateinamen ein: $dir = opendir("img"); $datei = readdir($dir);
2
Um alle Dateinamen im geöffneten Verzeichnis auszulesen, benutzen wir wie gewohnt eine while-Schleife. Nach Abschluss der Schleife wird das geöffnete Verzeichnis mit closedir() wieder geschlossen. Auch diese Funktion benötigt als Argument den Verzeichniszeiger, um zu wissen, welches Verzeichnis geschlossen werden soll: $dir = opendir("img"); while ($datei = readdir($dir)) { // Verarbeitung der Dateinamen } closedir($dir);
3 Die Dateinamen werden in einem Array $bilder abgelegt, das wir zur Sicher-
heit vor der Schleife als leeres Array initialisieren. Innerhalb der Schleife werden die Dateinamen als Parameter eines img-Elements geschrieben und der Reihe nach im Array abgelegt:
Nun müssen wir nur noch berücksichtigen, dass für readdir() auch das aktuelle und das darüberliegende Verzeichnis als Dateinamen gelten. Beide Verzeichnisse werden traditionell durch Punkte symbolisiert, das aktuelle Verzeichnis durch einen Punkt, das übergeordnete durch zwei Punkte.
5
Filtern wir innerhalb der Schleife diese beiden unerwünschten Dateinamen mit einer if-Abfrage aus, ist unsere Routine zum vollständigen Auslesen eines Dateiverzeichnisses bereits fertig und sieht so aus: $bilder = array(); $dir = opendir("img"); while ($bild = readdir ($dir)) { if ($bild != "." && $bild != "..") { $bilder[] = ""; } } closedir($dir);
219
6
Für die Zufallsauswahl benötigen wir lediglich die Anzahl der Einträge im Verzeichnis weniger 1 (der Array-Index beginnt ja bei 0, nicht bei 1). Dafür setzen wir die Funktion count() ein. Anschließend können wir über die rand()-Funktion eine Zufallszahl im gewünschten Intervall bestimmen: $max = count($bilder)-1; $zufall = rand(0,$max);
7 Da die if-Abfrage nur aus einer Anweisung besteht, können wir sie in einer Zeile notieren und auf die Mengenklammern verzichten. Damit besitzt auch die whileSchleife nur noch eine Anweisung und lässt sich ebenfalls kompakter notieren:
while ($bild = readdir ($dir)) if ($bild != "." && $bild != "..") $bilder[] = "";
8 Das war's schon. Nun können wir an beliebiger Stelle auf einer Webseite über
das zufällig ausgewählte Bild einfügen. Das folgende Script spielt das Verfahren kurz durch. Dabei wird der Einfachheit halber das Zufallsbild in einer eigenen Variablen $bild gespeichert. Damit das Bild auf der Webseite optisch mehr Halt bekommt, wird das img-Element um ein borderAttribut erweitert. Die Webseite nennt außerdem die Nummer des ausgewählten Bildes und die Gesamtzahl aller Bilder:
In dem kleinen niedersächsischen Dorf Bargfeld lebte der deutsche Dichter Arno Schmidt. Ein digitales Bilderbuch mit zufällig ausgewählten Fotos aus Bargfeld ist eine Sache weniger Zeilen PHP-Code.
Menschen, nicht Maschinen: Linus Torvalds
Wie PHP und MySQL kommt auch das dritte große Open-Source-Projekt aus dem nordischen Raum: Linux-Erfinder Linus Torvalds wurde am 28. Dezember 1969 in Helsinki geboren. Den Grundstein für das Betriebssytem Linux legte Torvalds mit einer Umfrage im Usenet im August 1991. Von seinen bescheidenen Anfängen als Unix-Variante neben anderen Unix-Varianten hat sich Linux inzwischen als ernsthafte Alternative zum dominierenden Windows entwickelt. Anders als die Open-Source-Pioniere wie Stallman oder Raymond scheint Torvalds die Öffentlichkeit geradezu zu scheuen, es gibt so gut wie keine öffentlichen Aussagen zu Politik, Gesellschaft oder Microsoft. Auf seiner Homepage finden sich lediglich Bilder seiner Tochter und, natürlich, des obligatorischen Linux-Pinguins Tux. Zu betrachten unter der Adresse: http://www.cs.helsinki.fi/u/torvalds/.
221
Kapitel 8
Fauler Zauber und andere Fallgruben
Bislang herrscht bei uns nur eitel Freude und Sonnenschein, alle Scripte laufen perfekt, Fehler waren ausgeschlossen und auch die Datenbank machte uns keinen Strich durch die Rechnung. Aber es wird Zeit, den Tatsachen ins Auge zu sehen: Fehler passieren, Scripte stürzen ab und falsche Eingaben zerschießen Datenbanken. In diesem Kapitel widmen wir uns den notwendigen Präventivmaßnahmen.
Ihr Erfolgsbarometer
Das können Sie schon: Sie haben die mächtigen Einsatzmöglichkeiten von numerischen und assoziativen Arrays kennen gelernt.
92
Dank PHPMyAdmin war der Einstieg in MySQL nicht schwer und Sie haben gelernt, wie Sie von PHP aus auf MySQL-Daten zugreifen können.
120
Am Beispiel einer Logdatei haben Sie den Einsatz der Dateitypen von MySQL gelernt und wissen nun, wie Sie Daten via PHP speichern
150
Ausgefeilte Formularauswertung, Zufallszahlen, Datensätze löschen, Bilderbücher – ist alles kein Problem mehr.
184
Das lernen Sie neu: Fehler gibt es immer wieder ...
224
Fauler Zauber mit »Magic Quotes«
224
Sichere Variablenübernahme
228
Die Sollbruchstellen die() und exit()
233
Datei- und Datenbankfehler abfangen
234
Fehlermeldungen protokollieren
241
Typische Fehler
246
223
Fehler gibt es immer wieder ... Ok, ich geb's besser gleich zu, Sie werden es ohnehin schon gemerkt haben – ich habe Sie bislang ein wenig an der Nase herumgeführt und so getan, als ob Fehler, Fehleingaben oder Programmabstürze praktisch nicht auftauchen. Dass das leider nicht der Fall ist, weiß natürlich jeder, der auch nur ein paar Zeilen PHP-Code ausprobiert hat. Sie, zum Beispiel. So kurz kann ein Codesegment gar nicht sein, dass man in ihm nicht mindestens einen verhängnisvollen Tippfehler unterbringen könnte, der selbst das kleinste Script gnadenlos zu Fall bringt. Gegen Fehler gibt es kein Patentrezept, aber vielleicht tröstet es Sie, dass auch ich bei der Entwicklung der in diesem Buch vorgestellten Beispielscripts und Strategien immer wieder verblüfft oder auch schimpfend vor meinem Computer saß, auf ein scheinbar fehlerfreies Script starrte und mich fragte, was um alles in der Welt da denn jetzt falsch sein könnte. Häufig sind leicht zu übersehende Flüchtigkeitsfehler schuld, wenn ein Programm nicht das tut, was es tun soll. Kleine Tippschlampereien haben bei PHP bekanntlich große Folgen – ein Semikolon da, wo keines hingehörte, ein Variablenname, wo eigentlich eine Funktion aufgerufen wurde, ein Großbuchstabe, der klein hätte sein müssen, ein versehentlich doppelt vergebener Variablenname und ähnliche Kleinigkeiten genügen, damit der PHP-Interpreter die Ausführung des Scripts beharrlich verweigert oder völlig unerwartete Ergebnisse auswirft. Auch wenn man Fehler nie hundertprozentig ausschließen kann, so gibt es doch eine Reihe von Strategien und Vorgehensweisen, die einem dabei helfen, Script-Fallgruben zu vermeiden und typischen Fehlern schneller auf die Spur zu kommen. Daher widmen wir uns in diesem Kapitel den verschiedenen Möglichkeiten, bei PHP oder MySQL etwas falsch zu machen und der Frage, was man im Falle eines Falles unternehmen kann, um einen Fehler zu lokalisieren und zu beheben.
Fauler Zauber mit »Magic Quotes« Im vorherigen Kapitel stießen wir nebenbei auf eine Besonderheit von PHP, die unter dem Namen »Magic Quotes« bekannt (oder genauer gesagt: berüchtigt) ist. Wenn Sie einem Script zum Beispiel mit get oder post eine Variable übergeben, die ein Anführungszeichen " oder ein Hochkomma ' enthält, dann werden diese Zeichen von PHP häufig automatisch maskiert, also mit einem Backslash versehen.
224
Fauler Zauber mit »Magic Quotes«
Das scheint auf den ersten Blick ganz sinnvoll zu sein, sind doch Anführungszeichen oder Hochkommata für PHP Markierungen dafür, dass ein Textstring beginnt oder endet. Will man Variablen, bei denen solche Steuerzeichen zum Wert der Variablen gehören und nicht Anfang oder Ende einer Zeichenkette markieren, etwa in eine Datenbank schreiben, dann muss man den problematischen Zeichen einen Backslash voranstellen, aus " wird dann also \". Und da, so dachten sich wohl die Entwickler von PHP, Variablen, die mit post oder get übergeben werden, irgendwann immer in eine Datenbank geschrieben werden, ist es doch eine gute Idee, diese Zeichen von Anfang an automatisch zu maskieren und so dem PHP-Programmierer die Mühe zu sparen. Das klingt eigentlich ganz plausibel, hat aber auf lange Sicht sehr fatale Konsequenzen. Das Grundproblem besteht darin, dass PHP am Wert einer Variablen herumpfuscht, ohne dass man als PHP-Programmierer darüber die Kontrolle hätte. Mit anderen Worten: Sie können in solchen Fällen nie sicher sein, welchen Inhalt eine Variable, die über ein Formular eingegeben wurde, denn nun wirklich besitzt. Doch das wäre vielleicht noch nicht so schlimm, wenn sich alle PHP-Installationen auf allen Servern in diesem Punkt gleich verhielten. Dann könnte man diese Eigenheit von PHP berücksichtigen und müsste sich weiter keine Gedanken machen. Doch genau das ist leider nicht der Fall. Wie PHP mit diesen Sonderzeichen in übergebenen Variablenwerten umgeht, hängt von der jeweiligen PHP-Installation ab. Und das bedeutet, dass ein Script, das auf dem einen Server ganz vorzüglich läuft, auf dem anderen zu seltsamen Fehlermeldungen und Fehlverhalten führt. So kann es passieren, dass Sie lokal ein Script entwickeln und bei der Portierung auf Ihren Webserver feststellen müssen, dass Ihre gesamte Formularverwaltung nicht mehr so funktioniert wie geplant. Oder dass Ihre gesamte Website beim Wechsel des Webhosters plötzlich an den seltsamsten Stellen hakelt. Da das Problem sich nur unter bestimmten Bedingungen bemerkbar macht, etwa, wenn über ein Formular eines der problematischen Steuerzeichen eingegeben wird, kann es mitunter einige Zeit dauern, bis der Fehler im laufenden Betrieb auftritt. Dann steht man erst recht vor einem Rätsel und fragt sich verwundert, warum das, was bislang so klaglos funktionierte, plötzlich anfängt, herumzuzicken, obwohl man doch gar nichts am Script geändert hat. Machen wir uns das Problem rasch an einem einfachen Scriptbeispiel deutlich.
225
1
Legen Sie eine neue PHP-Datei namens »test.php« an, die nichts anderes macht, als eine Variable via get entgegenzunehmen und am Bildschirm auszugeben:
2
Rufen Sie das Script mit einem Wert auf, der ein Hochkomma, einen Backslash oder ein Anführungszeichen enthält, etwa so: test.php?test="Dies ist ein 'Test'."
3
Je nach den Einstellungen der PHP-Installation erzeugt das kleine Testscript eine unterschiedliche Anzeige. Sind die Magic Quotes aktiviert, dann werden Anführungszeichen und Hochkommata maskiert und Sie sehen diese Anzeige: \"Dies ist ein \'Test\'.\"
4
Sind Magic Quotes dagegen ausgeschaltet, erhalten Sie eine völlig andere Anzeige im Browserfenster – nämlich exakt den Text, der mit get übergeben wurde: "Dies ist ein 'Test'."
Kurz – die Magic Quotes sind leider ganz und gar nicht magisch, sondern eher ein lästiger fauler Zauber, der uns über den wahren Wert einer Variablen im Unklaren lässt.
Bei aktivierten Magic Quotes setzt PHP ungefragt Escape-Zeichen vor die Anführungszeichen und Hochkommata. Das ist zwar gut gemeint, aber leider ganz und gar nicht gut.
226
Magic Quotes ausgetrickst
Leerzeichen in URLs
Leerzeichen in URLs sind nicht erlaubt und müssen durch %20 ersetzt werden. Das gilt auch für mit get übergebene Parameter. In vielen Fällen korrigiert der Browser diesen Eingabefehler und führt die Ersetzung automatisch durch, bevor er den Webserver kontaktiert. Falls dies nicht der Fall sein sollte, müssen Sie bei der Eingabe selbst darauf achten.
Magic Quotes ausgetrickst Um die fatalen Stolperfallen, die sich mit den Magic Quotes auftun, sicher zu umgehen, bleibt uns bei einer Formularauswertung nichts anderes übrig, als alle übergebenen Variablen zu normieren, sprich von PHP eventuell eingefügte Escape-Zeichen zu entfernen und so den Zustand wieder herzustellen, der vor dem automatischen Eingriff der Magic Quotes herrschte. Dafür stellt PHP eine einfache Funktion zur Verfügung: stripslashes() – wobei sich hier die gar nicht so leicht zu beantwortende Frage stellt, warum die PHP-Entwickler ein Feature wie Magic Quotes einbauen, wenn sie danach eine Funktion implementieren, mit der die Magic Quotes wieder deaktiviert werden. Da hätte man doch lieber gleich auf das seltsame Feature verzichten sollen. Da sie das aber nicht getan haben, müssen wir uns vor dem Einsatz der Funktion vergewissern, ob Magic Quotes auf dem aktuellen Server überhaupt aktiviert sind. Denn nur dann müssen Sie mit der Funktion die von PHP eingefügten Backslashes entfernen. Ist dies nicht der Fall, können die übergebenen Variablen unverändert passieren.
1 Um festzustellen, ob die Magic Quotes aktiviert sind, rufen wir die Funktion
get_magic_quotes_gpc() ohne Parameter auf. Falls Magic Quotes aktiviert sind, liefert die Funktion eine 1 zurück, andernfalls eine 0.
2
Damit können wir die Funktion in eine if-Abfrage einbauen. Falls sie eine 1 zurückgibt, wird dies von if als logisches true interpretiert und damit die Anweisung ausgeführt: if (get_magic_quotes_gpc()) $test = stripslashes($test);
Nach dieser Abfrage können Sie sicher sein, dass Ihr Script auf jedem PHPServer in der Variable $test exakt den Inhalt besitzt, der ihr über die Formulareingabe zugewiesen wurde. Das bedeutet aber auch, dass Zeichenketten nicht (wie bisher) unbearbeitet in ein MySQL-Statement übernommen werden dürfen.
227
Machen wir uns das Problem wieder an einem einfachen Beispiel klar. Gesetzt den Fall, die Variable $test enthält die Zeichenkette »Mal seh'n« und soll in eine Tabelle namens tabelle in das Feld text geschrieben werden, so sieht die INSERT-Anweisung etwa so aus: INSERT INTO tabelle (text) VALUES ('$test')
Diese Anweisung wird aber nun in folgender Form übermittelt: INSERT INTO tabelle (text) VALUES ('Mal seh'n')
In diesem Fall übernimmt MySQL als Wert für das Feld text den Text »Mal seh« und interpretiert das anschließende Apostroph als Ende der Zeichenkette. Mit dem folgenden »n« weiß MySQL dann allerdings nichts anzufangen – und unternimmt daher auch nichts. Mit anderen Worten: Das INSERT-Kommando wird einfach ignoriert, eventuell erhalten Sie noch eine Fehlermeldung, dass Ihre MySQL-Syntax fehlerhaft sei und das war's. Um das zu vermeiden, muss der Apostroph wie gehabt maskiert werden, die Anweisung INSERT INTO tabelle (text) VALUES ('Mal seh\'n')
wird klaglos übernommen und der Text »Mal seh'n« in das Feld text eingefügt. Da wir nicht wissen können, ob und wenn ja, welche problematischen Sonderzeichen eine Zeichenkette enthält, die wir in eine Datenbanktabelle schreiben wollen, stellt PHP die Funktion addslashes() zur Verfügung, mit der alle nötigen Escape-Sequenzen in einem String eingefügt werden, um die Zeichenkette sicher in die Datenbank zu kriegen. Um unsere Beispielvariable $test also im INSERT-Kommando benutzen zu können, müssen wir sie zuvor mit $test = addslashes($test);
um die fehlenden Escape-Zeichen erweitern.
Sichere Variablenübernahme Man kann die vorherigen Absätze auch so zusammenfassen: Unsere bisherigen Formularauswertungen sind sehr blauäugig und naiv. Denn ganz so einfach, wie es sein könnte, ist es dank der lästigen Magic Quotes leider doch nicht. Wer wirklich sicher sein will, dass seine Scripte in allen PHPUmgebungen funktionieren, der kommt um eine selbst geschriebene Funktion zur Variablenübernahme aus Formularen nicht herum.
228
Sichere Variablenübernahme
Das ist zwar ein wenig ärgerlich, aber glücklicherweise nicht weiter kompliziert. Die benötigte Funktion ist nur wenige Zeilen lang und man muss sich nur angewöhnen, get- und post-Variablen nicht direkt über die Arrays $_GET oder $_POST einzulesen, sondern nur über die eigenen Funktionen. Im Folgenden wird am Beispiel der post-Variablen das Vorgehen durchgespielt.
1
An die Stelle der direkten Zuweisung tritt der Aufruf einer Funktion, die die übergebene post-Variable in unserem Sinne normiert. Wird mit einem Formular eine post-Variable namens »text« übergeben, dann soll die Zuweisung im Auswertungsscript also nicht mehr über $text = $_POST['text'];
2 erfolgen, sondern über den Funktionsaufruf $text = PostVar("text");
3
Damit steht der Funktionsrumpf bereits fest. Wir benötigen eine Funktion, die den Namen der Variablen entgegennimmt und die normierte Variable zurückgibt.
4
Die eigentliche Normierung besteht aus nur zwei Programmanweisungen. Im ersten Schritt wird die gewünschte Variable aus dem Array $_POST ausgelesen, im zweiten in einer if-Anweisung gegebenenfalls von überflüssigen Backslashes befreit. Die gesamte Funktion sieht also so aus:
5
Nach diesem Beispiel lässt sich auch schnell eine get-Variante schreiben, die immer dann zum Einsatz kommt, wenn Ihr Script Variablen aus dem Array $_GET auslesen soll:
229
6
Um unsere neue Funktion PostVar() zu testen, basteln wir eine einfache Datei »test.php«. Zu Beginn steht unsere neue Funktion, im HTML-Teil stellt ein MiniFormular ein Eingabefeld zur Verfügung, das die übergebenen Texte an »test.php« übergibt. Zur Kontrolle wird die Eingabe vor und nach der Normierung angezeigt: "; echo "Nachher: ",PostVar("test"); ?>
Mit einer kleinen, selbst geschriebenen Funktion kann man in seinen Scripts die Eingriffe durch Magic Quotes neutralisieren.
230
Die fehlerbereinigte Mottomaschine
Nachdem alle post-Variablen in unseren Scripts unabhängig von der jeweiligen PHP-Konfiguration immer im selben, unveränderten Format vorliegen, müssen wir uns nur noch angewöhnen, immer dann, wenn wir Zeichenkettenvariablen in eine MySQL-Tabelle eintragen möchten, die Steuerzeichen zu maskieren. Dafür stellt, wie oben schon angemerkt, PHP die Funktion addslashes() zur Verfügung, deren Einsatz wir am Beispiel unserer Mottomaschine durchspielen.
Die fehlerbereinigte Mottomaschine Am Ausgabescript, wie es im letzten Kapitel entwickelt wurde, ändert sich natürlich nichts, aber im Maschinenraum von »bearbeiten.php« sind noch ein paar Kleinigkeiten zu erledigen.
1
Zuerst ergänzen wir den Script-Teil der Datei um unsere neue PostVar()-Funktion, die wir noch ein wenig anpassen. Da wir die Motto-Eingaben vor der Speicherung in der Motto-Tabelle mit trim() von überflüssigen Leerzeichen befreien, können wir das gleichzeitig erledigen:
2
Als Nächstes müssen wir uns kurz überlegen, welche Variablen überhaupt von Magic Quotes betroffen sind. Die Angaben, die mit get übergeben werden – id und aktion –, scheiden aus. Hier handelt es sich ja um Werte, die von unserem Script erzeugt werden und die garantiert kein problematisches Steuerzeichen enthalten. Da wir im get-Teil des Scripts überdies keine Daten in die Tabelle schreiben, sondern nur lesen oder löschen, kann der Teil so bleiben, wie er ist.
3 Ähnliches gilt für den id-Wert, der vom Eingabeformular über ein verborgenes
Eingabefeld übermittelt und im UPDATE-Statement benutzt wird. Auch hier handelt es sich um einen vom Script verwalteten Wert, der kein kritisches Sonderzeichen enthalten und auch nicht durch eine Benutzereingabe verändert werden kann.
231
4
Bleiben also nur die beiden Werte für motto und quelle. Hier besteht die Möglichkeit, über das Eingabeformular beliebige und also auch problematische Zeichen einzugeben. Diese Werte müssen also auf jeden Fall über unsere neue Funktion eingelesen werden. Der Einsatz von addslashes() sorgt dafür, dass eventuell vorhandene, problematische Zeichen mit dem notwendigen Escape-Zeichen versehen werden, bevor die Daten in die Tabelle geschrieben werden sollen: $motto = addslashes(PostVar("motto")); $quelle = addslashes(PostVar("quelle"));
5
Der Script-Teil der fehlerbereinigten Mottomaschine, die nun mit allen PHPInstallationen und allen Benutzereingaben zurechtkommt, ganz gleich, wie die Magic-Quotes-Einstellungen sind, sieht also so aus: id; $motto = $ds->motto; $quelle = $ds->quelle; } else { $id = $_POST['id']; $motto = addslashes(PostVar("motto")); $quelle = addslashes(PostVar("quelle")); if (!empty($id)) $query = "UPDATE motto SET motto = '$motto', quelle = '$quelle' WHERE id = $id"; elseif(!empty($motto)) $query = "INSERT INTO motto (motto, quelle) VALUES ('$motto','$quelle')"; $dummy = mysql_query($query); $motto = ""; $quelle = ""; $id = ""; } mysql_close($dz); ?>
232
Die Sollbruchstellen die() und exit()
Die Sollbruchstellen die() und exit() Vermutlich sind die Magic Quotes nicht die einzige Fehlerquelle, über die Sie beim Ausprobieren der verschiedenen Scripts und Beispiele bislang gestolpert sind, schließlich gibt es unzählige Möglichkeiten, einen Fehler zu machen. Tritt ein Fehler auf, der nicht sofort erkannt und behoben werden kann, ist es sinnvoll, das Script schrittweise abarbeiten zu lassen und Sollbruchstellen einzufügen, bei denen die Ausführung des Scripts unterbrochen wird. Dazu dienen die beiden Funktionen die() und exit(). Beide Funktionen sind in ihrer Wirkung radikal und führen zum sofortigen Abbruch des laufenden Scripts. Sobald der PHP-Interpreter auf diesen Befehl stößt, beendet er unverzüglich die Arbeit. Auch der HTML-Code nach dem PHP-Block wird nicht mehr ausgegeben!
Mit der Funktion die() lässt sich eine Fehlermeldung ausgeben und ein laufendes Script kurzerhand beenden.
Der Unterschied zwischen den beiden Funktionen besteht darin, dass Sie mit exit() ein Script kommentarlos abbrechen, während Sie mit die() noch eine letzte Meldung, etwa den Inhalt einer kritischen Variablen, ausgeben können. Das könnte zum Beispiel so aussehen die("Das Script wurde abgebrochen. \$variable = $variable");
Der Backslash bei \$variable sorgt übrigens dafür, dass das Dollarzeichen als einfacher Text und nicht als Anfang einer Variablen gewertet wird. PHP gibt also den Text $variable aus, nicht den Wert der Variablen $variable.
233
Datei- und Datenbankfehler abfangen Die Abbruchfunktionen die() und exit() werden häufig eingesetzt, um schwere Datei- oder Datenbankfehler abzufangen. Wenn – aus welchem Grund auch immer – der Zugriff zum MySQL-Server nicht möglich, oder eine Datei, auf die man via Script zugreift, nicht verfügbar ist, dann gibt PHP zwar Fehlermeldungen wie Can't connect to MySQL server on 'localhost'
oder Access denied for user: 'niemand@localhost'
aus, führt das Script aber ansonsten weiter fort. Das ist nun allerdings häufig nicht erwünscht. Wenn zum Beispiel die Mottomaschine keinen Zugriff auf den MySQL-Server hat, dann ist der Rest des Scripts sinnlos. Beim Aufruf der Seite hagelt es dann lediglich Fehlermeldung und das Ergebnis entspricht nicht so ganz den Erwartungen. Das kann einem bei lokalen Testläufen im stillen Kämmerlein zwar egal sein, doch wenn ein Besucher unsere Webseiten aufruft und mit dergleichen konfrontiert wird, hinterlässt das keinen sonderlich guten Eindruck.
1
Probieren wir das einfach am Beispiel der Mottomaschine aus, indem wir im Auswahl- bzw. Ausgabemodul bewusst Fehler bei der Kontaktaufnahme zum MySQL-Server einbauen: motto); $quelle = htmlentities($ds->quelle); mysql_close($dz); ?>
2 Statt in den beiden Variablen $motto und $quelle wie geplant ein zufällig
ausgewähltes Motto bereitzustellen, produziert das Script nur zahlreiche Fehlermeldungen.
234
Datei- und Datenbankfehler abfangen
Obwohl bereits der erste Zugriff auf den MySQL-Server fehlschlug und damit alle weiteren SQL-Statements sinnlos geworden sind, arbeitet PHP alle Anweisungen stur ab und es hagelt unschöne Fehlermeldungen.
Für den Fall eines schweren Datei- oder Datenbankfehlers, der dafür sorgt, dass der Rest des Scripts sinnlos geworden ist, sollte also eine kleine Fehlerbehandlungsroutine bereitstehen, die folgende Dinge erledigt:
•
Die für Nicht-Eingeweihte unverständliche PHP-Fehlermeldung unterdrücken.
•
Falls erforderlich eine verständliche Klartextmeldung wie etwa »Leider trat ein Fehler auf. Bitte versuchen Sie es später noch einmal.« ausgeben (das ist bei der Mottomaschine zum Beispiel nicht unbedingt nötig, der Rest der Webseite kann ja so bleiben, wie er ist, wir verzichten dann halt nur auf das wechselnde Motto).
•
Bei einem schweren Fehler das Script gegebenenfalls beenden.
235
3
Die erste Aufgabe ist am einfachsten zu lösen. Wenn PHP eine Fehlermeldung nicht ausgeben soll, genügt es, den so genannten »Fehler-Kontroll-Operator« @ vor den Funktionsnamen zu setzen. Möchten Sie, dass beim Fehlschlagen der Kontaktaufnahme zum MySQL-Server keine Fehlermeldung ausgegeben wird, dann können Sie dies zum Beispiel so erreichen: $dz = @mysql_connect($host, $user, $pass);
Mit einem Klammeraffen vor dem Funktionsnamen unterdrückt man die Ausgabe von Fehlermeldungen. So kann man die Teile der Webseite, die vom Fehler nicht betroffen sind, ohne störende Meldungen anzeigen lassen.
4
Um bei der Mottomaschine sämtliche MySQL-Fehlermeldungen zu unterdrücken, müssen Sie also nur vor alle MySQL-Funktionen den Fehler-Kontroll-Operator oder »Klammeraffen« setzen: motto); $quelle = htmlentities($ds->quelle); @mysql_close($dz); ?>
236
Datei- und Datenbankfehler abfangen
Wenn etwas so Fundamentales wie die Verbindung zum MySQL-Server fehlschlägt, dann hat es meist keinen Zweck, den Rest des Scripts abzuarbeiten. Hier sollte stattdessen mit die() das Script beendet und eine verständliche Fehlermeldung ausgegeben werden. Das einzige, was wir dazu benötigen, ist eine Möglichkeit, im Script entscheiden zu können, ob es abgebrochen werden muss oder nicht. Eine solche Möglichkeit bieten uns die Datei- und Datenbankfunktionen, die im Falle eines Fehlers keinen Datei- oder Datenbankzeiger, sondern den logischen Wert false zurückliefern. Damit ist es kein Problem mehr, mit einer einfachen if-Abfrage nach dem Aufruf von @mysql_connect() das Programm im Falle eines Falles mit einer Fehlermeldung zu beenden (zur Erinnerung: das ! ist das logische Negationszeichen, der Ausdruck !$dz ist also genau dann true, wenn $dz false ist und der MySQL-Zugriff fehlschlug): $dz = @mysql_connect($host, $user, $pass); if (!$dz) die ("Keine Verbindung zum MySQL-Server. Programm wird beendet.");
Das ganze lässt sich noch einfacher formulieren, wenn wir einen kleinen Trick anwenden, bei dem drei Sachverhalte zusammenspielen:
•
Sobald PHP auf eine logische Verknüpfung stößt, wird diese ausgewertet, dabei spielt es keine große Rolle, ob die Scriptumgebung überhaupt zum Auftauchen der Verknüpfung passt.
•
Eine or-Verknüpfung ist immer dann logisch wahr, also true, wenn einer der verknüpften Operanden true ist. Sobald PHP bei der Analyse einer or-Verknüpfung auf einen wahren Operanden stößt, wird die Analyse beendet – wahrer als wahr kann der Ausdruck schließlich nicht mehr werden.
•
Der Wahrheitswert von Datei- und Datenbankfunktionen ist bei geglückter Aktion true.
Kombinieren wir diese drei Punkte, so können wir die obigen zwei Zeilen unter Einsparung der if-Abfrage folgendermaßen notieren: $dz = @mysql_connect($host, $user, $pass) or die("Keine Verbindung zum MySQL-Server. Programm wird beendet.");
Wenn der Funktionsaufruf ein korrektes Ergebnis zurückliefert, wird die etwas eigenartig aussehende or-Verknüpfung also ignoriert, schließlich ist bereits der erste Operand wahr, das genügt für die Analyse, die Verknüpfung ist auf jeden Fall true. Liefert mysql_connect() nun allerdings den Wert false, dann macht sich PHP an die Analyse des Wahrheitswertes des zweiten Ausdrucks, stößt dabei auf die Funktion die() und beendet kurzerhand das gesamte Script.
237
Was für mysql_connect() gilt, gilt natürlich auch für alle anderen MySQLFunktionen von PHP. So können wir nun das kleine Script mysql.inc, das in unseren Beispielscripten den Kontakt zum Server und zur Datenbank aufbaut, so erweitern, dass es im Falle eines fatalen Fehlers den weiteren Programmablauf verhindert und stattdessen eine Fehlermeldung ausgibt:
Verlassen Sie sich übrigens nie darauf, dass das Script im Testlauf und auch auf dem Webserver tadellos läuft und Sie jetzt auf die Fehlerroutinen verzichten könnten. Ein Datenbankfehler kann jederzeit auftreten und hängt nicht von Ihrem Script ab. Auch wenn sämtliche Parameter korrekt und Ihr Script makellos ist, hilft das gar nichts, wenn der MySQL-Server aus welchen Gründen auch immer temporär nicht verfügbar ist. Auch in solchen Fällen erspart Ihnen eine die()-Anweisung an zentraler Stelle, dass Ihre Besucher mit einem Wust an Fehlermeldungen konfrontiert werden.
Fehlermeldungen bei fehlgeschlagenem Lese- oder Schreibzugriff Bei schweren Datenbankfehlern gibt PHP eine Fehlermeldung aus – bei kleineren, aber ebenso verhängnisvollen Pannen wie einem fehlgeschlagenen Lese- oder Schreibzugriff schweigt sich PHP dagegen häufig aus. Greifen Sie zum Beispiel mit einem SELECT-Statement auf eine Tabelle zu, die nicht existiert oder versuchen Sie mit INSERT einen Datensatz einzufügen, bei dem die Feldnamen nicht mit denen in der MySQL-Tabelle übereinstimmen, so werden Sie in aller Regel ebenso wenig eine Fehlermeldung erhalten wie bei dem Versuch, mit UPDATE einen Datensatz zu aktualisieren, der nicht existiert. Dabei quittiert MySQL natürlich jeden fehlgeschlagenen Zugriff mit einer Fehlermeldung, die Aufschlüsse über die Gründe gibt, warum ein Statement nicht ausgeführt oder ein Eintrag nicht vorgenommen werden konnte – aber PHP verschweigt diese Meldung und lässt den Anwender im Unklaren darüber, ob ein Tabellenzugriff nun erfolgreich war oder nicht.
238
Fehlermeldungen bei fehlgeschlagenem Lese- oder Schreibzugriff
Das klingt ein wenig seltsam, hat aber seine guten und unter anderem Sicherheitsgründe. Denn Fehlermeldungen könnten unter Umständen interne Informationen über Aufbau und Struktur einer Datenbank bzw. einer Tabelle enthalten, von denen man nicht möchte, dass sie jedermann durch Zufall oder eine gezielte Fehleingabe in einem Formular auf den Bildschirm zaubern kann. Andererseits kann es durchaus passieren, dass Sie fröhlich einen Datensatz nach dem anderen eintippen, um erst später zu bemerken, dass Ihre Tippbemühungen wirkungslos verpufft sind. Nun mag es zwar sein, dass man die Besucher seiner Webseite nicht mit eventuell auftretenden MySQL-Fehlermeldungen irritieren will, doch zumindest im lokalen Betrieb, bei der Entwicklung von Scripten und in der Testphase sollte man natürlich wissen, was da los ist. Glücklicherweise ignoriert PHP zwar die Fehlermeldungen vom MySQLServer, aber die Meldungen sind nicht verloren, sondern werden lediglich zwischengelagert und stehen mit Aufruf der Funktion mysql_error() zur Verfügung. So ist es möglich, auf Fehler individuell zu reagieren. Spielen wir das an einfachen Beispielen kurz durch und konstruieren wir ein paar Fehler.
Über die Funktion mysql_error() können Sie Fehlermeldungen auf Wunsch gezielt ausgeben.
1
Wir versuchen auf eine Tabelle zuzugreifen, die nicht existiert. Anschließend weisen wir der Variablen $fehler den Wert von mysql_error() zu. Falls $fehler nicht leer ist, trat ein Fehler auf und das Script gibt eine entsprechende Meldung aus: $fehler"; else echo "Alles klar!"; ?>
239
2
Ändern Sie den Wert von $query so, dass das SELECT-Statement sich auf eine existierende Tabelle bezieht, etwa $query = "SELECT * FROM motto";
3
und starten Sie es erneut. Statt der Fehlermeldung sehen Sie nun die beruhigende Meldung: »Alles klar!«
4 Ähnliche Fehlermeldungen erhalten Sie bei einem fehlerhaften INSERT- oder
UPDATE-Kommando. Bislang haben wir den Rückgabewert von MySQL in einer Variablen $dummy abgelegt und ignoriert, nun wird es Zeit, sich ein wenig darum
zu kümmern.
5
Wir provozieren eine Fehlermeldung mit einer Variablen, die nicht mit der Funktion addslashes() entschärft wurde, indem wir in ein Textfeld der Tabelle test einen Eintrag einfügen wollen, der ein nicht entwertetes – also mit einem Backslash als normales Zeichen deklariertes – Hochkomma enthält:
6
Lassen Sie dieses Script laufen, so werden Sie – natürlich vorausgesetzt, die Tabelle existiert und besitzt ein Textfeld namens text – keine Fehlermeldung erhalten und etwa erst bei einem Blick mit PHPMyAdmin in die Tabelle bemerken, dass das INSERT-Kommando nicht ausgeführt wurde.
7 Die Fehlermeldung kann nun mit einer ähnlichen if-Konstruktion wie im vorherigen Beispiel abgefragt werden:
240
Fehlermeldungen protokollieren
8 Der praktische Einsatz dieser kleinen Fehlerabfangroutine könnte zum Beispiel
so aussehen, dass die Webseite, über die man Daten in die Tabelle eintragen kann, einen Infobereich enthält, in den das Ergebnis der Fehlerabfrage ausgegeben wird. Statt der direkten Textausgabe könnte man etwa eine Variable $status einsetzen, deren Inhalt in diesem Infobereich angezeigt wird:
if (!empty($fehler)) $status = "Fehler"; else $status = "OK";
9 Natürlich können Sie Ihr Script nach einem fehlgeschlagenen INSERT oder
UPDATE auch mit die() abbrechen und sich die Fehlermeldung anzeigen lassen. Dabei können Sie auf die if-Konstruktion verzichten und sich mit mysql_error() als Argument von die() die Fehlermeldung anzeigen lassen:
$dummy = mysql_query($query) or die(mysql_error());
10 Aber natürlich will ich diesen Abschnitt nicht beenden, ohne Ihnen zu verra-
ten, wie Sie den Fehler vermeiden – denken Sie daran: Keine Eingabe von Zeichenketten in eine MySQL-Tabelle ohne addslashes():
Fehlermeldungen protokollieren Sie können PHP auch anweisen, eine Fehlermeldung nicht in der Webseite auszugeben, sondern in eine Textdatei zu schreiben. Keine Sorge, dazu müssen Sie nicht extra eine Dateiroutine schreiben, sondern können einfach auf die Funktion error_log() von PHP zugreifen. Mit dieser Funktion ist es möglich, einen beliebigen Text als Stringvariable in eine Datei auf dem Server zu speichern oder per E-Mail zu verschicken. Insgesamt bietet die Funktion vier verschiedene Möglichkeiten, die über einen ganzzahligen Wert von 0 bis 3 ausgewählt werden.
241
Ob error_log() auf eine Standard-Logdatei zugreift oder nicht, erfahren Sie mit einem Blick in die Konfiguration über phpinfo().
1
Sie können die Fehlermeldung in die Datei schreiben lassen, die in der PHPKonfiguration definiert ist. Ob dies der Fall ist und wo gegebenenfalls die Logdatei zu finden ist, können Sie zum Beispiel mit phpinfo() ermitteln. Sie finden den entsprechenden Eintrag im Abschnitt »PHP Core«. Normalerweise werden Sie diese Variante von error_log() wohl nicht benötigen, aber wenn doch, dann können Sie so $fehler in die Log-Datei schreiben: error_log($fehler,0);
2
Um sich $fehler per Mail schicken zu lassen, übergeben Sie der Funktion neben der Fehlermeldung auch die Mailadresse: $mail = "[email protected]"; error_log ($fehler,1,$mail);
3
Es besteht die Möglichkeit, die Fehlermeldung über den PHP-Debugger zu verschicken – aber das ist eine sehr spezielle Variante und spielt für uns überhaupt keine Rolle, weshalb es nach dieser Erwähnung auch gleich weiter geht zu ...
242
Fehlermeldungen protokollieren
4
... der letztlich interessantesten Variante: Sie können die Fehlermeldung an eine beliebige Textdatei anhängen lassen. Falls die angegebene Datei nicht existiert, wird sie automatisch angelegt: $log_datei = "error_log.txt"; error_log($fehler,3,$log_datei);
5
Da die nackte Fehlermeldung normalerweise nicht sehr hilfreich ist, nutzen wie die Möglichkeit aus, dass wir einen beliebigen String speichern können. Wir verknüpfen die Fehlermeldung mit Datum und Uhrzeit und fügen einen Zeilenvorschub samt Trennlinie ein: $fehler = date("Y-m-d | H:i:s | ") .mysql_error() .chr(13).chr(10) ."--------------------------" .chr(13).chr(10); error_log ($fehler, 3, "fehler_log.txt");
6
Diese (oder eine ähnliche) Routine kann nun als Funktion definiert und beispielsweise über die oben erläuterte or-Verknüpfung aufgerufen werden. Soll unsere Mottomaschine Fehlermeldungen nicht ausgeben, sondern in der Datei »fehler_log.txt« protokollieren, so lässt sich das so erreichen: motto); $quelle = htmlentities($ds->quelle); @mysql_close($dz) or mysql_fehler(); ?>
243
Die Protokolldatei auslesen und löschen Um einen Blick in die Protokolldatei zu werfen, genügt es, diese Datei einfach mit dem Webbrowser aufzurufen. Soll die Datei dagegen gelöscht werden, ist die Sache nicht ganz so einfach, dazu müssen Sie normalerweise einen FTP-Client starten. Das ist natürlich ein wenig umständlich, doch wozu gibt es PHP? Wir schreiben uns rasch ein kleines Script, mit dem wir die Fehlermeldung auslesen und auf Wunsch auch löschen können. Das Script (Dateiname: »loglesen.php«) soll nach dem Aufruf zuerst überprüfen, ob ein Fehlerprotokoll vorliegt und, falls dies der Fall ist, dieses in einem Inline-Frame anzeigen (womit wir uns das Auslesen der Datei via PHP ersparen) und eine Schaltfläche zum Löschen des Scripts bereitstellen.
1 Um zu überprüfen, ob die Logdatei existiert, setzen wir die Funktion
file_exists() ein. Falls die Datei nicht vorhanden ist, wird das Script kurzerhand mit die() beendet:
$logdatei = "fehler_log.txt"; if (!file_exists($logdatei)) die("Es liegt keine Fehlerdatei vor.");
2
Für die Anzeige der Fehlerdatei in einem Inline-Frame kommen wir mit einfachsten Basis-HTML aus, in das wir lediglich den Dateinamen als Variable via PHP einfügen:
Folgende Fehler traten auf:
<iframe src="" width="600" height="400">
3
Bleibt noch das Löschen auf Mausklick. Dafür benötigen wir ein kleines Formular mit einer Schaltfläche. Das Formular ruft »loglesen.php« mit einem post-Parameter auf, der hier auf den etwas martialischen Namen kill hört, an Hand dessen eine kleine Auswertungsroutine (um die wir uns gleich kümmern) erkennt, dass die Logdatei gelöscht werden soll:
244
Die Protokolldatei auslesen und löschen
4
Nun brauchen wir nur noch eine kleine Abfrage zu Beginn des Scripts, die überprüft, ob eine post-Variable existiert und nicht leer ist, um gegebenenfalls die Logdatei zu löschen. Eine Datei kann man mit PHP über die Funktion unlink() ohne weitere Rückfragen löschen.
5 Das ganze lässt sich mit einer einzigen Zeile Code erledigen. Da der Inhalt der
post-Variablen gleichgültig ist und es nur darauf ankommt, dass sie überhaupt existiert und nicht leer ist, müssen wir auf keinerlei Besonderheiten Rücksicht nehmen, sondern können die Variable einfach auslesen:
if (!empty($_POST['kill'])) unlink($logdatei);
6
Das war's schon. Die Datei »loglesen.php« ist zwar nach der Methode quick & dirty entstanden – es ging schnell und wir achten nicht so sehr auf wirklich sauberen Code –, aber sie funktioniert. Und da sie ausschließlich für interne Zwecke eingesetzt wird, soll uns das genügen:
Folgende Fehler traten auf:
<iframe src="" width="700" height="300">
245
Quick & dirty, aber es funktioniert tadellos: Mit wenigen Zeilen in PHP können wir uns die Logdatei anzeigen lassen und sie auf Wunsch mit einem Mausklick löschen.
Typische Fehler Es gibt unendlich viele Möglichkeiten, durch einen Tippfehler ein Script unbrauchbar zu machen. Aber es gibt eine Reihe von typischen Fehlern, die jedem PHP-Programmierer unterlaufen. Wenn Sie sich auf die Fehlersuche in Ihren Scripten machen, haben Sie hier einige Anhaltspunkte, worauf Sie besonders achten müssen. Beginnen wir mit einem klassischen Fehler – dem überschüssigen oder fehlenden Semikolon. Dabei ist ein fehlendes Semikolon noch relativ rasch zu finden, schließlich gibt PHP eine Fehlermeldung aus. Dumm nur, dass sich das fehlende Semikolon nicht in der Zeile findet, die PHP moniert, sondern in den Zeilen darüber. Im folgenden Script fehlt in der ersten Zeile das abschließende Semikolon, aber erst für die dritte Zeile merkt PHP einen Fehler an: $datei_name = "counter.txt" if (!file_exists($datei_name)) { $dz = fopen($datei_name, "w"); fwrite($dz,"0"); fclose($dz); }
246
Typische Fehler
Noch fataler als ein vergessenes, ist mitunter ein falsch gesetztes Semikolon. Denn hier liegt für PHP häufig kein erkennbarer Syntax-Fehler vor und das Script wird ohne weitere Fehlermeldung abgearbeitet – allerdings nicht mit dem Ergebnis, das wir uns vorgestellt haben. Ein besonders perfides Beispiel liefert diese kleine for-Konstruktion:
Was glauben Sie, werden Sie auf dem Bildschirm sehen, wenn Sie dieses Script starten? Die Zahlen von 1 bis 10? Weit gefehlt, probieren Sie's aus: Sie werden lediglich eine 11 zu sehen bekommen. Denn hier sorgt das Semikolon nach der for-Bedingung dafür, dass die echo-Anweisung nicht als Teil der Schleife, sondern als neue Anweisung interpretiert wird. PHP zählt also still vor sich hin und erhöht den Wert der Variablen $i. Sobald $i den Wert 11 erreicht, ist die Abbruchbedingung der Schleife erfüllt, PHP geht zur nächsten Anweisung über und gibt $i aus. Aus Sicht von PHP ist das alles völlig korrekt – dass wir uns das anders vorgestellt haben, kann der PHPInterpreter ja nicht ahnen, der führt nur Anweisungen aus und kann schließlich nicht Gedanken lesen. Schleifenkonstruktionen sind auch sonst ein nie versiegender Quell frustrierendster Fehlschläge. Besonders tückisch ist es, wenn eine Abbruchbedingung versehentlich so formuliert wurde, dass sie nie erreicht wird:
Was passiert hier? Sie erhalten eine schier endlose Zahlenreihe – so lange, bis entweder Sie den Browser schließen oder der Server die Verbindung von sich aus kappt. Denn diese Schleife wird nie verlassen – schließlich wird $I als Kontrollvariable eingesetzt – aber $i hochgezählt. An diesem Fehlerbeispiel sehen Sie auch gleich, wie wichtig die richtige Groß- und Kleinschreibung ist. Überhaupt müssen Sie bei den Namen von Variablen sehr sorgfältig darauf achten, dass Sie sie korrekt schreiben. Jedes Zeichen im Namen ist für PHP bedeutungsvoll. Machen Sie sich Ihr Programmiererleben also nicht unnötig schwer und vermeiden Sie besonders lange oder komplizierte Namen, ansonsten sind Tipp- und damit Programmfehler unvermeidbar. Tippfehler im Variablennamen sind auch deshalb so verhängnisvoll, weil PHP hier keinen Syntax-Fehler bemerken kann. Ein sehr beliebter Tippfehler mit weit reichenden Folgen steckt auch in dieser Konstruktion: if ($test = "test") echo $test;
247
Diese if-Abfrage ist immer wahr und wird immer ausgeführt – es handelt sich nämlich gar nicht um eine Abfrage, sondern um eine Wertzuweisung, bei der die Variable $test den Wert »test« bekommt. Und Wertzuweisungen sind für PHP immer true. Was hier eigentlich gemeint war – nämlich die Abfrage »wenn $test den Wert 'test' enthält, dann ...« wird mit dem doppelten Gleichheitszeichen notiert: if ($test == "test") echo $test;
Einer meiner häufigsten Tippfehler ist besonders blöd und hat mich schon manches Mal schier verzweifeln lassen. Bei Funktionsauswertungen rutscht mir immer wieder ein Dollarzeichen vor den Funktionsnamen, zum Beispiel so: $motto = $addslashes(PostVar("motto"));
Auch vergessene Anführungszeichen am Schluss einer Zeichenkette führen natürlich zu Fehlern. Und wie bei einem vergessenen Semikolon nennt Ihnen PHP meist eine ganz andere Zeilen als die, in der Sie die Anführungszeichen vergessen haben. In diesem Beispiel fehlen in Zeile 7 die abschließenden Anführungszeichen, aber PHP beklagt sich über ein »unexpected $end«, also ein unerwartetes Ende des Scripts in Zeile 12 – das ist das Ende des gesamten Listings, wäre das Listing noch länger, lägen Fehlermeldung und Fehlerort noch weiter auseinander:
... ;
Der Grund für dieses auf den ersten Blick seltsame Verhalten ist eigentlich ganz simpel. Nach dem geöffneten Anführungszeichen sucht der PHP-Interpreter im gesamten Code nach dem schließenden Anführungszeichen, findet aber keines mehr. Das Ende der Datei kommt für PHP also tatsächlich unerwartet – damit konnte der Interpreter wirklich nicht rechnen. Ähnliche Fehler produzieren auch vergessene Klammern, ganz gleich ob rund ) oder geschweift }.
248
Menschen, nicht Maschinen
Wenn Sie Anführungszeichen vergessen, durchsucht PHP den gesamten Code und stolpert plötzlich über das Ende der Datei.
Wann immer Sie also auf die Fehlermeldung »unexpected $end« stoßen, haben Sie wahrscheinlich irgendwo in Ihrem Script ein schließendes Anführungszeichen oder Ähnliches vergessen. Doch damit soll die kleine Blütenlese typischer Fehler beendet sein. Wenn Ihre Scripts also nicht auf Anhieb laufen, trösten Sie sich – mit diesem Problem sind Sie nicht allein. Menschen, nicht Maschinen: Kai Oswald Seidler und Kay Vogelgesang
Alle Beispielscripts in diesem Buch wurden auf einem Windows-XPComputer lokal entwickelt und getestet. Dass das überhaupt möglich ist, und Sie und ich auf einem normalen Heim-Computer mit minimalem Aufwand einen kompletten, voll funktionsfähigen Webserver mit PHP und MySQL installieren können, verdanken wir vor allem dem Duo Kai Oswald Seidler und Kay Vogelsang. Die beiden haben im Frühjahr 2002 das Projekt »ApacheFriends« ins Leben gerufen, mit dem Ziel, Ein- und Umsteigern den Umgang mit Apache, PHP, MySQL & Co. so einfach wie möglich zu machen – und mit Xampp ist ihnen das vollauf gelungen. Die private Homepage von Kai Seidler finden Sie unter http://oswaldism.de/, Kay Vogelsang ist privat mit http:// www.vogelgesang-berlin.de/ im Web vertreten.
249
Kapitel 9
Ein Gästebuch
Inzwischen haben Sie genügend Kenntnisse in PHP & MySQL, dass wir die Entwicklung eines Gästebuches in Angriff nehmen können. Damit verlassen wir den bislang umhegten privaten Bereich, bei dem man schon mal Fünfe gerade sein lassen kann. Diesmal müssen wir bei der Formularauswertung mögliche Fehler berücksichtigen, eine Vorschaufunktion bieten und Fehleingaben abfangen, damit unser Layout nicht zerstört wird. Außerdem erfahren Sie, wie Sie eine MySQL-Tabelle ohne Hilfe von PHPMyAdmin anlegen können.
Ihr Erfolgsbarometer
Das können Sie schon: Dank PHPMyAdmin war der Einstieg in MySQL nicht schwer und Sie haben gelernt, wie Sie von PHP aus auf MySQL-Daten zugreifen können.
120
Am Beispiel einer Logdatei haben Sie den Einsatz der Dateitypen von MySQL gelernt und wissen nun, wie Sie Daten via PHP speichern
150
Ausgefeilte Formularauswertung, Zufallszahlen, Datensätze löschen, Bilderbücher – ist alles kein Problem mehr.
184
Die korrekte Übernahme von Variablen bereitet Ihnen nun ebenso wenig Probleme, wie der Umgang mit leider unvermeidlichen Fehlermeldungen.
222
Das lernen Sie neu: Eine Tabelle in Handarbeit
252
Das Grundgerüst
256
Die Vorschauroutine
259
Einen Beitrag speichern
264
Gästebuch ausgeben
266
Fehleingaben abfangen
269
Umbrüche einfügen
272
Das Gästebuch komplett
274
251
Konzept eines Gästebuches Ein Gästebuch im Internet funktioniert wie ein Schwarzes Brett, an das jeder, der will, einen Zettel mit einer Nachricht oder Notiz hängen kann. Das Gästebuch soll den Besuchern Ihrer Webseite die Möglichkeit bieten, über ein Formular Grüße, Kommentare, Anregungen, Fragen, Kritik – kurz: Bemerkungen aller Art so zu hinterlassen, dass sie von den anderen Besuchern der Seite gelesen werden können. Dabei soll ein Eintrag im Gästebuch immer gleich aufgebaut sein. Zuerst steht der Nachrichtentext, darunter der Absendername und Datum und Uhrzeit des Eintrags. Die einzelnen Einträge werden durch eine Linie voneinander getrennt, die neuesten Einträge sollen zuoberst stehen. Das Eingabeformular steht am Fuß der Seite. Programmiertechnisch stellt uns ein Gästebuch vor eine relativ einfache Aufgabe, die wir mit den bisher vorgestellten Methoden lösen können. Doch der Teufel steckt wie so häufig im Detail. Was passiert zum Beispiel, wenn Ihre Besucher unendlich lange Zeilen eingeben? Oder wie reagiert Ihr Script, wenn jemand riesige Datenmengen über das Formular an den Webserver schickt? Wir werden uns also einige Gedanken zur Fehlerbehandlung machen müssen. Für den ersten Entwurf benötigen wir verschiedene Module, die wir später noch erweitern und anpassen werden:
•
Eine Datentabelle, der wir den Namen »guestbook« geben. Hier werden die Einträge des Gästebuchs gespeichert.
•
Das Gästebuch selbst. Dabei handelt es sich um eine Webseite, die den Inhalt der Tabelle »guestbook« ausliest, formatiert und anzeigt.
•
Das Eingabeformular, über das die Besucher der Webseite einen Kommentar ins Gästebuch eintragen können.
Eine Tabelle in Handarbeit Die Grundstruktur der benötigten Tabelle ist rasch entworfen und lässt sich mit PHPMyAdmin schnell zusammenklicken. Doch dieses Mal machen wir es anders und verzichten auf PHPMyAdmin. Denn auch wenn einem dieses Tool im Alltag unschätzbare Dienste leistet, so sollte man doch auch wissen, wie man ohne dieses Werkzeug zurechtkommt – und sei es nur, um die Leistung von PHPMyAdmin hinterher umso besser würdigen zu können.
252
Eine Tabelle in Handarbeit
Wir bauen die Tabelle also von Hand mit PHP. Dabei beginnen wir ganz einfach und legen eine Tabelle »guestbook« an, die vorerst nur ein einziges Feld mit dem Namen »eintrag« besitzt. In diesem Feld wird später der Gästebucheintrag gespeichert, das Feld ist folglich vom Typ TEXT. Um eine Tabelle anzulegen benutzt man in MySQL die Anweisung CREATE TABLE, der man den Namen der Tabelle und mindestens eine Felddefinition in Klammern übergibt. Die Felddefinition besteht mindestens aus der Angabe des Feldnamens und des Datentyps des Feldes: CREATE TABLE guestbook (eintrag TEXT)
Wie alle anderen Anweisungen auch wird dieses Kommando mit mysql_ query() an den Server geschickt. Der PHP-Code zur Anlage der Tabelle mit dem gewünschten Feld sieht so aus:
Ein Feld reicht für das Gästebuch natürlich nicht aus, wir müssen die Tabellenstruktur also erweitern. Dazu setzt man bei MySQL die Anweisung ALTER TABLE ein. In Kombination mit ADD wird ein neues Feld hinzugefügt, wobei Sie für jedes neue Feld ein mit einem Komma abgetrenntes ADD-Kommando einfügen müssen. Dabei können Sie nicht nur die Feldeigenschaften, sondern auch seine Position in der Tabelle bestimmen. Möchten Sie etwa, dass ein Feld ganz an den Anfang der Tabelle gesetzt wird, hängen Sie das Schlüsselwort FIRST an, mit AFTER hingegen geben Sie den Namen des Feldes an, hinter dem das neue Feld eingeordnet werden soll. Geben Sie keine Position an, wird das neue Feld an das Ende der Tabelle angehängt. Die Reihenfolge der Felder spielt für die Funktion von MySQL keine Rolle, unter Umständen aber für uns. Solange Sie Daten über eine eindeutige Angabe von Feld und Inhalt einfügen, also zum Beispiel so: INSERT INTO test (name, vorname, rolle) VALUES ('Mercier', 'Louis', 'Schmuggler')
253
so lange ist die Reihenfolge der Felder gleichgültig. Bei diesem Beispiel ist auch ohne Bedeutung, ob die Tabelle noch weitere Felder besitzt und wenn ja, an welcher Stelle sie stehen. Anders sieht die Sache allerdings aus, wenn Sie die vereinfachte INSERTAnweisung benutzen, bei der Sie lediglich die einzufügenden Werte angeben. In diesem Fall müssen Sie für jedes Feld des Eintrags einen Wert nennen und die Werte auch in der richtigen Reihenfolge eintragen. Soll ein Feld leer bleiben oder von MySQL automatisch ausgefüllt werden, dürfen Sie es nicht vergessen, sondern müssen es in der INSERT-Anweisung leer lassen. Besteht eine Tabelle namens test zum Beispiel aus den Feldern id, name, vorname, rolle und sie möchten einen Datensatz über das kurze INSERT-Statement einfügen, bei dem Sie lediglich den Wert für name angeben, dann sieht die Anweisung also so aus: INSERT INTO test VALUES(,'Mercier',,)
Dergleichen kann sich natürlich zu einer tückischen Tippfehlerfalle entwickeln, weshalb Sie sich doch lieber für die etwas längere, aber sicherere Version entscheiden sollten. Für noch mehr Übersicht sorgt, besonders bei Tabellen mit vielen Spalten, der Einsatz von SET im MySQL-Statement, bei dem Feldname und der dazugehörige Inhalt in Form einer Gleichung aufgeführt werden: INSERT INTO test SET name = 'Mercier', vorname = 'Louis', rolle = 'Schmuggler'
Zurück zu unserer Gästebuchtabelle. Wir ergänzen die Tabelle nun um zwei Felder:
•
datum: Hier speichern wir Datum und Uhrzeit des jeweiligen Gästebucheintrages. Das Feld ist vom Typ DATETIME und soll am Anfang der Tabelle eingefügt werden.
•
gast: Dieses Feld nimmt den Namen des Autors auf und ist vom Typ VARCHAR mit einer Länge von 100 Zeichen und soll vor eintrag bzw. nach datum stehen.
Das entsprechende MySQL-Kommando in PHP sieht also folgendermaßen aus (die zeilenweise Notation dient lediglich der Übersicht und ist nicht zwingend erforderlich):
254
Eine Tabelle in Handarbeit
Nun fehlt uns nur noch unser obligatorisches Indexfeld id, das vom Typ SMALLINT ist, die Eigenschaften UNSIGNED und AUTO_INCREMENT besitzt, der Primärschlüssel (PRIMARY KEY) und das erste Feld der Tabelle sein soll:
Natürlich können Sie auch alles auf einmal mit CREATE TABLE definieren. Dazu listet man die einzelnen Felddefinitionen einfach der Reihe nach und mit einem Komma getrennt auf:
Möchten Sie via PHP ein Feld aus einer Tabelle löschen, so setzen Sie dafür ALTER TABLE zusammen mit dem Kommando DROP ein, dem Sie einfach nur den Namen des zu löschenden Feldes übergeben. Mit dem folgenden Statement löschen wir das Feld gast und legen gleichzeitig an seiner Stelle ein Feld namens verfasser an:
255
Wir hätten das Feld natürlich auch einfach umbenennen können, wozu das Kommando CHANGE dient, mit dem sich die Eigenschaften einzelner Felder gezielt verändern lassen. Das folgende Script benennt das Feld verfasser in autor um und erhöht die Feldlänge von 50 auf 100 Zeichen:
Das Grundgerüst Wie schon beim Maschinenraum der Mottomaschine soll das Formular des Gästebuches die Eingabe- und Ausgabefunktion miteinander kombinieren. Allerdings möchten wir den Gästen hier die Möglichkeit bieten, ihre Einträge in einer Vorschau zu kontrollieren und gegebenenfalls zu korrigieren, bevor sie sie endgültig in das Gästebuch eintragen. Unser Formular bietet dafür zwei Schaltflächen, über die eine wird der Eintrag in das Gästebuch aufgenommen, über die zweite kann man sich eine Vorschau anzeigen lassen und seinen Eintrag gegebenenfalls noch bearbeiten. Das Formular besteht also aus zwei Feldern – einem Textfeld für den Eintrag und einem Eingabefeld für den Namen – und zwei Schaltflächen, mit denen man zwischen »Vorschau« oder »Eintrag« entscheidet. Mit dem folgenden HTML-Code erzeugen wir ein Formular, das die eingegebenen Werte für eingabe und autor wie gehabt mit post an die Auswertungsroutine übergibt (um die wir uns später kümmern):
256
Das Grundgerüst
Bevor wir uns um die eigentliche Scriptroutine kümmern, entwerfen wir noch das komplette Grundgerüst von »guestbook.php«, das wir im Verlauf dieses Kapitels nach und nach ausfüllen werden. Dabei handelt es sich um Standard-HTML, das mit sparsamen style-Angaben ein wenig formatiert wurde. Damit das Gästebuch immer zentriert und mit einer Breite von 500 Pixeln im Browser dargestellt wird, wird es innerhalb einer einzeiligen und -zelligen Tabelle ausgegeben, die über eine style-Angabe auf eine Breite von 500 Pixeln gesetzt und über ein
-Element zentriert wird. Da das Eingabeformular später auch als Korrekturformular der Vorschau fungieren soll, übernehmen wir hier, wie schon bei der Mottomaschine, die eventuell vorhandenen Werte für eintrag und autor, die im Falle eines Falles in den Variablen $eintrag und $autor vorliegen. Damit die Eingaben auch in sauberem HTML-Code angezeigt werden, setzen wir die Funktion htmlentities() ein. Darauf haben wir beim Maschinenraum der Mottomaschine, zu dem ja nur wir Zugang haben, noch verzichtet, aber beim Gästebuch können wir nicht wissen, auf welchem System es aufgerufen wird und sollten uns daher bemühen, mögliche Stolpersteine aus dem Weg zu räumen: <style type="text/css"> body, table, form, p {font-family : Arial}
257
Mein Gästebuch
Das Gästebuch macht noch nicht allzu viel her und funktionieren tut es auch noch nicht. Aber immerhin wissen wir schon mal, wie das Eingabeformular aussehen wird.
258
Die Vorschauroutine
Die Vorschauroutine Der erste Schritt zur Auswertung der Benutzereingaben ist die Entwicklung einer Routine zur Darstellung der Beitragsvorschau. Nach einem Klick auf die Schaltfläche »Vorschau« soll der Beitrag oberhalb des Formulars so angezeigt werden, wie er im Gästebuch erscheinen würde. Dabei kümmern wir uns noch nicht um mögliche Fehlerquellen bzw. fehlerhafte Einträge, sondern berücksichtigen vorerst lediglich die leidigen Magic Quotes, die wir mit der im vorigen Kapitel entwickelten Funktion PostVar() unschädlich machen und dabei auch gleich überflüssige Whitespaces mit trim() entfernen. Außerdem sorgen wir dafür, dass die Einträge via htmlentities() in korrektes HTML umgewandelt werden. Das Formular liefert uns drei Werte: den Eintrag als eintrag, den Namen des Verfassers als autor und den Status, über den das Script entscheiden kann, was mit den Daten passieren soll (Vorschau oder speichern) als status. Diese Werte speichern wir wie gewohnt in entsprechenden Variablen. Am Kopf unserer Datei »guestbook.php« fügen wir nun den Code ein, der uns die über das Formular eingegebenen Daten für das Script bereitstellt. Da der Wert für status vom Script erzeugt wird und keine problematischen Zeichen enthalten kann, lesen wir diesen Wert direkt aus $_POST aus. Fügen wir außerdem für den später benötigten Zugriff auf den MySQL-Server unsere include()-Anweisung zur Kontaktaufnahme hinzu, so erhalten wir diesen Codeblock:
Da zu jedem Eintrag im Gästebuch aber noch Datum und Uhrzeit an den Autorennamen angefügt werden soll – und zwar in der Form Giesbert Damaschke, am 17. 8. 2004 um 21:30
– ermitteln wir über die Funktion date() noch die benötigten Daten.
259
Wie schon in Kapitel 2 erläutert, übergibt man dieser Funktion bestimmte Parameter als Zeichenkette und erhält eine entsprechend formatierte Datums- und Zeitangabe zurück. Um etwa das aktuelle Datum in der Form »tt. mm. jjjj« zu erhalten (wobei Tag und Monat ohne führende Null erscheinen sollen), benutzt man diesen Funktionsaufruf: $datum = date("j. n. Y.");
Die Parameter j, n und Y liefern die gewünschten Werte für Tag (»17«), Monat (»8«) und Jahr (»2004«), der Punkt und das Leerzeichen werden in das Ergebnis integriert, so dass $datum schließlich den Wert »17. 8. 2004« enthält. Auf ähnliche Weise ermittelt man die aktuelle Uhrzeit: $zeit = date ("H:i");
Die Parameter H und i liefern die Werte für Stunde (»21«) und Minute (»30«), der Doppelpunkt wird eingefügt, $zeit enthält also den Wert »21:30«. Natürlich kann man das ganze auch kombinieren, nach der Zuweisung $datum = date("j. n. Y. H: i");
enthält $datum eine Zeichenkette mit dem aktuellen Datum und der mit einem Komma abgetrennten aktuellen Uhrzeit, etwa »17. 8. 2004, 21:30«. Damit haben wir fast die Formulierung, die wir benötigen. Wenn wir die Zeichenkette aber nun um die beiden Wörtchen »am« und »um« ergänzen möchten – $datum = date("am j. n. Y. um H: i");
erhalten wir nicht die eigentlich gewünschte Ausgabe, sondern diesen auf den ersten Blick irritierenden Text: pm08 17. 8. 2004 u08 21:30
Woran liegt's? Ganz einfach: die Buchstaben a und m sind ebenfalls Parameter für date(). Mit a fordern Sie die im angelsächsischen Raum gebräuchliche Angabe »am« bzw. »pm« an, wobei »am« für »ante meridiem« (vormittags) und »pm« für »post meridiem« (nachmittags) steht. Und da 21:30 eindeutig nach Mittag ist, liefert also das a zu Beginn das Ergebnis »pm«. Mit dem m erhalten wir den aktuellen Monat als Zahl mit führender Null, womit sich auch die »08« erklärt. Das u wird von date() ignoriert und einfach ausgegeben. Um das kleine Malheur zu beheben und trotzdem die gewünschte Zeichenkette in $datum ablegen zu können, müssen wir die problematischen Zeichen a und m mit dem Escape-Zeichen \ maskieren bzw. »entwerten«, damit date() sie nicht mehr als Parameter, sondern als auszugebendes Zeichen interpretiert: $datum = date("\a\m j. n. Y. u\m H: i");
260
Die Vorschauroutine
Nun können wir die Vorschau des Beitrags unterhalb der Überschrift »Mein Gästebuch« im Rahmen einer if-Abfrage einfügen.
Die Vorschau soll natürlich so aussehen, wie der spätere Eintrag. Die Einträge im Gästebuch sollen durch eine kleine Linie voneinander getrennt werden, die wir am einfachsten mit Standard-HTML erzeugen:
Bei der Ausgabe der Vorschaudaten müssen wir HTML- und PHP-Code mischen. Um die Notation zu vereinfachen wird für die Ausgabe der Vorschau der PHP-Code vorübergehend verlassen. Anschließend wechseln wir wieder zurück zu PHP und tragen die schließende Mengenklammer der ifAbfrage ein. Außerdem müssen wir daran denken, $eingabe und $autor mit htmlentities() zu kodieren. Bei $datum wird diese Funktion nicht benötigt, hier tauchen ja keine Sonderzeichen auf, über die HTML bei der Ausgabe stolpern könnte.
So sieht Ihr Eintrag derzeit aus:
<small>
Um Ihren Beitrag zu bearbeiten, benutzen Sie bitte das Formular.
Im direkten Anschluss an diesen Codeblock folgt der HTML-Code für das weiter oben entwickelte Formular. Da die Variablen im Formular übernom-
261
men und als Feldinhalte angezeigt werden, erhalten wir nun das gewünschte Ergebnis. Die Besucher können im Formular ihren Beitrag formulieren und ihn sich jederzeit über die Schaltfläche »Vorschau« anzeigen lassen. Bei einem Test werden Sie vermutlich sofort bemerken, dass Zeilenumbrüche oder Absätze nicht erkannt bzw. in der Vorschau nicht angezeigt werden. Mit diesen und ähnlichen Formatierungsfeinheiten beschäftigen wir uns später, jetzt geht es erst mal darum, dass ein Klick auf »Eintragen« etwas bewirkt.
Die Vorschau- und Bearbeitungsfunktion bietet dem Autor bei seinem Gästebucheintrag die volle Kontrolle über seinen Beitrag.
Inhalte und Formate Bevor wir uns daran machen, die Eingaben in die Tabelle zu übernehmen und die Gästebuchtabelle auszugeben, machen wir eine kurze Pause und uns ein paar Gedanken über unser Vorgehen.
262
Inhalte und Formate
Vielleicht haben Sie sich gefragt, warum wir beispielsweise beim Datum einen scheinbar komplizierten Weg einschlagen. Statt in der Tabelle ein Datumsfeld vom Typ DATETIME anzulegen, könnten wir doch auch gleich in PHP den Autoreintrag so erweitern, dass die Variable $autor nicht nur den Namen, sondern auch Datum und Uhrzeit des Eintrags enthält. Beim Zugriff auf die Tabellendaten liefert uns MySQL, falls nicht anders angegeben (und falls keine Einträge gelöscht wurden), die Einträge in der Reihenfolge ihrer Eingabe – und das ist bei einem Gästebuch ja automatisch chronologisch sortiert. Um die Ausgabe so zu gestalten, dass die neusten Einträge – also die mit den höchsten Index-Nummern – am Anfang statt am Ende stehen, müssen wir doch nur absteigend nach dem Feld id sortieren lassen, etwa so: ORDER BY id DESC
Das Datumsfeld ist also eigentlich überflüssig. Oder warum haben wir die beiden Variablen $eintrag und $autor nicht gleich mit htmlentities() HTML-konform kodiert? Schließlich werden die Daten später doch auf jeden Fall auf einer Webseite ausgegeben, da ist es doch vielleicht ganz bequem, wenn die benötigten Daten in der Tabelle bereits ein wenig vorformatiert vorliegen und wir nicht bei jedem Zugriff darauf achten müssen, die Variablen korrekt zu kodieren. Beide Einwände zielen im Kern auf die Frage, warum Daten und Formate eigentlich getrennt werden sollten. Die gemeinsame Speicherung scheint auf den ersten Blick ganz praktisch, führt aber kurz oder lang in eine sehr problematische Sackgasse. Beim scheinbar überflüssigen Datumsfeld wird das Problem besonders deutlich. Speichert man Autor und Datum ausformuliert und formatiert in einem Feld, dann spart man zwar ein Feld in der Datenbank und erhält dennoch das gewünschte Ergebnis – doch man erhält nur noch dieses, kein anderes. Was ist, wenn sich unsere Vorstellung vom Aufbau des Gästebuches eines Tages ändert und das Datum beispielsweise wie bei einem Brief rechts oberhalb des Beitrags stehen soll, während der Name des Verfassers weiterhin unten links bleibt? In diesem Fall müsste man das anfangs so praktisch erscheinende Mischmaschfeld mit Autor, Datum und Format mühsam in seine Bestandteile zerlegen und separat speichern. Wenn die Datensätze nicht nur den möglichst reinen Inhalt enthalten, sondern bereits vorformatierte Daten, dann sind Sie zur korrekten Anzeige und Verarbeitung Ihrer Daten darauf angewiesen, dass Sie ein Ausgabemedium zur Verfügung haben, das mit diesem Format zurechtkommt. In gewisser Weise
263
machen Sie dann aus Ihren eigentlich formatunabhängigen Inhalten proprietäre Einträge, die ohne eine bestimmte Software nicht mehr zu lesen sind. Und noch ein Punkt sollte Ihnen zu denken geben: Wenn Sie Inhalte und Formate in der Datenbank mischen, dann wissen Sie bei einem Scriptzugriff nie wirklich so ganz genau, was Ihnen die Datenbank liefern wird. Vorformatierte Inhalte? Und wenn ja – inwieweit vorformatiert? Und was ist, wenn Sie sich später entscheiden, keine Absätze zuzulassen, die Daten in der Datenbank aber bereits mit - oder
-Elementen gespeichert sind? Oder wenn Sie vom einfachen HTML zu XML oder anderen Formatierungsbzw. Auszeichnungsprachen wechseln möchten? Wenn Ihre Daten dann in einem bestimmten Format gespeichert sind, müssen Sie sie erst mühselig konvertieren, bevor Sie mit ihnen weiter arbeiten können. Generell ist es eine gute Idee, bei der Arbeit mit Datenbanken Inhalt und Form strikt und eindeutig zu trennen. Die Datenbank liefert den möglichst reinen, unformatierten Inhalt, die Formatierung und Anpassung an das jeweilige Ausgabemedium erledigt ein Script. Nur so ist die größtmögliche Kompatibilität der Daten gewährleistet. Angesichts einer so bescheidenen Aufgabe wie der Anlage eines Gästebuches mögen Ihnen diese Überlegungen vielleicht etwas überzogen vorkommen und natürlich ist unser aktuelles Projekt nicht wirklich gefährdet, wenn Sie die Einträge formatiert speichern. Aber man sollte sich schlechten Programmierstil gar nicht erst angewöhnen, auch und gerade dann nicht, wenn es sich um scheinbar simple Fälle handelt. Übung macht den Meister – das gilt leider auch für schlechte Angewohnheiten. Es ist sehr viel leichter, von Anfang an auf einen möglichst sauberen Stil zu achten, als sich Jahre später, wenn man mit seinen schlechten Angewohnheiten nicht mehr weiter kommt, an neue Methoden und Strategien zu gewöhnen. Nach diesem kleinen Schlenker ins Abstrakt-Grundsätzliche, wenden wir uns wieder unserer konkreten Aufgabe zu.
Einen Beitrag speichern Wenn der Besucher mit seinem Beitrag zufrieden ist, kann er ihn über die Schaltfläche »Eintragen« dauerhaft ins Gästebuch übernehmen. Das heißt, noch kann er das nicht. Aber gleich.
264
Einen Beitrag speichern
Für die Speicherung in der Datenbank benötigen wir neben den Werten von $eintrag und $autor auch das Datum im passenden Format für den MySQLDatentyp DATETIME. Nun können wir über die date()-Funktion von PHP eine entsprechende Zeichenkette bilden, wir können es aber auch einfach MySQL überlassen, den Zeitpunkt einzutragen und uns die Mühe sparen, indem wir den Wert für das Datum über die MySQL-Funktion NOW() ermitteln, die ohne Parameter aufgerufen wird. Die Funktion liefert auch den aktuellen Sekundenwert, den wir im DATETIME-Feld allerdings nicht benötigen. Aber das macht nichts, MySQL schneidet die überschüssigen Angaben einfach ab. Zeit- und Datumsfunktionen in MySQL
MySQL beherrscht zahlreiche Funktionen im Umgang mit Zeit- und Datumsangaben. Hier sind die drei wichtigsten: NOW() liefert den aktuellen Zeitpunkt in Form von JJJJ-MM-TT HH:MM:SS. CURDATE() ermittelt das aktuelle Datum in Form von JJJJ-MM-TT. CURTIME() gibt den aktuellen Zeitpunkt in Form von HH:MM:SS an.
In der Grundform sieht unser INSERT-Kommando als Wert der Variablen $query ungefähr so aus: $query = "INSERT INTO guestbook SET datum = NOW(), eintrag ='$eintrag', autor = '$autor' ";
Da wir die beiden Zeichenketten noch mit addslashes() behandeln müssen, bevor wir sie an MySQL übergeben, ist diese Lösung allerdings noch fehleranfällig – gibt ein Gast etwa ein Anführungszeichen oder ein Hochkomma ein, liefert MySQL eine Fehlermeldung und trägt den neuen Datensatz nicht ein. Wir haben nun zwei Möglichkeiten: Entweder definieren wir zwei temporäre Variablen, denen wir mit addslashes($eintrag) bzw. addslashes($autor) die entsprechend präparierten Werte übergeben, oder wir fügen den Funktionsaufruf gleich in die Definition von $query ein. Da wir allerdings innerhalb des Strings keinen Funktionsaufruf einsetzen können, unterbrechen wir die Zeichenkette und fügen ihn über den Verkettungsoperator, den Punkt, ein. Das sieht auf den ersten Blick vielleicht etwas verwirrend aus, ist im Grund aber ganz einfach und bietet, da wir die Definition
265
von $query zeilenweise notieren können, besonders bei der Definition von mehreren Feldern ein Maximum an Übersichtlichkeit: $query = "INSERT INTO guestbook SET datum = NOW(), eintrag ='".addslashes($eintrag)."', autor = '".addslashes($autor)."' ";
So kann kein Zweifel mehr darüber bestehen, in welches Feld welche Werte in welchem Format geschrieben werden. Nach der Definition von $query wird die MySQL-Anfrage wie gewohnt an den Server übergeben, wobei wir einen möglichen Datenbankfehler über die() abfangen: $sql = mysql_query($query) or die(mysql_error());
Während der Entwicklungsarbeit benötigen wir zwar die Fehlermeldung, um einen Tippfehler lokalisieren und beheben zu können, später sollte man hier aber statt der nackten Ausgabe der Fehlermeldung mit mysql_error() einen freundlichen Hinweis einfügen, der darüber informiert, dass leider ein Fehler aufgetreten sei und man es bitte später noch einmal probieren möge.
Gästebuch ausgeben Das Gästebuch selbst besteht im Grunde nur aus der Ausgabe aller in der Gästebuchtabelle enthaltenen Einträge. Dergleichen ist für uns inzwischen auch schon fast eine Routine-Aufgabe. Allerdings möchten wir dieses Mal nicht einfach nur Werte auslesen, sondern der Datumswert soll, wie bei der Vorschau, von MySQL gleich im passenden Format wie Giesbert Damaschke, am 17. 8. 2004 um 21:30
geliefert werden, ohne dass wir uns in PHP noch groß um die Formatierung kümmern müssen. Dazu setzen wir die schon in Kapitel 6 vorgestellte MySQL-Funktion DATE_FORMAT() ein, die sich nicht nur auf Werte im Format TIMESTAMP, sondern auf alle Datumsangaben anwenden lässt. Mit den Parametern %e. %c. %Y formatiert MySQL das Datum im Format »17. 8. 2004«, mit %k:%i erhalten wird die Uhrzeit im Format »21:30«. Da MySQL bei dieser Funktion alle Parameter am vorangestellten %-Zeichen erkennt, müssen wir uns nicht darum sorgen, dass die beiden Wörtchen
266
Gästebuch ausgeben
»am« und »um« die Formatierung zerstören könnten. Mit der folgenden Anweisung liefert uns MySQL also das Datum im gewünschten Format unter dem Namen datum: DATE_FORMAT(datum,'am %e. %c. %Y um %k:%i') as datum
Da die Anzeige chronologisch absteigend sortiert sein soll – die neuesten Einträge sollen zuoberst angezeigt werden – müssen wir die Daten mit einem ORDER BY datum DESC
anfordern. Als komplettes SELECT-Statement, mit dem wir neben dem formatierten Datum auch den Eintrag samt Autorennamen in der richtigen Reihenfolge anfordern, ergibt sich also: SELECT DATE_FORMAT(datum,'am %e.%c.%Y um %k:%i') AS datum, eintrag, autor FROM guestbook ORDER BY datum DESC
Der Rest ist nun nicht mehr kompliziert. Wir lesen die Einträge der Reihe nach in einer while-Schleife aus und kodieren $eintrag und $autor vor der Ausgabe mit htmlentities(). Die Ausgabe erfolgt in einem kleinen HTML-Schnipsel, für den wir den PHP-Code erneut kurz unterbrechen. Der Code-Abschnitt zur Anzeige des vollständigen Gästebuches sieht bislang also so aus: $query = "SELECT DATE_FORMAT(datum,'am %e. %c. %Y um %k:%i') AS datum, eintrag, autor FROM guestbook ORDER BY datum DESC"; $sql = mysql_query($query) or die(mysql_error()); while ($ds = mysql_fetch_object($sql)) { $eintrag = $ds->eintrag; $autor = $ds->autor; $datum = $ds->datum; ?>
<small>
267
Der Gästebuch-Prototyp Nun können wir uns daran machen, alle Teile zusammenzusetzen, um so einen ersten funktionsfähigen Prototypen des Gästebuchs zu bekommen. Wir müssen uns nur kurz klar machen, was genau zu sehen ist, wenn die Seite guestbook.php aufgerufen wird. Dabei gibt es drei verschiedene Möglichkeiten:
•
Die Seite wird aufgerufen, ohne dass die Variable $status vorliegt. In diesem Fall wurde die Seite im Browser aufgerufen, es müssen also alle Gästebucheinträge und das Eingabeformular am Schluss angezeigt werden.
•
Die Variable $status hat den Wert »Vorschau«. Der Besucher hat demnach einen Beitrag geschrieben und die Seite über einen Klick auf die Vorschau-Schaltfläche aufgerufen. Hier würden die bisherigen Beiträge nur stören. Der Besucher sieht also nur die Vorschau und das Formular zur Bearbeitung seines Beitrags.
•
Die Variable $status hat den Wert »Eintragen«. Der Beitrag soll ins Gästebuch aufgenommen werden. In diesem Fall wird der Beitrag in die Tabelle übernommen und anschließend die Seite komplett angezeigt. Der neu hinzugekommene Beitrag steht oben.
Das Script muss also zu Beginn entscheiden, ob das Gästebuch vollständig angezeigt werden soll oder nicht. Dafür führen wir die Variable $anzeigen ein, der wir am Anfang den Wert true zuweisen. Wird die Vorschau angefordert, so setzen wir $anzeigen auf false. Eine spätere if-Abfrage wertet die Variable aus und zeigt das Gästebuch nur an, wenn der Wert von $anzeige true ist. Noch etwas gilt es zu bedenken. Wenn die Seite aufgerufen und das Gästebuch vollständig angezeigt wird, dann besitzen die Variablen $eintragen und $autor nach der Ausgabeschleife den Inhalt des zuletzt ausgegebenen Eintrages, der dann automatisch im Formular übernommen wird. Wir können dies verhindern, indem wir in der Ausgabeschleife andere Variablennamen benutzen, oder indem wir die Variablen am Schluss der Ausgabe mit unset($eintrag, $autor);
löschen, was ein wenig einfacher und übersichtlicher ist, als die Einführung temporärer Variablen. Da das Script noch im Entwicklungsstadium ist, begnügen wir uns vorerst mit einer etwas abstrakten Fassung, in der wir vor allem die Struktur von »guestbook.php« eintragen:
268
Fehleingaben abfangen
Mein Gästebuch
Fehleingaben abfangen Unser Gästebuch funktioniert im Grunde schon ganz ordentlich, ist aber vor Fehleingaben noch nicht gefeit. Man kann zum Beispiel einen leeren Eintrag abschicken, oder, im Gegenteil, einen unsinnig langen. Beides ist natürlich unschön und sollte behoben werden. Bevor wir also einen Gästebucheintrag überhaupt akzeptieren und weiter verarbeiten, müssen wir die Inhalte von $eingabe und $autor überprüfen. Das Vorgehen ähnelt dem Verfahren, das wir schon beim Kontaktformular eingesetzt haben. Hier wie dort arbeiten wir mit einer Variablen namens $fehler, in der die Fehlermeldungen als HTML-Listenfeld zusammengesetzt werden. Das einleitende Script wird also nach der Variablenzuweisung um diese drei Zeilen ergänzt: $fehler = ""; if (empty($eintrag)) $fehler .= "
Der Eintrag ist leer
"; if (empty($autor)) $fehler .= "
Sie haben keinen Namen eingetragen
";
Damit im Falle eines Fehlers das Script auch entsprechend reagieren kann, fügen wir zu Beginn, vor der Auswertung von if ($status == "Vorschau")
269
eine if-Abfrage nach diesem Muster ein: if (!empty($fehler)) { $anzeigen = false; // keine Anzeige des Gästebuchs echo "
Leider konnte Ihr Beitrag nicht angenommen werden:
"; echo "
$fehler
"; }
Bei unvollständigen Angaben bricht das Script die Arbeit mit einer Fehlermeldung ab. So vermeiden wir unsinnige Einträge im Gästebuch.
An diese Konstruktion fügt sich die erste $status-Abfrage mit elseif an, so dass die weitere Auswertung nur dann stattfindet, wenn kein Eingabefehler aufgetreten ist. Zu beachten ist hier noch, dass die Variablen $eintrag und $autor erhalten bleiben, also im Formular auch nach einer Fehlermeldung ausgegeben werden. Das ist beabsichtigt, denn so bieten wir den Gästen die Gelegenheit, den Eintrag zu bearbeiten – wer nur aus Flüchtigkeit den Autorennamen vergessen hat, möchte schließlich nicht seinen Eintrag noch einmal vollständig wiederholen müssen. Ein weiterer Stolperstein bei Formulareingaben sind überlange Beiträge, mit denen wir kurzen Prozess machen und sie einfach zurecht stutzen. Beim Eingabeformular sollte sich natürlich ein Hinweis finden, dass Beiträge, die länger als ein bestimmter Grenzwert sind, automatisch gekürzt werden. Damit wir bei diesem Grenzwert flexibel sind und ihn später schnell anpassen können, definieren wir zu Beginn des Scripts den Grenzwert als Variable: $grenzwert = 1000;
Das Formular ergänzen wir also um folgenden Hinweis: <small> Ihr Eintrag (maximal Zeichen):
270
Fehleingaben abfangen
Zum Kürzen des Eintrags setzen wir eine kleine if-Konstruktion ein, die mit der Funktion strlen() die Länge von $eingabe bestimmt und für den Fall, dass unser Grenzwert überschritten wird, $eingabe mit substr() auf die gewünschte Länge bringt: if (strlen($eintrag) > $grenzwert) $eintrag = substr($eintrag,0,$grenzwert);
Was für $eintrag gilt, gilt natürlich auch für $autor. Auch hier wird unser Script mit einer überlangen Eingabe unschön ins Stolpern gebracht. Doch hier können wir auf eine Überprüfung in PHP verzichten und uns mit HTML begnügen. Schließlich gibt es für -Elemente das Attribut maxlength, mit dem die maximal mögliche Länge einer Eingabe definiert wird. Wir müssen also lediglich die entsprechende Zeile im Formular an die maximal mögliche Länge von 50 Zeichen für den Autorennamen anpassen:
<small>Ihr Name:
Aber es gilt noch einen weiteren möglichen Eingabefehler zu unterbinden. Geben Sie im Formular einen sehr langen Text ohne Leerzeichen oder Zeilenumbruch ein, der in seiner Gesamtlänge aber unterhalb des Grenzwertes liegt, so wird die Eingabe akzeptiert – und zerstört das komplette Layout des Gästebuches. Da der Browser keine Möglichkeit hat, die extrem lange Eingabe zu umbrechen, gibt er sie nolens volens am Stück aus. Effekt: Das Fenster wird extrem breit, die Anzeige wird unter Umständen völlig unlesbar.
Bei einer überlangen Zeile ohne Umbruchmöglichkeit für den Browser müssen wir Leerzeichen einfügen, damit die Anzeige des Gästebuches nicht zerstört wird.
271
Um diesen Effekt zu verhindern müssen wir $eintrag vor der Ausgabe auf das Vorhandensein von Leerzeichen überprüfen. Falls wir nach zum Beispiel 60 Zeichen noch auf kein Leerzeichen gestoßen sind, können wir davon ausgehen, dass es sich bei der Eingabe wohl um keinen normalen Text handelt. In diesem Fall zerteilen wir $eingabe mit der Funktion wordwrap() in handliche und darstellbare Teilstücke. Mit dieser Funktion ist es möglich, in eine Zeichenkette in regelmäßigen Abständen ein frei definierbares Trennzeichen einzufügen. Um etwa in $eingabe alle 60 Zeichen ein Leerzeichen einzufügen, benötigen wird diese Anweisung: wordwrap($eintrag, 60, " ", 1);
Zur Leerzeichen-Überprüfung setzen wir strpos() ein. Diese Funktion ermittelt die Position des ersten Auftauchens eines gesuchten Zeichens. Falls das gesuchte Zeichen überhaupt nicht vorhanden ist, gibt sie den Wert false zurück. Setzen wir die Leerzeichen-Überprüfung als Bedingung einer if-Abfrage ein, so können wir mit folgendem Programmcode dafür sorgen, dass extrem lange, umbruchlose Eingaben automatisch umbrochen werden: if (!strpos($eintrag," ") || strpos($eintrag," " > 60)) $eintrag = wordwrap($eintrag, 60, " ", 1);
Umbrüche einfügen Schon bei den ersten Tests der Vorschauroutine ist uns aufgefallen, dass das Formular zwar manuell eingefügte Zeilenumbrüche akzeptiert, aber diese Zeilenumbrüche in der Vorschau ignoriert werden. Die Erklärung für dieses seltsame Verhalten ist einfach und uns bereits vom Kontaktformular aus Kapitel 3 vertraut. Mit der Betätigung der Return-Taste werden die beiden ASCII-Codes »13« (Carriage Return, Wagenrücklauf) und »10« (Zeilenvorschub, Line-Feed) eingefügt, die bei einer Ausgabe normalerweise einen Zeilenumbruch bewirken – nur nicht in HTML, hier werden alle Umbrüche im Quelltext ignoriert und nur bei
, und ähnlichen Elementen ein Zeilenumbruch oder ein neuer Absatz eingefügt. So kommt es, dass zwar die Anzeige im Bearbeitungsformular korrekt ist, nicht aber die Vorschau selbst.
272
Umbrüche einfügen
Die eingegebenen Zeilenumbrüche werden zwar vom Formular korrekt erfasst und in den Variablen gespeichert, aber in HTML natürlich nicht angezeigt.
Wir haben nun verschiedene Möglichkeiten, mit diesem Problem umzugehen. Wir könnten es einfach ignorieren. Aber das ist eine unschöne Lösung und für die Besucher unserer Webseite frustrierend. Wir könnten die Codefolge »1310« jedesmal bei der Ausgabe durch ein ersetzen. Dann würde Vorschau und Formularinhalt zusammenpassen. Aber das ist auch nicht zu empfehlen, da einfache Zeilenumbrüche auch aus Versehen entstehen können und dann zu einem unschönen Schriftbild führen. Schließlich bleibt noch die Möglichkeit, das einfache Auftreten von »1310« zu ignorieren und erst bei zwei aufeinander folgenden Zeilenumbrüchen davon auszugehen, dass der Autor einen Absatz einfügen wollte, und dann die Codefolge »13101310« bei der Ausgabe durch ein
zu ersetzen. Diese Möglichkeit bildet einen guten Kompromiss und wird im Folgenden umgesetzt. Bei dieser Aktion darf der eigentliche Inhalt von $eintrag natürlich nicht verändert werden, die Austauschaktion darf nur während der Ausgabe in der Vorschau oder bei der Anzeige aller Einträge des Gästebuchs vorgenommen werden. Bislang zeigen wir $eintrag mit folgendem HTML-/PHP-Gemisch an:
273
An die Stelle der PHP-Funktion htmlentities() setzen wir nun einfach eine eigene Funktion namens »format«, die sich zum einen um die HTMLKodierung, zum anderen um das Einfügen von -Elementen kümmert. Die Code-Zeile zur Ausgabe von $eintrag sieht also so aus:
Wir müssen nur noch die passende Funktion in unseren Code einfügen. Um ein bestimmtes Zeichen oder eine bestimmte Zeichenfolge innerhalb einer Zeichenkette durch andere Zeichen auszutauschen, benutzen wir wie schon früher die Funktion substr_replace(). Um die ASCII-Codefolge »13101310« zu suchen, können wir wie gehabt nach der Zeichenfolge chr(13).chr(10).chr(13).chr(10) suchen, es geht aber auch ein wenig leichter. So steht die Zeichenfolge \r für ein Return (also den ASCII-Code 13), ein \n für einen Zeilenvorschub (oder, damit man es sich leichter merken kann: für eine neue Zeile), also den ASCIICode 10. Um nach zwei aufeinander folgenden Zeilenumbrüchen zu suchen, suchen wir nach \r\n\r\n. Mit der folgenden Anweisung tauschen wir in der Variablen $text also die manuellen Zeilenumbrüche durch ein doppeltes aus: str_replace("\r\n\r\n","
",$text)
Jetzt können wir die benötigte Funktion problemlos zusammensetzen: function format ($text) { $ergebnis = htmlentities($text); $ergebnis = str_replace("\r\n\r\n","
",$ergebnis); return $ergebnis; }
Das Gästebuch komplett Nachfolgend nun das komplette, in diesem Kapitel Stück für Stück entwickelte Script im funktionsfähigen Gesamtzusammenhang:
274
Das Gästebuch komplett
function format ($text) { $ergebnis = htmlentities($text); $ergebnis = str_replace("\r\n\r\n","
Kaum ein Maskottchen oder Produkt-Logo hat eine derartig steile Karriere hinter sich wie der freundlich und zufrieden dreinblickende Pinguin Tux, der weltweit das Betriebssystem Linux symbolisiert. Tux ist das Ergebnis eines Designwettbewerbs aus dem Jahr 1996 und wurde von Larry Ewing mit der Open-Source-Software The Gimp gezeichnet. Larry Ewings Homepage finden Sie unter der Adresse http:// primates.ximian.com/~lewing/.
Dass Linux von diesem freundlichen Pinguin symbolisiert wird, verdanken wir Linus Torvalds Vorliebe für diese Vögel und Larry Ewings Geschick im Umgang mit The Gimp.
277
Kapitel 10
Ein Weblog
All together now – hier, im letzten Kapitel des Buches, laufen die Fäden zusammen und werden zu einem so genannten Weblog oder Blog verknotet. Das Blog dient der Aufnahme von Fundstücken aus dem World Wide Web und anderswo und ist ein kleines, funktionierendes Content Management System, über das Sie Ihren Auftritt im Internet organisieren können.
Ihr Erfolgsbarometer
Das können Sie schon: Am Beispiel einer Logdatei haben Sie den Einsatz der Dateitypen von MySQL gelernt und wissen nun, wie Sie Daten via PHP speichern
150
Ausgefeilte Formularauswertung, Zufallszahlen, Datensätze löschen, Bilderbücher – ist alles kein Problem mehr.
184
Die korrekte Übernahme von Variablen bereitet Ihnen nun ebenso wenig Probleme, wie der Umgang mit leider unvermeidlichen Fehlermeldungen.
222
Die Arbeit an einem Gästebuch hat Ihnen gezeigt, wie man Eingebefehler abfängt und wie wichtig die Trennung von Daten und Formaten ist.
250
Das lernen Sie neu: Was ist ein »Weblog«?
280
Das Grundgerüst
282
Die Tabellen
286
Das Admin-Interface
287
Noch einmal: Datums- und Zeitfunktionen
291
Das Blog anzeigen
294
Einen Kennwortschutz einfügen
298
Die Formatierung der Eingabe
302
279
Was ist ein »Weblog«? Wer auf hoher See unterwegs ist, der führt über die Ereignisse seiner Reise traditionell ein »Logbuch«. Wer sich in den digitalen Weiten des World Wide Webs tummelt, der sammelt seine Entdeckungen in einem »Weblogbuch«, oder kurz: »Weblog«. Noch kürzer: »Blog«. Ein Weblog ist also eine Webseite, auf der ihr Autor seine Fundstücke aus dem Netz ausstellt, auf verborgene Schätze im Internet hinweist, besonders bemerkenswerte Ereignisse kommentiert, skurrile Meldungen verlinkt oder einfach nur seine Gedanken zum Tag notiert (die Grenzen zum digitalen Tagebuch sind bei einem Blog fließend). Kernstück eines Blogs ist die Software, mit der es erstellt wird. Natürlich kann man seine Beobachtungen zum Weballtag auf die gute alte Art und Weise per Hand notieren, also Webseiten in HTML bauen. Doch der eigentliche Clou bei einem Weblog (und der Grund für ihren großen Erfolg) ist die benutzte Software. Hierbei handelt es sich um mehr oder weniger leistungsfähige Content Management Systeme (CMS), die es dem Benutzer erlauben, frisch drauflos zu schreiben, ohne sich allzu sehr um die Technik kümmern zu müssen. Bei einer Blogsoftware laufen HTML, PHP und MySQL also zu einem kompletten Webauftritt zusammen – und genauso eine Software werden wir zum Abschluss des Buches in diesem Kapitel entwickeln.
Die Zielvorgabe Unser Blogsystem soll einerseits flexibel und leistungsfähig genug sein, dass es nicht nur zur Demonstration der grundlegenden Techniken, sondern auch zum praktischen Einsatz im Internet taugt. Andererseits darf das System aber auch nicht so komplex werden, dass seine Entwicklung und Beschreibung ein eigenes Buch erfordern würde. Wir erarbeiten im Folgenden also ein Grundgerüst, das von Ihnen ganz nach Wunsch ausgebaut und erweitert werden kann, das sich aber auch bereits so, wie es hier vorgestellt wird, im Internet nicht zu verstecken braucht und es Ihnen ermöglicht, Meldungen, Kommentare und anderes einfach und schnell im Internet zu publizieren, ohne dass Sie jedes Mal am HTML-Code einer Webseite herumbasteln oder neue HTML-Dateien anlegen müssten. Dabei setzen wir überwiegend Techniken und Methoden ein, die wir im Verlauf des Buches kennen gelernt haben und die wir hier und da noch ein
280
Die Zielvorgabe
wenig verfeinern. Dieses Mal geht es weniger darum, Ihnen weitere Funktionen vorzustellen, sondern darum, das bisher gelernte Wissen in der Praxis einzusetzen. In diesem Kapitel möchte ich Ihnen zeigen, wie Sie aus den verschiedenen Bruchstücken aus HTML, PHP und MySQL einen kompletten Webauftritt erstellen, der nicht aussieht wie eine halbfertige Baustelle aus hier und da zusammenkopierten Democode-Blöcken. Das System soll uns die Möglichkeit bieten, rubrizierte Textmeldungen abzulegen, die auf der Blogseite nach Rubriken sortiert und über ein Menü, das automatisch aus den vorhandenen Rubrikennamen generiert wird, abrufbar sein sollen. Neben der Erfassung von Texten muss uns das System außerdem ermöglichen, Formatierungen wie fett oder kursiv einzusetzen, wozu wir einen einfachen Pseudocode entwickeln, der es uns auch erlaubt, Zeichen, die wir nicht direkt über die Tastatur eingeben können – wie etwa französische Anführungszeichen » ... « – zu benutzen. Wir benötigen zwei Webseiten: einmal das eigentliche Blog, das Ihre Besucher zu sehen bekommen und dessen Datei wir »index.php« nennen, und zum anderen ein Administrations-Interface, über das Sie Beiträge erfassen können (zur Bearbeitung bzw. zum Löschen der Beiträge sei der Einfachheit halber auf PHPMyAdmin verwiesen). Den Admin-Zugang könnte man zwar auch in index.php integrieren und zum Beispiel über einen get-Parameter beim Aufruf der Seite auswählen, aber dann wird die Blogdatei ein wenig unübersichtlich. Einfacher ist es da, eine eigene Webseite namens »admin.php« anzulegen und Codeteile, die in beiden Dateien benötigt werden, in einer externen Datei abzulegen, die jeweils über include() eingebunden wird. Während index.php für jedermann im Internet zugänglich sein soll, gilt dies natürlich nicht für die Admin-Seite. Hier benötigen wir also einen Kennwortschutz. Dieser Kennwortschutz kann (wie in Kapitel 3 gezeigt) ein Teil von admin.php sein, wir können hierfür aber auch eine MySQL-Lösung benutzen. Das mag in diesem Fall ein wenig übertrieben wirken, aber damit legen wir den Grundstein zu einer Multiuser-Umgebung. Alle berechtigten Personen werden mit Username und Passwort in die Admin-Tabelle eingetragen und das Admin-Interface überprüft zu Beginn anhand dieser Tabelle die Zugangsberechtigung des Users. Schließlich kann man bei der Sammlung und Kommentierung von Fundstücken aus dem World Wide Web Hilfe gut gebrauchen und das Projekt im Team erarbeiten.
281
Neben der Admin-Tabelle benötigen wir natürlich auch eine Tabelle, in der die eigentlichen Blog-Einträge gespeichert und aus der ein PHP-Script die benötigten Daten ausliest. Damit sind die Zielvorgaben hinreichend klar, beginnen wir mit der Umsetzung.
Das Grundgerüst Bevor man daran geht, ein PHP-Script oder eine MySQL-Tabelle anzulegen, sollte man sich an einem Modell klarmachen, wie die Webseite aussehen soll, die über das Script und die Datenbank erstellt wird. Denn erst wenn man weiß, was man eigentlich erreichen will, weiß man auch, wie man bei der Programmierung vorgehen sollte.
Das geplante Weblog als Layoutentwurf – so, oder doch so ungefähr, soll unser Weblog am Ende aussehen. Das Menü auf der linken Seite wird automatisch erzeugt und richtet sich danach, welche Rubriken vorhanden sind. Kommt eine neue hinzu, wächst das Menü an, verschwindet eine, wird das Menü um einen Eintrag kleiner. Natürlich ohne dass Sie sich darum kümmern müssten.
282
Das Grundgerüst
So, wie ein Architekt von einem neuen Gebäude zuerst eine Skizze macht und ein kleines Modell baut, so sollte man auch bei Webseiten zuerst auf einem Blatt Papier den Aufbau der Seite skizzieren und diese Skizze im nächsten Schritt als Layout- oder Designprobe mit Blindtext in HTML umsetzen. Blindtext
Als Blindtext bezeichnet man Texte, die bei der Entwicklung von Layouts als Füllmaterial dienen, um die Wirkung und das Aussehen einer (Web)Seite beurteilen zu können. Einfacher Buchstabensalat ist dafür meist untauglich, ein guter Blindtext vermittelt in der Verteilung der Wort- und Absatzlängen und dem Gemisch aus Groß- und Kleinbuchstaben einen optischen Eindruck davon, wie die Seite später mit richtigen Inhalten aussehen wird. Der Klassiker unter den Blindtexten ist das pseudolateinische Kauderwelsch »Lorem ipsum«. Im Internet finden Sie diverse Sammlungen unterschiedlicher Blindtexte. Hier können Sie sich auch einen Blindtext in beliebiger Länge erzeugen lassen: http://www.blindtexte.de/ http://www.loremipsum.de/ http://www.newmediadesigner.de/
Blindtexte sind wichtige Hilfsmittel beim Entwurf einer Webseite (hier: http://www.newmediadesigner.de)
1
Unser Blog soll eine einfache, bewährte Struktur erhalten: Links steht das Menü, rechts daneben wird der Inhalt der jeweils gewählten Rubrik angezeigt. Dafür setzen wir eine zweispaltige Tabelle ein, die über ein
-Element im Browserfenster zentriert wird und deren Breite wir auf 640 Pixel fixieren. So ist nicht nur sichergestellt, dass die geplante Seite auf praktisch allen Computersystemen angezeigt werden kann, sondern – und das ist fast noch wichtiger – dass der Text der
283
Webseite auch bei größeren Auflösungen und Browserfenstern nicht unlesbar in die Breite geht, sondern immer zentriert und in einer lesbaren Darstellung bleibt.
2
In der linken Spalte, die etwa ein Fünftel der Tabelle einnimmt, soll das Menü erscheinen, das über ein Script automatisch erzeugt wird, im restlichen Bereich der Tabelle werden die einzelnen Meldungen der aktiven Rubrik absatzweise untereinander angezeigt. Zur Trennung der Einträge arbeiten wir mit einer gepunkteten Linie. Am Kopf der Tabelle steht eine große Überschrift, die mit dem Titel der Webseite im Browser übereinstimmt. Hierfür setzen wir am einfachsten eine Variable $blog_title ein, die am Kopf des Dokuments definiert wird. Die Formatierung der Datei erfolgt über eine externe CSS-Datei »styles.css«, die wir im -Bereich von index.php einbinden.
3
In seiner Grundstruktur – für die wir, abgesehen vom Titel, noch keine Zeile PHP benötigen –, sieht index.php also so aus: = $blog_title ?>
284
Das Grundgerüst
4
Sowohl die Menü- als auch die Blog-Einträge werden jeweils von einem
Element umschlossen, dem wir über »styles.css« die gewünschten Trennlinien geben. Ein Menüeintrag hat dabei eine denkbar simple Struktur:
5
Ein Blog-Eintrag ist nicht sehr viel komplizierter und soll in seiner Grundstruktur so aussehen:
Damit steht auch bereits fest, wie viele Felder unsere Tabelle haben muss. Neben den sechs Feldern von »Datum« bis »Link«, benötigen wir noch ein Feld für den Index. Das Erscheinungsbild des Blogs wird über die Style-Definitionen in »styles.css« definiert, die in unserem Beispiel folgendermaßen aussehen: body, p, td {font-family : Arial} body {background-color: silver} p {font-size : 15px;} td {vertical-align : top;} a {font-weight : bold; text-decoration : none} #container { background-color : #a3d1d1; border : 1px solid black; padding : 0px } #titel { text-align : center; font-size : 30px; font-weight : bold; border-bottom : 2px dotted navy; padding : 10px } /* Menue */ #menue {border-right : dotted navy 2px;} #menue p { border-bottom: dotted navy 2px; padding : 5px; margin: 0px 4px 0px 4px;
285
font-size: 18px; font-weight : bold; } #menue p a {color : black} #menue p a:hover {color : white} /* Blog */ #blog {padding : 10px} #blog p { border-bottom : dotted navy 2px; margin : 0px 10px 0px 0px; padding : 10px 0px 10px 0px; } #blog p big {font-size : 18px; font-weight : bold} #blog p small {font-size : 12px} #blog p a {color : maroon} #blog p a:hover {color : white}
Die Tabellen Zu den benötigen MySQL-Tabellen muss nicht mehr viel gesagt werden, ihr Aufbau ergibt sich aus den Anforderungen des Layouts, sie sind mit PHPMyAdmin schnell erstellt. Sie können die Tabellen natürlich auch via PHP erzeugen. Die Kennwort-Tabelle soll »blog_admin« heißen und folgende Struktur haben: $query = "CREATE TABLE blog_admin ( id SMALLINT UNSIGNED AUTO_INCREMENT PRIMARY KEY, name VARCHAR(255), kennwort VARCHAR(50) )";
Die Blog-Tabelle wird einfach »blog« getauft und wird, wie beim Grundgerüst erwähnt, mit sieben Feldern angelegt: $query = "CREATE TABLE blog ( id SMALLINT UNSIGNED AUTO_INCREMENT PRIMARY KEY, datum DATETIME, titel VARCHAR(255), beitrag TEXT, rubrik VARCHAR(255), link VARCHAR(255), url TEXT, )";
286
Das Admin-Interface
Das Admin-Interface Damit wir unser Grundgerüst zum funktionstüchtigen Blog erweitern können, benötigen wir natürlich zuerst ein paar Blog-Einträge, die dargestellt werden sollen. Entwerfen wir also zuerst die Eingaberoutine des AdminModuls (vorerst noch ohne Kennworteingabe). Das Admin-Modul basiert auf dem im vorigen Kapitel entwickelten Gästebuch und sollte keine Probleme oder Fragen aufwerfen. Bei der Variablenzuweisung $datum = datum("now") handelt es sich um den Aufruf einer Funktion, die wir im Anschluss an diesen Abschnitt entwickeln werden und die wir der Vollständigkeit halber bereits in das Listing aufgenommen haben. Erklärungsbedürftig ist vielleicht auch die if-Abfragen zu $link und $url. Für einen Link auf einer Webseite werden bekanntlich zwei Dinge benötigt: der Linktitel und der URL. Die if-Abfrage überprüft nun, ob ein Titel ohne URL vorliegt und gibt gegebenenfalls eine Fehlermeldung aus. Für den umgekehrten Fall, dass zwar ein URL, aber kein Titel eingegeben wurde, wird der Titel auf einen Standardwert gesetzt (hier: »Quelle«). Außerdem benötigen wir für die Ausgabe der Vorschau die im vorigen Kapitel entwickelte Funktion format(). Da wir diese Funktion auch für die Einträge im eigentlichen Blog benötigen, lagern wir sie in die Datei »#_functions.inc« aus. In der Datei wird sich auch die erwähnte Funktion datum() befinden und der Einfachheit halber legen wir dort auch unsere Funktion PostVar() ab. Der PHP-Kopf der Datei »admin.php« sieht – noch ohne Kennwortabfrage – so aus: "; if (empty($beitrag)) $fehler .= "Der Beitrag ist leer. ";
287
if (empty($rubrik)) $fehler .= "Es wurde keine Rubrik angegeben. "; if (!empty($link) && empty($url)) $fehler .= "Link ohne URL. "; } ?>
Auch der Auswertungs- und Formularteil von admin.php ähnelt dem Gästebuch und muss im Grunde nicht weiter kommentiert werden. Bei der Vorschauanzeige wechseln wir zwischen PHP und HTML. Da es Einträge ohne einen Link zu anderen Seiten im Internet geben können soll, wird mit einer if-Abfrage überprüft, ob die Variable $url einen Wert enthält und nur in diesem Fall die Linkzeile ausgegeben. Damit zwischen Blog und Admin-Interface keine allzu großen optischen Unterschiede bestehen, wird dieselbe Style-Datei benutzt: = $blog_title ?>
} elseif ($status == "Eintragen") { $query = "INSERT INTO blog SET datum = now(), titel ='".addslashes($titel)."', beitrag ='".addslashes($beitrag)."', rubrik ='".addslashes($rubrik)."', link ='".addslashes($link)."', url ='".addslashes($url)."' "; $sql = mysql_query($query) or die(mysql_error()); unset($status,$titel,$beitrag,$rubrik,$link,$url); } ?>
Mit diesem Grundgerüst der Admin-Routine ist es nun möglich, beliebige Einträge anzulegen.
Über ein einfaches Interface werden die Blog-Einträge erfasst. Grobe Eingabefehler werden abgefangen, eine Vorschaufunktion vermittelt einen Eindruck vom späteren Eintrag.
290
Noch einmal: Datums- und Zeitfunktionen
Noch einmal: Datums- und Zeitfunktionen Im Blog sollen die Datumseinträge in der Form von 22. August 2004, 14:21
erscheinen. Nun können uns zwar PHP und MySQL die Daten in praktisch allen beliebigen Formaten präsentieren, nur eines geht nicht von Haus aus: eine Anzeige der deutschen Monatsnamen. Mit PHP kann man dieses Problem, wie in Kapitel 4 erläutert, über ein Array $monate mit den deutschen Monatsnamen lösen. Mit date("n") lässt sich die aktuelle Monatsnummer von 1 bis 12 ermitteln, die wir um eins vermindern – der Index bei einem numerischen Array beginnt ja beim Wert 0, nicht bei 1 – und so den benötigten Index für $monate erhalten: $monate = array("Januar","Februar", "März", "April", "Mai", "Juni", "Juli", "August", "September", "Oktober", "November", "Dezember"); $datum = date("j. ").htmlentities($monate[date("n")-1]).date (" Y, H:i");
So weit, so gut. Doch was mit PHP geht, geht nicht mit MySQL, hier erhalten wir auf jeden Fall immer die englischen Monatsnamen. Nun könnte man sich von MySQL das Datum in englischer Form nennen lassen und es anschließend mit den String-Funktionen in PHP ummodeln, also etwa »February« durch »Februar« ersetzen. Doch dazu bräuchte man jede Menge if-Abfragen, was recht brachial und plump ist. Es geht auch sehr viel eleganter und einfacher: Wir lassen uns von MySQL das Datum als so genannten Unix-Timestamp schicken. Bei diesem bereits in Kapitel 7 kurz erwähnten »Zeitstempel« handelt es sich gewissermaßen um eine Universalwährung in Sachen Datums- und Zeitangaben, die die verflossenen Sekunden seit dem 1. Januar 1970, 0:00:00 Uhr zählt. In PHP können wir einen Unix-Timestamp dann über die date()-Funktion ins gewünschte Format bringen. Bislang haben wir date() nur mit den verschiedenen Parametern für Zeitund Datumsangaben eingesetzt, die Funktion akzeptiert aber noch einen zweiten Wert: den Unix-Timestamp des Datums, das formatiert werden soll. Wird dieser Wert – wie in unseren bisherigen Scripts – nicht angegeben, greift date() auf den aktuellen Zeitpunkt zu. Mit $zeit = date("H:i");
291
erhält man also die aktuelle Uhrzeit, mit $zeit = date("H:i", 11235);
den Zeitpunkt, der 11.235 Sekunden nach dem Beginn der Unix-Zeitrechnung erreicht wurde, nämlich den 1. August 1970, 04:07:15. Da wir sowohl in der Vorschau als auch bei der Bloganzeige die Datumsangabe benötigen, ist es sinnvoll, die Ermittlung des Datumswertes einer Funktion zu überlassen, die wir in »#_functions.inc« auslagern. Wird die Funktion mit dem Wert »now« aufgerufen, so gibt sie den aktuellen Zeitpunkt im vom uns gewünschten Format zurück, ansonsten benutzt sie den übergebenen Wert als Unix-Timestamp. Zusammen mit unserer format()und der PostVar()-Funktion sieht die Datei »#_functions.inc« dann so aus: ",$ergebnis); return $ergebnis; } function datum($t) { $monat = array("Januar","Februar", "März", "April", "Mai", "Juni", "Juli", "August", "September", "Oktober", "November", "Dezember"); if ($t == "now") $ergebnis = date("j. ").htmlentities ($monat[date("n")-1]).date(" Y, H:i"); else $ergebnis = date("j. ",$t).htmlentities ($monat[date("n")-1],$t).date(" Y, H:i:s",$t); return $ergebnis; } ?>
Bevor wir uns mit den weiteren Funktionen des Admin-Interfaces beschäftigen, widmen wir uns der Ausgaberoutine in index.php, also unserem eigentlichen Blog. Geben Sie dazu einige Testeinträge ein und achten Sie darauf, unterschiedliche Rubriken zu benutzen.
292
Menüeinträge auslesen und anzeigen
Menüeinträge auslesen und anzeigen Auch bei den PHP- und MySQL-Kommandos, die wir zur Anzeige des Weblogs benötigen, können wir zum größten Teil auf bereits entwickelte Routinen zurückgreifen und diese an unsere Zwecke anpassen. Nur ein Punkt ist wirklich neu, nämlich die automatische Erzeugung des Menüs. Widmen wir uns also diesem Problem zuerst. Wir benötigen eine Funktion, die uns die Rubrikeneinträge in der Tabelle blog sortiert ausliest und die doppelten Einträge entfernt. Wenn wir zum Beispiel vier Einträge mit der Rubrik »Kino« haben, dann würde ein einfaches SELECT-Statement zur Abfrage der Rubriken auch viermal das Wort »Kino« ermitteln. Für das Menü genügt aber natürlich ein einziger Eintrag. Hier setzen wir die MySQL-Funktion DISTINCT() ein, die genau die benötigten Daten liefert, nämlich nur jeden in einem Feld vorkommenden Begriff genau einmal. So können wir die benötigten Rubrikeneinträge aus der Tabelle auslesen und in einem Array $rubriken ablegen. Als Eintrag für rubriken[0] tragen wir den Punkt »Aktuell« ein. Über diesen Menüpunkt sollen im Blog alle Einträge in ihrer chronologischen Reihenfolge angezeigt werden. Das ganze ist eine Sache weniger Code-Zeilen. Da die while-Schleife nur eine Anweisung enthält, können wir sie einzeilig notieren.
rubrik; // Ausgabe des Menüs ?>
293
Zur automatischen Erzeugung des Rubrikenmenüs genügt im Grund je eine Zeile MySQL und eine Zeile in PHP. Nur selten erreicht man mit weniger Aufwand ein besseres Ergebnis.
Für die Ausgabe setzen wir eine foreach-Schleife ein. Damit das Script später erkennen kann, welcher Menüpunkt ausgewählt wurde, wird der Index-Wert von $rubriken als get-Parameter id eingesetzt. Da auch hier innerhalb der Schleife nur eine Anweisung ausgeführt werden muss, können wir die Schleife erneut einzeilig notieren. Der vollständige Code zur automatischen Erzeugung der Menüspalte lässt sich damit mit einer einzigen Zeile in PHP bilden: foreach($rubriken as $index => $menue) echo "
Allerdings hat dieses Menü noch einen kleinen Schönheitsfehler und trägt auch die Rubrik als aktiven Link ein, die bereits angezeigt wird. Doch das bügeln wir später aus.
Das Blog anzeigen Die Ausgabe der einzelnen Blog-Einträge ist im Prinzip ganz einfach. Wir müssen lediglich den get-Parameter auswerten, den entsprechenden Eintrag aus dem $rubriken-Array lesen und diesen Wert für die WHERE-Bedingung in einem SELECT-Statement benutzen. Da der get-Parameter über eine manuelle Eingabe in der Adresszeile verändert werden kann, können wir nicht ausschließen, dass er vom Besucher der Seite manipuliert und unser Script unter Umständen zum Absturz gebracht wird. Um das zu verhindern, muss zu Beginn überprüft werden, ob der mit
294
Das Blog anzeigen
get übergebene Wert von id innerhalb der erlaubten Grenzen liegt. Der
niedrigste Wert ist dabei 0, der höchste die Anzahl der Array-Einträge minus eins (die Zählung im Array beginnt ja bei 0). Außerdem müssen wir, für den Fall, dass ein Buchstabenstring als get-Parameter übergeben wird, die Variable $id über die Funktion settype() zwingend in einen Integer-Wert umwandeln. Unsinnige Texte werden dabei automatisch zum Wert 0. $id = $_GET['id']; settype($id,"integer"); if ($id < 0 || $id >= count($rubriken)) $id=0;
Für den Fall, dass die Seite ohne get-Parameter oder mit dem get-Parameter 0 aufgerufen wird, sollen alle Einträge in chronologisch absteigender Folge angezeigt werden, in diesem Fall entfällt die WHERE-Klausel. Die Entscheidung, welche Anfrage an den MySQL-Server gerichtet wird, lässt sich über eine einfache if-Abfrage treffen. Für unsere Datumsfunktion benötigen wir den Datumswert als Unix-Timestamp, wozu wir die MySQL-Funktion UNIX_TIMESTAMP einsetzen. Als Argument übergeben wir das datum-Feld, über AS lassen wir uns das Ergebnis unter dem Namen datum liefern. Damit der Code nicht zu unhandlich wird, setzen wir für die WHERE- und die SELECT-Klausel zwei Variablen ein: $where = $rubriken[$id]; $select = "UNIX_TIMESTAMP(datum) AS datum, titel, beitrag, rubrik, link, url"; if (empty($id)) $query = "SELECT $select FROM blog ORDER BY datum DESC"; else $query = "SELECT $select FROM blog WHERE rubrik = '$where' ORDER BY datum DESC";
Anschließend können wir die Anfrage an den Server schicken und die Werte in dem bekannten Verfahren auslesen: while ($ds = mysql_fetch_object($sql)) { $timestamp = $ds->datum; $titel = $ds->titel; $beitrag = $ds->beitrag; $rubrik = $ds->rubrik; $link = $ds->link; $url = $ds->url; $datum = datum($timestamp): // Ausgabe des Eintrags }
295
Für die Ausgabe der Werte setzen wir im Grunde den gleichen Code ein wie für die Ausgabe der Vorschau: echo "
Binden wir die Datei »#_functions.inc« schließlich noch über eine include()Anweisung am Kopf von index.php ein, so erhalten wir zur Anzeige des Weblogs diesen Code:
Zwischenstand Unser kleines Blog besteht nun aus vier Dateien: index.php, admin.php, #_functions.inc und styles.css. Die Funktionalität des Blogs ist zu großen Teilen gegeben, ein paar Kleinigkeiten müssen noch ergänzt werden:
•
Die Kennwortabfrage für admin.php. Dies ist die wohl wichtigste Funktion, schließlich möchten Sie bestimmt nicht, dass nun jedermann durch den simplen Aufruf der Datei admin.php Beiträge in Ihrem Blog schreiben kann.
•
Die Formatierungsroutine für die Ausgabe von Sonderzeichen. Hier handelt es sich um eine Erweiterung der format()-Funktion und die Entwicklung eines einfachen Pseudocodes.
•
Die Menüanzeige ausbessern, damit ausgewählte Punkte nicht mehr als Link erscheinen.
Da die Kennwortabfrage am wichtigsten ist, kümmern wir uns zuerst um diesen Punkt.
Einen Kennwortschutz einfügen Bereits in Kapitel 3 haben wir gesehen, wie einfach man einen Kennwortschutz für Webseiten realisieren kann. Dort haben wir noch mit einer externen Datei gearbeitet, hier setzen wir die Tabelle blog_admin ein. Tragen Sie mit PHPMyAdmin in diese Tabelle für die Kennwortroutine einige Namen samt Kennwörtern ein. Beim Aufruf der Datei admin.php soll zuerst ein kleines Formular zur Eingabe von Name und Kennwort angezeigt werden. Erst wenn die Eingabe korrekt war, wird das Bearbeitungsformular gezeigt, das neben dem Formular nun auch den Namen des aktuell angemeldeten Admin enthalten soll.
298
Einen Kennwortschutz einfügen
Das Formular zur Kennworteingabe ist denkbar einfach:
Damit vor der Anmeldung auch wirklich nur das Eingabeformular angezeigt wird, setzen wir eine Variable $angemeldet ein. Diese Variable wird im Script-Teil im Kopf von admin.php mit dem Wert false initialisiert. Nur für den Fall, dass $angemeldet den Wert true erhält, wird das Eingabeformular angezeigt oder eine Eingabe ausgewertet. Damit ändert sich die Struktur von admin.php. Das einleitende Script erhält nun diesen Aufbau:
299
Auch der -Teil ändert sich in Abhängigkeit von $angemeldet. An erster Stelle steht nun eine if/else-Abfrage, die für den Fall, dass $angemeldet den Wert false besitzt, das Formular zur Kennworteingabe anzeigt, andernfalls wie gehabt das Eingabeformular:
Beim Aufruf von admin.php werden zuerst die beiden post-Variablen $name und $kennwort ausgelesen und nur für den Fall, dass beide Werte vorliegen, wird die Analyse des Kennwortes begonnen. Andernfalls wird $angemeldet auf den Wert false gesetzt: $name = $_POST['name']; $kennwort = $_POST['kennwort']; if (!empty($name) && !empty($kennwort)) { // Analyse } else $angemeldet = false;
Die eigentliche Analyse von Name und Kennwort besteht aus einer einfachen MySQL-Abfrage. Zuerst wird der Datensatz angefordert, bei dem der Name mit dem eingegebenen Namen übereinstimmt: $query = "SELECT name, kennwort FROM blog_admin WHERE name = '$name'"; $sql = mysql_query($query) or die(mysql_error());
Falls es zum eingegebenen Namen einen Eintrag gibt, so liefert uns unsere Anfrage genau ein Ergebnis. Ob dies der Fall ist, ermitteln wir über die Funktion mysql_num_rows(), mit der wir die Anzahl der gefundenen Datensätze erfahren. Ist dieser Wert gleich 1, so ist der eingegebene Name korrekt. Über einen einfachen Vergleich des zu diesem Namen gehörenden Kennwortes
300
Einen Kennwortschutz einfügen
können wir dann entscheiden, ob das eingegebene Kennwort zum Namen passt. Ist dies der Fall, so erhält $angemeldet den Wert true. if (mysql_num_rows($sql) == 1) { $ds = mysql_fetch_object($sql); if ($ds->kennwort == $kennwort) $angemeldet = true; }
Setzen wir die Teile zusammen, so erhalten wir folgenden Code-Block, mit dem wir den eingegebenen Namen und das Kennwort überprüfen können: $name = $_POST['name']; $kennwort = $_POST['kennwort']; if (!empty($name) && !empty($kennwort)) { $query = "SELECT name, kennwort FROM blog_admin WHERE name = '$name'"; $sql = mysql_query($query) or die(mysql_error()); if (mysql_num_rows($sql) == 1) { $ds = mysql_fetch_object($sql); if ($ds->kennwort == $kennwort) $angemeldet = true; } } else $angemeldet = false;
So weit, so gut. Doch die Sache hat noch einen kleinen Haken: Nach der korrekten Eingabe von Namen und Kennwort gelangen wir zwar zum Eingabeformular, doch sobald wir einen Eintrag anlegen möchten, stolpern wir wieder über die Kennwortabfrage. Der Grund: Beim Aufruf von admin.php über das Blog-Eingabeformular enthalten $name und $kennwort keine Werte (mehr) und unsere Kennwortabfrage weist uns also ab. Doch es gibt eine einfache Lösung: Nach erfolgter Anmeldung liegen in $name und $kennwort ja korrekte Inhalte vor. Fügen wir diese Werte über -Felder vom Typ hidden in unser Blog-Eingabeformular, dann werden neben den eigentlichen Eingaben auch immer $name und $kennwort
übermittelt und wir passieren die Kennwortabfrage am Anfang unseres Scripts. Fügen Sie also an beliebiger Stelle im Blog-Eingabeformular diese beiden Zeilen ein:
301
Die Formatierung der Eingabe Wenn wir im Blog nicht nur normalen Text, sondern auch Auszeichnungen wie fett oder kursiv benutzen möchten, können wir nicht einfach den entsprechenden HTML-Code in das Formular eingeben. Zwar würde dieser Code gespeichert, aber da wir vor der Ausgabe die Funktion htmlentities() einsetzen, würde aus einem fett in der Tabelle in der Ausgabe ein , der Code würde also bei der Ausgabe im Browser nicht ausgeführt, sondern angezeigt. Am einfachsten lässt sich dieses Problem durch die Einführung eines Pseudocodes lösen, statt der typischen HTML-Angaben wie fett speichert man etwa [b]fett[/b]. Dieser Code bleibt von htmlentities() unberührt und kann anschließend durch die benötigten HTML-Anweisungen ersetzt werden. Um das zu erreichen, wird die Funktion format() entsprechend erweitert: function format ($text) { $ergebnis = htmlentities($text); $ergebnis = str_replace("\r\n\r\n","
Über diese Funktion können wir auch Sonderzeichen in unseren Blog-Einträgen benutzen, die wir über die Tastatur nicht eingeben können, wie französische Anführungszeichen, typographische Gedankenstriche (an Stelle der kurzen Bindestriche), ein korrekter Apostroph statt des Hochkommas und Ähnliches mehr: function format ($text) { $ergebnis = htmlentities($text); $ergebnis = str_replace("\r\n\r\n","
Durch eine Ergänzung der format()-Funktion eröffnen sich neue Möglichkeiten. Die Funktion kann beliebig erweitert und Ihren Anforderungen angepasst werden.
Schönheitsreparatur beim Menü Auf unserer To-do-Liste steht jetzt nur noch ein Punkt, die Schönheitsreparatur der Menüausgabe. Diese Aufgabe ist schnell erledigt. Bei der Ausgabe der Menüpunkte muss der Rubrikeneintrag, dessen Index-Wert mit $id übereinstimmt, von der Verlinkung ausgenommen werden. Und damit der aktuelle Menüpunkt auch optisch hervorgehoben ist, färben wir ihn noch weiß ein: foreach($rubriken as $index => $menue) { if ($index == $id) echo "
Kleine Ursache, große Wirkung: Fügt man eine if-Abfrage bei der Ausgabe des Menüs ein, kann man den aktuell aktiven Eintrag hervorheben.
Menschen, nicht Maschinen: Sie, ich, wir alle
Dieses Buch ist jetzt bald zu Ende – doch Ihr Weg durch das Internet und Ihr Beitrag zum Netz geht, hoffe ich, gerade erst so richtig los. Das World Wide Web ist ein Medium, das wie kaum ein anderes von der aktiven Mitarbeit der Netizens lebt und wie Sie in diesem Buch gelernt haben, ist es gar nicht so schwer, vom passiven Surfer zum aktiven Netizen zu werden. Und das beste an der Sache: Je stärker Sie sich am Geschehen im Internet beteiligen, desto stärker profitieren Sie vom Nutzen des Internet. Give a bit, take a bit – nehmen Sie vom Netz und geben Sie dem Netz etwas zurück. Denken Sie daran: Das Internet verbindet keine Maschinen, sondern Menschen.
304
Internetlexikon
Internetlexikon @, At-Sign, At-Zeichen, Klammeraffe Steuerzeichen; trennt in einer E-Mail-Adresse den Namen von der Domain nach dem Muster: »[email protected]«. Setzt man den Klammeraffen vor einen Funktionsnamen, werden die Fehlermeldungen des Servers ausgeblendet. Das wird benötigt, wenn man eigene Fehlerbehandlungsroutinen schreiben möchte.
Abbruchbedingung Eine Bedingung, die eintreten muss, damit eine Programmschleife verlassen wird.
Apache Name des bekanntesten und wichtigsten Webservers im Internet. Der Name ist ein Wortspiel mit »Apache / a patchy«.
Array In einem Array lassen sich mehrere Werte unter einem Namen zusammenfassen. Array ist das englische Wort für »Feld«, daher werden diese Variablen mitunter auch als Feldvariablen bezeichnet.
ASCII Abkürzung für »American Standard Code for Information Interchange«. Definiert die Kodierung von 128 (englischen) Schrift- und Steuerzeichen, die für alle Computer und für alle elektronischen Systeme verbindlich gilt.
Ausdruck Ein Ausdruck ist ein Vergleich, eine Funktion, eine Operation oder sonstige Kombinationen aus Werten, die einen neuen Wert erzeugen.
Blog Kurzform von »Weblog«; Oberbegriff für Webseiten, bei denen die Besitzer in Form eines Logbuchs über ihre Entdeckungen im World Wide Web berichten oder Kommentare zu aktuellen Ereignissen abgeben. Der Autor des Blogs benötigt keine oder nur rudimentäre technische Kenntnisse und benutzt zur Erstellung und Pflege seines Blogs spezielle Software.
305
Boolesche Verknüpfung / Logische Verknüpfung Nach dem Mathematiker George Boole (1815–1864) benannte Methode zur formallogischen Verknüpfung von Bedingungen oder Aussagen. Bei einer AND-Verknüpfung (logisches UND) müssen alle mit AND verbundenen Bedingungen eintreffen, bei einer OR-Verknüpfung (logisches ODER) genügt es, wenn eine der kombinierten Bedingungen zutrifft.
Compiler Wörtlich: Übersetzer. Ein Compiler übersetzt den Quellcode in ein ausführbares Programm.
Content-Management-System, CMS System zur Produktion, Publikation und Verwaltung von Inhalten im Internet; im Kern basiert ein CMS auf verschiedenen Templates oder Webseitenvorlagen, in die mehrere Autoren ihre Texte und Bilder eingeben. Die Formatierung und webgerechte Aufbereitung erfolgt automatisch. Große Websites mit häufig wechselnden Inhalten wären ohne ein CMS nicht realisierbar, aber auch für die private Homepage kann ein (einfaches) CMS hilfreich sein.
Cookies Kleine Textdateien, die Webserver an den Browser schickt, um dort eine Markierung zu hinterlassen, an der der Server den Browser wieder erkennt. Ein Cookie kann auf der Festplatte gespeichert und beim nächsten Zugriff auf eine Webseite erneut geladen werden, ein temporärer Cookie wird nur im Speicher gehalten und gelöscht, sobald das Browserfenster geschlossen wird.
Datentyp Ein Datentyp legt fest, welche Art von Informationen in einer Variablen oder Konstanten gespeichert werden können. Im Prinzip ist PHP eine typenlose Sprache, bei der während des Programmablaufs entschieden wird, welchen Datentyp eine Variable besitzt, eine Variable kann ihren Typ dabei mehrmals wechseln. Die wichtigsten Typen sind Integer zur Aufnahme ganzzahliger Werte, Double und Float zur Darstellung von Fließkomma-Zahlen, String für Zeichenketten und Boolean für die beiden logischen Wahrheitswerte true und false.
Escape-Sequenz Zeichenkombinationen aus einem Backslash »\« mit einem anderen Zeichen, wird zur Ausgabe reservierter Steuerzeichen wie »$« oder »"« benötigt.
306
Internetlexikon
Funktion Ein spezielles Codesegment als ein in sich abgeschlossener Bestandteil des Quellcodes zur Lösung besonderer Aufgaben.
HTML-Entity Spezieller HTML-Code zur Darstellung von Sonderzeichen außerhalb der Standard-ASCII-Tabelle. Die HTML-Entity für ein »ä« lautet beispielsweise »ä«.
Interpreter Programm, das Quellcode zeilenweise abarbeitet und ausführt. Ein Interpreter erzeugt kein separates Programm, für jeden Durchlauf muss der Quellcode erneut interpretiert werden. PHP ist eine Interpreter-Sprache.
Konstanten Symbolische Bezeichner für bestimmte Werte. Im Unterschied zu Variablen können Konstanten zwar definiert, danach aber nicht mehr verändert werden.
Linux Eine von Linus Torvalds entwickelte Unix-Variante. Linux wird von einer Vielzahl freiwilliger Helfer und Programmierer weiterentwickelt und gilt heute als das leistungsfähigste Unix für Computer mit einer CPU von Intel. Linux wird übers Internet kostenlos verteilt.
Magic Quotes Name einer Core-Funktion von PHP, bei der Get-, Post- und Cookie-Variablen automatisch maskiert werden (problematische Zeichen werden mit einem Backslash versehen). Um eine einheitliche Installationsbasis zu erreichen, sollten Magic Quotes deaktiviert werden.
OOP Abkürzung für Objektorientierte Programmierung. OOP ist ein in den 80ger Jahren entwickeltes Programmierkonzept, in dem Daten und Funktionen nicht getrennt, sondern als einheitliches Objekt betrachtet werden, das bestimmte Eigenschaften besitzt. Diese Art der Programmstrukturierung erlaubt ein Höchstmaß an Flexibilität und Effizienz.
307
Open Source Oberbegriff für Software, deren Quelltext offen und frei zugänglich ist. Open-Source-Software lebt meist von zahlreichen freiwilligen Mitarbeitern und ist häufig kostenlos. Trotzdem unterliegt Open-Source-Software in der Regel bestimmten Lizenzbedingungen und ist keine Freeware.
Operand Wert, der mit einem anderen Wert durch einen Operator verknüpft wird. Typischerweise werden je zwei Operanden mit einem Operator verbunden.
Operator Symbolisches Zeichen, mit dem zwei oder mehrere Werte verknüpft werden und eine Aktion ausführen (z.B. Wertzuweisung mit dem Gleichheitszeichen) oder einen neuen Wert definieren (etwa durch eine Addition oder eine andere arithmetische Operation).
Parser Überprüft den PHP-Code auf korrekte Syntax.
Perl Perl ist wie PHP eine serverbasierte Scriptsprache.
PHPMyAdmin Leistungsfähiges Verwaltungstool für MySQL-Datenbanken.
Programmier- und Scriptsprachen Bei einer Programmiersprache wird der Programmcode durch einen so genannten Compiler in Maschinencode umgesetzt und als direkt ausführbare Programmdatei gespeichert. Die Anweisungen eines Scripts werden dagegen bei jedem Aufruf erneut sequentiell abgearbeitet. Scripts sind normalerweise rechenintensiver und langsamer als Programme, was bei heutigen Computern nicht mehr so stark ins Gewicht fällt. Es gibt server- und clientseitige Scriptsprachen. PHP ist eine serverseitige Scriptsprache, die einzelnen Scriptbefehle werden vom PHP-Interpreter auf dem Server umgesetzt, dem Webbrowser des Anwenders wird das Ergebnis geliefert. Javascript ist ein Beispiel für eine clientseitige Scriptsprache, hier werden die Befehle in den HTML-Code eingebettet und erst im Browser ausgeführt.
308
Internetlexikon
Quellcode, Quelltext, Sourcecode Der Begriff Quellcode ist ein an das englische »Sourcecode« angelehntes Kunstwort und meint die Programmanweisungen in Textform, aus denen erst ein Compiler ein lauffähiges Programm erzeugt oder die von einem Interpreter sequentiell abgearbeitet werden. Der Code ist gewissermaßen die »Quelle« oder der »Ursprung« des Programms.
SQL / MySQL Abkürzung für »Standard Query Language«. Ein SQL-Server ist ein Datenbankserver, der mittels SQL-Kommandos gesteuert wird. MySQL ist eine sehr leistungsfähige Open-Source-Variante von SQL.
Unix-Timestamp Der Unix-Timestamp ist die Anzahl der Sekunden, die seit dem 1. Januar 1970, 0:00 Uhr GMT (Greenwich Mean Time) verflossen sind.
Variable Symbolischer Bezeichner für einen bestimmten Wert. Der Wert kann im Laufe des Programms verändert werden.
Whitespace Als Whitespace, also »weißen Raum«, bezeichnet man bestimmte Zeichen, die auf dem Bildschirm oder Ausdruck als leer oder unsichtbar erscheinen, wie Leerzeichen, Zeilenumbruch, Tabulator und Ähnliches.
Xampp Abkürzung für Apache, MySQL, PHP, Perl. Das X zu Beginn ist ein Platzhalter für das Betriebssystem.
Zeichenkette Datentyp; eine Zeichenkette besteht aus beliebigen Ziffern, Buchstaben und Zeichen.
309
Liebe Leserin, lieber Leser, herzlichen Glückwunsch, Sie haben es geschafft. Sie können nun mit PHP und MySQL dynamische Webseiten programmieren. Ist es Ihnen nicht viel leichter gefallen, als Sie am Anfang dachten? Genau das ist das Ziel unserer Bücher aus der easy-Reihe. Sie sollen helfen, erfolgreich die ersten Schritte zu gehen, und den Leser auf keinen Fall mit unverständlichem Fachchinesisch überhäufen. Als Lektor hoffe ich, dass Sie durch das Buch die richtige Unterstützung bekommen haben. Denn für Ihre Zufriedenheit stehen alle Beteiligten mit ihrem Namen: der Verlag, die Autoren, die Druckerei. Aber niemand ist perfekt. Wenn Sie Fragen haben: Fragen Sie. Wenn Sie Anregungen zum Konzept haben: Schreiben Sie uns. Und wenn Sie uns kritisieren wollen: Kritisieren Sie uns. Ich verspreche Ihnen, dass Sie Antwort erhalten. Denn nur durch Sie werden wir noch besser. Ich freue mich auf Ihr Schreiben!
Boris Karnikowski Lektor Markt + Technik Pearson Education Deutschland GmbH Martin-Kollar-Str. 10-12 81829 München E-Mail: [email protected] Internet: http://www.mut.de
... aktuelles Fachwissen rund, um die Uhr – zum Probelesen, Downloaden oder auch auf Papier. www.InformIT.de
InformIT.de, Partner von Markt+Technik, ist unsere Antwort auf alle Fragen der IT-Branche. In Zusammenarbeit mit den Top-Autoren von Markt+Technik, absoluten Spezialisten ihres Fachgebiets, bieten wir Ihnen ständig hochinteressante, brandaktuelle Informationen und kompetente Lösungen zu nahezu allen IT-Themen.
wenn Sie mehr wissen wollen ...
www.InformIT.de
Wichtige String-Funktionen in PHP echo $string; print $string;
Gibt $string aus; kann zu Beginn eines PHP-Blocks mit einem Gleichheitszeichen abgekürzt werden: . htmlentities($string)
Wandelt alle Sonderzeichen in $string in die korrekte HTML-Entity. str_replace ($suche, $ersetzen, $string)
Tauscht alle $suche in $string durch $ersetzen aus. strchr ($string, $suche); strstr($string, $suche)
Identische Funktionen; ermitteln das erste Vorkommen von $suche in $string und liefern den Rest von $string zurück. strip_tags($string)
Entfernt sämtliche PHP- und HTML-Anweisungen in $string. strlen($string)
Ermittelt die Länge (= Anzahl der Zeichen) in $string. strpos($string, $suche)
Ermittelt die Position von $suche in $string. strrev($string)
Dreht die Zeichenfolge von $string um, aus »zeichen« wird z. B. »nehciez«. str_repeat($string, $anzahl)
Gibt $string $anzahl-mal aus; str_repeat("*",5) erzeugt z. B. *****. strtolower($string); strtoupper($string)
Wandelt $string in Klein- bzw. in Großbuchstaben um. substr($string, $pos, $length)
Ermittelt ein Teilstück von $string, beginnend bei $pos, mit der Länge $length. Fehlt $length, wird der Reststring ab $pos zurückgegeben. trim($string)
Entfernt Leerzeichen, Tabulatoren und ähnlichen »Whitespace« zu Beginn und Ende von $string.
PHP und MySQL $dz = mysql_connect($host, $user, $pass);
Stellt eine Verbindung zum MySQL-Server $host mit dem Usernamen $user und dem Passwort $pass her. mysql_select_db($database, $dz);
Öffnet die Datenbank $database für die Verbindung $dz. mysql_query($query)
Übermittelt eine Anfrage $query an den MySQL-Server; es muss eine Verbindung zum Server geöffnet und eine Datenbank ausgewählt sein. mysql_error()
Gibt die MySQL-Fehlermeldung aus.
Wichtige MySQL-Anweisungen SELECT feld FROM tabelle
Liest den Wert von feld aus tabelle aus, mehrere Felder werden mit Komma getrennt, alle Felder mit * selektiert. WHERE bedingung ORDER BY feld
Spezifizieren das SELECT-Statment; WHERE beschränkt die Auswahl auf alle Einträge, für die bedingung wahr ist, ORDER BY sortiert die Ausgabe nach feld. INSERT INTO tabelle (werte)
Fügt werte als neuen Datensatz in tabelle ein. Mehrere Werte werden durch Komma getrennt. UPDATE tabelle SET feld = wert WHERE bedingung
Aktualisiert in den Datensätzen von tabelle, für die bedingung zutrifft, den Eintrag in feld mit wert. COUNT(*)
Zählt die Anzahl aller Datensätze, wird als Teil des SELECT-Statements eingesetzt und kann über WHERE auf bestimmte Einträge beschränkt werden.
Copyright Daten, Texte, Design und Grafiken dieses eBooks, sowie die eventuell angebotenen eBook-Zusatzdaten sind urheberrechtlich geschützt. Dieses eBook stellen wir lediglich als Einzelplatz-Lizenz zur Verfügung! Jede andere Verwendung dieses eBooks oder zugehöriger Materialien und Informationen, einschliesslich der Reproduktion, der Weitergabe, des Weitervertriebs, der Platzierung im Internet, in Intranets, in Extranets anderen Websites, der Veränderung, des Weiterverkaufs und der Veröffentlichung bedarf der schriftlichen Genehmigung des Verlags. Bei Fragen zu diesem Thema wenden Sie sich bitte an: mailto:[email protected]
Zusatzdaten Möglicherweise liegt dem gedruckten Buch eine CD-ROM mit Zusatzdaten bei. Die Zurverfügungstellung dieser Daten auf der Website ist eine freiwillige Leistung des Verlags. Der Rechtsweg ist ausgeschlossen.
Hinweis Dieses und andere eBooks können Sie rund um die Uhr und legal auf unserer Website