Programmieren lernen in PHP 5

Jörg Krause Programmieren lernen in PHP 5 v Bleiben Sie einfach auf dem Laufenden: www.hanser.de/newsletter Sofort an...
Author:  Jörg Krause

253 downloads 2936 Views 7MB Size Report

This content was uploaded by our users and we assume good faith they have the permission to share this book. If you own the copyright to this book and it is wrongfully on our website, we offer a simple DMCA procedure to remove your content from our site. Start by pressing the button below!

Report copyright / DMCA form

'; } ?> Die Schleife arbeitet mit der Laufvariablen $i. Der Startwert ist 10. Die Schleife wird solange durchlaufen, wie $i kleiner oder maximal gleich 24 ist. Nach jedem Durchlauf wird $i um 2 erhöht. Dabei wird die Zählvariable bei jedem Durchlauf um 2 erhöht.

6.3 Schleifen __________________________________________________________ 115 Abbildung 6.6: Ausgabe des Skripts aus Listing 6.10

Die Variable in den drei Elementen der for-Schleife muss nicht durchgehend verwendet werden. Dies ist zwar im Hinblick auf lesbare Skripte zu empfehlen, notwendig ist es jedoch nicht, wie das folgende Beispiel zeigt:

for-Schleife
'; $k += 2; } ?>

Listing 6.11: Abbruchbedingung und Iteration nutzen verschiedene Variablen (for.2varloop)

In diesem Skript wird $i wieder als Laufvariable eingesetzt. Allerdings findet sie im Block überhaupt keine Verwendung. Das ist auch nicht notwendig. Es geht hier nur darum, sicher eine bestimmte Anzahl von Durchläufen des Anweisungsblocks auszuführen. Zusätzlich wird die zur Anzeige benötigte Variable $k in der for-Anweisung initialisiert. Das wirkt sich aber auf den Verlauf der Schleife nicht aus. Alle drei Parameter der for-Schleife sind optional. Ohne Iterationsvariab- for(;;) le wird die Schleife endlos durchlaufen. Sie können in diesem Fall wieder continue auf break zurückgreifen, um die Schleife mit einer zusätzlichen Bedin- break gung zu verlassen. Ebenso kann der Test der Abbruchbedingung und die Ausführung des Iterationsschrittes mit continue erzwungen werden.

"; if ($i > 5) break; } ?>

Listing 6.12: for ohne Parameter (for_endless)

V V V 1 2 3 4 5 6 7 8 9 10 11 12 13 14 A B C D E

116 ______________________________ 6 Das Steuerrad für PHP: Kontrollstrukturen Die leere for-Anweisung führt eine Endlosschleife aus. Die Steuerung des Abbruchs übernimmt nun break:

if ($i > 5) break; Eine andere Schreibweise für eine Endlosschleife ist übrigens while(TRUE). Der flexible Umgang mit den Schleifenvariablen kennt praktisch keine Grenzen. Es spielt offensichtlich keine Rolle, ob hier Variablen zum Einsatz kommen oder nicht. Wenn Sie nur einfach eine Liste ausgeben möchten, kann der entsprechende Befehl sehr knapp ausfallen. Mehrere Anweisungen im Parameterbereich werden durch Kommata getrennt: Listing 6.13: Mehrere Ausdrücke in for (for_multi)

"); ?> Im Beispiel wird nicht zufällig die Anweisung print anstatt des flexibleren echo verwendet. echo ist ein Sprachkonstrukt, keine Funktion, und gibt deshalb nichts zurück. print dagegen wird die Parameter zurückgegeben. Normalerweise wird dieser Rückgabewert weggeworfen. Die forSchleife erwartet jedoch von jedem direkt eingegebenen Wert, dass er sich als Ausdruck verhält – Ausdrücke geben immer etwas zurück. An dieser Stelle kann echo deshalb nicht funktionieren. Versuchen Sie es dennoch, erhalten Sie einen Laufzeitfehler.

6.3.4

Felder bestellen: foreach

Manchmal werden die Inhalte von Arrays ausgegeben. Wenn sich der Inhalt ändert, ist die für eine for-Schleife nötige Größenangabe ein zusätzlicher Schritt. Den können Sie sich sparen, wenn Sie foreach verwenden. Wörtlich übersetzt heißt diese Anweisung: »Für jeden«. Die Schleife wird also für jedes Element eines Arrays durchlaufen. Gegenüber der while-Schleife mit list und each vereinfacht sich die Syntax deutlich. Hier die einfachste Syntax für eindimensionale Arrays:

foreach($array as $element) { ... } Dabei wird das Array $array von Anfang bis Ende durchlaufen und bei jedem Schleifendurchlauf wird das aktuelle Element der Variablen $element zugewiesen. Das Schlüsselwort as ist fester Bestandteil der Anweisung und niemals optional. Zuerst ein einfaches Beispiel mit einem assoziativen Array: Listing 6.14: Ausgabe eines einfachen Arrays (foreach)


6.3 Schleifen __________________________________________________________ 117

} ?>

echo "$postleitzahl
";

Im Skript wird zuerst ein Array aufgebaut. Die Daten können ebenso auch einer Datenbank entstammen:

$plz = array("12683","12459","10999","13055"); Dann überträgt foreach das erste Element in die Laufvariable $postleitzahl.

foreach($plz as $postleitzahl) { Dieser Wert wird ausgegeben.

echo "$postleitzahl
"; Am Ende wird wieder zum Schleifenanfang gesprungen und das nächste Element des Arrays ausgelesen. Sind keine Elemente mehr vorhanden, bricht die Schleife ab und das Programm wird nach der schließenden Klammer fortgesetzt.

} Abbildung 6.7: Ausgabe des Skripts aus Listing 6.14 Wenn Sie Arrays mit Schlüssel-/Wertepaaren bauen, kann foreach mit foreach für einer erweiterten Syntax diese Paare direkt auslesen. Die grundlegende Arrays mit Schlüsseln Syntax lautet:

foreach($array as $schluessel => $wert) { # auszuführende Befehle } Hier wird der Operator => eingesetzt, der schon bei der Konstruktion des => Arrays verwendet wurde.

"Krause", "Ort" => "Berlin", "Website" => "www.joerg.krause.net"); foreach($myarray as $key => $val) { echo "$key: $val
"; } ?> Diese Schleife arbeitet wie die zuerst vorgestellte, nur werden hier sowohl Schlüssel als auch Werte ausgelesen. Wenn Sie ein eindimensionales Array auslesen werden als Schlüssel die internen Indizes ausgegeben – fortlaufenden Zahlen, beginnend mit 0 für das erste Element.

Listing 6.15: Assoziative Arrays mit Schlüssel/Wertpaaren (foreach_hash)

V V V 1 2 3 4 5 6 7 8 9 10 11 12 13 14 A B C D E

118 ______________________________ 6 Das Steuerrad für PHP: Kontrollstrukturen Mehr Informationen zu Arrays und Anwendungsbeispiele für foreach finden Sie im Abschnitt 5.3 Zugriff auf Array-Elemente ab Seite 94. Abbildung 6.8: Ausgabe des Skripts aus Listing 6.15

6.4

Ordnung ins Chaos: Funktionen

Funktionen sind kleine Programmabschnitte oder Module, die PHPCodes enthalten. Sie werden, ebenso wie die bereits erläuterten eingebauten Funktionen, aus anderen Funktionen oder der »Stammebene« des Skripts heraus aufgerufen. An Funktionen können Sie Parameter übergeben und diese im Original ändern lassen oder eine Kopie des Wertes verwenden. Funktionen können Werte zurückgeben, beispielsweise das Ergebnis einer Berechnung.

6.4.1 function

Die Welt erschaffen: Funktionsdefinition

Nutzerdefinierte Funktionen werden durch das Schlüsselwort function eingeleitet. Die Syntax kann folgendermaßen aussehen:

function myfunction($param, $param2, ...) { // Hier werden Befehle ausgeführt return $rueckgabe; } Der Funktionskopf besteht aus dem Namen der Funktion (hier: myfunction) und in runden Klammern einer Auflistung der erwarteten Parameter. Diese Werte werden der Funktion beim Aufruf übergeben. Ein Zwang zur Übergabe von Werten besteht nicht, schreiben Sie einfach ein leeres Klammernpaar. return

Die Anweisung return enthält als Parameter den Rückgabewert. Dies kann ein Ausdruck oder eine einzelne Variable sein. An welcher Stelle innerhalb der Funktion Sie return einsetzen, spielt keine Rolle. Auch die mehrfache Notation ist zulässig – hier wird nach dem Motto »Wer zuerst kommt, siegt« verfahren und die Funktion wird sofort verlassen. Aus Gründen sauberer Programmierung sollten Sie aber return trotzdem nur einmal und nur am Ende einsetzen.

Späte Bindung

Wo im Skript die Funktion definiert wird, spielt bei PHP5 keine Rolle. Man spricht in diesem Fall von einer späten Bindung (engl. late binding). Hintergrundinformationen dazu finden Sie im nächsten Kasten.

6.4 Ordnung ins Chaos: Funktionen ______________________________________ 119

Niemals zu spät: Späte Bindung in PHP5 In PHP3 mussten Funktionen vor ihrer ersten Verwendung im Skript geschrieben werden. Der PHP-Interpreter arbeitete das Skript von oben nach unten durch. Fand er einen Funktionsaufruf und die Definition der Funktion stand dahinter, passierte nichts. In PHP4 und PHP5 werden die Funktionen erst nach dem Abarbeiten des Skripts im Parser gebunden. Dadurch spielt es keine Rolle, wann sie definiert werden. »Bindung« ist ein Fachausdruck, der aussagt, wann die Adresse der übersetzten Funktion im Speicher ermittelt und zum Aufruf bereitgestellt wird.

V V V 1 2 3 4 5 6 7 8 9 10 11 12 13 14 A B C D E

Richtig argumentieren: Funktionsargumente Die Übergabe von Argumenten an die Funktion (die dann dort Parametern entsprechen) kann auf vielfältige Art und Weise erfolgen. Im einfachsten Fall geben Sie Variablennamen an:

function nameausgeben($name, $ort) { echo "$name wohnt in $ort."; } Der Aufruf der Funktion kann nun erfolgen, indem Werte eingesetzt werden:

nameausgeben("Max Müller", "Berlin"); Der Rückgabewert interessiert hier nicht, also wird auch kein return benötigt. Beim Aufruf können natürlich auch Variablen eingesetzt werden. Das folgende Beispiel ist äquivalent zu dem vorherigen:

$name = "Max Müller"; $ort = "Berlin"; nameausgeben($name, $ort);

6.4.2

Kleine Welten: Variablen in Funktionen

Die Variablennamen innerhalb einer Funktion müssen sich nicht von denen in anderen Funktionen oder außerhalb der Funktion unterscheiden, da sie per Definition lokal sind. Der Zugriff auf globale Variablen ist aber durch die zusätzliche Anweisung global möglich.

"; } $name = "Joerg Krause";

Listing 6.16: Verhalten lokaler und globaler Variablen beim Funktionsaufruf (function_global)

120 ______________________________ 6 Das Steuerrad für PHP: Kontrollstrukturen show_location("Berlin"); ?> In diesem Skript wird zuerst eine Funktion definiert. Diese erwartet einen Parameter, der in der lokalen Variablen $ort abgelegt wird.

function show_location($ort) Dann wird die globale Variable $name in der Funktion sichtbar gemacht.

global $name; Es folgt eine Ausgabe, die sowohl die globale Variable als auch den Parameter umfasst.

echo "$name wohnt in $ort.
"; Der eigentliche Programmablauf beginnt mit der Zuweisung der globalen Variablen und setzt mit dem Funktionsaufruf fort:

$name = "Joerg Krause"; show_location("Berlin");

Von Geltungsbereichen und Variablen: »global« und »lokal« Variablen gelten immer in einen bestimmten Bereich. Wenn Sie das gesamte Skript betrachten, sind dort angelegte oder von PHP selbst initialisierte Variablen »global«. Innerhalb von Funktions- und Klassendefinition sind sie nicht sichtbar. Umgekehrt gelten dort angelegte Variablen als »lokal«. Sie sind wiederum nicht außerhalb des Bereiches sichtbar, wo sie definiert wurden. Die Ausgabe in der folgenden Abbildung zeigt das Verhalten der Funktionsvariablen: Abbildung 6.9: Ausgabe des Skripts aus Listing 6.16 Frontalangriff: Zugriff auf alle globalen Variablen Mit dem Schlüsselwort global teilen Sie PHP mit, dass die Variable in einem globalen Kontext bereits existiert. Der Inhalt der Variable wird dann übernommen. Umgekehrt werden sich Änderungen an der Variablen innerhalb des Blocks auch global widerspiegeln. Oft wird der Zugriff auf mehrere Werte notwendig sein. Sie können hinter global mehrere Variablen schreiben, durch Kommata getrennt:

global $x, $y, $zahl; GLOBALS[]

Reicht auch das nicht aus, machen Sie mit einem einzigen Befehl alle globale Variablen verfügbar. Intern verwaltet PHP die Variablen in einem Array. Hier ein kleines Beispiel:

6.4 Ordnung ins Chaos: Funktionen ______________________________________ 121 "; } $name = "Joerg Krause"; $ort = "Berlin"; show_location(); ?>

Listing 6.17: Zugriff auf globale Variablen mit GLOBALS[] (function_globals)

Beachten Sie hier, dass der Schlüssel des Arrays der Name der Variablen ohne das führende $-Zeichen ist. Ansonsten arbeitet dieses Skript wie das aus Listing 6.16. Wenn Sie die konkreten Namen einer Variablen nicht kennen oder sehr viele globale verwendet werden, ist der bisherige Weg über global nicht erfolgversprechend. Naheliegend wäre folgende Variante:

global $GLOBALS; Leider funktioniert das so nicht. Sie müssen die Werte einzeln aus dem $GLOBALS-Array holen.



Listing 6.18: Alle globalen Variablen in einem Array sichtbar machen (function_glob2)

Das letzte Beispiel dürfte eine nähere Erklärung wert sein, weil es doch deutlich anspruchvoller ist, als die bisherigen Varianten. Verwendet werden die Variablennamen aus $GLOBALS, die mittels array_keys() extrahiert werden. Der Zugriff auf den Namen erfolgt mittels der dynamischen Zuweisung von Variablen mit ${$name}. Dabei ist $name nicht die Variable selbst, sondern der Name einer anderen Variablen, auf die verwiesen wird. Konstante Bedingungen: Variablen statisch machen Variablen innerhalb eines Gültigkeitsbereiches sind flüchtig – beim Ver- static lassen der Funktion werden sie gelöscht, beim erneuten Eintritt wieder angelegt. In solchen Fällen müssten Sie immer auf globale Variable zurückgreifen, was bei großen Projekten zu einem unüberschaubaren Chaos an Variablennamen führen würde. Mit dem Schlüsselwort static

V V V 1 2 3 4 5 6 7 8 9 10 11 12 13 14 A B C D E

122 ______________________________ 6 Das Steuerrad für PHP: Kontrollstrukturen können Sie Variablen innerhalb einer Funktion so definieren, dass sie erhalten bleiben, wie das folgende Beispiel zeigt: Listing 6.19: Statische Variablen (function_static)

"; $zahl++; } ausgabe(); ausgabe(); ausgabe(); ?> Der Operator ++ erhöht die Variable jedes Mal um eins. Die Zuweisung des Startwerts erfolgt nur beim ersten Aufruf der Funktion, die drei Aufrufe führen also tatsächlich zur Ausgabe von 22, 23 und 24.

Abbildung 6.10: Ausgabe des Skripts aus Listing 6.19 Übergabe von Werten: Per Referenz oder per Wert? Die Veränderung der übergebenen Variablen kann manchmal erwünscht sein. So könnte eine Funktion sämtliche übergebenen Werte in mit dem HTML-Tag fett ausgeben: Listing 6.20: Funktion mit referenzierten Argumenten (function_ref)

$html
"; } $ausgabe = "Test"; echo $ausgabe; echo "
"; machfett(&$ausgabe); echo $ausgabe; ?> Die Funktion machfett() nutzt einen referenzierte Parameter – anstatt des Wertes in $ausgabe wird ein Verweis auf diese Variable übergeben. Dass dieser Verweis innerhalb der Funktion einen anderen Namen trägt ($html), spielt keine Rolle. Tatsächlich wird nach der Ausführung der Inhalt von $ausgabe verändert sein.

Abbildung 6.11: Ausgabe des Skripts aus Listing 6.20 Der Name der Variablen spielt keine Rolle. Entscheidend ist die Kennzeichnung der Argumente mit &. In diesem Fall wird der globalen Vari-

6.4 Ordnung ins Chaos: Funktionen ______________________________________ 123 ablen der neue Wert zugewiesen. Dies ist auch ein Trick, um mehrere Werte aus einer Funktion heraus zu ändern. Bei der Rückgabe mit return sind Sie ja auf einen Wert beschränkt.

Von Referenzen und Werten Normalerweise werden die Parameterwerte, wenn sie als Variable angegeben werden, der Funktion in Kopie übermittelt. Änderungen an der Kopie wirken sich nicht auf die Quelle aus. Diese Art der Übergabe wird als »by value« bezeichnet und ist bei PHP – wie bei vielen anderen Sprachen auch – Standard. Im Gegensatz dazu wird bei der Übergabe per Referenz, »by reference«, ein Verweis auf die Quelle transportiert. Abgesehen davon, dass Änderungen sich nun auf die Quelle auswirken, ist diese Form auch etwas schneller.

Argumentationskunst: Probleme mit Argumenten Das Beispiel in Listing 6.20 mag Ihnen zu umständlich erscheinen. Die folgende Zeile ist kompakter, verständlicher und falsch:

echo machfett($ausgabe); Syntaktisch ist dies richtig, der PHP-Parser wird nicht mit einer Fehlermeldung reagieren. Das Problem ist eine falsche Parameterübergabe. Die Beispielfunktion machfett() gibt nichts zurück – sie ändert nur eine übergebene Variable. Die Anweisung echo erwartet aber Werte, die sie an den Browser senden kann. An die eingeschlossene Variable $ausgabe kommt sie nicht heran. Diese wird zwar geändert, das Ergebnis aber quasi verworfen. Wenn Sie die Anwendung dennoch in dieser Form benötigen, setzen Sie return ein:

$html"; } $ausgabe = "Test"; echo $ausgabe; echo "
"; echo machfett($ausgabe); ?>

Listing 6.21: Funktionsrückgabe mit echo ausgeben (function_echo)

Sie können generell einzelne Argumente beim Aufruf weglassen. In die- Optionale sem Fall wird die betreffende Variable nicht initialisiert. Um zusätzliche Parameter Tests zu vermeiden und Laufzeitfehler innerhalb der Funktion nicht zu provozieren, können Sie jedes Argument mit einem Standardwert belegen. Man spricht in solchen Fällen von optionalen Parametern. Die Syntax verlangt, dass der Funktionskopf um eine Zuweisung erweitert wird:

function nameausgeben($name = "Name", $ort = "Ort")

V V V 1 2 3 4 5 6 7 8 9 10 11 12 13 14 A B C D E

124 ______________________________ 6 Das Steuerrad für PHP: Kontrollstrukturen Eleganter ist die Verwendung von Konstanten. Sie erreichen so mehr Ordnung und eine bessere Lesbarkeit Ihrer Skripte:

define("NONAME", "Kein Name"); ... function nameausgeben($name = NONAME, $ort = "Ort") Probleme mit optionalen Parametern

Anfängern bereiten optionale Parameter oft Schwierigkeiten. Der Umgang damit ist einfach, solange die Anwendung in der gezeigten Form erfolgt. Es ist jedoch auch möglich, einige Parameter mit Standardwerten zu belegen und andere nicht. Das folgende Beispiel funktioniert problemlos:

function nameausgeben($name, $ort = "Ort") Der umgekehrte Fall erscheint ebenso einfach, führt jedoch zu einem Laufzeitfehler:

function nameausgeben($name = "Name", $ort) Dieses Beispiel funktioniert nur, wenn tatsächlich beide Parameter übergeben werden. Der folgende Aufruf kann nicht funktionieren:

nameausgeben("Berlin"); Woher soll PHP wissen, dass Sie den zweiten Parameter meinen? Fazit: optionale Parameter müssen im Funktionskopf immer rechts stehen und von rechts auflösbar sein. Flexibel argumentieren: Variable Argumentelisten Manchmal müssen Sie Funktionen definieren, die mehrere Argumente haben. Es kann nun vorkommen, dass an der einen oder anderen Stelle die Anzahl der Argumente nicht bekannt ist. Das folgende Beispiel zeigt eine Funktion, die eine variable Anzahl Elemente übernimmt und formatiert zurückgibt. Wie viele Elemente es sind, spielt keine Rolle: Listing 6.22: Umgang mit variablen Argumentelisten (function_argv)

".func_get_arg($i).""; } return $result; } $str = 'Test'; echo 'Fett:'; echo html_fett('B','Dies ', 'ist ', 'ein ', $str); echo '
'; echo 'Kursiv: '; echo html_fett('I', 'Noch ', 'ein ', $str); echo '
'; ?>

6.4 Ordnung ins Chaos: Funktionen ______________________________________ 125 Interessant ist vor allem der Umgang mit den Argumenten in der Funktion. Tatsächlich werden keine Parameter angegeben. Das ist logisch, weil diese ja nicht präzise beschrieben werden können. Diese Funktion akzeptiert hier eine beliebige Anzahl Parameter:

function html_fett() Die tatsächliche Anzahl wird dann als erstes ermittelt:

$argc = func_num_args(); Dann wird das erste Argument ausgelesen:

$tag = func_get_arg(0); Da die Anzahl der Argumente bekannt ist, kann diese Information für eine Schleife verwendet werden, die alle weitere Argumente ausliest und entsprechend behandelt.

for ($i = 1; $i < $argc; $i++) { $result .= "<$tag>".func_get_arg($i).""; } Das Ergebnis wird zurückgegeben.

return $result; Variable Argumentlisten sind auch bei einigen internen Funktionen und Anweisungen zulässig, wie beispielsweise echo und max. Abbildung 6.12: Ausgabe des Skripts aus Listing 6.22 Die speziellen Funktionen, mit denen der Umgang mit variablen Parame- func_num_args terlisten möglich ist, noch einmal auf einen Blick: func_get_arg • func_num_args()

func_get_arg

Diese Funktion gibt die Anzahl der Parameter zurück. • func_get_arg(index) Hiermit ermitteln Sie einen konkreten Parameter, die Auswahl erfolgt durch den Index, der die Argumentliste von 0 beginnend durchzählt. • func_get_args() Diese Funktion gibt ein Array mit den Parametern zurück. Das folgende Beispiel implementiert zwei Funktionen, die beliebig viele Parameter akzeptieren. Realisiert wird eine mathematische Funktion zur Berechnung der Summe und des Durchschnitts.


Listing 6.23: Funktionen mit variablen Argumentelisten (function_argv2)

V V V 1 2 3 4 5 6 7 8 9 10 11 12 13 14 A B C D E

126 ______________________________ 6 Das Steuerrad für PHP: Kontrollstrukturen

}

$arr = func_get_args(); for ($i = 0; $i < $num; $sum += $arr[$i++]); return $sum;

function avg() { $num = func_num_args(); $arr = func_get_args(); $sum = 0; for ($i = 0; $i < $num; $sum += $arr[$i++]); return $sum / $num; } printf("Summe: %0.2f%s", sum(13, 12, 7, 8, 23, 100), '
'); printf("Durchschnitt: %0.2f", avg(13, 12, 7, 8, 23, 100)); ?> Die Funktion sum nutzt die Parameterinformationen, um die Anzahl der Werte zu ermitteln. Die gesamte Berechnung findet auf dieser Basis in der for-Anweisung statt. Die Funktion avg berechnet den Durchschnittswert. Dazu wird die nach dem bei sum gezeigten Verfahren ermittelte Summe durch die Anzahl der Werte dividiert. Die Anzahl ermittelt func_num_args. Im Beispiel wurde gezeigt, dass keine Parameterangaben im Kopf der Funktionsdeklaration notwendig sind. Wenn Sie dennoch Parameter angeben, werden diesen Argumente vom Anfang der Liste zugewiesen. Unabhängig davon werden alle Werte von den Parameterfunktionen verwaltet. Das folgende Beispiel gibt »14« zurück: Listing 6.24: Zusätzliche Auswertung des ersten Parameters (function_argv3)

$first übernimmt hier den ersten Wert: 1. Die gesamte Argumentliste, die func_get_arc zurückgibt, steht dort als Array. Der erste Index ist 0, entsprechend zeigt der Index 3 auf den Wert 4 im Beispiel. Antwortverhalten: Rückgabe mehrerer Werte Die Rückgabe mehrerer Werte ist nicht vorgesehen. Da es aber sonst keine Beschränkung des Typs gibt – sowohl Arrays als auch Objekte sind erlaubt –, bietet sich ein einfacher Trick zur Übergabe mehrerer Werte an. Eine Variante kennen Sie bereits: die Übergabe von Variablen als Referenz mit vorangestelltem &-Zeichen. Daneben können Sie auch als Rückgabewert ein Array einsetzen:

6.4 Ordnung ins Chaos: Funktionen ______________________________________ 127 ", $html, ""); return $html; } $html = "Mustertext"; list($opentag, $html, $closetag) = machfett($html); echo $opentag, $html, $closetag; ?>

Listing 6.25: Rückgabe eines Arrays (function_array)

Die Auflösung wird mit list vorgenommen. Oft ist diese Schreibweise offensichtlicher und leichter zu verstehen als der Umgang mit Referenzen. list liest so viele Werte aus einem Array aus, wie Variablen als Parameter angegeben wurden. Dies ist im übrigen eine eingebaute Funktion, die variable Argumentlisten versteht. Abbildung 6.13: Ausgabe des Skripts aus Listing 6.25 Selbstgespräche führen: Einführung in die Rekursion PHP erlaubt rekursive Funktionsaufrufe. Dabei ruft eine Funktion sich selbst auf. Das ist eine recht häufig verwendete Programmiertechnik. In der Mathematik gibt es ganze Reihe von Definitionen, bei denen sich die Funktion durch einen Verweis auf sich selbst erklärt wird. Am bekanntesten ist die Berechnung der Fakultät:

n! = n·(n-1)! Hinzu kommt eine Abbruchbedingung, die auf dem Sonderfall 1! = 1 basiert. Als Lösung kann nun eine Funktion dienen, die folgenden Aufbau hat:

Diese Funktion besteht aus zwei Zeilen: Zuerst wird der Sonderfall und damit die Abbruchbedingung behandelt, danach die Berechnung gemäß der Vorschrift. Am Anfang mag dieses Verfahren schwer vorstellbar sein. Vor allem das »Ende« ist nicht sofort erkennbar. Abbildung 6.14 zeigt den Weg, den das Programm nimmt. Wenn die Funktion sich selbst aufruft, startet sie wie jeder andere Funktionsaufruf auch. Ist die untergeordnete Funktion beendet, kehrt sie an die aufrufende Stelle zurück, sodass beim Auflösen der Kette praktisch nur noch Funktionsenden bearbeitet werden. Das

Listing 6.26: Rekursive Funktion: Fakultät berechnen (recursion_f)

V V V 1 2 3 4 5 6 7 8 9 10 11 12 13 14 A B C D E

128 ______________________________ 6 Das Steuerrad für PHP: Kontrollstrukturen heißt: Bei dem gezeigten Wert 4 wird die Funktion nacheinander viermal aufgerufen und dann viermal verlassen. Abbildung 6.14: Prinzip der Rekursion anhand der Berechnung der Fakultät

Wozu man das braucht

Vermutlich kommen Sie selten in die Verlegenheit, die Fakultät berechnen zu müssen. Rekursive Funktionen sind dennoch ein fester Bestandteil der Programmierwelt und sehr oft anzutreffen. Sie werden beispielsweise benötigt, um verschachtelte Strukturen auszugeben. Dabei kann es sich um Verzeichnisse oder Menüführungen handeln. Eine Eigenschaft dieser Strukturen ist die unbekannte Tiefe, die sie annehmen können. Rekursive Funktionen sind – theoretisch – per Definition auf unbekannte Tiefe ausgelegt. In der Praxis sieht das anders aus.

Alles hat seine Grenze Jeder Aufruf einer rekursiven Funktion aus sich selbst heraus legt die benötigten Aufrufparameter in einem speziellen internen Speicher ab – dem Stapelspeicher (engl. stack). Dieser hat eine begrenzte Kapazität. Ist er erschöpft, bricht PHP mit dem Fehler »PHP has encountered a Stack overflow« ab. Experimentell konnte ich eine Grenze von etwa 220 rekursiven Aufrufen feststellen. Das mag aber von System zu System verschieden sein.

6.4 Ordnung ins Chaos: Funktionen ______________________________________ 129 Als praktischere Anwendung sei hier ein anderes Beispiel angeführt – die Ausgabe eines Verzeichnisbaumes. Auch wenn die nötigen Funktionen erst später behandelt werden, sollte das Prinzip dennoch klar werden.

<pre> read()) { if (!ereg('^[.]{1,2}', $entry)) { if (is_dir("$path/$entry")) { printf ("% ".$depth."s /%s\n", "+-", $entry); showdir($path.'/'.$entry, $depth + 3); } else { printf ("% ".$depth."s %s\n", "|-", $entry); } } } $folder->close(); } $start = "/inetpub/wwwroot"; showdir($start, 0); ?> Die Funktion showdir, die die gesamte Arbeit erledigt, ist sicher eine genaue Betrachtung wert. Zuerst wird mit der Funktion dir ein Verzeichnisobjekt erzeugt, am Anfang mit dem Pfad, der mit dem ersten Aufruf mitgegeben wird.

$folder = dir($path); Objekte dieser Art bringen verschiedene Methoden mit – das sind Funktionen, die auf Daten des Objekts angewendet werden. Im Beispiel werden nacheinander Verzeichniseinträge mit read() gelesen.

while ($entry = $folder->read()) Dann werden die beiden Verzeichnisse ».« und »..« ermittelt. Diese sollen nicht in die Anzeige mit einbezogen werden.

if (!ereg('^[.]{1,2}', $entry)) Für alle anderen Elemente, also Verzeichnisnamen und Dateien, wird eine Einrückung berechnet. Diese basiert auf der Variablen $depth, die mit jeder Ebene erhöht wird.

printf ("% ".$depth."s /%s\n", "+-", $entry);

Listing 6.27: Ausgabe von Verzeichnisbäumen (recursion_dir)

V V V 1 2 3 4 5 6 7 8 9 10 11 12 13 14 A B C D E

130 ______________________________ 6 Das Steuerrad für PHP: Kontrollstrukturen Handelt es sich bei dem Eintrag um ein Verzeichnis, wird die Ebene erhöht und die Funktion ruft sich selbst auf, um das Verzeichnis auszugeben. Findet sie dort weitere Verzeichnisse, wird der Prozess fortgesetzt.

if (is_dir("$path/$entry")) { showdir($path.'/'.$entry, $depth + 3); Falls es keine Verzeichnisse mehr gibt, wird der aktuelle Eintrag als Dateiname ausgeben. Dies ist zugleich auch die Abbruchbedingung für die Rekursion.

} else { printf ("% ".$depth."s %s\n", "|-", $entry); Zuletzt werden alle Schleifen geschlossen und das Verzeichnisobjekt vernichtet.

$folder->close(); Möglicherweise werden Sie erwarten, dass Verzeichnisse mit mehr als 200 Einträgen nicht funktionieren. Das ist aber nicht das Problem. Während der Abarbeitung wird nur dann ein rekursiver Aufruf erfolgen, wenn ein Unterverzeichnis entdeckt wurde – die Tiefe der Verzeichnisstruktur ist hier der kritische Wert. Allerdings dürften 200 Verzeichnisebenen in der Praxis mehr als ausreichend sein. Vorsicht Falle!

Ein ganz anderes Problem werden Sie bemerken, wenn Sie eine sehr tiefe Struktur analysieren oder versehntlich im Rootverzeichnis des Computers starten. Bei einigen 10 000 Verzeichnissen – das ist durchaus normal – dauert die Analyse spürbar. Auch schnelle Computer können damit einige Minuten beschäftigt sein. Fatal ist das ganze auf einem Webserver, wenn viele Nutzer parallel zugreifen. Spürbare Prozessorbelastung wirkt sich dann auf alle aus. Ist das System so eingerichtet, dass jedem Prozess nur eine begrenzte Prozessorleistung zur Verfügung steht, kann sich die Analyse ewig hinziehen. Insofern sind rekursive Lösungen generell mit Vorsicht zu genießen. Machen Sie sich ernsthaft darüber Gedanken, wie tief die Analyse einer Struktur erfolgt und wie schnell die Funktion den Stapel wieder auflöst. Vermeiden Sie unter allen Umständen zeitraubende Berechnungen in der unteren Ebene, wo der Aufruf sehr oft erfolgt.

6.5 Fehler einfangen: try@catch _________________________________________ 131 Abbildung 6.15: Ausgabe des Skripts aus Listing 6.27

6.5

Fehler einfangen: try@catch

In den bisherigen PHP-Versionen war keine wirklich brauchbare Fehlerbehandlung zu finden. Mit PHP5 fanden nicht nur zwei neue Schlüsselwörter zu Flusskontrolle im Fehlerfall Eingang, sondern gleich ganz neue Klassen zum Erkennen von spezifischen Fehlerzuständen. Die Integration gelang leider nicht vollständig, sodass interne Laufzeitfehler nach wie vor mit dem Fehleroperator @ abgefangen werden müssen.

V V V 1 2 3 4 5 6 7 8 9 10 11 12 13 14 A B C D E

132 ______________________________ 6 Das Steuerrad für PHP: Kontrollstrukturen

6.5.1

Bei Fehler: Abbiegen

In diesem Abschnitt werden die beiden Anweisungen try und catch kurz vorgestellt. Ein genauerer Ausblick auf die Verwendung setzt ein Verständnis für objektorientierte Programmierung voraus. Im Zusammenhang mit der entsprechenden Einführung finden Sie eine Fortsetzung des Themas im Abschnitt 7.5 Eingebaut: Die Fehlerklassen ab Seite 155. Das Prinzip von try und catch ist einfach. Ein Programmzweig, indem

Fehler auftreten könnten, wird mit einem try-Block umschlossen:

try { // Hier können Fehler passieren } Tritt ein Fehler zur Laufzeit in diesem Bereich auf, erzeugt PHP5 keine Fehlerausschrift, sondern sucht zuerst das nächste catch. Wird ein solches Schlüsselwort gefunden, werden die darin befindlichen Anweisungen ausgeführt, vorzugsweise schreibt man dort die Fehlerbehandlung hinein. Es ist möglich, mehrere catch-Zweige hintereinander zu platzieren, um auf verschiedene Arten von Fehler zu reagieren. Abschnitt 7.5 Eingebaut: Die Fehlerklassen ab Seite 155 zeigt dies im Detail. Als Auslöser dient das Schlüsselwort throw, dass eine so genannte Fehlerklasse instantiiert und an den passenden catch-Zweig schickt. Fehlt da nicht was? Umsteiger aus anderen Sprache kennen try/catch vermutlich. Allerdings verhält sich PHP hier grundsätzlich anders. Zum einen ist der Programmierer selbst dafür verantwortlich, alle erdenklichen Fehler zu beachten und passende Abfragen zu erstellen. Echte Laufzeitfehler, wie eine Division durch Null, lassen sich nach wie vor nicht abfangen. Insofern ist das try/catch-Konzept in PHP5 sicher ein Fortschritt gegenüber den Vorgängerversionen, aber bei weitem nicht so komfortabel wie es Java- oder C++-Entwickler gewohnt sind. Technisch liegt das daran, dass PHP5 zwar ein paar objektorientierte Funktionen verpasst bekam, aber im Kern nicht damit arbeitet, Laufzeitfehler also nicht Klassen entstammen, die auf catch wirken könnten, sondern simple Textbotschaften erzeugen. Schade eigentlich! Konsequenterweise fehlt dann auch das vierte Schlüsselwort im Bunde: finally. Normalerweise fügt sich ein finally-Zweig an den letzten catchBlock an. Er enthält Anweisungen, die unbedingt ausgeführt werden müssen, unabhängig davon, ob ein Abbruch des try-Abschnitts erfolgte oder nicht. Dies passiert auch dann, wenn eine Funktion in catch oder try mit return verlassen wurde. Fehlerbehandlung ist kein Programmiermittel! Die Fehlerbehandlung mit try/catch ist kein Mittel, um den Programmfluss zu steuern. Es sollten tatsächlich nur dann Fehlerroutinen aufgebaut

6.5 Fehler einfangen: try@catch _________________________________________ 133 werden, wenn ungewöhnliche Abläufe zu behandlen sind. Wenn Sie auf Dateien prüfen, verwenden Sie zuerst eine Funktion wie file_exists, um festzustellen, ob eine Datei vorhanden ist. Erst wenn dies angezeigt wird und der Ladevorgang dann misslingt, sollte die Fehlerverwaltung greifen. Alle »Fehler«, die im normalen Betrieb auftreten können, sind deshalb durch normale Programmbefehle zu behandeln. Leider ist das try/catch-Modell von PHP5 dafür nicht ideal ausgebildet.

6.5.2

Einfache Fehlerbehandlungen

Die Fehlerbehandlung mit try/catch erlaubt einfacheren und besser lesbareren Quellcode. Statt die vielfältigen Fehlerausgaben innerhalb eines Skripts weit zu verstreuen, kann man sich auf wenige Punkte beschränken, was leichter zu pflegen ist. Insofern spricht einiges für die Anwendung, trotz der nach Meinung des Autors insgesamt misslungenen Umsetzung. Ein einfaches Beispiel soll die grundsätzliche Arbeitsweise erläutern:

$a = 45; $b = $a - 45; $c; try { if ($b == 0) { throw new Exception('Division durch Null'); } $c = $a / $b; } catch(Exception $exception) { echo "Ein Fehler trat auf: $exception"; } Die Klasse Exception bietet unter Umständen detaillierte Informationen. Abschnitt 7.5 Eingebaut: Die Eine nähere Behandlung erfolgt unter Fehlerklassen ab Seite 155 zeigt dies im Detail. Die Ausgabe dieses Skripts zeigt, wie die Fehlerbehandlung wirkt:

Ohne entsprechende Fehlerbehandlung erscheint ein Laufzeitfehler:

6.5.3

Fehlerunterdrückung mit @

Jeder Funktion, die PHP5 intern oder als Teil eines Moduls bietet, kann der Fehleroperator @direkt vorangestellt werden:

$fh = @fopen(“file.html“, “r“);

Listing 6.28: Fehler gezielt verarbeiten (trycatch1)

V V V 1 2 3 4 5 6 7 8 9 10 11 12 13 14 A B C D E

134 ______________________________ 6 Das Steuerrad für PHP: Kontrollstrukturen Geht bei der Ausführung etwas schief, wird kein Fehler angezeigt. Sie sollten aber unbedingt dafür sorgen, dass auf mögliche Fehlerzustände im Code reagiert wird. Die meisten Funktionen geben bestimmte Werte zurück, beispielsweise das Ergebnis einer Berechnung, eine Referenz auf Daten usw. Im Fehlerfall wird meist FALSE zurückgegeben. Ein entsprechender Test sollte sich deshalb immer anschließen:

if ($fh === FALSE) echo “Es trat ein Fehler auf“; Es ist auch möglich, Fehler beim Zugriff auf Array-Elemente zu unterdrücken.

$result = @$array[$key]; Beachten Sie hier, dass das Ergebnis nicht FALSE, sondern NULL ist. Sie müssen eine explizite Prüfung deshalb mit isset vornehmen. Zum Unterdrücken von Fehlern bei Methodenaufrufen nutzen Sie folgende Syntax:

@$this->foo($bar); Das Voranstellen beim Methodennamen ist dagegen falsch:

$this->@foo($bar); Eine einfache Fehlerverzweigung Die können eine Fähigkeit von PHP5 nutzen, um auf Fehler sehr einfach zu reagieren. Wenn ein Boolescher Ausdruck ausgewertet wird, erkennt PHP5 mehrere Operanden. Bei einer OR-Verknüpfung kann der Ausdruck nur TRUE sein, wenn der erste Operand bereits TRUE ist. Es wäre dann nicht erforderlich, den Ausdruck weiter auszuwerten – am Ergebnis kann sich nichts mehr ändern. Diese Optimierung kann man ausnutzen:

$fh = @fopen(“datei“, “r“) or die(“Fehler“); In diesem Ausdruck wird die Funktion fopen ausgeführt. Normalerweise gibt diese eine Referenz auf eine Datei zurück, was PHP5 in einem Booleschen Ausdruck als TRUE wertet. Damit wird die weitere Verarbeitung der Zeile abgebrochen und der Befehl die niemals erreicht. Anders geht es, wenn ein Fehler auftritt. Nun ist der erste Teil FALSE und PHP wertet den zweiten Teil aus. die

Der Befehl die beendet das Programm mit einer selbst definierten Meldung. Den ursprünglichen Fehler erkennen Um den ursprünglich erzeugten Fehler zu sehen, können Sie die Variable $php_errormsg abfragen. Diese Variable wird allerdings standardmäßig nicht gesetzt. Sie können die entsprechende Konfiguration jedoch leicht per Skript erledigen:

Listing 6.29: Fehler erkennen und abfangen (errorcheck)

ini_set('track_errors', 1); $fh = @fopen("unbekannte_datei", "r"); if ($fh === FALSE) {

6.5 Fehler einfangen: try@catch _________________________________________ 135

}

echo "Datei nicht gefunden: "; echo $php_errormsg;

Dieses Skript setzt den Parameter track_errors aus der Datei php.ini. Alternativ zum Aufruf per Skript wäre es also auch möglich, dies in der Konfigurationsdatei zu erledigen. Abschnitt 14.2 Konfiguration mit »php.ini« ab Seite 350 zeigt die entsprechenden Details. Fehlerreaktionen steuern Darüber hinaus werden interne Fehler erkannt und in verschiedene Feh- error_reporting lerklassen eingeteilt. Mit der Funktion error_reporting können Sie im Skript steuern, welche Fehler angezeigt und welche unterdrückt werden. Die folgende Tabelle zeigt alle Bitwerte und die Namen der Fehlerklassen: Bitwert

Fehlername

Beschreibung

1

E_ERROR

Fehler im Programmablauf

2

E_WARNING

Warnungen

4

E_PARSE

Fehler in der Syntax

8

E_NOTICE

Nachrichten

16

E_CORE_ERROR

Fehler des PHP-Interpreters

32

E_CORE_WARNING

Warnung des PHP-Interpreters

64

E_COMPILE_ERROR

Zend-Compiler-Fehler

128

E_COMPILE_WARNING

Zend-Compiler-Warnung

256

E_USER_ERROR

512

E_USER_WARNING

1024

E_USER_NOTICE

Diese Konstanten steuern das Verhalten der nutzerdefinierten Fehlerbehandlung mit der Funktion user_error

E_ALL

Alle Fehler

Tabelle 6.2: Konstanten der Fehlerklassen

Die Fehlernamen sind in PHP als Konstanten vordefiniert. Setzen Sie diese einfach als Parameter ein. Mehrere Werte können Sie mit dem Operator | (ODER) verbinden:

Mit Hilfe von E_ALL und der Negation ^ können gezielt bestimmte Warnungen ausgeschaltet werden. Eine eigene Fehlerbehandlung erstellen Als letzte Maßnahme zu einer ordentlichen Fehlerverarbeitung kann man eine Funktion definieren, die immer dann aufgerufen wird, wenn ein

Listing 6.30: Fehler und Warnungen unterdrücken

V V V 1 2 3 4 5 6 7 8 9 10 11 12 13 14 A B C D E

136 ______________________________ 6 Das Steuerrad für PHP: Kontrollstrukturen Laufzeitfehler auftritt. Es wäre zwar nahliegend, dafür throw zu verwenden, aber das funktioniert nur mit eigenen Klassen, nicht mit Laufzeitfehlern, die PHP5 selbst definiert. Will man – zwecks konsistenter Programmierung – nun den eigenen Fehlerbehandler nutzen, muss man eigene Fehler mit trigger_error auslösen. Das es keine Zusammenspiel mit try/catch gibt, ist mehr als nur ärgerlich. Es ist die Meinung des Autors, dass sich die PHP-Entwickler hier krass disqualifiziert haben. Die Definition einer eigenen Fehlerbehandlungsmethode erfolgt mit set_error_handler: Listing 6.31: Eigene Fehlerbehandlung (errorhandler)

function myhandler($errno, $errstr, $errfile, $errline) { switch ($errno) { case E_USER_ERROR: echo "Fehler: $errstr trat auf in $errfile auf Zeile $errline"; break; } } ini_set('track_errors', 1); set_error_handler('myhandler'); $fh = @fopen("unbekannte_datei", "r"); if ($fh === FALSE) { echo "Datei nicht gefunden: "; trigger_error($php_errormsg, E_USER_ERROR); } Die Funktion trigger_error löst den Fehler aus und übergibt eine Fehlermeldung nebst Fehlernummer. Der Handler erhält zusätzlich als dritten und vierten Parameter Dateinamen und Zeilennummer aus. Kombinationen aus trigger_error und throw

Eine Idee für Fortgeschrittene

Wer die Entwicklung von Bibliotheken tion der Fehlerbehandlung aus Fehlerbehandler und throw erstellen. Fehler vom Nutzer der Klasse mit können.

plant, könnte sich eine Kombinatrigger_error und eigenem Dabei würde dann der interne try/catch abgefangen werden

6.5 Fehler einfangen: try@catch ________________________________________ 137

7 Sammeltransporte: Objekte In der Welt der Programmiersprachen haben sich zunehmend objektorientierte Modelle etabliert. PHP ist strenggenommen keine objektorientierte Sprache, wie C++, C# oder Java, sondern eine prozedurale (imperative) Sprache. Sie verfügt aber dennoch über einige objektorientierte Ansätze. In professionellen Skripten werden Sie immer wieder damit konfrontiert und oft sind mit diesen Techniken einfache und clevere Lösungen möglich.

7

Sammeltransporte: Objekte

7.1 Einführung in die Welt der Objekte ___________________________________ 139

7.1

Einführung in die Welt der Objekte

Objektorientiert programmieren setzt voraus, das die dahinter liegenden Was es mit Paradigmen verstanden wurden. Einführungen in diese Welt leiden Objekten auf sich meist unter einer Flut neuer Begriffe, die sich gegenseitig erklären – we- hat nig hilfreich, wenn ein Ansatzpunkt fehlt.

7.1.1

Das Konzept

Ein Blick in die reale Welt hilft vielleicht, das Konzept objektorientierter Programmierung besser aufzunehmen. In der realen Welt ist alles ein Objekt. Jedes Ding besteht aus einem Zustand, beschrieben durch Eigenschaften und zulässigen Verhaltensregeln. Dabei können Gegenstände sehr simpel sein, komplexere Objekte wie Tiere oder Menschen dagegen kaum noch erfassbar. Klassen als Abbild von realen Objektdefinitionen In der Programmierung werden solche zusammen agierenden Gebilde aus Eigenschaften und Ablaufregeln als Objekte bezeichnet. In klassischen Programmen speichern Sie Daten in Variablen und geben dann durch Programmanweisungen und Funktionen Regeln vor, nach denen das Programm abläuft. Interaktion mit Schnittstellen schafft dann die Vielfalt der Abläufe. Objektorientierte Programme bestehen aus Sammlungen von Objekten. Die Idee dahinter ist die Zusammenfassung gleichartiger oder ähnlicher Was sind Strukturen und zusammengehörender Elemente. Solche Gebilde werden Klassen? als Klassen bezeichnet. Es werden also nicht immer wieder Objekte definiert, wenn man sie benötigt, sondern nur ein Mal – als Klasse. Wenn der Programmierer dann ein Objekt benötigt, beispielsweise um eine Programmfunktion auszulösen, erzeugt er aus der Klasse ein Objekt ab und verwendet dies. Dieser Vorgang wird auch als »instanziieren« bezeichnet. Das Objekt ist eine »Instanz« der Klasse. Aus einer Klasse kann man beliebig viele Objekte erzeugen. Diese sind voneinander völlig getrennt und werden für sich wiederum in Variablen gespeichert. Umgang mit Klassenhierarchien In komplexeren Applikationen, wo die objektorientierten Modelle zur Höchstform auflaufen, schreibt man einfach Klassen und baut auf diesen immer komplexere auf. Oder man schreibt umfangreiche Klassen und stellt diese anderen Entwicklern als Bibliothek zur Verfügung. In jedem Fall gibt es Mitglieder (Variablen, Funktionen) die man intern benötigt und solche, die man dem verwendenden Programm bereitstellen will. Für diese bietet PHP5 entsprechende Schlüsselwörter wie private und protected an, die später noch genauer untersucht werden.

V V V 1 2 3 4 5 6 7 8 9 10 11 12 13 14 A B C D E

140 __________________________________________ 7 Sammeltransporte: Objekte Eine andere Form der Kontrolle besteht in der Definition, wer von einer Klasse ableiten kann oder sogar muss (abstract) bzw. wo dies explizit untersagt ist (final). Schnittstellen zur Kommunikation Programme, die aus vielen Klassen bestehen, benötigen öffentliche Mitglieder, um Kommunikationswege zwischen den Objekten zu schaffen. Nach außen, zum späteren Nutzer beispielsweise einer Bibliothek, sind diese Darstellungen meist weniger gedacht. Um nun einen Teil eines Objekts zu definieren, der in der Verwendung völlig frei ist, dienen Schnittstellendefinitione (interface). Diese sehen aus wie Klassen, enthalten aber keinen Code, sondern nur die Definitionen der Methoden, also die Köpfe. Auch dies wird noch kurz betrachtet.

7.1.2 class

Listing 7.1: Eine Klasse definieren (class_basic)

Das erste Objekt

An dieser Stelle können Sie schon das erste Objekt ausprobieren. Dies beginnt natürlich mit der Definition einer Klasse. In PHP verwenden Sie dazu die Anweisung class.

language); echo strftime('%A', $this->datetime); setlocale(LC_TIME, $old); } public function month() { $old = setlocale(LC_TIME, $this->language); echo strftime('%B', $this->datetime); setlocale(LC_TIME, $old); } } $dd = new printdate; $de = new printdate; $dd->language = 'de'; $de->language = 'fr'; $dd->datetime = $de->datetime = time(); $dd->weekday(); echo '
';

7.1 Einführung in die Welt der Objekte ___________________________________ 141 $de->weekday(); ?> Das Skript zeigt sowohl die Klassendefinition als auch die Instanziierung der Objekte. Die Klasse printdate kennt zwei Eigenschaften und zwei Methoden. Sie soll Wochentage und Monatsnamen in verschiedenen Sprachen ausgeben. Die beiden öffentlichen Eigenschaften sind: • $language Eine Codierung, welche Sprache verwendet wird. • $datetime Das Datum, zu dem Wochentag oder Monat ausgegeben wird. Die öffentlichen Methoden sind die Handlungsanleitungen: • weekday() Hiermit erfolgt eine Ausgabe des Wochentags • month() Diese Methode gibt den Monatsnamen aus. Das Objekt besteht also aus zwei Eigenschaften und zwei Methoden. Die Das Gerüst einer Klasse wird in folgendem Mantel erstellt: Klasse

class printdate { } Innerhalb der geschweiften Klammern werden die Eigenschaften als Eigenschaften Variablendefiniert:

$language; $datetime; Methoden werden dagegen wie Funktionen erzeugt:

function weekday() { } function month() { } Parameter und Rückgabewerte können Sie ebenso verwenden, wie Sie dies von normalen Funktionen gewohnt sind. Zugriffsmodifikatoren Im Beispiel wurde bereits der Modifikator public verwendet, um anzuzeigen, dass der Zugriff ohne weiteres aus jedem Teil des Skripts möglich ist. Die Angabe kann auch entfallen. Aus Kompatibilitätsgründen mit PHP4 – wo es die Zugriffsmodifikatoren noch nicht gab – nimmt PHP5 public als Standardwert an. Soll ein Mitglied einer Klasse nur intern verwendet werden, beispielsweise als Hilfsvariable, dann wird es mit private gekennzeichnet. Ein Zugriff vom Objekt aus führt dann zu einem Laufzeitfehler.

Methoden

V V V 1 2 3 4 5 6 7 8 9 10 11 12 13 14 A B C D E

142 __________________________________________ 7 Sammeltransporte: Objekte Klassen können auch vererbt werden, dazu folgt später noch eine Einführung. Soll der Zugriff nur von der eigenen und der vererbten Klasse aus möglich sein, nicht jedoch vom Objekt aus, nutzt man das Schlüsselwort protected. Umgang mit den Definitionen in der Klasse: $this $this

Der Zugriff auf Eigenschaften und Methoden innerhalb der Klasse verwendet die spezielle Variable $this. Wenn Sie sich »virtuell« innerhalb der Klassendefinition befinden, existiert ja eigentlich noch kein Objekt. $this nimmt diese Instanziierung quasi voraus und verweist auf die Klasse selbst. Praktisch läuft dieser Vorgang natürlich erst dann ab, wenn ein Objekt erzeugt wurde. Wenn viele Objekte existieren, gibt es auch ebenso viele $this-Instanzen. Zur Trennung von Objekt und Eigenschaft oder Methode wird der Operator -> eingesetzt. Dies gilt für $this und jede andere Objektvariable. Ob es sich um eine Eigenschaft oder Methode handelt, erkennt PHP alleine anhand der runden Klammern. Achten Sie darauf, bei Methoden die runden Klammern nicht zu vergessen – auch wenn keine Parameter folgen. Wenn Sie diese weglassen, erkennt PHP eine Eigenschaft. Wie bei Variablen üblich, werden nicht vorhandene Variablen beim ersten Aufruf angelegt und bleiben leer, wenn sie nicht verwendet werden. Eine Fehlermeldung wird hier nicht erzeugt. Sie sollten dennoch explizit Startwerte vergeben, um immer mit einem definierten Zustand beginnen zu können. Das erste Beispiel könnte dann folgendermaßen aussehen:

public $language = ’de’; public $datetime; Allerdings muss der Wert, der hier zugewiesen wird, eine Konstante (oder ein Literal) sein. Funktionen wie time sind nicht möglich, weil die Auswertung bei der Übersetzung des Skripts erfolgt, nicht bei der Abarbeitung. Im Beispiel erfolgt der Zugriff auf die Eigenschaften innerhalb der Klasse mit Hilfe von $this.

$old = setlocale(LC_TIME, $this->language); echo strftime('%A', $this->datetime); setlocale(LC_TIME, $old); Das Objekt erzeugen Von der Klasse zum Objekt

Die bis hierher definierte Klasse ist noch völlig funktionslos. Sie nimmt nicht einmal Speicher in Anspruch – außer dem Platz für den Quelltext. Erst durch Instanziierung zur Laufzeit wird sie aktiv.

new

Dafür ist eine weitere Anweisung zuständig: new. Als Parameter wird der Name einer Klasse angegeben, als Ergebnis entsteht ein Objekt. Im Beispiel werden zwei davon erzeugt:

$dd = new printdate; $de = new printdate;

7.2 Erweiterte Techniken für Objekte _____________________________________ 143 Die Objekte – mit den Eigenschaften $language und $datetime und den Methoden weekday() und month() – $dd und $de sind völlig unabhängig voneinander. Erst jetzt wird auch tatsächlich Speicher in Anspruch genommen. Der Zugriff auf die Eigenschaften erfolgt wie bei Variablen. Anstatt der internen Klassenvariablen $this – die hier nicht mehr existiert – muss nun natürlich die Objektvariable verwendet werden.

$dd->language = 'de'; $de->language = 'fr'; $dd->datetime = $de->datetime = time(); Beachten Sie die Position des $-Zeichens – es wiederholt sich nicht hinter dem ->-Operator. Methoden werden ebenso wie Funktionen verwendet, nur steht auch hier wieder die Objektvariable davor. Damit ist klar, in welchem Objekt die entsprechende Aktion ausgelöst wird:

$dd->weekday(); echo '
'; $de->weekday(); Denken Sie an die runden Klammern, damit PHP den Aufruf als den einer Methode erkennt. Abbildung 7.1: Datumsoperation mit Klassen (class_basic)

7.2

Erweiterte Techniken für Objekte

Mit der gezeigten Form der Definition einer Klasse und ihrer Eigenschaf- Zugriff auf ten und Methoden können Sie schon viel erreichen. Wenn Sie solche Klassen und Klassen häufig verwenden, müssen Sie sich über die Benennung der Vererbung Eigenschaften und Methoden weniger Gedanken machen. Die Klasse bildet einen abgeschlossenen Namensraum – Konflikte mit Definitionen gleichnamiger Funktionen im imperativen Teil des Skripts oder anderen Klassen können nicht auftreten.

7.2.1

Direkter Zugriff auf Klassen

Manchmal lohnt es sich, auch dann eine Klasse zu definieren, wenn die :: Existenz eines Objekts gar nicht notwendig wäre. Man spricht dann von so genannten statischen Mitgliedern. Die Kennzeichnung erfolgt mit dem Schlüsselwort static. Der Zugriff erfolgt in PHP5 mit dem Operator »::«.

V V V 1 2 3 4 5 6 7 8 9 10 11 12 13 14 A B C D E

144 __________________________________________ 7 Sammeltransporte: Objekte Listing 7.2: Klassen ohne Instanziierung verwenden (classstatic)

'; echo calc::in2cm(4.5); ?> Das Beispiel zeigt eine Umrechnung von Zentimeter in Zoll (in steht für inches) und umgekehrt. Eine Zuweisung zu Eigenschaften und ein Erhalten eines Objektes allein deswegen wäre zu umständlich. Die direkte Verwendung bringt hier Vorteile. Vor allem müssen Sie sich keine Gedanken darüber machen, ob irgendwo anders eine Funktion cm2in() oder in2cm() existiert. Der Aufruf nennt sowohl die Klasse als auch die Funktion:

echo calc::cm2in(3); Nicht alles ist so machbar

Manche Probleme wären ohne diese Methode nicht lösbar. Wenn Sie zwei Klassendefinitionen haben, können Sie nicht auf Methoden oder Eigenschaften der anderen Definition zugreifen: new ist hier nicht zulässig und $this verweist immer nur auf die eigene Klasse. Mit dem ::Operator können Sie jedoch auch innerhalb einer Klassendefinition den Namen einer anderen Klasse verwenden.

Abbildung 7.2: Zoll/ZentimeterBerechnungen (classfunction)

7.2.2

Konstruktoren und Destruktoren

Klassen verfügen über Konstruktoren und Destruktoren. Wird eine Klasse mit new erzeugt, befindet sich dass erzeugte Objekt erst mal in einem undefinierten Zustand, zumindest solange, bis den Eigenschaften Werte zugewiesen und dazu eventuell nötige Methoden aufgerufen wurden.

7.2 Erweiterte Techniken für Objekte _____________________________________ 145 Um diesen Weg zu verkürzen kann man einen so genannten Konstruktor definieren. Dies ist eine normale Methode mit dem vordefinierten Namen __construct2. Darin erfolgen alle Zuweisungen, die in irgendeiner Form erforderlich sind, um einen definierten Anfangszustand zu erreichen. Das folgende Beispiel nutzt einen Konstruktor:

class User { private $name; private $login; private $password; private $status; const USER = 'USER'; function __construct() { $this->status = USER; } public function SetName($n, $l, $p) { $this->name = $n; $this->login = $l; $this->password = $p; } public function GetName() { return $this->login; } public function GetPassword() { return $this->password; } public function GetStatus() { return $this->status; }

} $ma = new User(); echo "Mitarbeiter hat Status: " . $ma->GetStatus(); In diesem Fall wird der Status fest zugewiesen. Da die Eigenschaft $status privat ist, kann man den Wert später nicht wieder ändern. Im Gegensatz zum Konstruktor gibt es auch einen Destruktor. Dieser wird aufgerufen, wenn das Objekt zerstört wird. Das passiert entweder,

2

Achtung! Da sind zwei Unterstriche davor.

Listing 7.3: Klasse mit Konstruktor (class_construct)

V V V 1 2 3 4 5 6 7 8 9 10 11 12 13 14 A B C D E

146 __________________________________________ 7 Sammeltransporte: Objekte wenn es gezielt mit unset vernichtet wird, oder am Ende des Skripts. Der Einsatz erfolgt, wenn bestimmte Vorgänge unbegingt ausgeführt werden müssen, unabhängig vom Verlauf oder Abbruch des Codes. Dies betrifft beispielsweise das Schließen von Datenbankverbindungen oder geöffneten Dateien.

7.2.3 Eigenschaften weitergeben

Vererbung und Schnittstellen

Wenn Sie über objektorientierte Programmierung lesen, werden Sie sehr bald auf das Wort Vererbung stoßen. Bislang spielte es hier keine Rolle. Sie müssen Vererbung nicht verwenden. Erst bei größeren Projekten wird es sinnvoll sein. Was aber hat es damit auf sich? Wenn Sie eine Klasse definiert haben, kommt vielleicht der Zeitpunkt, wo eine Erweiterung notwendig wird. Vielleicht fallen Ihnen aber auch mehrere Variationen dieser Klasse ein. Anstatt nun mehrere Klassen zu definieren, ist es besser, eine Basisklasse zu entwerfen und daraus Subklassen abzuleiten, die nur die geänderten Eigenschaften und Methoden enthalten. Damit die Subklassen überhaupt eine Funktionalität haben, müssen Sie von einer Mutterklasse dies erben. Dieser Vorgang wird Vererbung genannt.

PHP – überall Klassen? Wenn Sie sich professionelle Skripte aus dem Web anschauen, kommen dort fast ausschließlich Klassen zum Einsatz. Heißt das nun, dass wer professionell programmieren will, muss Klassen verwenden? Der Grund ist ein anderer: Klassen bieten Softwareentwicklern handsfeste Vorteile bei der Nutzung fremden Codes und der Verteilung des eigenen an Fremde. Durch die Kapselung der Variablennamen kommt es nicht mehr Konflikten mit dem globalen Adressraum der Zielapplikationen. Dabei spielt es oft keine Rolle, ob objektorientierte Ansätze darüber hinaus noch genutzt werden. In PHP wird die Vererbung mit der Anweisung extends gesteuert. Dabei definieren Sie eine Klasse und geben mit extends an, von welcher Klasse zusätzliche Eigenschaften und Methode geerbt werden sollen. extends

Aus Ketten solcher Vererbungen entsteht eine Hierarchie. Dies ist auch mit PHP möglich. Ebenso können Methoden überschrieben werden. Tritt in einer Klasse, die bereits Methoden geerbt hat, eine Methode gleichen Namens auf, überschreibt diese die ursprüngliche Methode. Vererbung mit extends Die Vererbung auf einfachster Ebene ist leicht zu verstehen. Stellen Sie sich nochmals die Klasse User aus dem letzten Abschnitt vor. Um andere Arten von Benutzern anzulegen, wäre eine neuen Definition wenig sinnvoll. Einfacher geht es folgendermaßen:

7.2 Erweiterte Techniken für Objekte _____________________________________ 147 class Admin extends User { } Die neue Klasse Admin kennt nun erstmal genau die Eigenschaften und Methode wie die Klasse User. Allerdings muss sie dafür sorgen, dass Eigenschaften, die mit der Kennzeichnung protected freigegeben wurden, erneut zu deklarieren sind. Das nächste Beispiel verwendet dieselbe Klasse User, jedoch mit einer veränderten Zeile für die Definition der Eigenschaft $status:

protected $status; In der abgeleiteten Klasse wird dann die Referenz auf diese Eigenschafte wiederholt und der veränderte Konstruktor überschreibt den vorhergehenden:

class Admin extends User { const ADMIN = 'ADMIN'; protected $status;

}

function __construct() { $this->status = ADMIN; }

Braucht man mehrere ähnliche Klassen, sind solche Ableitungen ein effizientes Arbeitsmittel. Änderungen an der Basisklasse wirken sich zwangsläufig auf alle Ableitungen aus, was die Pflege vereinfacht. Bevor Sie jedoch gleich superumfangreiche Hierarchien entwerfen seien Sie gewarnt: Dies ist eine Kunst, die man erst nach langer Erfahrung im Umgang mit objektorientierter Programmierung beherrschen kann. Schnittstellen Schnittstellen sind im Rahmen eines Einsteigerbuches kaum relevant. Sie sollen dennoch erwähnt werden. Zum einen, weil sie neu in PHP5 sind, zum anderen, weil es zeigt, dass es weit mehr gibt, als hier kurz behandelt werden kann. Immerhin ist damit auch eine satte Lernkurve verbunden, was bei kleineren Projekten nicht gerechtfertigt ist. Angenommen, Ihr System aus Mitarbeiterklassen dient als Basis für eine Software, die Mitarbeiter verwaltet. Andere Entwickler sollen Zusatzmodule schreiben und dafür gegebenenfalls weitere Klassen nutzen dürfen, die mehr oder weniger der vorgestellten Klasse User ähneln. Um diese mit umfassender Funktionalität ausstatten zu können, müssten Sie sehr weitreichende Strukturen der Basisklasse vorausdenken. Das funktioniert in der Praxis nicht. Deshalb einigt man sich darauf, nur den Aufbau der Klasse vorzugeben, nicht jedoch die Implementierung. Als Vereinbarung über den Aufbau dient die Schnittstelle. Für User sieht sie folgendermaßen aus:

Listing 7.4: Eine Klasse ableiten (class_extends)

V V V 1 2 3 4 5 6 7 8 9 10 11 12 13 14 A B C D E

148 __________________________________________ 7 Sammeltransporte: Objekte Listing 7.5: Eine Schnittstelle wird definiert (interface)

interface Employees { public function public function public function public function }

SetName($n, $l, $p); GetName(); GetPassword(); GetStatus();

Wenn nun eine neue Klasse erzeugt werden will, die zu den anderen kompatibel sein soll, muss sie lediglich diese Schnittstelle benutzen – man spricht dann von »implementieren«:

class User implements Employees Es ist dann Sache der Klasse, die Methoden zu definieren, also den Code mitzubringen. Dies ist ein wesentlicher Unterschied zu extends, wo Methode mitsamt dem Code übernommen wird. Ende der Vererbung Soll die Vererbung unterdrückt werden, stellt man einer Klasse das Schlüsselwort final davor.

final class Admin Damit wird verhindert, dass aus einer endgültig ausformulierten Klasse weitere Varianten entstehen, die sich möglicherweise widersinnig oder unlogisch im Sinne des ursprünglichen Entwicklers verhalten. Bitte vererben! Zu final gibt es auch ein Gegenstück: abstract. Dies dient Klassen als Definition dafür, dass der erbende Teil noch selbst Code aufbringen muss. Das ähnelt den Schnittstellen, dient jedoch nicht als Erweiterung einer bestehenden Hierarchie unabhängig von der bestehend, sondern in Abhängigkeit von dieser. Die Entscheidung darüber, ob Schnittstellen oder abstrakte Klassen genutzt werden, setzt wieder einige Erfahrung voraus. Wichtig zu wissen ist, dass auch einzelne Methoden als abstract bezeichnet werden können, während eine Schnittstelle immer das gesamte Gebilde betrifft.

7.3 Funktionen für Objekte

Spezielle Funktionen

Des weiteren sollten Sie sich mit einigen Funktionen auseinandersetzen, die den Umgang mit Klassen unterstützen. Eine vollständige Übersicht über Syntax und Anwendungsbeispiele finden Sie in der Referenz.

7.3.1

Methoden aufrufen

Der Aufruf von Methoden mit den Operatoren -> und :: ist manchmal nicht hinreichen flexibel. Sie können dies auch mit Hilfe einer Funktion initiieren:

7.3 Spezielle Funktionen _______________________________________________ 149 '; echo call_user_method($f[1], $calc, 4.5); ?>

Listing 7.6: Methoden per Funktion aufrufen (classdynamic)

 Zoll // 4.5 Zoll  cm

// 3 cm

Die Funktion call_user_method erwartet mindestens zwei Parameter: Den Namen einer Methode und einer Klasse. Der dritte und eine beliebige Anzahl weiterer Parameter werden an die Methode beim Aufruf übergeben. Ergänzend sei auf call_user_method_array hingewiesen, wo die Parameter als Array übergeben werden. Das ist interessant, wenn sehr viele Parameter erforderlich sind.

7.3.2

Eigenschaften von Klassen ermitteln

Wenn Sie große Projekte in Planung haben, helfen Ihnen einige Funktionen, flexibel auf Klassen zu reagieren. So ermitteln die folgenden Funktionen Eigenschaften von Klassen durch Zugriff auf bereits abgeleitete Objekte: • method_exists($object, "method_name") Gibt TRUE zurück, wenn die Methode in dem angesprochenen Objekt existiert. • is_subclass_of($object, "superclass") Gibt TRUE zurück, wenn das Objekt $object von der Klasse superclass abgeleitet wurde, beispielsweise durch extends. • get_class_methods("classname") Diese Funktion gibt ein Array mit allen Methoden der Klasse zurück. Es spielt keine Rolle, ob ein Objekt dieser Klasse erzeugt wurde. Weitere Funktionen finden Sie in der Referenz. Ein Anwendungsbeispiel zeigt das folgende Skript:


Listing 7.7: Ermitteln von definierten Methoden (calls_methods)

V V V 1 2 3 4 5 6 7 8 9 10 11 12 13 14 A B C D E

150 __________________________________________ 7 Sammeltransporte: Objekte } $arr = get_class_methods('calc'); foreach($arr as $method) echo "$method
"; ?> Die Klasse wird hier wie üblich definiert. Objekte werden nicht instanziiert. Mit der foreach-Schleife werden die Methodennamen ausgegeben. Der Einsatz bietet sich vor allem zur Fehlersuche an, aber auch zum Abfangen von Fehlern bei der Verwendung fremder Klassen. Abbildung 7.3: Ausgabe von Listing 7.7

7.4

Klassenpraxis

Ein Anwendungs- In der Praxis werden Klassen überwiegend eingesetzt, um in vielen Programmen wiederverwendet werden zu können. Solche Definitionen beispiel

zeichnen sich deshalb durch eine gewisse Universalität aus. Das folgende Projekt zeigt die Entwicklung einer einfachen Klasse und eine Strategie, wie davon andere abgeleitet werden können.

7.4.1

Herausforderung: Grafik selbstgebaut

Häufig benötigt man beim Aufbau von Webseiten kleine Grafiken, die als Abstandhalter, Linien oder Graphen verwendet werden. Dies sind in der Regel kleine GIF-Bildchen, einfarbige, im Idealfall nur 1x1 Pixel große Elemente, die erst im Browser ihre endgültige Größe erreichen. Nun können Sie sich Dutzende Varianten vorher in Adobe Photoshop anfertigen – oder diese von PHP generieren lassen. Ohne GD2Bibliothek

Für die automatische Generierung von Grafiken gibt es die GD2Bibliothek. Der Einstieg ist aber nicht einfach und der Umgang damit nicht unproblematisch. In Abschnitt 13.2 Hilfsdesigner: Bildfunktionen ab Seite 315 finden Sie dazu eine praktische Einführung.

Bilder selbstgemacht

Hier geht es nur um die Erzeugung eines kleinen Standard-GIFs. Die innere Struktur eines solchen Bildes ist klar festgelegt. Entsprechend bietet es sich an, dies in der Klasse bei Bedarf zusammenzusetzen. GIF ist – wie jedes andere Bildformat auch – sehr genau definiert. Praktisch setzt sich ein Bild aus Basisinformationen und Bilddaten zusammen. Bei GIF beginnt die Bilddatei mit den Zeichen »GIF« (3 Bytes), dann folgt die Version »89a« (3 Bytes) und der Bildgröße (4 Bytes sowie Informationen über den Aufbau der Farbtabellen.

7.4 Klassenpraxis______________________________________________________ 151 Abbildung 7.4: Aufbau des Kopfes einer GIFDatei

Abbildung 7.4 zeigt den Aufbau des Kopfes, wie sie in der Klassendefinition verwendet wird. Das Bild soll 1x1 Pixel groß werden. Anschließend folgt die Farbtabelle und verschiedene weitere Bildinformationen, unter anderem für Transparenz. Dazu gibt es eine Reihe Spezialliteratur; der genaue Aufbau soll hier nicht weiter betrachtet werden. GIF erlaubt auch die Definition von Sequenzen (animierte GIFs und die Kompression der Bilddaten). Beides wird hier nicht benötigt. Der Code 0x3B schließt das Bild übrigens ab und muss immer am Ende stehen. Die erste Klasse Die erste Klasse erzeugt lediglich ein schwarzes Pixel. Sie wird später um eine Farbkomponente erweitert.

end = str_repeat('f', 1530); } private function hex2bin($s) { $t = pack("H*", $s); return $t; } public function Create ($incolor = 0) { $pix = Giffy::ini . $this->color . $this->end; if ($incolor == 1) { $pix .= Giffy::inc; } else {

Listing 7.8: Klasse zum Erzeugen eines 1x1-Pixel-GIF (giffy)

V V V 1 2 3 4 5 6 7 8 9 10 11 12 13 14 A B C D E

152 __________________________________________ 7 Sammeltransporte: Objekte $pix .= Giffy::nor; } return $this->hex2bin($pix);

} } $gifPix = new Giffy(); header ("Content-type: image/gif"); echo $gifPix->Create(); ?> Wenn Sie die Klasse abschreiben, achten Sie unbedingt auf die exakte Schreibweise der Zahlenkolonnen am Anfang – diese müssen auch in einer Zeile stehen, der Umbruch ist nur für den Druck eingebaut worden. Die Klasse definiert folgende intern verwendete Eigenschaften: • $ini Startsequenz der GIF-Datei • $end Endsequenz der Farbtabelle der GIF-Datei • $nor Endsequenz für transparente Bilder • $inc Endsequenz für nichttransparente Bilder Die Variable $end besteht nur aus FF-Bytes und wird mit dem Konstruktor giffy() aufgefüllt.

$this->end = str_repeat('f', 1530); Das Bild selbst setzt die öffentliche Methode Create zusammen. Da mit Hexadezimalzahlen gearbeitet wird, die in Form von Zeichenketten existieren, müssen diese am Ende noch in eine binäre Form gebracht werden. In PHP5 verwenden Sie für binäre Operationen am besten die Funktion pack. Sie »verpackt« Zeichenketten und Zahlen in binäre Formate. Das funktioniert so ähnlich wie bei printf, mit einer Formatanweisung:

$t = pack("H*", $s); Der Buchstabe »H« steht dabei für hexadezimale Zahlen, das Sternchen wiederholt diese Formatierung solange wie Eingabedaten in der Variablen $s zu finden sind. Verwendung der Klasse

Das reihenweise Erzeugen und Speichern von Bildern ist sicher nicht besonders hilfreich. Einfacher ist es, die generierten Bilder direkt zum Browser zu senden. Die Klasse wird deshalb um Code erweitert, der das Bild erzeugt und direkt an den Browser sendet. Dazu wird das Objekt erzeugt und mit echo die Ausgabe der Methode Create an den Browser gesendet. Damit dieser die Angaben bearbeiten kann, werden entsprechende Kopfdaten mitgegeben:

header("Content-type: image/gif"); Wichtig ist, dass vor der Ausgabe von Headern keine weiteren Daten gesendet werden – auch keine Leerzeichen. Natürlich muss der Aufruf des Skripts aus Listing 7.8 irgendwie initiiert werden. Dazu dient eine kleine HTML-Datei als Test:

7.4 Klassenpraxis______________________________________________________ 153 Braucht man einzelnen GIF-Punkte?
JA
NEIN


Listing 7.9: Nutzung der dynamischen GIF-Erzeugung (GiffyTest1)

Das Skript besteht nur aus reinem HTML. Beachten Sie den Aufbau der -Tags. Hier wird als Ziel kein Bild angegeben, sondern das zuvor definierte PHP-Skript.

Das Ergebnis ist schon recht ansehnlich. Ein schwarzes GIF abzulegen wäre jedoch einfacher gewesen; Farbe muss also her! Abbildung 7.5: Test der Klasse »Giffy«

Eine Erweiterung der Klasse um eine Farbfunktion ist deshalb der nächste Schritt. Erweiterung einer Klasse Die Erweiterung erfolgt mit Hilfe der Anweisung extends. Dabei kann eine Erweiterung der Klasse nicht nur die Eigenschaften und Methoden der Mutterklasse erben, sondern auch überschreiben. Beides wird in der folgenden Definition ausgenutzt.

color = $color; $gif = parent::Create($incolor); return $gif; }

} $gifPix = new GiffyColor(); header ("Content-type: image/gif"); echo $gifPix->Create(isset($_GET['color']) ?

Listing 7.10: Erweiterung der Mutterklasse (Ausschnitt aus giffy2)

V V V 1 2 3 4 5 6 7 8 9 10 11 12 13 14 A B C D E

154 __________________________________________ 7 Sammeltransporte: Objekte

?>

$_GET['color'] : '000000');

Nach der Einleitung mit extends wird eine neue Methode Create definiert. Diese überschreibt die bereits in der Mutterklasse vorhandene Funktion gleichen Namens:

function Create($color, $incolor = 0) Neu an der Definition ist ein weiterer Parameter: $color. Dieser wird verwendet, um die entsprechende Eigenschaft in der Mutterklasse zu setzen. Der Zugriff gelingt, weil diese Eigenschaft in der Klasse als protected gekennzeichnet wurde.

$this->color = $color; Dann wird die alte Funktion create der Mutterklasse aufgerufen. Die »Eltern«-Klasse wird hier mit parent direkt adressiert und mit dem ::Operator angesprochen, weil die Verwendung von $this zu einem Namenskonflikt führt. Die Parameter entsprechen natürlich der alten Definition:

$gif = parent::Create($incolor); Die Klasse verwenden

Die Verwendung unterscheidet sich nur durch den zusätzlichen Parameter $color und natürlich durch Aufruf der neuen Klasse:

$gifPix = new GiffyColor(); header("Content-type: image/gif"); echo $gifpix->create(isset($_GET['color']) ? $_GET['color'] : '000000'); Der Zugriff auf das Array $_GET erfasst per HTTP-GET übertragene Parameter. Diese Technik wird ausführlich in Abschnitt 9.2 Daten per URL weiterreichen ab Seite 213 erläutert. Damit das funktioniert, wird die Testdatei ebenfalls erweitert. Dazu wird der Parameter color an den Aufruf des Skripts angehängt: Listing 7.11: Aufruf für GiffyColor (GiffyTest2)



7.5 Eingebaut: Die Fehlerklassen ________________________________________ 155
Auch wenn es der Druck nicht erlaubt: Abbildung 7.6 zeigt farbige Bilder. Von Vorteil ist nun, dass Sie die Farben dynamisch erzeugen können, beispielsweise für eine personalisierte Seite, bei der sich die Benutzer aus einer Vielzahl von Farben eigene aussuchen können. Sie sparen sich die prophylaktische Anfertigung hunderter Minibildchen. Abbildung 7.6: Tatsächlich farbig: Bunte GIFs dynamisch erzeugt

Fehlersuche Nachteilig bei diesem Verfahren ist die mangelnde Testmöglichkeit. Feh- Wenn es nicht ler im Skript werden nicht angezeigt, weil der Browser fehlerhafte Bild- funktioniert daten – die eine Fehlerausgabe für ihn ist – einfach ignoriert oder ein Standardbild darstellt. Rufen Sie die Klassendefinition deshalb zuerst direkt auf. Dann sehen Sie zwar kein Bild, dafür aber eventuell auftretende Warnungen oder Hinweise. Wenn nichts mehr angezeigt wird, handelt es sich um Bilddaten – dann steht dem regulären Aufruf nichts mehr im Wege.

7.5

Eingebaut: Die Fehlerklassen

Im letzten Kapitel wurde bereits kurz die Fehlerbehandlung mit try/catch vorgestellt. Für den praktischen Einsatz ist etwas mehr Aufwand nötig, der sich aber lohnt, wenn größere Programme geschrieben werden.

7.5.1

Die Klasse Exception

PHP5 verfügt über eine eingebaute Klasse, die die Fehlerbehandlung kontrolliert: Exception (dt. Ausnahme). Diese Klasse ist folgendermaßen definiert:

class Exception { function __construct(string $message=NULL, int code=0) { if (func_num_args()) { $this->message = $message; }

V V V 1 2 3 4 5 6 7 8 9 10 11 12 13 14 A B C D E

156 __________________________________________ 7 Sammeltransporte: Objekte

}

$this->code = $code; $this->file = __FILE__; $this->line = __LINE__; $this->trace = debug_backtrace(); $this->string = StringFormat($this);

protected protected protected protected

$message = 'Unknown exception'; // Text $code = 0; // User Code $file; // Dateiname $line; // Quellzeile

private $trace; private $string;

}

// Trace

final function getMessage() { return $this->message; } final function getCode() { return $this->code; } final function getFile() { return $this->file; } final function getTrace() { return $this->trace; } final function getTraceAsString() { return self::TraceFormat($this); } function _toString() { return $this->string; } static private function StringFormat(Exception $exception) { } static private function TraceFormat(Exception $exception) { }

Wenn man nun eigene Ausnahmen definiert, wird sinnvollerweise von dieser Klasse abgeleitet. Das folgende Beispiel zeigt, wie dies prinzipiell aussieht: Listing 7.12: Eigene Ausnahmeklasse (try_numexc)


7.5 Eingebaut: Die Fehlerklassen ________________________________________ 157 try {

if(!is_int($i)) { throw new NumberFormatException('$i ist keine Zahl.'); } else { echo 'OK'; }

} catch (NumberFormatException $exception) { echo $exception->toString(); } ?> Die Klasse NumberFormatException wird direkt von Exception abgeleitet. Sie verfügt deshalb über die passenden Methoden zum Aufnehmen und Ausgaben einer Fehlermeldung. Damit diese auch benutzt werden können, ist der Konstruktor der Stammklasse aufzurufen:

parent::__construct($exception); Im try-Block des Testskripts erfolgt dann eine entsprechende Fehlerprüfung und bei Bedarf die Auslösung des Fehlers:

throw new NumberFormatException("$i ist keine Zahl."); Im catch-Zweig wird dann darauf reagiert. Welche konkrete Reaktion ein Skript verlangt, hängt von der Schwere des Fehlers ab. Entweder erfolgt eine entsprechende Fehlerausgabe mit nachfolgendem Programmabbruch oder beispielsweise ein »stiller« Neustart. Zum unmittelbaren Beenden des Programms bietet sich die Anweisung die an:

die($exception->getMessage());

7.5.2

Praktischer Einsatz der Fehlerbehandlung

Fehlerklassen sind normalerweise Teil der Konstruktion von Bibliotheken. Als Entwickler einer solchen Funktionssammlung definieren Sie nicht nur die Verwendung, sondern auch die Fehlerbehandlung. Der Nutzer der Klasse ist dafür zuständig, dann auf die Fehler in entsprechender Weise zu reagieren. Erst bei diesem Szenario wird deutlich, wozu das try/catch-Konzept tatsächlich in der Lage ist. Es degradiert sich selbst lediglich deshalb, weil die interne Laufzeitfehlbehandlung in das Konzept nicht eingeschlossen ist, was den praktischen Nutzen mehr oder weniger auf die Bibliotheksprogrammierung beschränkt. Das Verständnis dafür ist dennoch für jeden PHP-Entwickler notwendig, weil die meisten früher oder später fremde Bibliotheken nutzen.

V V V 1 2 3 4 5 6 7 8 9 10 11 12 13 14 A B C D E

158 __________________________________________ 7 Sammeltransporte: Objekte Um die Sache etwas zu verdeutlichen, soll das letzte Beispiel nochmals leicht verändert benutzt werden. Funktion und Fehlerklasse sind nun beides Klassen und stehen als externe Bibliothek zur Verfügung. Sie sind folgendermaßen definiert: Listing 7.13: Eine kleine Musterbibliothek (try_numexclib)

$i ist keine Zahl."); } else { echo 'OK'; } } } ?> Das typische Szenarion sieht nun folgendermaßen aus: Diese Bibliothek wird von einem Entwickler erstellt und der Allgemeinheit verfügbar gemacht. Ein anderer Programmierer möchte die Klasse nun nutzen. Er weiß, welche Klassen enthalten sind und welche Fehler ausgelöst werden, wenn bestimmte Bedingungen nicht erfüllt sind. Er nutzt die Klasse folgendermaßen:

Listing 7.14: Nutzung einer Bibliothek (try_numexc2)

getMessage(); } ?> Hier sieht die Sache nun deutlich einfacher und konsistenter aus. Das ist der Sinn der Fehlerbehandlung. Denn der Anwender der Bibliothek kann entscheiden, ob und wie er Fehler abfängt und wie er mit ihnen im

7.5 Eingebaut: Die Fehlerklassen ________________________________________ 159 catch-Zweig verfährt. Um die eigentliche Fehlerprüfung muss er sich dagegen nicht kümmern. Wie im realen Leben tritt natürlich nicht nur ein einziger Fehler auf. Ein und derselbe Prozess kann verschiedene Fehler erzeugen. So könnte sich an die Zahlenprüfung noch eine solche auf negative Zahlen anschließen. Durch die Aneinanderreihung von catch-Zweigen kann auf jeden Fehler einzeln reagiert werden.

V V V 1 2 3 4 5 6 7 8 9 10 11 12 13 14 A B C D E

7.5 Eingebaut: Die Fehlerklassen ________________________________________ 161

8 Daten bewegen: Dateisystem und FTP Mit PHP können Sie komfortabel auf das Dateisystem zugreifen. Damit ergeben sich umfangreiche Anwendungsmöglichkeiten. Der Zugriff ist dabei nicht nur auf das lokale Dateisystem des Servers beschränkt, sondern kann sich auch auf andere Computer im Internet erstrecken – per FTP (File Transfer Protocol) oder HTTP. Umgekehrt können Sie auch zulassen, dass Benutzer Dateien auf den Server hochladen – auch dafür stellt PHP eine sehr einfach zu programmierende Technik zur Verfügung.

8

Daten bewegen: Dateisystem und FTP

8.1 Dateisystem _______________________________________________________ 163

8.1

Dateisystem

Der Zugriff auf das Dateisystem ist eine enorme Erleichterung bei der Umsetzung vieler Projekte. Sie können mit Hilfe von Dateien Daten dauerhaft speichern, Grundeinstellungen und Stammdaten lesen. Viele praktische Anwendungen gibt es darüber hinaus, beispielsweise: • Protokolle schreiben Protokollieren Sie Nutzerbewegungen in eigenen Dateien. • Formulardaten ablegen

Wozu Sie Dateifunktionen verwenden können

Speichern Sie Formulare als Dateien ab. • News des Tages Bauen Sie dynamische Daten in Ihre Websites ein, die Sie oder andere als Textdatei abgelegt haben, beispielsweise für Tagestipps. • Datenspeicher Legen Sie Daten, die sich nur selten ändern, in Textdateien ab. Die Arbeit mit Dateien erfolgt nach einem einfachen Schema. Zuerst wird die Datei geöffnet, dann werden Daten herausgelesen oder hineingeschrieben und dann wird die Datei wieder geschlossen. Wenn eine Datei nicht existiert, kann sie beim Öffnen automatisch angelegt werden. Wenn eine Datei geöffnet ist, kann der gesamte Inhalt in eine Variable transportiert werden. Besser ist die Verwendung eines Dateizeigers. Dieser markiert eine bestimmte Position in der Datei und steuert die Ausgabe der enthaltenen Daten. PHP kann zwischen Binär- und Textdateien unterscheiden. Textdateien Binär oder Text? werden im ASCII-Modus geöffnet und es bieten sich spezielle Bearbeitungsfunktionen dafür an. Um mit Dateien arbeiten zu können, werden so genannte Datei-IDs oder Handles Handles erzeugt. Ein Handle ist ein Verweis auf eine Datei. Funktionen zur Dateimanipulation nutzen Handles zur Zugriffssteuerung. Dies ist einfacher, als immer wieder den kompletten Pfad zu einer Datei anzugeben.

Handlungsanleitungen in Form von Handles Im Buch wird sehr oft der Begriff »Handles« genutzt. Generell handelt es sich dabei um eine Referenz (Verweis) auf eine bestimmte Verbindung. Der Begriff ist üblich und wurde deshalb nicht übersetzt.

Zugriff auf entfernte Server Als Dateiname kann, außer einem physischen Pfad auf einem Unix- oder Windows-System, auch eine HTTP- oder FTP-Adresse genutzt werden. Dann wird eine Verbindung zu einem Webserver (http:) oder einem FTP-

V V V 1 2 3 4 5 6 7 8 9 10 11 12 13 14 A B C D E

164 ________________________________ 8 Daten bewegen: Dateisystem und FTP Server aufgebaut. FTP-Verbindungen können lesen und schreiben, Daten aus HTTP-Verbindungen können Sie natürlich nur lesen. Für FTP und auch für HTTP stehen neben den Standardfunktionen für die Dateieinund -ausgabe auch spezielle Module zur Verfügung.

8.1.2

Zugriff auf Dateien

Dateien lesen ist der elementarste Schritt. Der Webserver muss dazu keine besonderen Voraussetzungen erfüllen – im Gegensatz zum Schreiben, wo bestimmte Rechte existieren müssen. Sie können also sofort loslegen. Dateien ins Skript einbinden Mit der Anweisung include wird eine PHP- oder HTML-Datei eingeschlossen und so ausgeführt, als wäre sie alleine aufgerufen worden. Sie können dies auch in Schleifen einsetzen. Hier ein Beispiel für die einfachste Anwendung:

"; include("kopf.inc.php"); echo "
"; ?> Das Skript führt zuerst die erste echo-Anweisung aus. Dann wird die Datei kopf.inc.php geladen und komplett verarbeitet. Anschließend wird die zweite echo-Anweisung ausgeführt. In PHP ist es möglich, dass die Befehlsstruktur in einer mit include eingebundenen Datei als Block aufgefasst wird. Damit ist auch die Anwendung der Anweisung return möglich. Der Rückgabewert wird der Variablen des aufrufenden Skripts übergeben: Listing 8.1: Rückgabewerte eines Moduls (include1)

"; $value = include("modul.inc.php"); echo $value, ' = ', $path; echo "
"; ?> Das Skript bindet die Datei modul.inc.php normal ein, als wäre der Code an dieser Stelle geschrieben worden.

$value = include("modul.inc.php"); Wenn in diesem Skript eine return-Anweisung steht, wird deren Wert an die Variable $value übergeben.

8.1 Dateisystem _______________________________________________________ 165

Listing 8.2: modul.inc.php zu Listing 8.13

Die Verwendung von return ist allerdings tückisch. Ähnlich wie bei Probleme mit Funktionen wird der nach dem return liegende Teil nicht mehr verarbei- return tet. Das gilt auch für dahinter liegende HTML-Tags, die vielleicht nicht direkt im Zusammenhang mit dem PHP-Code stehen. Listing 8.3: Ausgabe des Skripts aus Listing 8.2 Wenn Sie mit include und return arbeiten, sollten Sie sich darüber klar sein, dass es einen wesentlichen Unterschied zu Funktionen gibt: Die Variablen des eingeschlossenen Blockes sind im gleichen Sichtbereich wie der umschließende Bereich – außerhalb einer Funktion also global sichtbar. Umgekehrt sind vor dem Aufruf von include bereits definietrte Variablen auch im Block sichtbar. Wenn Sie ein Modul fest in die Seite einbinden möchten, so als wäre es require an dieser Stelle direkt untergebracht, nutzen Sie dagegen die Anweisung require.

"; require("header.inc.php"); ?>

Listing 8.4: Modul mit require einbinden

In Dateien, die mit require eingebunden werden, muss der PHP-Code in den Begrenzungszeichen stehen.

Die Unterschiede zwischen include und require Der Unterschied zwischen den beiden Befehlen liegt im Zeitpunkt der Verarbeitung der einzuschließenden Datei. require wird zuerst ausgeführt – vor dem Parsen des gesamten Skriptes. Bei include dagegen erfolgt die Integration erst zu dem Zeitpunkt, wenn die Abarbeitung an dieser Stelle angelangt ist. Wird die Stelle interpretiert, kann sie natürlich auch in einer Schleife stehen. Allerdings sollte include dann als Block gekennzeichnet sein und in geschweiften Klammern stehen. Unterschiedlich ist auch das Fehlerverhalten: Bei include wird lediglich eine Warnung erzeugt, wenn die Datei nicht gefunden werden kann, require bricht dagegen mit einem Fehler ab.

Informationen zur Verwendung von $_SERVER finden Sie im Daten über den Server ermitteln ab Seite 219.

3

Abschnitt 9.3

V V V 1 2 3 4 5 6 7 8 9 10 11 12 13 14 A B C D E

166 ________________________________ 8 Daten bewegen: Dateisystem und FTP Tipps im Umgang mit eingeschlossenen Dateien Sicherheitsprobleme

Normalerweise können Nutzer den Inhalt der Skripte nicht sehen. Jede Datei mit der Endung PHP oder PHP5 wird vom Webserver an PHP gesendet. Es ist natürlich auch möglich, jede andere Endung anzugeben, auch HTML. Das geht bei Dateien, die mit Sicherheit keinen PHP-Code enthalten, aber zu Lasten der Leistung. Oft werden Dateien, die mit include eingeschlossen werden sollen, mit .INC bezeichnet. Auch diese Endung wird nicht verarbeitet. Das ist für den Ablauf des Skripts egal – die Verarbeitung erfolgt im Rahmen des »umgebenden« Skripts und damit unter dessen Regie. Wenn nun aber ein Nutzer den Pfad zu den Include-Dateien herausbekommt, kann er deren Namen in der Adresszeile des Browsers direkt eingeben. Der Webserver wird die Endung nicht kennen und dem Browser die Datei direkt anbieten. Der erkennt einfachen Text und stellt ihn dar. Da in Include-Dateien auch Kennwörter für Datenbanken stehen können, entsteht so eine erhebliche Sicherheitslücke.

Abhilfe

Abhilfe schaffen Sie sehr einfach. Benennen Sie einfach alle IncludeDateien mit .INC.PHP. So haben Sie eine eindeutige Kennzeichnung und erzwingen im Notfall das Parsen des Codes. Das mag zwar zu einer Fehlermeldung führen – an den Inhalt gelangt der Nutzer dennoch nicht. Mehrfacheinbindung und verschachtelte Module

Probleme mit verschachtelten Dateien include_once require_once

Normalerweise ist es kein Problem, wenn Sie innerhalb einer mit include oder require eingeschlossenen Datei weitere Einschlüsse vornehmen. Handelt es sich jedoch um dieselbe Datei, wird ein Laufzeitfehler erzeugt, wenn dort beispielsweise Funktionen definiert werden. Der mehrfache Einschluss ist zwar möglich – nicht aber die mehrfache Definition von Funktionen oder Klassen, die daraus möglicherweise resultiert. Um dieses Problem zu vermeiden, können Sie die Anweisungen include_once und require_once verwenden. Damit erfolgt die Aktivierung des Inhalts garantiert nur einmal. Daten aus Textdateien holen

readfile

Abbildung 8.1: News aus einer Textdatei

Die Funktion readfile liest eine Datei und sendet deren gesamten Inhalt ohne weitere Bearbeitung an den Browser. Als Parameter wird der Dateiname mit den nötigen Pfadangaben übergeben. Hier sollte kein ausführbarer PHP-Code stehen, sonst wird dieser im Browser angezeigt und nicht ausgeführt. Zuerst das Ergebnis:

8.1 Dateisystem _______________________________________________________ 167 "; readfile($datei); echo "
"; ?>

Listing 8.5: Datei einlesen und ausgeben (readfile)

Das Skript wird bis readfile normal abgearbeitet. Mit Aufruf der folgenden Zeile, wird die Datei gelesen und sofort ausgegeben:

readfile($datei); Die abschließende Ausgabe einer Linie erfolgt nach dem Text der Datei NEWS2.TXT, zur Kennzeichnung der Grenzen:

echo "
"; Analog funktioniert auch file, die gelesene Datei wird dabei in einem Array abgelegt. Jede Zeile wird zu einem Element eines eindimensionalen Arrays. Der Zeilenumbruch verbleibt am Ende des Elements. Das ist natürlich nur sinnvoll, wenn es sich um Textdateien handelt, die zeilenweise aufgebaut sind. Im folgenden Beispiel liest ein Skript »sich selbst« sein. Anschließend wird es zeilenweise mit Zeilennummern ausgegeben.

%4d: %s
", $line, htmlspecialchars($data)); } ?> Hier wird zuerst der Name des Skripts ermittelt, das gerade läuft (das Skript gibt sich also selbst aus): basename($_SERVER['PHP_SELF']). Dieser Name wird als Parameter für file verwendet:

$filearray = file(basename($_SERVER['PHP_SELF'])); Jetzt steht das Skript zeilenweise im Array $filearray. Die Schleife durchläuft nun das Array Zeile für Zeile:

while(list($line, $data) = each($filearray)) Jede Zeile wird so formatiert, dass der Browser die HTML-Tags nicht ausführt, sondern anzeigt.

printf("%4d: %s
", $line, htmlspecialchars($data)); Der Weg über file ist meist der einfachste. Für den Umgang mit dem Inhalt stehen Ihnen danach alle Arrayfunktionen zur Verfügung. In der Kombination von Dateizugriff und Arrayoperation ist der Funktionsvorrat in PHP5 sehr leistungsfähig. Die folgende Abbildung zeigt, wie die Ausgabe des Skripts erfolgt:

Listing 8.6: Datei in Array einlesen und verarbeiten (fileread)

V V V 1 2 3 4 5 6 7 8 9 10 11 12 13 14 A B C D E

168 ________________________________ 8 Daten bewegen: Dateisystem und FTP Abbildung 8.2: Ausgabe mit Zeilennummern

Direkt mit Textdateien arbeiten Um direkt mit Dateien arbeiten zu können, dient ein so genanntes DateiHandle4. Dies ist eine Referenz auf die geöffnete Datei. fopen

Die für die Erzeugung des Handles zuständige Funktion heißt fopen. Sie können den Dateinamen und ein Attribut angeben. Das Attribut bestimmt, wie die Datei geöffnet wird: • r Öffnet eine Datei zum Lesen und setzt den Dateizeiger auf den Anfang (das erste Zeichen in der Datei). • r+ Öffnet eine Datei zum Lesen und Schreiben und setzt den Dateizeiger auf den Anfang (das erste Zeichen in der Datei).

• w Öffnet eine Datei zum Schreiben. Wenn die Datei nicht existiert, wird sie angelegt. Wenn die Datei vorhanden ist und Daten enthält, werden diese gelöscht und die Länge wird auf 0 gesetzt. • w+ Öffnet eine Datei zum Schreiben und Lesen. Wenn die Datei nicht existiert, wird sie angelegt. Wenn die Datei vorhanden ist und Daten enthält, werden diese gelöscht und die Länge wird auf 0 gesetzt.

• a Öffnet die Datei zum Schreiben. Wenn die Datei nicht existiert, wird sie neu angelegt. Vorhandene Daten bleiben erhalten. Der Dateizeiger steht am Ende der Datei (a steht für append, dt. anhängen).

4

Dies ist ein feststehender Begriff, der üblicherweise nicht übersetzt wird.

8.1 Dateisystem _______________________________________________________ 169

• a+ Öffnet die Datei zum Schreiben und Lesen. Wenn die Datei nicht existiert, wird sie neu angelegt. Vorhandene Daten bleiben erhalten. Der Dateizeiger steht am Ende der Datei. Jedes der Attribute kann mit einem vorangestellten b kombiniert werden, Binärdateien um den Zugriff auf Binärdateien zu ermöglichen. Daraus ergeben sich dann folgende Kombinationen:

• br, br+ • bw, bw+ • ba, ba+ Geöffnete Dateien müssen wieder geschlossen werden, um Systemres- fclose sourcen zu schonen und anderen Prozessen den Zugriff zu ermöglichen.

fclose($handle); Der Zugriff auf die geöffnete Datei erfolgt mit einer ganzen Palette von Dateifunktionen, denen alle ein Parameter gemeinsam ist: Das bereits erwähnte Datei-Handle. Zeilen- und Zeichenweise aus einer Textdatei lesen Die Funktion fgets liest aus einer Datei von der Position des Dateizei- fgets gers.

$bytestream = fgets($handle, 2048); Dies erfolgt, bis mindestens eines der drei folgenden Ereignisse eintritt: • Die Anzahl Bytes, die angegeben wurde, ist erreicht • Ein Zeilenende wurde erreicht. Dies wird anhand des Zeilenumbruchs \n erkannt. Das Zeilenumbruch-Tag
, das in HTML benutzt wird, erkennt die Funktion nicht. • Das Dateiende wurde erreicht. Die Funktion fread entspricht fast der Funktion fgets, interpretiert aber fread nicht den Zeilenumbruch. Damit wird tatsächlich bis zum Dateiende oder der angegebenen Anzahl Bytes gelesen – die Funktion kann daher auch für Binärdateien genutzt werden:

$bytestream = fread($handle, 4096); Das Beispiel liest 4 KByte aus einer Datei, die vom Handle $handle adressiert wird. Das Einblenden eines Tipps des Tages ist eine typische Anwendung. AnwendungsSenden Sie jeden Tag per FTP eine Textdatei an Ihren Webserver, die beispiel automatisch in eine HTML-Seite eingebettet werden soll. Das folgende Skript liest die Datei zeilenweise und gibt nur die Zeile aus, die zu einem bestimmten Tag passt. Den Aufbau der Nachrichtendatei finden Sie in Listing Listing 8.8:

V V V 1 2 3 4 5 6 7 8 9 10 11 12 13 14 A B C D E

170 ________________________________ 8 Daten bewegen: Dateisystem und FTP Listing 8.7: Zeilenweises Lesen einer Datei (file_fgets)

"; } } fclose($fp); ?> Das Beispiel in Listing 8.7 enthält keine Besonderheiten, wendet aber mehrere übliche Techniken an, die Sie beherrschen sollten. Zuerst wird ein Handle auf die Datei erstellt und in der Variablen $fp gespeichert:

$fp = fopen("news.txt", "r"); Die Zuweisung in der Schleife liest die nächste Zeile aus der angegebenen Datei, immer zu Stücken von 1 024 Byte (1 KB):

$line = fgets($fp, 1024) Der gesamte Ausdruck wird FALSE, wenn der Zugriff misslingt. Dies ist normalerweise nur am Ende der Datei der Fall. Hier werden also Zugriff, Auslesen der Daten und Prüfung auf Dateiende in einem einzigen Ausdruck zusammengefasst. Der Dateizeiger wird automatisch weiter gesetzt, sodass die Ausgabe mit die nächste Zeile fortgesetzt wird:

echo fgets($fp, 1024)."
" Dies funktioniert beim Ablauf nun so: Jede Zeile wird gelesen und mit Hilfe der Funktion preg_match analysiert:

preg_match("/^\[[$select]+\]/", $line) Die Funktion preg_match nutzt einen einfachen regulären Ausdruck zur Prüfung. Mehr zu regulären Ausdrücken finden Sie in Abschnitt 13.3 Suchexperten: Reguläre Ausdrücke ab Seite 323. Solche Ausdrücke beschreiben Suchmuster und dienen hier der Erkennung der Wochentage in eckigen Klammern. Wenn die Prüfung erfolgreich, in der Datei der Wochentagscode vorhanden war, dann wird die darauf folgende Zeile ausgeführt:

echo fgets($fp, 1024) . "
"; Diese liest nun die unmittelbar nach dem Code stehende Zeile und gibt sie aus. Die komplette Nachrichtendatei hat damit zwangsläufig folgenden Aufbau (jede Zeile endet mit einem Zeilenumbruch): Listing 8.8: Die Nachrichtendatei news.txt für Listing 8.7

[Mon] Heute beginnt die Woche! [Tue] Nur noch 4 Tage [Wed] Das Wochenende naht

8.1 Dateisystem _______________________________________________________ 171 [Thu] Fast fertig [Fri] Freitag nach 1... [Sat] Was suchst Du hier heute? [Sun] Was suchst Du hier heute? Praktisch kann man so sehr effizient jede erdenkliche Art von Textdateien analysieren, Teile daraus extrahieren und beliebig verwenden. Der umgekehrte Weg – das Schreiben von Dateien – ist der nächste logische Schritt. Zeilenweise in eine Textdatei schreiben Mit fputs werden Zeichenketten in eine Textdatei geschrieben. Die Angabe der Länge ist optional – ohne Angabe werden alle verfügbaren Daten übertragen. Wenn Sie Daten vor der Ausgabe formatieren möchten, nutzen Sie die Funktion sprintf. Die so bearbeitete Zeichenkette kann leicht weiter verwendet werden, auch zum Schreiben in eine Textdatei. Auch andere Formatierfunktionen wie number_format sind eine gute Ergänzung. Das folgende Beispiel schreibt die Felder eines Formulars in eine Textda- Anwendungstei. Mehr Informationen zu Formularen finden Sie im Abschnitt 9.1 beispiel Daten aus einem Formular ermitteln ab Seite 197. Der Name der Datei setzt sich aus dem Zeitstempel (Datum und Uhrzeit im Unix-Timestamp-Format) und einer fortlaufenden Nummer zusammen.

Form schreiben
Listing 8.9: Formulardaten in Dateien speichern (file_formsave)

V V V 1 2 3 4 5 6 7 8 9 10 11 12 13 14 A B C D E

172 ________________________________ 8 Daten bewegen: Dateisystem und FTP break; case (strlen($plz) != 5): break; case (strlen($ort) < 2): break; default: $disabled = 'disabled'; $message = 'Vielen Dank für Ihre Nachricht'; $fc = 0; $fn = 'data/form_' . (string) time(); while (file_exists($file = sprintf('%s_%02d.frm', $fn, $fc++))); $fp = fopen($file, 'w'); foreach($_POST as $field => $value) { $field = str_pad(ucfirst("$field:"), 10, ' ', STR_PAD_RIGHT); fwrite($fp, sprintf("%s% 21s\n",$field,$value)); } fclose($fp);

} ?>

Name type="Text" size="30" name="name" value="">
Anschrift type="Text" size="30" name="adresse" value="">
PLZ type="Text" size="3" name="plz" value=""> Ort type="Text" size="26" name="ort" value="">
type="Submit" value="Absenden">
Das Skript verwendet einige Techniken, die auch in anderen Zusammenhängen interessant sind. So erfolgt vor der Abspeicherung eine Prüfung der Formulardaten. Das Beispiel in Listing 8.9 funktioniert außerdem nur, wenn der Webnutzer Schreibrechte im Unterverzeichnis /DATA hat (und dieses auch existiert).

8.1 Dateisystem _______________________________________________________ 173

Restriktionen: Rechte auf einem Webserver Bei der Einrichtung der Schreibrechte müssen Sie daran denken, dass der Webserver als spezielles Benutzerkonto (beispielsweise »nobody«) arbeitet und alle Benutzer aus dem Internet quasi über dieses Konto hereinkommen. Eine sehr strenge Vergabe der Rechte verhindert möglicherweise, dass die hier gezeigten Skripte funktionieren.

Funktionsweise Zur Prüfung wird eine switch-Anweisung eingesetzt. Diese prüft nacheinander die Felder auf bestimmte Eigenschaften. Wenn die Eigenschaft nicht TRUE ist, wird mit der Block mit break verlassen:

switch (TRUE) { case (strlen($name) < 3): break; case (strlen($adresse) < 5): break; case (strlen($plz) != 5): break; case (strlen($ort) < 2): break; Nur wenn alle Felder korrekt ausgefüllt wurden, wird der defaultZweig ausgeführt. Als Information wird dem Benutzer das Formular erneut angezeigt – diesmal mit gesperrten Feldern und einer Nachricht:

default: $disabled = 'disabled'; $message = 'Vielen Dank für Ihre Nachricht'; Dann werden die Formulardaten gespeichert. Zuerst ist dazu ein eindeutiger Dateiname erforderlich. Den ersten Teil bildet ein fester Pfad und ein Zeitstempel:

$fc = 0; $fn = 'data/form_' . (string) time(); Falls gleichzeitig mehrere Zugriffe auf das Formular erfolgen, wird der Zeitstempel (der sich nur jede Sekunde ändert), mit einer fortlaufenden Nummer ergänzt. Dazu wird in einer while-Schleife solange auf bereits vorhandene Nummern geprüft, bis ein freier Wert gefunden wurde. Gleichzeitig wird dieser freie Wert als Pfadname in der Variablen $file abgelegt. sprintf formatiert den Dateinamen in der Form data/form98124758_00.frm:

while (file_exists($file = sprintf('%s_%02d.frm', $fn, $fc++))); Anschließend wird diese Datei angelegt und zum Schreiben geöffnet:

$fp = fopen($file, 'w');

V V V 1 2 3 4 5 6 7 8 9 10 11 12 13 14 A B C D E

174 ________________________________ 8 Daten bewegen: Dateisystem und FTP Dann werden alle Felder ausgelesen (es spielt keine Rolle, wie viele es sind oder wie diese heißen):

foreach($_POST5 as $field => $value) Für die Darstellung werden die Feldname rechtsbündig mit Leerzeichen aufgefüllt (str_pad). Um eine bessere Lesbarkeit zu erreichen wird das erste Zeichen großgeschrieben (ucfirst):

$field = str_pad(ucfirst("$field:"), 10, ' ', STR_PAD_RIGHT); Die Felddaten selbst werden linksbündig aufgefüllt, dazu eignet sich sprintf. Die fertigen Daten werden in die Datei geschrieben:

fwrite($fp, sprintf("%s% 21s\n",$field,$value)); Folgen keine Felder mehr, wird die Datei geschlossen:

fclose($fp); Die folgende Abbildung zeigt eine typische Datei und wie die Daten abgelegt sind: Abbildung 8.3: Ansicht der Datei mit Formulardaten im Editor Das Formular selbst enthält wenig Besonderheiten. Beachten Sie die Sperrung der Felder nach erfolgreicher Anzeige. Abbildung 8.4: Das Formular nach dem Ausfüllen

Um Formulare ansehnlich zu gestalten, sollten Sie HTML-Tabellen einsetzen. So lassen sich Texte und Felder unabhängig voneinander ausrichten. Anzahl der Zeilen einer Textdatei bestimmen Die Anzeige der Zeilenanzahl ist leicht möglich, wenn die Funktion file in Verbindung mit count genutzt wird.

5

Mehr Informationen über die Bedeutung dieses Arrays finden Sie im Abschnitt 9.1 Daten aus einem Formular ermitteln ab Seite 197.

8.1 Dateisystem _______________________________________________________ 175 Das Skript kombiniert zwei Funktionen in einer Zeile. Die innere wird zuerst ausgeführt.

Listing 8.10: Anzahl Zeilen einer Textdatei (file_count)

Die Funktion file liest eine Datei in ein Array ein. Um die Daten geht es dabei nicht, weswegen auch keine Zuweisung an eine Variable erfolgt:

file("news.txt") Statt dessen wird das Array an count übergeben. Diese Funktion gibt die Anzahl der Elemente – hier also die Anzahl der Zeilen – zurück. echo gibt dieses Ergebnis aus. Datei in eine Zeichenkette einlesen Manchmal wird der Inhalt einer Datei nicht in einem Array, sondern in einer einzigen Zeichenkette benötigt. Vor allem im Hinblick auf die regulären Ausdrücke bieten sich gute Verarbeitungsmöglichkeiten an. Als mdirekter Befehl bietet sich file_get_contents an:

Das @ unterdrückt Fehlermeldungen, die erzeugt werden, wenn die Datei nicht existiert oder die Zugriffsrechte nicht ausreichen.

Umgang mit dem Dateizeiger beim Lesen und Schreiben Beim Lesen von Zeichen aus Dateien kann man, wenn auch mit etwas Aufwand, gezielt auf bestimmte Zeilen und Zeichen zugreifen. Prinzipiell ändert das aber nichts am sequenziellen Zugriff auf den Inhalt. Spätestens beim Schreiben hilft auch der Dateizeiger nicht weiter. Sie können also niemals auf direktem Weg mittendrin Zeilen einfügen oder an den Anfang setzen. »Anhängen« ist wörtlich zu nehmen, Daten können nur am Ende angefügt werden. Wenn ab der Position des Dateizeigers geschrieben wird, überschreibt PHP den an dieser Stelle befindlichen Inhalt. »Einfügen« gibt es nicht – in der Notation einer Textverarbeitung ist der Zugriff immer nach dem Prinzip »Überschreiben« gestaltet. Ebenso problematisch ist das gezielte Löschen einer Zeile. Nur mit der Kombination mehrerer Befehle und entsprechendem Leistungsbedarf des Skripts ist dies möglich. Das folgende Beispiel zeigt die prinzipielle Vorgehensweise, unter Nutzung eines Arrays:

V V V 1 2 3 4 5 6 7 8 9 10 11 12 13 14 A B C D E

176 ________________________________ 8 Daten bewegen: Dateisystem und FTP Listing 8.11: Löschen einer Zeile aus einer Textdatei (file_deleteline)

'; unset($myfile[$line]); $fh = fopen("$datei.bak", "w"); fputs($fh, implode('', $myfile)); fclose($fh); ?> Das Skript liest wieder eine Datei in ein Array ein.

$myfile = file($datei); Dann wird ein Element dieses Arrays gelöscht; in diesem Fall das vierte:

unset($myfile[$line]); Anschließend wird eine neue Datei zum Schreiben geöffnet, gebildet aus dem ursprünglichen Namen und der Dateierweiterung ».bak«:

$fh = fopen("$datei.bak", "w"); Das Array wird mit implode zu einer Zeichenkette zusammengefasst und diese dann in die Datei übertragen:

fputs($fh, implode('', $myfile)); Beachten Sie, dass Arrays nullbasiert indiziert sind, die erste Zeile der Textdatei also den Index 0 trägt. Entsprechend wird im Beispiel die vierte Zeile gelöscht. Der Zeilenumbruch, der jede Zeile abschließt, bleibt beim Einlesen in das Array erhalten, sodass implode ohne weitere Parameter genutzt werden kann. Das ist natürlich zugleich ein flexibler Weg, mit Dateien umzugehen, denn Sie können mit den Arrayfunktionen komfortabel die Daten manipulieren. Große Datenmengen sind aber damit trotzdem nur schwer handhabbar. Verwenden Sie dann besser Datenbanken, die auf diese Art der Manipulation spezialisiert sind. Wenn Sie nur lesend arbeiten, können Sie auch die internen Dateizeiger nutzen. Beim Schreiben finden diese keine Berücksichtigung. Mit dem Dateizeiger arbeiten Bei den bisherigen Ausführungen wurde unterstellt, dass der Dateizeiger beim Lesen automatisch weiter wandert und beim Schreiben an das Ende der geschriebenen Zeichen gesetzt wird. Wenn Sie sich aber in einer Textdatei frei bewegen möchten, ist eine gezielte Positionierung des Zeigers sinnvoll. Dateiende beachten

Bei solchen Bewegungen ist es wichtig, nicht versehentlich über das Dateiende hinaus zu lesen. In diesem Fall bricht entweder die genutzte Funktion ab oder PHP reagiert mit einem Laufzeitfehler. Das Dateiende können Sie mit feof ermitteln:

8.1 Dateisystem _______________________________________________________ 177 // übergeordnete Schleife if (feof($handle)) { break; } // Ende der Schleife Die Funktion feof gibt TRUE zurück, wenn das Ende der Datei erreicht wurde. Einige Funktionen werden mit Fehlermeldungen reagieren, wenn Zugriffe nach Erreichen des Dateiendes erfolgen. Die Funktion ftell gibt die aktuelle Position des Dateizeigers an. Sie Dateizeiger können sich damit eine bestimmte Position merken, andere Operationen positionieren ausführen und dann die alte Position mit fseek wiederherstellen. Wenn Sie mit Textdateien arbeiten, werden Sie vielleicht versuchen, Daten an bestimmten Positionen zu speichern. Eine Operation »Einfügen« gibt es jedoch nicht. Dateieigenschaften ermitteln

is_dir ermittelt, ob der Name ein Verzeichnis ist. An der Art des Na- Verzeichnis mens selbst kann man nicht feststellen, ob es eine Datei oder ein Ver- erkennen zeichnis ist. Die Funktion is_file ermittelt, ob es sich um eine reguläre Datei han- Datei erkennen delt. Dies gilt auf einem Windows-System für alle Dateien. Unix-Systeme können noch zwischen Dateien und Links unterscheiden.

is_link ermittelt, ob es sich um einen Link (Verweis) handelt. Die unter Hardlinks Windows üblichen Verknüpfungen sind keine echten, sondern nur simu- erkennen (Unix) lierte Links. PHP erkennt diese als Datei, nicht als Link. Die Funktion filemtime gibt das Datum zurück, an dem die Datei das Dateidatum letzte Mal geändert wurde. Der Rückgabewert ist der Unix-Zeitstempel, der für die Ausgabe formatiert werden muss, beispielsweise mit date(). Hinweise zu dieser Funktionen finden Sie in Abschnitt 13.4.2 Datumsfunktionen ab Seite 337.

filesize gibt die Größe der Datei in Byte zurück. Nutzen Sie die folgen- Dateigröße de Funktion, um Umrechnungen in KByte oder MByte vorzunehmen: pow(2,10)) { if ($v > pow(2,20)) { $r = (integer)($v / pow(2,20)); $r .= " MB"; } else { $r = (integer)($v / pow(2,10)); $r .= " KB"; } // end if } else {

Listing 8.12: Umrechnung von Byte in KB/MB (file_getreal)

V V V 1 2 3 4 5 6 7 8 9 10 11 12 13 14 A B C D E

178 ________________________________ 8 Daten bewegen: Dateisystem und FTP $r = (string) $v . " Byte"; } // end if return $r;

} $size = filesize(“news.txt”); echo GetRealVolume($size); ?>

Zuerst wird die Größe einer Datei ermittelt:

$size = filesize(“news.txt”); Die Funktion GetRealVolume() nutzt die Potenzfunktion pow, um die Grenzen für die Umrechnung zu erkennen. Zuerst werden alle Daten größer als 1 KByte (210) erkannt:

if ($v > pow(2,10)) Dann erfolgt noch mal die Unterscheidung für 1 MByte (220):

if ($v > pow(2,20)) Um den Wert in MB darzustellen, wird dieser durch 220 dividiert und dann wird » MB« angehängt.

$r = (integer)($v / pow(2,20)); $r .= " MB"; Ebenso wird mit KByte verfahren:

$r = (integer)($v / pow(2,10)); $r .= " KB"; Alle anderen Fälle belassen den Wert und hängen die Zeichenkette »Byte« an:

} else { $r = (string) $v . " Byte"; } // end if Der Wert wird dann zurückgegeben:

return $r; Statusinformationen aktualisieren

Die Statusinformationen werden von PHP in einem internen Cache gehalten. Wenn Sie eine Datei mehrfach abfragen, wird sich die Antwort nicht ändern, auch wenn sich die Dateieigenschaften geändert haben. Sie können diesen internen Puffer mit der folgenden Funktion löschen und dann die Eigenschaften erneut abfragen:

clearstatcache(); Wenn Sie damit rechnen können, dass sich die Eigenschaften während der Ausführung eines Skripts nicht ändern, sollten Sie diesen Puffer in Anspruch nehmen. Dateizugriffe benötigen einen erheblichen Teil der Systemleistung, vor allem wenn viele Nutzer parallel zugreifen. Denken Sie bei der Auswahl eines Lösungsweges daran, dass sich Dateien zum Speichern von Daten nur bedingt eignen. Schneller sind Datenbanken, die oft über ausgefeilte Puffermechanismen verfügen.

8.1 Dateisystem _______________________________________________________ 179

8.1.3

Mit Dateien arbeiten

Um mit Dateien effektiv arbeiten zu können, sind Funktionen zum Verschieben, Kopieren, Löschen und Umbenennen notwendig. Diese Funktionen werden nachfolgend vorgestellt. Dateien kopieren Die einfachen Dateifunktionen setzen voraus, dass Sie genau wissen, wie copy die zu behandelnden Dateien heißen. Pfadangaben können nach Bedarf eingesetzt werden. Das folgende Skript legt zu jeder Datei eine Sicherheitskopie an und ändert dabei die Dateierweiterung. Als Datenquelle werden die in Listing 8.9 erzeugten Formulardateien genutzt.

"; } } closedir($dp); ?>

Listing 8.13: Kopieren einer Datei mit Umbenennung (file_copy)

Wenn Sie das Skript ausführen, benötigen Sie Schreibrechte für den Webnutzer im Verzeichnis /DATA. Falls die vorangegangenen Beispiele funktionierten, sollte dies bereits eingestellt sein. Sie können auch ein anderes Verzeichnis mit Hilfe der Variablen $dir konfigurieren. Das Skript durchläuft ein Verzeichnis, das zuvor mit opendir geöffnet wurde:

$dp = opendir($dir); while ($file = readdir($dp)) Dann wird mit Hilfe eines regulären Ausdrucks festgestellt, ob es ein Verzeichnisstammeintrag (».« für das aktuelle Verzeichnis oder »..« für das übergeordnete) oder eine bereits gesicherte Datei ist:

if (!preg_match('/(\.{1,2}|\.bak)$/', $file)) Informationen zu regulären Ausdrücken und der Funktion preg_match Was ist finden Sie im Abschnitt 13.3 Suchexperten: Reguläre Ausdrücke ab Seite preg_match? 323. Für alle anderen Dateien erfolgt nun der Kopiervorgang, verbunden mit der Umbenennung durch Anhängen der Dateierweiterung .BAK.

copy("$dir/$file", "$dir/$file.bak"); Die Funktion copy gibt TRUE zurück, wenn der Kopiervorgang erfolgreich war. Andernfalls wird FALSE zurückgegeben. PHP gibt außerdem eine

V V V 1 2 3 4 5 6 7 8 9 10 11 12 13 14 A B C D E

180 ________________________________ 8 Daten bewegen: Dateisystem und FTP Warnung aus, die Sie unterdrücken können, indem Sie ein @ vor den Funktionsaufruf stellen:

@copy("$dir/$file", "$dir/$file.bak"); Beim copy-Befehl sind Platzhalterzeichen leider nicht erlaubt. Hinweise, wie Sie mit ganzen Verzeichnissen umgehen, finden sie deshalb im nächsten Abschnitt. Umbenennen

Die Funktion rename benennt Dateien um. Ein anderer Einsatz ist das Verschieben von Dateien, denn rename kann ebenso wie copy mit vollständigen und auch relativen Pfaden umgehen. Stimmt der Pfad von Quelle und Ziel nicht überein, wird die Datei verschoben, auch wenn der Dateiname gleich bleibt. Das folgende Skript holt den letzten Stand der Dateien aus der Sicherung wieder zurück. Dazu werden zuerst alle Dateien gelöscht, für die eine Sicherung existiert. Dann werden die Dateinamen umbenannt.

Listing 8.14: Umbenennen und Löschen von Dateien (file_unlink)

"; } } } closedir($dp); ?> Bedenken Sie hier auch, dass der Nutzer im Zielverzeichnis Schreibrechte benötigt. Wie bereits zuvor gezeigt, wird das gesamte Verzeichnis durchlaufen. Nun werden nur die Dateien herausgefiltert, zu denen eine Sicherungskopie existiert:

if (preg_match('/\.bak$/', $file)) Falls dazu ein Original vorhanden war, kann der Umbenennungsvorgang beginnen:

if (file_exists("$dir/$file")) Dieser Prozess besteht aus zwei Schritten. Zuerst wird das Original gelöscht, dann wird die Sicherungskopie in den Namen des Originals umbenannt:

unlink ("$dir/$file"); rename ("$dir/$file.bak", "$dir/$file");

8.2 Umgang mit Verzeichnissen _________________________________________ 181 Windows-Nutzern mag die Bezeichnung unlink wenig erklärlich sein. Dateien löschen Sie stammt aus dem Unix-Umfeld. Dennoch funktioniert sie auch unter Windows ohne Probleme.

8.2

Umgang mit Verzeichnissen

Hier und im Folgenden wird immer von Verzeichnissen gesprochen, um über einheitliche Termini für alle Plattformen zu verfügen. Unter Windows sind damit »Ordner« (engl. folder) gemeint.

8.2.1

Basisfunktionen

Basisfunktionen für den Verzeichniszugriff sind dir und mkdir. Klassen und Funktionen Wenn Sie objektorientierte Funktionen mögen, können Sie die virtuelle dir Klasse dir verwenden, um auf Verzeichnisse in Form von Eigenschaften und Methoden zuzugreifen. Andernfalls stehen auch klassische Funktionen zur Verfügung. Verzeichnisse anlegen und löschen Zum Anlegen wird mkdir verwendet, gelöscht wird dagegen mit rmdir. Die Funktionen erwarten jeweils einen Verzeichnisnamen mit oder ohne Pfad dahin. Die Operation nimmt keinen Bezug auf andere Vorgänge mit Dateien, deshalb wird hier auch kein Verzeichnis- oder Dateihandle benötigt.

8.2.2

Im Verzeichnissystem bewegen

Um sich im Verzeichnissystem bewegen zu können, reichen die Verzeichnisfunktionen aus. Die Anwendung ist dennoch nicht trivial, denn es sind viele Sonderfälle zu betrachten, wenn man sich im Verzeichnisbaum frei bewegt. Vorab zwei Besonderheiten. • Beim Durchlaufen eines Verzeichnisses werden immer auch zwei »Verzeichnisse« ausgegeben, die folgende Bedeutung haben: - ».«. Der alleinstehende Punkt verweist auf das aktuelle Verzeich-

nis. - »..«. Der doppelte Punkt ist ein Alias für das übergeordnete Ver-

zeichnis. Sie können diese Namen angeben, wenn eine Leseoperation ein Ziel benötigt. Sie können diese Namen aber nicht verwenden, um sie zu Löschen, Umzubenennen oder zu Verschieben. • Verzeichnisse werden sequenziell durchsucht, so wie das Betriebssystem die Daten zurückgibt. Weder die Reihenfolge noch die Folge von Dateien oder Verzeichnissen kann beeinflusst werden.

V V V 1 2 3 4 5 6 7 8 9 10 11 12 13 14 A B C D E

182 ________________________________ 8 Daten bewegen: Dateisystem und FTP Das folgende Skript liest ein Verzeichnis komplett und bietet Sortiermöglichkeiten. Es basiert auf Arrays – in denen die Verzeichnisinformationen zwischengespeichert werden. Listing 8.15: Verzeichnis auslesen und sortieren (file_dirsort)

A..Z
"; $dscsort = "Z..A"; $dp = opendir($dir); while ($file = readdir($dp)) { $directory[(int) is_dir($file)][] = $file; } echo '

Verzeichnisse

'; foreach($directory[1] as $z) echo "$z
"; $sort = $_GET['sort']; if ($sort == 'dsc') { rsort($directory[0]); } else { asort($directory[0]); } echo "

Dateien $ascsort $dscsort

"; foreach($directory[0] as $z) echo "$z
"; closedir($dp); ?> Der Umgang mit Arrays und den zur Verfügung stehenden Funktionen wurde bereits in Kapitel 5 Komplexe Datenstrukturen: Arrays ab Seite 83 gezeigt. Informationen zum $_GET-Array finden Sie im Abschnitt 9.2 Daten per URL weiterreichen ab Seite 213. Die Überführung in ein Array zeigt der folgende Ausschnitt:

while ($file = readdir($dp)) { $directory[(int) is_dir($file)][] = $file; } Dabei wird ein zweidimensionales Array angelegt. Die erste Dimension enthält nur zwei Elemente, 0 und 1. Die Entscheidung, ob eine Datei unter 0 oder 1 einsortiert wird, trifft die Funktion is_dir, die als Index genutzt wird. Entsprechend ist schon beim Anlegen des Arrays die Trennung von Verzeichnissen und Dateien erfolgt. Der Index der zweiten Dimension bleibt leer – PHP kümmert sich darum und vergibt fortlaufend Ziffern.

8.3 Verbindungen zu Servern ___________________________________________ 183 Abbildung 8.5: Ausgabe einer sortierten Verzeichnisliste

8.3

Verbindungen zu Servern

Daten können nicht nur von der lokalen Festplatte des Webservers gelesen werden. Dieselben Funktionen eignen sich auch für den Zugriff auf entfernte Server per HTTP und FTP.

8.3.1

HTTP-Verbindungen

Um Daten per HTTP oder FTP zu laden, sind keine besonderen Befehle file_get_content nötig. Die Funktion fopen kann als Dateiname auch ein vollständig qualifizierten URL verarbeiten. Die betreffende Seite wird geöffnet und kann mit den üblichen Zugriffsmethoden gelesen werden. Meist wird jedoch die Datei als Zeichenkette benötigt. Die Funktion file_get_content ist ideal zum Lesen, sie akzeptiert jede URL und gibt den Inhalt der gelesenden Datei als Zeichenkette zurück.

Vorsicht! Copyright! Bevor Sie einfach auf fremde Server zugreifen, informieren Sie sich über bestehende Copyrights und andere Rechte der Sitebetreiber. Am sichersten ist es, sich eine schriftliche Genehmigung einzuholen. Das »Absaugen« fremder Inhalte ist generell kritisch.

V V V 1 2 3 4 5 6 7 8 9 10 11 12 13 14 A B C D E

184 ________________________________ 8 Daten bewegen: Dateisystem und FTP Beispiel. Auslesen von Daten bei »Amazon.de« Der Einsatz ist äußerst vielfältig. Sie können so auf sehr einfache Art und Weise Inhalte aus fremden Seiten auslesen. Das folgende Beispiel zeigt, wie Sie nach Eingabe einer ISBN-Nummer die aktuelle Platzierung des Titels bei Amazon ermitteln können. Listing 8.16: Fremde Inhalte per HTTP auslesen (amazon)

Platzierung von Buchtiteln ermitteln

'; } else { if (preg_match('|\s*([0-9.]{1,8})\s*]+>|Ui' , $strSite, $arrResult)) { $rank = $arrResult[1]; $result = "Platzierung für ISBN $isbn ist: $rank"; } else { $result = 'Keine Platzierung'; } } } else { if ($_SERVER['REQUEST_METHOD'] == 'POST') { $result = "ISBN falsch"; } } echo <<
ISBN:
$result
FORM; ?> Dieses Skript verwendet Formulare. Informationen dazu enthält Abschnitt 9.1 Daten aus einem Formular ermitteln ab Seite 197. Parameterisierte Anfragen dieser Art sind kritisch, weil Sie nicht mit überschaubarem Aufwand jeden Fehlerzustand abfangen können. So reagiert Amazon auf eine nicht existente ISBN mit einer Weiterleitung zu einer Fehlerseite. Eine Weiterleitung (Redirect) unterstützt der HTTPWrapper von PHP nicht. Im Ergebnis wird eine leere Seite zurückgege-

8.3 Verbindungen zu Servern ___________________________________________ 185 ben, was mit file_get_contents aber kein Problem darstellt. Allerdings kann der Zugriff aus anderen Gründen (Leitung, Server, Provider, ...) misslingen. Deshalb werden Fehlermeldungen mit dem Fehleroperator @ unterdrückt. Eingabefehler kompensiert der reguläre Ausdruck am Anfang. preg_replace entfernt hier alle Zeichen, die nicht Ziffern oder das Zeichen »X« sind.

$isbn = preg_replace('/[^0-9]|X/i', '', $isbn); if (preg_match('|\d{10}|', $isbn)) Informationen zu regulären Ausdrücken und der Funktion preg_replace Was ist finden Sie Abschnitt 13.3 Suchexperten: Reguläre Ausdrücke ab Seite preg_replace? 323. Dann wird die URL eingelesen und in einer Zeichenkette gespeichert:

$strSite = @file_get_contents($url); Die Funktion strstr sucht das Vorkommen der Zeichenkette »Verkaufsrang« und gibt die Zeichenkette $strSite ab dem Fundort zurück.

$strSite = strstr($strSite, 'Verkaufsrang'); Wurde diese Stelle gefunden, holt ein regulärer Ausdruck die Platzierung aus dem Rest der Zeichenkette.

if (preg_match('|<[^>]+>([0-9.]{1,8})]+>|U' , $strSite, $arrResult)) In der Seite6 sieht eine solche Platzierung folgendermaßen aus:

Amazon.de Verkaufsrang 93 Der fett gedruckte Teil ist der Beginn der Zeichenkette in $strSite. Der Ausdruck ermittelt den Inhalt des ersten HTML-Tags, das folgt – funktioniert also unabhängig davon, ob Amazon irgendwann die Farbe ändert oder <span> statt verwendet. Erkannt werden zwischen den Tags Ziffern und der Punkt (Tausendertrennung). Abbildung 8.6: Mögliche Ausgabe des Skripts

Beachten Sie, dass der Zugriff einige Zeit in Anspruch nehmen kann, abhängig von der Verbindung des PHP-Servers zu Amazon, der Seitengröße und der Reaktionsgeschwindigkeit des Amazon-Servers. Eine Besonderheit ist noch für die Schreibweise der URL anzumerken. Schreibweise des Diese muss, konform zu der entsprechenden RFC, mit einem schließen- URL 6

Amazon-Version von Februar 2004

V V V 1 2 3 4 5 6 7 8 9 10 11 12 13 14 A B C D E

186 ________________________________ 8 Daten bewegen: Dateisystem und FTP den »/« geschrieben werden. Andernfalls funktioniert es nicht. Im Browser müssen Sie dass nicht, weil der das ergänzt. Falls der Inhalt einer Seite nicht als Zeichenkette, sondern als Array benötigt wird, nutzen Sie die Funktion file (statt file_get_content). Andere Wrapper-Zeichenketten Die Dateifunktionen nutzen das neue Stream-Modul in PHP5 (eingeführt mit PHP 4.3). Dies erlaubt den Zugriff auf entfernte Server mit den folgenden Protokollen: • file:// Dateizugriff. Dies ist der Standardwert und die Angabe kann deshalb entfallen. kann beispielsweise /home/users/docs.txt sein. • http:// HTTP-Zugriff auf normale Webserver. kann beispielsweise www.comzept.de sein. • https:// Zugriff per SSL auf geschützte Websites. • ftp:// • ftps:// Zugriff auf FTP mit und ohne Verschlüsselung. Als kann beispielsweise mit der Syntax user:[email protected] auch der Zugriff auf geschützte Server erfolgen. Speziell für FTP gibt es auch ein eigenes Funktionsmodul, dass nachfolgende vorgestellt wird.

8.3.2

FTP-Verbindungen mit Dateifunktionen

Ebenso wie mit dem Zugriff per HTTP funktioniert es auch mit FTP. Dabei besteht die Problematik oft in der Notwendigkeit, Kennwort und Name zu übermitteln. Dafür gibt es eine besondere Form der URL, die jeder FTP-Server verstehen kann. FTP-Adresse

Bei FTP-Servern gilt folgender Aufbau des URL:

ftp://user:[email protected]/pfad/datei.ext HTTP-Adresse

HTTP-Server hingegen werden folgendermaßen angesprochen:

http://server.domain.tld:port/pfad/datei.ext/ Andere Protokolle können Sie hier nicht verwenden. Die Portangabe kann entfallen, wenn es sich um die Standardports handelt. Für HTTP ist der Standardport 80, für FTP ist es 21. Zugriff auf andere Ressourcen PHP ist gut geeignet, auf alle Ressourcen eines Servers zugreifen zu können. Sicher kennen Sie die vielen Free-E-Mail-Angebote im Internet, die

8.4 FTP-Funktionen____________________________________________________ 187 oft Browser-basierte Schnittstellen bereitstellen. Der Vorteil liegt auf der Hand. Sie können Ihre E-Mail von jedem Punkt aus nur mit einem Browser lesen. Damit sind Sie unabhängig von der Bereitstellung eines entsprechenden E-Mail-Clients. Die üblichen Protokolle für E-Mail sind POP3 und IMAP4. Am weitesten POP3 abfragen verbreitet ist POP3. Entsprechend groß ist auch das Angebot an POP3Servern. Die per SMTP empfangene E-Mail wird dann den Clients per POP3 zum Download zur Verfügung gestellt. Die Umsetzung auf den Browser geschieht sinnvollerweise im Server. Als Ausgangspunkt für derlei Versuche eignen sich die Stream-Funktion Wie es weiter aus dem Modul stream sowie fsockopen als »Urfunktion« der Server- geht... zugriffsmethoden. fsockopen ist jedoch verhältnismäßig primitiv und baut eine reine Socket-Kommunikation (also auf TCP-Ebene) auf. Für den nötige Protokollablauf müssen Sie selbst sorgen. Das heißt in der Praxis, dass Sie ausgezeichnete Kenntnisse der verwendeten Protokoll, beispielsweise POP3 oder SMTP benötigen. An dieser Stelle sei auf das Buch »PHP 5 – Grundlagen und Profiwissen« vom Autor dieses Buches verwiesen, dass ab Mai 2004 bei Hanser erhältlich ist und diese Themen tiefgehend behandelt. Um den Zugriff so einfach wie möglich zu gestalten und Bibliotheksentwicklern weitere Werkzeuge an die Hand zu geben, besteht in PHP5 die Möglichkeit, eigene Protokolle zu »erfinden«. Das sieht dann folgendermaßen aus:

fopen(“mysql://localhost:3306/select/fromlist/table/where”); Dazu muss man freilich eine Klasse entwickeln, die die Anfrage verarbeitet und Zeichenketten so zurückgibt, dass der Zugriff mit den Dateifunktionen auf den von fopen erzeugten Handler gelingen kann.

8.4

FTP-Funktionen

Eine ganze Reihe von Funktionen dient dazu, speziell für die Verbindung mit FTP-Servern eingesetzt zu werden. Die Funktionsliste zeigt eindrucksvoll die Möglichkeiten, in diesem Abschnitt wird das Prinzip anhand einiger Beispiele erläutert.

8.4.1

Verbindung zu FTP-Servern

Die Funktion ftp_connect gibt ein Handle der Verbindung zurück. Mit diesem Handle arbeiten alle anderen Funktionen. Handles sind Verweise auf Verbindungen.

V V V 1 2 3 4 5 6 7 8 9 10 11 12 13 14 A B C D E

188 ________________________________ 8 Daten bewegen: Dateisystem und FTP

Ersetzen Sie in allen folgenden Skripten die Zeichenfolge durch den Namen oder die IP-Adresse Ihres FTPServers, beispielsweise beim Provider. Wenn der FTP-Server eine Anmeldung verlangt, ändern Sie auch die folgenden beiden Zeilen (sind in jedem Skript vorhanden):

$name = "Administrator"; $pass = "unknown";

Der anonyme Zugriff auf FTP-Server FTP-Server können entweder anonyme Verbindungen akzeptieren oder Name und Kennwort verlangen. Anonyme Server dienen meist als reine Downloadserver und verfügen nicht über Schreibrechte. Das folgende Skript zeigt, wie Sie eine Verbindung zu einem FTP-Server aufbauen. Listing 8.17: Verbindung zu einem FTP-Server herstellen (ftp_open)

"; $open = ftp_connect($host); if ($open) echo "FTP-Server $host gefunden"; ?> Das Skript definiert zuerst eine FTP-Adresse. Die im Browser übliche Protokollangabe »ftp://« kann hier entfallen.

$host = ""; Dann wird die Verbindung geöffnet und – wenn dies erfolgreich war – ein Handle darauf zurückgegeben.

$open = ftp_connect($host); Das Handle ist entweder FALSE oder ein ganzzahliger Wert, den PHP als TRUE interpretiert.

if ($open) echo "FTP-Server $host gefunden"; Die folgende Ausgabe ist zu sehen, wenn der FTP-Server erwartungsgemäß reagiert hat: Abbildung 8.7: Ausgabe des Skripts aus Listing 8.17 im Erfolgsfall

Das nun existierende Handle – im letzten Beispiel in der Variablen $open – wird in allen folgenden Beispielen weiter verwendet. Beachten Sie, dass der Zugriff in Abhängigkeit vom FTP-Server und der Verbindung einige Zeit benötigt. Vor allem wenn Sie zu Hause entwickeln und nur per ISDN mit dem Internet verbunden sind, kann das Öffnen eines Servers im Internet spürbar dauern.

8.4 FTP-Funktionen____________________________________________________ 189

Handlungsanleitungen in Form von Handles Im Buch wird sehr oft der Begriff »Handles« genutzt. Generell handelt es sich dabei um eine Referenz (Verweis) auf eine bestimmte Verbindung, beispielsweise zu einem anderen Server.

Zugriff auf geschützte Seiten Oft ist für die Verbindung mit einem FTP-Server die Angabe eines Benutzernamens und Kennwortes erforderlich. Das folgende Beispiel zeigt, wie dies mit PHP möglich ist.

"; $name = "Administrator"; $pass = "clemens"; $open = ftp_connect($host); if ($open) { echo "Verbindung zu $host hergestellt.
"; $logged = ftp_login($open, $name, $pass); if ($logged) { echo "Anmeldung erfolgt

"; } } ?>

Listing 8.18: Zugriff auf FTPServer mit Name und Kennwort (ftp_login)

Die Verbindungsaufnahme erfolgt, wie schon zuvor gezeigt. Dann erfolgt eine Anmeldung an den FTP-Server. Der FTP-Server lässt Verbindungen zu geschützten Seiten erst nach einer Authentifizierung zu.

$logged = ftp_login($open, $name, $pass); Diese Anmeldung kann jederzeit erfolgen, muss als zeitlich nicht zwingend der Verbindungsaufnahme folgen. Dies ist im FTP begründet, denn die Initiative zur Übertragung der Anmeldung ergreift der Client. Die Ausgabe in Abbildung 8.8 erfolgt, wenn der Verbindungsversuch erfolgreich war. Abbildung 8.8: Erfolgreiche Ausführung des Skripts aus Dieses Beispiel zeigt, wie die Verbindung komplett hergestellt wird. Alle Listing 8.18 anderen FTP-Funktionen benötigen diese Eröffnung der Verbindung oder die verkürzte, in Listing 8.18 gezeigt Version.

V V V 1 2 3 4 5 6 7 8 9 10 11 12 13 14 A B C D E

190 ________________________________ 8 Daten bewegen: Dateisystem und FTP

8.4.2

Navigation im Verzeichnisbaum

FTP-Server sind wie lokale Verzeichnissysteme organisiert. Sie benötigen also Funktionen, mit denen Sie sich im Verzeichnisbaum bewegen können. Das folgende Skript versucht vom angewählten Stammverzeichnis »wwwroot« aus das übergeordnete Verzeichnis zu erreichen. Listing 8.19: Navigation auf FTP-Servern (ftp_cdup)

"; ftp_cdup($open); echo ftp_pwd($open); ?> Dieses Skript setzt voraus, dass $open bereits ein gültiges Handle enthält, die Verbindung also steht. Falls die Site geschützt ist, muss außerdem die Anmeldung mit ftp_login erfolgt sein. Zuerst wird das aktuelle Verzeichnis gewechselt. Falls die Funktion ftp_chdir FALSE zurückgibt, bricht das Skript mit einer Fehlerausgabe ab:

@ftp_chdir($open, "wwwroot") or die("Fehler bei chdir"); Läuft das Skript weiter, wird das neue Verzeichnis ausgegeben:

echo ftp_pwd($open); echo "
"; Dann erfolgt ein Wechsel in das nächst höhere Verzeichnis:

ftp_cdup($open); echo ftp_pwd($open); Die Ausgabe erscheint in der gezeigten Form nur, wenn das übergeordnete Verzeichnis tatsächlich existiert. Man muss allerdings beachten, dass der durchsuchbare Verzeichnisbaum dem des angebotenen virtuellen Servers entspricht. Das gezeigt Root-Verzeichnis muss nicht (und darf eigentlich auch nicht) die Root des Servers sein. Abbildung 8.9: Navigation im Verzeichnisbaum

Navigationen in fremden Verzeichnissystemen können misslingen. Sie sollten deshalb die Fehlerausgaben mit dem @-Operator unterdrücken, wie es im letzten Listung gezeigt wurde.

8.4 FTP-Funktionen____________________________________________________ 191 Erzeugen und Entfernen eines Verzeichnisses Wenn entsprechende Rechte auf einem FTP-Server gegeben sind, können Sie auch Verzeichnisse anlegen und sich darin bewegen, Dateien hineinkopieren und wieder löschen.



Listing 8.20: Erzeugen und Wechseln von Verzeichnissen (ftp_chdir)

Dieses Skript erzeugt ein neues Verzeichnis, wechselt dann dorthinein und gibt den Namen des nun aktuellen Verzeichnisses aus. Ebenso ist natürlich das Löschen möglich. Dazu müssen Sie sicherstellen, dass das zu löschende Verzeichnis das aktuelle ist. Das nächste Skript setzt dafür die ftp_cdup-Funktion ein.

"); ftp_chdir($open, "upload"); echo "Aktuelles Verzeichnis: ". ftp_pwd($open); ftp_cdup($open); ftp_rmdir($open, "/upload"); echo "
Aktuelles Verzeichnis: ". ftp_pwd($open); ?>

Listing 8.21: Löschen von Verzeichnissen auf einem FTPServer (ftp_rmdir)

Die ftp_cdup-Funktion stellt sicher, dass das Verzeichnis nicht mehr das aktuelle ist. Fehlt sie, würde das zu der in Abbildung 8.10 gezeigten Fehlermeldung führen. Ist das Verzeichnis vorhanden und stimmen die Zugriffsrechte, wird es mit ftp_rmdir entfernt. Zuvor sollten Sie sicherstellen, dass es leer ist. Auch bei diesen Funktionen ist der Fehleroperator @ sinnvoll. Die Skripte Was bedeutet müssen dann natürlich um eine eigene Fehlerbehandlung ergänzt wer- das @-Zeichen? den. Abbildung 8.10: Fehlerausschrift, wenn das aktuelle Verzeichnis gelöscht wird

Anzeige von Verzeichnisdaten Ist das richtige Verzeichnis auf dem FTP-Server erreicht, kann eine Dateiliste helfen, die richtige Datei auszuwählen. Der Test auf Eigenschaften ist nicht ganz einfach, weil verschiedene FTP-Server hier nicht einheitlich arbeiten. Das folgende Skript zeigt, wie man es auf einem zwar primitiven, aber vergleichsweise sicheren Weg ausführen kann. Wegen der vielen Zugriffe – jeder Name führt zu einem meist nicht erfolgreichen

V V V 1 2 3 4 5 6 7 8 9 10 11 12 13 14 A B C D E

192 ________________________________ 8 Daten bewegen: Dateisystem und FTP chdir per FTP – kann das Skript einige Zeit in Anspruch nehmen und auch etwas Bandbreite benötigen. Listing 8.22: Ausgabe einer Verzeichnisliste mit FTP (ftp_nlist)

Verzeichnisse


'; foreach($slist[0] as $file) echo $file[count($file)-1] . "
"; echo '
Dateien
'; foreach($slist[1] as $file) echo $file[count($file)-1] . "
"; ?> Nach der bereits gezeigten Verbindungsaufnahme wird eine umfassende Verzeichnisinformation abgerufen:

$nlist = ftp_rawlist($open, ftp_pwd($open)); $nlist enthält jetzt ein Array, dass für jede Datei bzw. jedes Verzeichnis einen Eintrag enthält. Dieses Array wir durchlaufen:

foreach($nlist as $file) Das erste Zeichen enthält den Buchstaben »d«, wenn es sich um ein Verzeichnis handelt. Der erste Teil der Zeile ist eine Angabe der Art:

tuuugggooo Dabei steht »t« für den Typ (d für Verzeichnis, - für Datei oder l für Link). Die Dreiergruppen bilden die Zugriffsrechte ab (u für User, g für Group, o für Other). Zur Unterscheidung von Dateien und Verzeichnissen reicht also das erste Zeichen. Entsprechend dieser Angabe werden die Zeilen in ein zweites Array $slist überführt.

if ($file[0] == 'd') Dieses zweidimensionale Array enthält nun in der ersten Dimension die Unterscheidung Datei und Verzeichnis, in der zweiten dagegen ein weiteres Array, dass die Felder der Einträge speichert. Die Felder sind durch

8.4 FTP-Funktionen____________________________________________________ 193 Leerzeichen getrennt. Die Aufsplittung wird deshalb mit explode vorgenommen:

$slist[0][] = explode(' ', $file); } else { $slist[1][] = explode(' ', $file); Jetzt werden die beiden Arrays behandelt: Index 1 enthält die Dateien – diese werden aufsteigend sortiert:

asort ($slist[1][count($slist[1])-1]); Index 0 enthält die Verzeichnisse – diese werden absteigend sortiert:

rsort ($slist[0][count($slist[0])-1]); Jetzt folgen einige Formatierungen der Seite mit HTML und die Ausgabe der beide Arrays mit foreach.

echo '
Verzeichnisse
'; foreach($slist[0] as $file) echo $file[count($file)-1] . "
"; echo '
Dateien
'; foreach($slist[1] as $file) echo $file[count($file)-1] . "
"; Die Ausgabe zeigt Verzeichnisse und Dateien an, sortiert und getrennt nach dem Typ, zeigt Abbildung 8.11. Abbildung 8.11: Anzeige der Dateien und Verzeichnisse eines FTP-Servers

In der Referenz finden Sie weitere Beispiele und eine Auflistung aller Optionen. Sie können sich natürlich auch mit einem weiteren foreach alle Elemente ausgeben lassen. Außer dem Namen wird der Eigentümer, die Größe und das Datum angezeigt.

V V V 1 2 3 4 5 6 7 8 9 10 11 12 13 14 A B C D E

194 ________________________________ 8 Daten bewegen: Dateisystem und FTP In einigen Fällen kann auch eine Unterscheidung des Betriebssystems notwendig werden. Dann hilft ftp_systype; die Funktion erkennt den Basistyp des Systems (beispielsweise »Unix«). Das letzte Listing, dass die Funktion ftp_rawlist verwendete, funktionierte mit der Version PHP5.0.0RC1 nicht unter Windows. Der Fehler ist bereits aus PHP4 bekannt, wo seit 4.0.6 der Einsatz nur unter Unix möglich war. Erstaunlich, dass sich dieses Verhalten auch mit PHP5 nicht gebessert hat, obwohl der Bug bekannt ist. Das Bildschirmfoto für die Abbildung wurde unter Linux gemacht, damit der erhoffte Effekt wenigstens gezeigt werden kann.

8.4 FTP-Funktionen____________________________________________________ 195

9 Daten aus dem Browser: Formulare und Links Formulare sind der Schlüssel zu interaktiven Webseiten. Der Nutzer wird in die Lage versetzt, Daten einzugeben, und der Server kann auf diese Daten in vielfältiger Weise reagieren. Die Darstellung der Formulare erfolgt mit Hilfe dafür vorhandener HTMLTags, den Formular-Elementen. Die Übertragung der Daten zum Server übernimmt HTTP mit den Methoden POST oder GET.

9

Daten aus dem Browser: Formulare und Links

9.1 Daten aus einem Formular ermitteln __________________________________ 197

9.1

Daten aus einem Formular ermitteln

Formulare werden enorm leistungsfähig, wenn es gelingt, die Daten in einem Skript weiterzuverarbeiten. Wie dies erfolgt, finden Sie in diesem Abschnitt.

9.1.1

Formulare in HTML erstellen

HTML-Formulare sind der einzige praktikable Weg, wie Daten vom HTML-Formulare Browser zum Server und damit zu Ihrem Skript gelangen können. Ein Formular besteht aus dem
-Tag mit verschiedenen Parametern und den Feld-Elementen, HTML-Tags zur Darstellung von Eingabefeldern. HTML-Eingabefelder können nur innerhalb des -Containers existieren. Außerhalb werden Sie je nach Browser nicht oder falsch dargestellt, funktionslos sind sie dort auf jeden Fall. Welche Funktion nun tatsächlich ausgelöst wird, wenn das Formular versendet wird, hängt vom Parameter action des Tags ab. Vielleicht kennen Sie bereits die Möglichkeit mit Formularen E-Mails zu versenden. Das ist aber eine Aktion, die der Browser selbst ausführt. Er erkennt den Präfix mailto: und startet das E-Mail-Programm7.

E-Mail-Formular Nachricht: E-Mail:
Das einfache Formular aus Listing 9.1 sendet eine E-Mail. Der gesamte Prozess läuft allerdings clientseitig ab. Dabei erkennt der Browser die Zeichenfolge mailto: und ruft das lokal installierte E-Mail-Programm auf. Ohne ein solches Programm funktioniert das Skript nicht. Eleganter ist natürlich ein vollständig im Server ablaufender Prozess.

7

Mithin funktioniert die Sache nur, wenn der Browser mailto: kennt.

Listing 9.1: Einfaches Formular in HTML, noch ohne PHP

V V V 1 2 3 4 5 6 7 8 9 10 11 12 13 14 A B C D E

198 __________________________ 9 Daten aus dem Browser: Formulare und Links

Ausflug in die Welt von HTTP Wenn ein Formular abgesendet wird, teilt der Browser dies dem Server mit einem speziellen HTTP-Kommando mit: POST. Der Webserver weis dann, dass im Körper der Anforderung weitere Informationen stehen – die Formulardaten. Diese erscheinen dort als zeilenweise Liste, bestehend aus dem Feldnamen, einem, Gleichheitszeichen und den Felddaten.

E-Mail per Skript versenden In solchen Fällen ist ein Skript auf dem Server notwendig, das unabhängig vom Browser und dessen Installationsumgebung E-Mails versenden kann. Praktisch ist dazu im Formular nur eine Zeile auszutauschen:

Zwei Dinge sind hier anders: zum einen wird als auszuführender Befehl für den -Tag nicht mehr eine lokale Anweisung angegeben, sondern ein Skript auf dem Server. Zum anderen wird explizit auf die zu verwendende Datenübertragungsmethode gezeigt: POST. Browserseitig können Formulare ausgewertet und der Inhalt der Felder beeinflusst werden, indem eine Skriptsprache eingesetzt wird, die der Browser versteht, beispielsweise JavaScript. Im Beispiel wurde bereits gezeigt, wie ein Text-Feld erzeugt wird. In Tabelle 9.1 finden Sie eine Übersicht über alle in HTML erlaubten Feldelemente. Tabelle 9.1: HTML-Formularelemente

Element

Beschreibung

Attribute

text

Einzeiliges Eingabefeld

size, value, name

checkbox

Kontrollkästchen

value, checked, name

radio

Optionsfelder

value, checked, name

submit

Sendeschalter

value, name

reset

Schalter zum Rücksetzen

value, name

password

Verdecktes Eingabefeld

size, value, name

hidden

Unsichtbares Feld

value, name

button

Schaltfläche

value, name

image

Bild, ersetzt submit

src, name, Bildattribute (img)

file

Eingabefeld und Schaltfläche

name, accept

Wenn Sie im Umgang mit diesen Elementen unsicher sind, konsultieren Sie eine HTML-Dokumentation. Die hier vorgestellten Anwendungen arbeiten mit Elementen, wie sie bereits unter HTML 3.2 definiert wurden.

9.1 Daten aus einem Formular ermitteln __________________________________ 199 Auswertung von Formulardaten Die Auswertung und Übergabe der Formulardaten in PHP ist recht ein- $_POST fach. PHP erkennt selbstständig die vom Browser übertragenen Daten und platziert diese in entsprechenden Arrays. Für Formulare – deren Daten per POST übertragen werden – heißt das Array $_POST. Dies ist ein so genanntes Superarray, das heißt, es ist nicht nur global sondern ohne weiteres zutun auch in allen Funktionen und Klassen aufrufbar. Meist ist der Zugriff auf skalare Variablen einfacher. Folgende Technik Bequemer hat sich bewährt, um Standardwerte zu sezten und den Zustand »Feld Umgang mit $_POST wurde ausgefüllt« zu erkennen:

$feld = isset($_POST[’feld’]) ? $_POST[’feld’] : ’stammwert’; Hier wird zuerst überprüft, ob das Element $_POST[’feld’] gesetzt ist; der Benutzer also Zeichen eingegeben hat. Ist das der Fall, wird eben dieser Inhalt in die Variable $feld übertragen. Andernfalls wird der Stammwert der konstanten Zeichenkette entnommen, die auch leer sein kann. Jedes Formularelement ist durch das Attribut name gekennzeichnet. Es erscheint in PHP als Index des $_POST-Arrays mit dem Namen des Formularelements; das Arrayelement ist dann mit den eingegebenen Daten gefüllt. Durch Bilder erzeugte Schaltflächen übermitteln in den Variablen $name_x und $name_y die Position des Mauszeigers, relativ zur linken oberen Ecke des Bildes. Das folgende Bild zeigt ein typisches Formular, das danach präsentierte Skript erzeugt es: Abbildung 9.1: Ein typisches Formular

"; echo "Ihr Name: {$_POST['name']}
";

Listing 9.2: Auswertung komplexer Fomulare (form_complex)

V V V 1 2 3 4 5 6 7 8 9 10 11 12 13 14 A B C D E

200 __________________________ 9 Daten aus dem Browser: Formulare und Links echo echo echo echo

"E-Mail: {$_POST['email']}
"; "Bewertung: {$_POST['rank']}
"; "Ihre Nachricht:
"; "
{$_POST['message']}
"; echo "Gekauft bei: {$_POST['purchase']}"; } else { echo <<Wie hat Ihnen das Buch "Programmieren lernen" bisher gefallen?

9.1 Daten aus einem Formular ermitteln __________________________________ 201
Mein Name:
Meine E-Mail:
Bewertung: 1 2 3 4 5 (Schulnoten)
Nachricht:
Wo haben Sie es gekauft? <select size=”1” name=”purchase”>
FORM; } // if-else ?> Das Beispiel mag auf den ersten Blick etwas unübersichtlich erscheinen. Analysieren Sie die Funktion schrittweise: Das Skript ruft sich selbst auf, der eigene Name wird PHP_SELF entnommen8:

Das Skript ist deshalb zweigeteilt, es enthält sowohl das Formular zum Senden als auch das Skript zum Auswerten. Die Antwort wird nur angezeigt, wenn die Variablen $sent und $name einen Wert enthalten. PHP wertet gefüllte Variablen (Formularelemente) als TRUE, ungefüllte oder nicht vorhandene als FALSE.

if ($sent and $name) { Damit $sent unabhängig von Aktionen des Benutzers ist, wird es als verstecktes Feld definiert:

In der Auswertephase werden die Daten wiedergegeben. Es werden lediglich die Variablen angezeigt, zu denen Felder existieren. Abbildung 9.2: Das gesendete Formular

8 Die geschweiften Klammern sind hier erforderlich, weil der Teil in einem Heredoc-Abschnitt steckt, wo die Auflösung von Arrayzugriffen versagt, wenn keine explizite Kennzeichnung erfolgt.

V V V 1 2 3 4 5 6 7 8 9 10 11 12 13 14 A B C D E

202 __________________________ 9 Daten aus dem Browser: Formulare und Links

9.1.2

Formularelemente analysieren

Im Beispiel in Listing 9.2 wurde bereits von der Tatsache Gebrauch gemacht, dass nicht vorhandene oder nicht ausgefüllte Formularelemente gezielt ausgewertet werden. Es ist daher wichtig zu wissen, wie sich bestimmte Elemente verhalten. Werteübergaben aus Formularfeldern checkbox

Das Kontrollkästchen (checkbox) überträgt den Wert des Attributes value. Wenn value nicht angegeben wurde, wird das aktivierte Kontrollkästchen als »on« übertragen. Ein nicht aktiviertes Kontrollkästchen überträgt nichts, die Variable für dieses Feld wird deshalb nicht erzeugt. Zur Prüfung in PHP5 bietet sich die Funktion empty an. Sie gibt true zurück, wenn das Feld leer war.

radio

Optionsfelder dienen der Auswahl aus einer fest begrenzten Wertemenge. Gruppen entstehen, indem mehrere dieser Felder den gleichen Namen tragen. Wird keines der Felder ausgewählt, erscheint es nicht als Variable. Wird eines ausgewählt, wird der Wert des Attributes value übertragen. Sie können die Angabe eines Wertes erzwingen, indem eine Option mit dem Attribut checked gesetzt wird.

text hidden

ADMINFORM; } } else { sqlite_create_function($db, 'MAKEDATE', 'makedate', 1); $news = sqlite_array_query($db, 'SELECT blog, source, MAKEDATE(date) AS date FROM ' . TABLE . ' ORDER BY date DESC'); foreach ($news as $blog) { echo << Quelle: {$blog['source']} vom {$blog['date']}


11.6 SQLite ganz praktisch _____________________________________________ 293
{$blog['blog']}
BLOG; } } sqlite_close($db); ?>

Wie es funktioniert Das Skript beginnt mit den beiden konfigurierbaren Parametern. Zuerst das Kennwort, dass den MD5-Hash des tatsaächlichen Kennworts darstellt. Die gezeigte Zeichenfolge entspricht dem Kennwort »Joerg«: define (PASSWORD, 'b8412671e5c89c647b691d6559129999');

Die Eingabe des Kennworts erfolgt später als GET-Parameter (siehe dazu Abschnitt 9.2 Daten per URL weiterreichen ab Seite 213) im URL. Der zweite konfigurierbare Wert ist der Name der Tabelle: define (TABLE, 'blog');

Nun wird eine Funktion definiert, die später von SQLite heraus aufgerufen wird, um die Ausgabe des Datums zu modifizieren: function makedate($date) { return "Eintrag vom: $date"; }

Solche benutzerdefinierten SQL-Funktionen sind eines der raffiniertesten Konstrukte in PHP5 und SQLite, denn sie »verweben« Datenbank und Code und erlauben kompakte Lösungen. Der Pfad zur Datenbank muss immer ein absoluter Pfad sein. Deshalb wird die Funktion realpath verwendet, um aus dem aktuellen Verzeichnis den Pfad zu ermitteln: $path = realpath('.') . '/blogger';

Dann wird die Datenbank geöffnet und ein Handle (in $db) erzeugt. Existiert die Datenbank nicht, wird sie erzeugt: if ($db = sqlite_open("$path/blogger.db", 0666, $error))

Nun ist zu prüfen, ob die Tabelle bereits existiert. Dazu wird die MasterTabelle abgefragt: $tables = sqlite_array_query($db, "SELECT * FROM sqlite_master WHERE type='table'");

Um den Tabellennamen zu erhalten, wird das Array der Tabelleninformationen durchlaufen und bei Erfolg die Variable $exists auf TRUE gesetzt:

V V V 1 2 3 4 5 6 7 8 9 10 11 12 13 14 A B C D E

294 __________________________ 11 Datenbanken: So werden Daten gespeichert $exists = false; foreach ($tables as $table) { if ($table['tbl_name'] == TABLE) { $exists = true; break; } }

Falls die Tabelle noch nicht existiert, wird sie angelegt: if (!$exists) { sqlite_query($db, 'CREATE TABLE ' . TABLE . ' (id INTEGER PRIMARY KEY, blog TEXT, source VARCHAR(100), date DATETIME )'); }

Alle weiteren Operationen gehen davon aus, dass die Tabelle existiert. Nun erfolgt die Auswertung des Administrationsformulars, das weiter unten noch erzeugt wird. Dazu wird geprüft, ob die Sendeschaltfläche gedrückt wurde. Mehr Informationen zu Formularen finden Sie im Abschnitt 9.1.2 Formularelemente analysieren ab Seite 202. if (isset($_POST['Send'])) {

Wurde das Formular ausgefüllt, wird das aktuelle Datum ermittelt. Mehr Informationen zu Datumsoperationen finden Sie im Abschnitt 13.4.2 Datumsfunktionen ab Seite 337: $date = date('j.n.Y, h:i');

Dann werden die Daten in die Datenbanktabelle eingetragen: sqlite_query($db, 'INSERT INTO ' . TABLE . ' (blog, source, date) ' . "VALUES ('{$_POST['blog']}', '{$_POST['source']}', '$date')"); } }

Der Rest des Skripts beschäftigt sich mit dem Eingabeformular und der Ausgabe der Daten. Das Eingabeformular wird erzeugt, wenn an den URL die Parameter admin=Kennwort angehängt wurden, wobei statt »Kennwort« das in der MD5-Form kodierte Wort zu verwenden ist.

11.6 SQLite ganz praktisch _____________________________________________ 295 Abbildung 11.6: Administration des Weblogs

Zuerst wird jedoch geprüft, ob überhaupt der Parameter admin existiert: if (isset($_GET['admin']))

Dann erfolgt der Vergleich mit dem gespeicherten Hash: if (md5($_GET['admin']) == PASSWORD)

Stimmt alles, wird die Administrationsform erzeugt: echo << Quelle:

Text:


ADMINFORM;

Ist kein Kennwort angegeben worden, wird die Ausgabe erzeugt: } else {

Dazu wird zuerst die benutzerdefinierte Funktion in SQLite bekannt gemacht. Definiert wurde makedate oben bereits: sqlite_create_function($db, 'MAKEDATE', 'makedate', 1);

Jetzt erfolgt die Abfrage, wobei im SQL-Befehl die Funktion MAKEDATE benutzt werden kann: $news = sqlite_array_query($db, 'SELECT blog, source, MAKEDATE(date) AS date FROM ' . TABLE . ' ORDER BY date DESC');

Das Ergebnis ist ein Array, dass mit foreach ausgegeben werden kann: foreach ($news as $blog) { echo <<
V V V 1 2 3 4 5 6 7 8 9 10 11 12 13 14 A B C D E

296 __________________________ 11 Datenbanken: So werden Daten gespeichert
Quelle: {$blog['source']} vom {$blog['date']}
{$blog['blog']}
BLOG; } }

Am Ende ist die Datenbank noch zu schließen: sqlite_close($db);

Abbildung 11.7: Ein einfaches Weblog

11.6.3 Diskussion SQLite ist für viele Fälle nicht nur sehr einfach einzusetzen, sondern auch clever programmierbar. Allein die benutzerdefinierten Funktionen erlauben sehr kompakte Lösungen – ein Feature, dass MySQL schmerzlich vermissen lässt. Es lohnt sich also unbedingt, sich mit SQLite auseinanderzusetzen, wenn ein Projekt ausschließlich für PHP5 geschrieben wird. Auf eine Abwärtskompatibilität zu PHP4 muss man hier freilich verzichten. Das vorgestellte Skript ist sehr primitiv. Sie sollten es vor dem ersten Einsatz noch um Fehlerroutinen erweitern, die mögliche Fehlzustände abfangen. Außerdem sollte vermieden werden, dass Einträge doppelt eingetragen werden. Und nicht zuletzt sollte eine Chance bestehen, die Einträge wieder zu entfernen oder dies automatisch nach Ablauf einer gewissen Zeit erledigen zu lassen.

11.6 SQLite ganz praktisch _____________________________________________ 297

12 Symbiose: PHP und JavaScript Richtig gute Webseiten entstehen, wenn Sie einen ganzheitlichen Ansatz bei der Programmierung verfolgen: Kombinieren Sie clever server- und clientseitige Techniken. Mit PHP5 und JavaScript stehen Ihnen zwei äußerst vielseitige Sprachen mit ähnlicher Syntax zur Verfügung. Dieses Kapitel zeigt Ihnen, wie Sie damit elegant umgehen. Schwerpunkt bildet der Umgang mit HTML-Formularen. JavaScript selbst ist im Web und in zahlreichen Büchern exzellent dokumentiert und wird hier ausnahmsweise vorausgesetzt.

12

Symbiose: PHP und JavaScript

12.1 Warum JavaScript? _______________________________________________ 299

12.1 Warum JavaScript? Einige Vertreter der reinen Web-Lehre werden beim Gedanken, JavaSc- Vor- und ript einzusetzen, erschaudern. Die Nachteile sind offensichtlich: Hat der Nachteile Benutzer JavaScript deaktiviert oder ist der Browser nicht von der neuesten Generation, gibt es Schwierigkeiten beim Einsatz. Um dieses zu umgehen, müssten einige Teile des Codes in PHP erneut ausgeführt werden, beispielsweise beim Prüfen von Formularen. Das ist doppelter Aufwand und erhöht die Fehlerquote. Auf der anderen Seite gehört meiner Meinung nach JavaScript zum festen Bestandteil der clientseitig verfügbaren Techniken. Der Prozentsatz der »Verweigerer« ist gering und bei vorteilhaftem Einsatz profitiert der Benutzer davon. Viele Web-Designer gehen inzwischen dazu über, ihre Website in zwei Versionen anzubieten – einer sehr einfachen ohne Skriptnutzung und einer Version, die Flash, JavaScript und Grafik nutzt. Beobachtungen zeigen, dass Benutzer die aufwändigste Version annehmen, wenn ihre Internetzugänge dies hinsichtlich der verfügbaren Bandbreite und Kosten gestatten. Mit jedem neuen ADSL-Anschluss und jeder besseren Standleitung in Unternehmen wird diese Schar größer. Bereiten Sie sich auf anspruchsvolle Benutzer vor und lernen Sie, clientseitige Techniken mit PHP5 zu verknüpfen.

12.1.1 Prinzipielle Fragen zu JavaScript Bevor Sie sich intensiv mit PHP5 und JavaScript auseinandersetzen, soll- Wie die ten Sie sich völlig klar darüber sein, wo was abläuft. PHP wird auf dem Zusammenarbeit Server verarbeitet. Die mit dem Skript erzeugten Ausgaben werden dann funktioniert zum Browser gesendet. Dieser verarbeitet die Informationen – HTML und natürlich auch JavaScript. Es liegt denn am gesendeten Code und der Interaktion des Benutzers, wie es weitergeht. Klickt der Benutzer auf einen Link, wird dieses als HTTP-Aktion an den Webserver gesendet. Ebenso funktioniert es bei Formularen – die Daten werden zusammengestellt und gesendet. Ein Skript auf dem Server kann die Daten dann verarbeiten. Datenaustausch zwischen den Welten Der Datenaustausch zwischen beiden Welten kann also nur an zwei Stellen stattfinden. Beim Aufbau der Seite können Sie Daten an JavaScript folgendermaßen übergeben: <script language="JavaScript"> var muster =

Der Wert der PHP-Variablen $muster steht nun in der JavaScriptVariablen muster zur Verfügung. Umgekehrt ist es schon etwas schwieriger. Daten vom Client können über einen Hyperlink (HTTP-GET), ein Formular (HTTP-POST) oder Cookies zum PHP-Skript gelangen. Coo-

V V V 1 2 3 4 5 6 7 8 9 10 11 12 13 14 A B C D E

300 ______________________________________12 Symbiose: PHP und JavaScript kies scheiden hier aus – die mit JavaScript erzeugten haben mit denen über HTTP gesendeten absolut nichts zu tun. Wenn Sie sowieso ein Formular senden, können Sie ihre mit JavaScript erzeugten Daten dort ablegen, wie der folgende Skriptausschnitt zeigt: Listing 12.1: JavaScript zum Versenden von Formularen verwenden

<script language="JavaScript"> function sendform() { document.form.myfield.value = "Wert"; document.form.method=post; document.form.submit(); } ...


Wenn das Formular abgesendet wird, ruft der Klick auf den SubmitSchalter die JavaScript-Funktion sendform() auf. Dort wird der Wert des versteckten Feldes "myfield" mit einem beliebigen Wert belegt und das Formular abgesendet. Alle anderen Felder werden unverändert verarbeitet. In PHP können Sie auf diese Variable über $_POST["myfield"] zu greifen, um den Wert auszulesen. Vorsicht mit HTML-Attributen Probleme beim Verzicht auf JavaScript

Um eine Schaltfläche zu beschriften, wird das Attribut value verwendet. Dies ist aber zugleich der Wert, der in PHP als Wert der Variablen übergeben wird. Wenn Sie nun Änderungen am Design vornehmen oder eine andere Sprache implementieren, ändern sich möglicherweise die Beschriftungen. Betrachten Sie folgende Schaltfläche:

Diese kann mit folgendem Skript ausgewertet werden: if ($_POST[‘submit’] == "Absenden")

Wenn Sie nun statt "Absenden" das Wort "Suchen" verwenden, funktioniert das Skript nicht mehr. Besser ist daher die folgende Auswertung: if (isset($_POST[‘submit’]))

Wenn Sie allerdings mehrere Submit-Schaltflächen unterscheiden möchten, funktioniert auch das nicht mehr. Dann wird Ihnen JavaScript eine große Hilfe sein. Wie das funktioniert, wird nachfolgend gezeigt.

12.1.2 JavaScript erkennen Alle Aktionen, die auf JavaScript basieren, setzen natürlich voraus, dass JavaScript auch aktiv ist. Jeder Benutzer kann in seinem Browser die Unterstützung für clientseitige Skriptsprachen abschalten. In manchen Firmen wird dies aus Sicherheitsgründen sogar administrativ festgelegt.

12.1 Warum JavaScript? _______________________________________________ 301 Wollen Sie diese Benutzer nicht ausschließen, ist eine einfachere Variante der Site ohne JavaScript sinnvoll. Die Abfrage der Browsereigenschaften ist nicht sinnvoll, weil diese ja nur So erkennen Sie die Möglichkeit, JavaScript zu verwenden, wiedergeben. Dies ist aber bei JavaScript allen modernen Browsern gegeben. Was tatsächlich eingestellt wurde, ist eine andere Frage. Das folgende Listing zeigt, wie dies funktionieren kann. Es ist aber nur eine von vielen möglichen Varianten. "; } else { echo ""; } // Aktion, die in Abhängigkeit von JS ausgeführt wird if (isset($_GET[’js’])) { echo "

JavaScript ist aktiviert...

"; } else { echo "

JavaScript ist nicht aktiviert...

"; } ?>

Das Skript nutzt das onLoad-Ereignis in JavaScript. Dies kann im Tag eingebaut werden und wird ausgelöst, bevor die Seite vollständig geladen wurde. Es ist mit Sicherheit das erste Ereignis, das aktiv wird. In diesem Fall wird einfach ein Reload der Seite ausgeführt – allerdings mit einem GET-Parameter im URL: js=1. Nachdem die Seite nun erneut aufgerufen wurde, kann in PHP die Variable $js ausgewertet werden. Jetzt gibt es zwei Möglichkeiten: • Entweder ist dies der erste Aufruf – dann ist $js nicht bekannt und das -Tag mit onLoad wird ausgeführt. Wenn JavaScript aktiv ist, kommt es zu einem erneuten Laden der Seite und die Variable $js ist bekannt, wie im nächsten Anstrich beschrieben. Falls JavaScript nicht aktiv ist, wird die Anweisung onLoad ignoriert und die Variable bleibt unbekannt. • Falls es sich schon um den zweiten Aufruf handelt, ist die Variable definiert. Dann wird die Zeile mit dem alleinstehenden -Tag ausgegeben. Da $js gesetzt ist, wird der Programmteil ausgeführt, der JavaScript benötigt.

Listing 12.2: So erkennen Sie JavaScript

V V V 1 2 3 4 5 6 7 8 9 10 11 12 13 14 A B C D E

302 ______________________________________12 Symbiose: PHP und JavaScript

12.2 Umgang mit Formularen JavaScript erlaubt manchmal einfach Lösungen für eine raffinierte Benutzerführung. Optimale Bedienbarkeit ist ein Erfolgsrezept für gute Webseiten.

12.2.1 Projekt: Eine Abstimmungssite Lassen Sie Benutzer ihre Stimme abgeben

Angenommen, Sie möchten auf Ihrer Webseite eine Abstimmung aufbauen, dann wäre ein Formular mit dem in Abbildung 12.1 gezeigten Aussehen so einfach wie möglich und so funktional wie nötig.

Abbildung 12.1: Formular zu Listing 12.3 in Aktion

Listing 12.3 zeigt den Code für dieses Formular, wobei die oben bereits beschriebene Mischung aus PHP und JavaScript mit der Wertübergabe verwendet wird. Listing 12.3: Formular für eine Online-Abstimmung (jsvote)

Vote-Form <script language="JavaScript"> function sendform(vote) { document.myform.method = "post"; document.myform.vote.value = vote; document.myform.action = ""; document.myform.submit(); }

Abstimmung

Bitte beurteilen Sie diese Site mit einer Schulnote:


12.2 Umgang mit Formularen ___________________________________________ 303 onclick=\"sendform(this.name)\">"; } ?>

{$_POST['vote']}"; } ?>

Im Skript wird ein Formular mit dem Namen myform und einem versteckten, aber leeren Feld vote definiert:


Dann wird eine Reihe Schaltflächen mit PHP erzeugt. Jede Schaltfläche enthält ein Ereignis onclick, das die JavaScript-Funktion sendform aufruft. Als Parameter wird der Name der Schaltfläche, die angeklickt wurde, übergeben (this.name): for($i = 1; $i <= 6; $i++) echo "";

Die Verarbeitung in der Funktion sendform simuliert ein vollständiges Formular. Zuerst wird die Methode eingestellt: document.myform.method = "post";

Dann wird das versteckte Feld vote mit dem Wert der Schaltfläche belegt. document.myform.vote.value = vote;

Jetzt wird das Ziel des Formulars eingestellt und dieses abgesendet: document.myform.action = ""; document.myform.submit();

Zugriff auf Formulare Der Zugriff auf Formulare ist per JavaScript sehr einfach. Wenn der Code im aktuellen Dokument steht, können Sie sich an folgenden Aufrufen orientieren. Dabei ersetzen Sie durch den Namen des Formulars (Attribut name="" im -Tag) und durch den Namen eines Felds (Attribut name="" im -Tag). Die folgenden Formen erlauben den Zugriff auf den Feldwert: document...value = "Neuer Wert"; variable = document...value;

Eigenschaften des Formulars werden folgendermaßen festgelegt:

V V V 1 2 3 4 5 6 7 8 9 10 11 12 13 14 A B C D E

304 ______________________________________12 Symbiose: PHP und JavaScript document..method = "Post"; document..action = "url";

Das Absenden des Formulars kann man auch durch JavaScript erledigen lassen, beispielsweise nach der Absolvierung aller Prüfungen: document..submit()

Konsistente Benutzerführung

Listing 12.4: Konsistente Ausgabe von Fehlermeldungen aus PHP und JS (jserror)

Was Sie bei der Entwicklung clientseitiger Prüfungen beachten sollten, betrifft eine konsistente Benutzerführung. Es ist unglücklich, zuerst mit JavaScript-seitigen »Alert«-Meldungen zu arbeiten und nach der Prüfung in PHP – die vielleicht umfassender und genauer ist – rote Fehlertexte auszugeben. In solchen Fällen mag Ihnen mit ein wenig JavaScript und dem HTML-Objektmodell geholfen sein. Das Skript in Listing 12.4 zeigt Fehlermeldungen im HTML-Text an – ebenso wie Sie dies mit PHP realisieren können. Es basiert auf einem Layer und einem kleinen Formular: Fehler anzeigen <script language="JavaScript"> ns = (document.layers) ? true : false; ie = (document.all) ? true : false; function show_error(Description) { if (Description.length < 2) { Description = ""; } if(ns) { document.layers['errors'].innerHTML = Description; document.layers['errors'].visibility = "show"; } if(ie) { document.all['errors'].innerHTML = Description; document.all['errors'].style.visibility = "visible" } }

12.2 Umgang mit Formularen ___________________________________________ 305 function check() { if (document.myform.namefield.value.length <= 2) { show_error('JavaScript: Zu wenige Zeichen'); } else { document.myform.action = ""; document.myform.submit(); } }


Abgefangen wird das onClick-Ereignis, dass zur ersten Prüfung mit JavaScript führt. In diesem Fall wird nur die Länge überwacht. Falls zu wenig Zeichen eingegeben wurden, erscheint eine entsprechende Meldung. Reicht die Anzahl der Zeichen aus, wird das Formular versendet – das Skript ruft sich dabei selbst auf. In PHP erfolgen weitere Prüfungen (im Beispielskript ist dies natürlich nur angedeutet). Je nach Struktur der Daten werden verschiedene Meldungen in der Variablen $errors abgelegt. In der Funktion show_error() erfolgt die Übergabe der Ergebnisse an JavaScript und die erneute Anzeige – ohne Bruch der Benutzerführung. Abbildung 12.2 zeigt dieses Wechselspiel – beim Absenden eines leeren Feldes erfolgt hier keine Übertragung zum Server. Mit wenig Aufwand ist es möglich, nun auch zwischen Browsern mit und ohne JavaScript zu unterscheiden. Ohne die Verfügbarkeit von JavaScript erfolgt die Prüfung der Daten nur mit PHP. Wenn JavaScript aktiviert ist, profitiert der Benutzer durch schnelleren Seitenaufbau und weniger Serverzugriffe. Abbildung 12.2: Perfekte Interaktion von JavaScript und PHP

V V V 1 2 3 4 5 6 7 8 9 10 11 12 13 14 A B C D E

306 ______________________________________12 Symbiose: PHP und JavaScript Browserprobleme beachten Wenn Sie mit Layern arbeiten, stoßen Sie schnell auf ein großes Problem: Die Implementierung im Internet Explorer und in Netscape basiert auf unterschiedlichen Objektmodellen. Es ist deshalb unbedingt notwendig, die entsprechenden Funktionen doppelt auszulegen. Browser erkennen

Die Entscheidung, welcher Browser zugreift, kann anhand folgender Codes getroffen werden: ns = (document.layers) ? true : false; ie = (document.all) ? true : false;

Der Netscape kennt das Objekt layers, entsprechend wird die Variable ns auf true gesetzt. Für den Internet Explorer wird dagegen ie gleich true, wenn das entsprechende Objekt all existiert. Was man als browserunabhängig bezeichnet ist ebenso eine weniger technische als mehr philosophische Frage. Die Beschränkung auf den kleinsten gemeinsamen Nenner ist keine gute Wahl, wenn Benutzer in Zeiten ständig besser verfügbarer Bandbreiten nach multimedialen Effekten schauen. Schlecht gemachte Seiten, die sinnlos mit solchen Effekten spielen, schrecken jedoch mehr ab. Es bleibt also in jedem Fall ein erheblicher Aufwand – zum einen eine mehrfache Optimierung, zum anderen eine die technischen Möglichkeiten optimal nutzende Programmierung. Eine praktische Anwendung der vorgestellten Tricks mit JavaScript wird im folgenden Abschnitt gezeigt.

12.3 Gutes Zusammenspiel: Der Chat Kleine Chat-Lösungen erfreuen sich nach wie vor großer Beliebtheit. Das So erstellen Sie eine Chat-Lösung hier vorgestellte Projekt realisiert einen Chat, der serverseitig auf MySQL und PHP-Sessions basiert, clientseitig die Darstellung aber durch JavaScript unterstützt. Dies vermindert etwas den Datentransfer zwischen Client und Server und bietet dadurch einen ähnlichen Komfort wie Chats, die auf Java basieren. Im Ganzen besteht der Chat aus einer Datenbanktabelle, die alle Einträge der Chatter ausnimmt und drei im Frame angeordneten Skripten.

12.3.1 Vorbereitung: Die Datenbank Zuerst der Code, mit dem Sie die Tabelle erzeugen können. Sie können diesen Text direkt an MySQL senden, beispielsweise mit dem Werkzeug phpMyAdmin. Listing 12.5: CREATE TABLE chat ( Tabellenstruktur id bigint(20) NOT NULL auto_increment, der Tabelle »chat« time varchar(10) NOT NULL, data text,

12.3 Gutes Zusammenspiel: Der Chat ____________________________________ 307 sender varchar(32) DEFAULT '1' NOT NULL, PRIMARY KEY (id), KEY id (id) );

Neben der ID wird ein Zeitstempel time und der Name des Chatters sender festgehalten. In data stehen die Einträge. Ein Frameset baut die Chatseite auf. Dort wird zum einen die Session gestartet und zum anderen eine JavaScript-Funktion definiert, die alle aktuellen Beiträge ausgibt. Diese Datei heißt index.php. Sie finden Sie in Listing 12.6. Die drei Framedateien bedienen den Chat folgendermaßen: • main.php Dieses Skript erzeugt keine sichtbaren Ausgaben. Per JavaScript lädt sie sich alle vier Sekunden erneut – dieser Wert ist natürlich einstellbar. Alle neuen Einträge, die in dieser Zeit aufgelaufen sind, werden in das JavaScript-Array msg[] geschrieben. Sie finden das Skript in Listing 12.7.

Aufbau des Frameset

• show.php Hier wird die Ausgabefunktion im Top-Frame aufgerufen. Alle Nachrichten, die aufgelaufen sind, werden nun angezeigt. Sie finden Sie in Listing 12.8. • send.php Neben der schon von main.php bekannten Ausgabefunktion werden hier zwei Aufgaben erledigt: Ein kleines Formular erfasst den Namen des Absenders und seine Nachricht. Diese Daten werden in die Datenbank geschrieben. Das Skript main.php kümmert sich dann wieder um die Darstellung. Sie finden Sie in Listing 12.9. Chatroom <script language="JavaScript"> msg = new Array(); function showchat() { for (i = 0; i < msg.length; i++) { show.document.write(msg[i]); show.document.write("
"); } show.document.write(""); }

Listing 12.6: Startdatei (index)

V V V 1 2 3 4 5 6 7 8 9 10 11 12 13 14 A B C D E

308 ______________________________________12 Symbiose: PHP und JavaScript

Listing 12.7: Steuerung im Hintergrund (main)


// MySQL-Daten hier ändern $hdlDB = mysql_connect('localhost', 'root', ''); $strSQL = "SELECT * FROM chat WHERE time > '$curTime'";

// Name der DB hier ändern $hdlRS = mysql_db_query('test', $strSQL, $hdlDB);

while ($arrRS = mysql_fetch_assoc($hdlRS)) { $arrMsg[] = '' . $arrRS['sender'] . ': ' . $arrRS['data']; $time = max($arrRS['time'], $time); } session_register('time'); ?> Chatroom <script language="JavaScript"> top.show.location.reload();

Listing 12.8: Ausgabe der laufenden Beiträge (show)

Chatroom <script language="JavaScript"> top.showchat();

12.3 Gutes Zusammenspiel: Der Chat ____________________________________ 309 2) {

Listing 12.9: Beiträge an den Chat absenden (send)

// MySQL-Daten hier ändern $hdlDB = mysql_connect('localhost', 'root', ''); $curTime = time(); $strSQL = "INSERT INTO chat (time, data, sender) VALUES ('$curTime','$newmsg','$sender')";

// Name der Datenbank hier ändern mysql_db_query('test', $strSQL, $hdlDB);

session_register('time'); } /* end if */ ?> Chatroom <script language="JavaScript"> top.show.location.reload();
<select name="sender" size="1">


Eine reine PHP-Lösung würde bei jedem Erneuern der Daten alle Frames neu laden. Eigentlich notwendig ist die Inanspruchname des Servers aber nur, wenn die Daten im Ausgabeframe aktualisiert werden müssen – also wenn neue Einträge vorliegen –, und wenn ein Benutzer selbst Daten abgesendet hat. Initiiert wird die Darstellung in main.php – alle vier Sekunden. Nach der Abfrage der Datenbank erfolgt die »Verlängerung« des Arrays msg[]: <script language="JavaScript"> top.show.location.reload();

Beim ersten Aufruf erscheinen alle bislang veröffentlichten Beiträge. Sendet aber ein Benutzer einen Beitrag ab oder erfolgt der automatische Refresh, sieht der vom Browser empfangene Quelltext für main.php innerhalb des JavaScript-Abschnitts beispielsweise folgendermaßen aus: <script language="JavaScript"> top.msg[0] = "Mixer: Ich komme hier selten vorbei"; top.show.location.reload();

Es werden also nur noch alle neuen Daten zum Browser übertragen – nicht die vielleicht schon hundert Zeilen, die im Chat bislang erzeugt wurden. Diese existieren nur in einer JavaScript-Variablen im TopFrame. Erst wenn der Top-Frame neu geladen wird, müssen auch alle Daten wieder übertragen werden. top.show.location.reload() stellt das Anzeigeframe (show) neu dar – ohne auf den Server zuzugreifen. Hier wird nur das Array msg[] ausgelesen. Ein identischer Aufruf findet sich auch in send.php, damit nach dem Absenden die eigenen Daten zügig im Anzeigeframe erscheinen.

12.3 Gutes Zusammenspiel: Der Chat ____________________________________ 311 Abbildung 12.3: Der Chatroom in Aktion

12.3.2 Mehr Leistung durch JavaScript Die vorgestellte Chatlösung ist sicher äußerst primitiv, enthält aber im Grunde alles, was an grundsätzlicher Funktionalität benötigt wird. Die feste Integration der Benutzer-Pseudonyme sollten Sie durch eine Benutzerverwaltung ersetzen. Außerdem ist die Ergänzung um Smileys, Benutzerfarben und spezielle Codes im Text empfehlenswert. HTML sollten Sie nicht zulassen, dies führt oft zu Missbrauch. Sinnvoll wäre auch, den Einstiegspunkt des Benutzers festzuhalten und erst ab diesem die Chatbeiträge auszugeben – sonst wird die Liste schnell endlos lang. Das alles ändert aber nichts am Prinzip. In jedem Fall sparen Sie durch JavaScript die Übertragung großer Datenmengen bei lebendigen Diskussionen und damit Bandbreite und Ladezeit. Ausblick Der Umgang mit JavaScript gehört zum Handwerkszeug des PHPProgrammierers und ist genauso elementar wie ein tiefgehendes Verständnis von HTML und den Vorgängen beim Zusammenspiel mit dem Webserver – also die Kenntnis der verwendeten Protokolle. Erst die ganzheitliche Betrachtung des Systems Webserver/Browser führt zu eleganten, leistungsfähigen und sicheren Lösungen. Jede Sprache und jeder Teil in diesem System hat seine spezifischen Stärken und ist für sich genommen weder besser noch schlechter als andere Teile. Die Aussage, bei der Formularverarbeitung auf JavaScript verzichten zu können (oder schlimmer: zu müssen), wenn man PHP zur Verfügung hat, ist grundsätzlich genauso falsch wie die grundsätzliche Verwendung von Flash, weil HTML die Wünsche der Designer nicht hinreichend erfüllt. Lassen Sie sich nicht von Puristen irritieren – schauen Sie über den Tellerrand und versuchen Sie optimale Lösungen zu finden, anstatt der vermeintlich reinen Lehre zu folgen. Ergänzungsmöglichkeiten In der Einführung zu MySQL finden Sie eine einfache, datenbankgestützte Mitgliederverwaltung, die sich ideal zur Ergänzung des Chats eignet.

V V V 1 2 3 4 5 6 7 8 9 10 11 12 13 14 A B C D E

312 ______________________________________12 Symbiose: PHP und JavaScript Schauen Sie sich einen kommerziellen Chat an, um weitere Funktionen kennenzulernen und dann in die eigene Lösung einzubauen. Wenn Sie jedoch planen, den Chat sehr groß werden zu lassen, ist ein Blick auf bereits etablierte Projekte sinnvoll, die teilweise sogar IRC unterstützen (Internet Relay Chat).

12.3 Gutes Zusammenspiel: Der Chat ____________________________________ 313

13 1000 kleine Helfer: Die PHP-Funktionen PHP kennt mehr als 2 000 Funktionen – Tendenz steigend. In vielen Fällen werden Sie einige Zeit für die Suche nach der passenden Funktion aufwenden. Es lohnt sich meist, denn die vorhandenen Lösungen sind schnell, stabil und sofort einsetzbar.

13

1000 kleine Helfer: Die PHPFunktionen

13.1 Übersicht_________________________________________________________ 315

13.1 Übersicht Beim täglichen Umgang mit PHP sind einige Funktionsgruppen beson- Was finden Sie in ders häufig im Einsatz. Es lohnt sich auch für Anfänger, damit die ersten diesem Kapitel? Experimente zu machen. In diesem Kapitel werden folgende Funktionen vorgestellt: • Bildfunktionen Mit diesem Funktionen aus der GD-Bibliothek können programmtechnisch Bilder erzeugt werden. • Reguläre Ausdrücke Suchen und Ersetzen in Perfektion – das ist das Aufgabengebiet regulärer Ausdrücke. Es gibt kaum ein professionelles Programm, das darauf verzichten kann. • Datumsfunktionen Datumsberechnungen sind ebenso häufig wie knifflig. Wie Sie schnell zu praktischen Lösungen kommen, zeigt der Abschnitt über die Datums- und Zeitfunktionen.

13.2 Hilfsdesigner: Bildfunktionen mit GD2 Bildfunktionen sind eine sehr beliebte und leistungsfähige Funktionen. Statt viele Bilder im Voraus mit aufwändigen Werkzeugen zu erzeugen, werden diese bei Bedarf in PHP generiert.

13.2.1 Bilddaten dynamisch erzeugen Wenn man sich den Vorgang der Übertragung einer Webseite vor Augen hält, erkennt man, dass alle Elemente der Seite auf einzelnen Anforderungen beruhen. Erst wird die aufgerufene Stammseite übertragen, dann wertet der Browser alle enthaltenen Elemente aus und ruft diese einzeln ab. Solange es Bandbreite und Systemleistung zulassen, erfolgt dieser Abruf parallel. Durch dieses Verfahren kann das Ziel eines Bildaufrufes natürlich von der Adresse der ursprünglichen Seite abweichen. Insbesondere ist die Angabe der Bildquelle nicht an eine Bilddatei gebunden, sondern es kann ebenso auch ein PHP-Skript sein. In HTML sieht ein Aufruf dann folgendermaßen aus:

Das Skript bild.php ist dann dafür verantwortlich, dem Browser die erwarteten Daten zu übertragen. Eine einfache Form wäre der Zugriff auf bereits vorhandene Bilddaten und die Versendung per Skript. Wenn Sie dem Skript Parameter übergeben, kann damit schon eine gewisse Dynamik erzielt werden.

V V V 1 2 3 4 5 6 7 8 9 10 11 12 13 14 A B C D E

316 ______________________________ 13 1000 kleine Helfer: Die PHP-Funktionen

Ein Beispielskript sähe dann so aus: Listing 13.1: Dynamische Bildauswahl



Das Skript besteht aus zwei wesentlichen Teilen. Zuerst wird ein Header erzeugt, der dem Browser den Bildtyp mitteilt: header("Content-type: image/gif");

Das ist nicht zwingend erforderlich, moderne Browser erkennen den Bildtyp automatisch. Ältere Browser haben aber manchmal Probleme mit dem korrekten Typ, außerdem könnte es die Verarbeitung beschleunigen, wenn der Typ nicht automatisch erkannt werden muss. Dann erfolgt die Auswahl der Bilddatei. Die Übertragung zum Browser erfolgt mit der Funktion readfile. readfile("/images/bild_a");

13.2.2 Bilder dynamisch erzeugen Das Prinzip der dynamischen Bildauswahl lässt sich perfektionieren, wenn auch das Bild selbst erst im Augenblick der Anforderung erzeugt wird. Wenn sich ein Benutzer angemeldet hat, könnte man eine Überschrift als Grafik erzeugen – mit dem Namen des Benutzers. Das folgende Skript zeigt das Prinzip. Dabei wird eine Eingabe verarbeitet und ein rechteckiges Bild erzeugt. Zuerst die Steuerdatei, in der das Bild angezeigt wird: Listing 13.2: HTML-Datei, in der ein Bild erzeugt wird (image_form)

Wie lautet Ihr Name?

Name:
2) {

13.2 Hilfsdesigner: Bildfunktionen mit GD2________________________________ 317 echo ""; } ?>

Aufgerufen wird, wenn das Bild im Browser zur Anzeige gelangt, das Skript imageheader.php. Zusätzlich wird der Parameter name übergeben, der aus dem Formular stammt. $width) { $text = 'Text ist zu breit'; $pt = 30; $x = $y = $height / 2; } else { $text = $_GET['name']; $x = round(($width / 2) - ($ttfwidth / 2), 0); $y = round(($height / 2) - ($ttfheight / 2), 0); } imagettftext($image, $pt, 0, $x, $y, $fcolor, $font, $text); # sende Bilddaten header("Content-type: image/png"); imagepng($image); imagedestroy($image); ?>

Dieses Skript erzeugt dynamisch ein Bild – im Beispiel im Format PNG – und sendet es direkt an den Browser. Danach wird es im Speicher zerstört – eine Kopie bleibt nicht auf der Festplatte. Das Erzeugen von Bildern mit PHP ist prinzipiell nicht schwer. Es gibt auch sicher sehr viele verschiedene Herangehensweisen. Einige grundlegende Techniken werden hier verwendet. Zuerst wird die Größe des Bildes festgelegt. Die Angabe erfolgt in Pixel. imagecreate erzeugt das Bild im Speicher und gibt ein Handle darauf zurück. Andere Funktionen, die Daten in das Bild schreiben, benötigen dieses Handle. Es wird hier in der Variablen $image gespeichert. $width = 468; $height = 80; $image = imagecreate($width, $height);

Listing 13.3: Erzeugung eines Bildes mit Kopfzeilen (imageheader)

V V V 1 2 3 4 5 6 7 8 9 10 11 12 13 14 A B C D E

318 ______________________________ 13 1000 kleine Helfer: Die PHP-Funktionen Anschließend werden Farben festgelegt. Die erste Farbe bestimmt den Hintergrund des Bildes. Farbwerte werden ebenfalls als Handle – also als Verweis auf Farbwerte – gespeichert. Im Beispiel werden zwei Farben benötigt. Die Angabe der Farben erfolgt mit Hilfe der drei Farbkanäle Rot, Grün und Blau. $bcolor = imagecolorallocate($image, 0xAA, 0xAA, 0xAA); $fcolor = imagecolorallocate($image, 0, 0, 0);

Dann wird der Font festgelegt. Die GD2-Bibliothek enthält einige eingebaute Fonts. Richtig Spaß macht der Umgang damit nicht. Besser ist es, Truetype-Fonts zu verwenden. Dazu muss die Freetype-Bibliothek vorhanden sein. Die meisten Provider bieten dies mit an. Wenn Sie lokal arbeiten, geben Sie den Pfad zu einem entsprechenden Font an. Auf einem Unix-Server kopieren Sie die Fonts in ein entsprechendes Verzeichnis, auf das PHP Zugriff hat. Unter Windows können Sie die installierten Fonts direkt verwenden: $font = "c:\windows\fonts\verdana.ttf";

Das Einpassen von Text in ein Bild ist nicht immer einfach. Bei festen Texten können Sie Position ausprobieren – aber dann ist die dynamische Bilderzeugung wenig sinnvoll. Mit Hilfe der Funktion imagettfbbox kann der Platz des Textes quasi vorausberechnet werden. Im Beispiel enthält $pt die gewünschte Größe des Textes in Punkt. $pt = 50; $area = imagettfbbox($pt, 0, $font, $_GET['name']);

Die Funktion gibt ein Array zurück, dass die Eckkoordinaten des Textes enthält. Breite und Höhe (in Pixel) entnehmen Sie folgendermaßen: $ttfwidth = $area[4]; $ttfheight = $area[7];

Beachten Sie, dass die Fontmaße immer in Punkt14 angegeben sind, die Bildmaße dagegen in Pixel. Falls die Breite für das in seinen Maßen feststehende Bild nicht ausreicht, wird eine Fehlermeldung angezeigt. Beachten Sie, dass Fehlerausgaben nicht im HTML-Code erfolgen können, sondern direkt in das Bild geschrieben werden: if ($ttfwidth > $width) { $text = 'Text ist zu breit'; $pt = 30; $x = $y = $height / 2;

Ist das Maß in Ordnung, wird die Position berechnet. Aus den Bild- und den Textmaßen wird sie mit folgender Formel so ermittelt, dass der Text immer zentriert wird: } else { $text = $_GET['name']; $x = round(($width / 2) - ($ttfwidth / 2), 0);

14

Siehe Kasten auf Seite 320.

13.2 Hilfsdesigner: Bildfunktionen mit GD2________________________________ 319 $y = round(($height / 2) - ($ttfheight / 2), 0); }

Dann erst wird der Text in das Bild geschrieben. Die Funktion imagettftext benötigt neben dem Handle für das Bild die Schriftgröße sowie einen Winkel, um den der Text gedreht erscheinen soll (dieser Wert ist hier 0). Zusätzlich sind die Koordinaten im Koordinatesystem des Bildes, die Farbe (hier: rot) und natürlich Font und Text aufgeführt. imagettftext($image, $pt, 0, $x, $y, $bcolor, $font, $text);

Nun ist das Bild fertig. Dem Browser wird ein spezieller HTTP-Header übermittelt, der den Typ angibt: header("Content-type: image/png");

Abschließend wird das Bild im gewünschten Format (PNG) im Speicher erzeugt und sofort an den Browser gesendet. imagepng($image);

Die im Speicher abgelegte Kopie wird dann vernichtet: imagedestroy($image);

Damit erscheint das Bild bereits: Abbildung 13.1: Dynamisch erzeugtes Bild (schwarze Schrift auf grauem Grund)

Die Fehlermeldung wird ebenfalls im Bild ausgegeben. Alternativ können Sie Fehlermeldungen nur in eine Datei schreiben und später auswerten. Das Skript, das für die Bildausgabe zuständig ist, endet nach der Ausgabe des Bildes. HTML-Ausgaben kann der Browser nicht mehr verarbeiten. Abbildung 13.2: Fehlerausgabe in einem Bild (schwarze Schrift auf grauem Grund)

V V V 1 2 3 4 5 6 7 8 9 10 11 12 13 14 A B C D E

320 ______________________________ 13 1000 kleine Helfer: Die PHP-Funktionen

Von Punkten und Pixeln und deren Beziehungen In der Drucktechnik werden Schriftgrößen oft in Punkt angegeben. Ein Punkt entspricht 1/72 Zoll, also etwa 0,353 mm. Dieses Buch wurde mit 9 Punkt geschrieben – die Schrift hat eine maximale Höhe (ohne Unterlängen) von 3,177 mm. Bildmaße basieren dagegen immer auf den Bildelementen – Pixel genannt. Ein moderner Monitor kann 1 280 x 1 024 Pixel darstellen. Bilder für die Anzeige auf Bildschirmen werden deshalb häufig in Pixeln skaliert, um für die spätere Anzeige optimiert zu werden. Umrechnungen zwischen Punkt und Pixel sind von der Auflösung des Mediums abhängig, auf dem ausgegeben wird. Deshalb erscheinen Bilder auf verschiedenen Monitoren unterschiedlich groß. Die Funktion imagettfbbox setzt einfach ein Verhältnis von 1:1 an; 1 Punkt entspricht einem Pixel. Dies ist nicht immer optimal, erleichtert aber die Berechnung erheblich.

13.2.3 Umgang mit Fehlern Der Umgang mit Fehlern ist in PHP bei der Bilderzeugung nicht einfach. Wenn der Browser kein Bild darstellt, hat PHP möglicherweise eine Fehlerausgabe direkt erzeugt. Damit kann der Browser aber nichts anfangen. Abbildung 13.3: Fehlerhafte Bilderzeugung

In solchen Fällen kann es hilfreich sein, die Bilddatei direkt aufzurufen – entweder in der Adresszeile des Browsers oder über einen Link. Fehlerausgaben werden dann sichtbar. Abbildung 13.4: Fehlerausgaben in Bildskripten Voraussetzung ist aber, dass der Browser die Daten nicht als Bild zu erkennen versucht. Entfernen Sie deshalb zur Fehlersuche die headerFunktion durch auskommentieren:

// header("Content-type: image/png");

13.2 Hilfsdesigner: Bildfunktionen mit GD2________________________________ 321

13.2.4 Weitere Bildfunktionen Die GD2-Bibliothek enthält neben der Darstellung von Texten auch einige Funktionen für Zeichnungen – Linien, Kreise und Rechtecke. Die damit erreichbaren Effekte sind durchaus passabel. Beispielhaft werden hier zwei Funktionen vorgestellt. Sie finden in der Referenz zu diesem Buch alle GD2-Funktionen mit vielen weiteren Beispielen. Zeichnen von Linien und Tabellen Tabellen bestehen aus Linien. Das folgende Beispiel zeigt die Anwen- imageline dung der Funktion imageline. Die Funktion zeichnet eine farbige Linie von x1, y1 nach x2, y2 im virtuellen Koordinatensystem.

Zuerst wird auch hier wieder ein Bild erzeugt, diesmal auf grauem Grund: $image = imagecreate(320, 50); imagecolorallocate($image, 155, 155, 155); $black = imagecolorallocate($image, 0, 0, 0);

Danach werden horizontale Linien gezeichnet: for ($i = 0; $i < 4; $i++) { imageline($image, 10, 10 + ($i * 10), 310, 10 + ($i * 10), $black); }

Zuletzt entstehen die vertikalen Linien: for ($i = 0; $i <= 30; $i++) { imageline($image, 10 + ($i * 10), 10, 10 + ($i * 10), 40, $black); }

Listing 13.4: Tabelle mit GD2 erzeugen (image_grid)

V V V 1 2 3 4 5 6 7 8 9 10 11 12 13 14 A B C D E

322 ______________________________ 13 1000 kleine Helfer: Die PHP-Funktionen Wie üblich erfolgt dann die Ausgabe des Bildes an den Browser: header("Content-type: image/png"); imagepng($image); imagedestroy($image);

Abbildung 13.5: Mit GD2 erzeugtes Gitter

Umgang mit fertigen Grafiken Sie können die GD2-Funktionen auch verwenden, um fertige Bilder zu manipulieren oder zu untersuchen. Browser stellen das endgültige Layout einer Seite schneller dar, wenn die Größe der Bilder angegeben wird. Das ist unter Umständen mühselig, wenn die Bilder wechseln und nicht immer exakt die gleiche Größe haben. Eine zwangsweise Skalierung durch den Browser ist ebenso unerwünscht, weil sich dadurch die Darstellungsqualität verschlechtert. Lassen Sie diese Aufgabe deshalb zuverlässig von PHP erledigen: Listing 13.5: Bilddaten erkennen (imagesize)

' , $img, $width, $height); echo $img; echo “

”; echo “Breite: $width
”; echo “Höhe: $height
”; ?>

Das kleine Skript ermittelt die Daten eines Bildes – egal in welchem Format dies vorliegt – mit Hilfe der Funktion getimagesize. $size = getimagesize($img);

Die Funktion gibt Breite und Höhe in einem Array zurück: $width = $size[0]; $height = $size[1];

Aus diesen Daten lässt sich leicht ein vollständiges -Tag für die HTML-Seite zusammenbauen: $img = sprintf('', $img, $width, $height);

Zuletzt erfolgt hier oder später die Ausgabe des Bildes. echo $img;

13.3 Suchexperten: Reguläre Ausdrücke__________________________________ 323

13.3 Suchexperten: Reguläre Ausdrücke Reguläre Ausdrücke begegnen dem Programmierer immer wieder. Anfänger empfinden die kryptischen Schlangen voller Sonderzeichen als unlesbar und auch mancher Profi schreibt lieber schnell ein paar Schleifen, als sich Gedanken über ein solches Muster zu machen. Dabei sparen reguläre Ausdrücke viele Zeilen Code und lösen manches Problem auf verblüffend elegante Weise. Dieser Abschnitt führt Sie in die Welt der regulären Ausdrücke ein und zeigt, wie Sie sich ein unglaublich spannendes Kapitel der Programmierkunst erschließen.

13.3.1 Kennen Sie Perl? Webprogrammierer probieren bei der Suche nach der richtigen Sprache meist zuerst Perl aus. Perl kann aber sehr abschreckend wirken, denn manche Skripte professioneller Programmierer sind gänzlich unleserlich – zeilenlange Sammlungen von Klammern, Schrägstrichen, Sternchen und Punkten. Verblüffend, dass diese Gebilde zu erstaunlichen Leistungen im Stande sind. PHP macht den Einstieg leichter und führt zu lesbaren und scheinbar einfacheren Programmen. Einsteigern entgeht dabei, dass Perl praktisch das Prinzip der regulären Ausdrücke in allen Sprachelementen verfügbar hat. Mit dem Umstieg auf PHP verliert man diese Funktionalität. Programme werden lesbarer, aber auch länger und umständlicher.

Wie Sie Zugang zu einem mächtigen Werkzeug finden

13.3.2 Überall reguläre Ausdrücke PHP verfügt dabei auch über Funktionen, die mit regulären Ausdrücken Suchmuster umgehen. Dies ist nicht so kryptisch wie in Perl, steht der Leistungsfähigkeit aber in nichts nach. Was aber sind diese Gebilde eigentlich? Reguläre Ausdrücke (aus dem englischen: regular expressions) beschreiben Suchmuster. Man kann damit nach Zeichen in einer Zeichenkette suchen – nicht mehr, aber auch nicht weniger. Das geht freilich mit einfachen Suchfunktion auch. Oft fehlt es aber an einer klaren Definition, was eigentlich gesucht werden soll. Wenn Sie in einem längeren Text nach Stellen suchen, die Währungsangaben beinhalten, dann nutzt eine normale Suchfunktion nicht. Viele Suchfunktionen in Editoren, Textverarbeitungen und anderen Programmen, die Textstellen suchen (wie beispielsweise »grep«), nutzen deshalb auch reguläre Ausdrücke. Diese erlauben auch die Suche nach allgemeineren Angaben. Die Möglichkeiten sind dabei aber so umfangreich, dass es sich schon wieder lohnt, ganze Bücher darüber zu schreiben. Die Vielfalt der Funktionen und die Mächtigkeit der Definitionen führt dann auch zu diesen unlesbaren, verwirrenden Konstrukten.

V V V 1 2 3 4 5 6 7 8 9 10 11 12 13 14 A B C D E

324 ______________________________ 13 1000 kleine Helfer: Die PHP-Funktionen Das Programm in der Zeile Wie der Ausdruck intern arbeitet

In einem regulären Ausdruck steckt, wenn man es genau betrachtet, ein komplettes Programm. Wenn man dies akzeptiert und versteht, dann ist der Entwurf und die Nutzung nicht schwieriger als mit jedem anderen Stück Code auch. Sie müssen sich die Zeit nehmen, einen regulären Ausdruck sorgfältig zu entwerfen und zu testen. Niemand – auch Profis nicht – schreiben einen neuen Ausdruck, der vielleicht nur 10 oder 20 Zeichen umfasst, in ein paar Sekunden auf. Intern arbeitet auch nicht ein einfacher Mustervergleich, sondern die Regex-Maschine, ein Programm, das die Ausdrücke auflöst und ausführt. Das wird bei umfangreichen Konstrukten spürbar – die Ausführung einer Suche mit einem regulären Ausdruck kann signifikant Rechenzeit in Anspruch nehmen. Und nicht zuletzt können solche Gebilde auch zu Programmschleifen führen, Abstürze verursachen und sich sonst wie jedes andere Programm daneben benehmen.

Reguläre Ausdrücke sind nicht trivial

Es ist eine Kunst, gute Programme zu schreiben. Ebenso ist es eine Kunst, gute reguläre Ausdrücke zu schreiben. Tatsächlich kann man komplexe Aussagen oft auf mehr als einem Weg ausdrücken. Der eine Weg ist vielleicht schneller, der andere kompakter, der dritte verständlicher. Lassen Sie sich nicht davon abhalten, reguläre Ausdrücke einzusetzen. So wie Ihre Programme im Laufe der Zeit immer besser werden, optimieren Sie auch die Suchmuster. Ein Testprogramm Als ersten Eindruck für die Nutzung von regulären Ausdrücken finden Sie hier ein Listing eines Testprogramms. Reguläre Ausdrücke selbst finden Sie darin noch nicht, sondern nur die wichtigsten PHPFunktionen, mit denen diese ausgewertet werden.

Listing 13.6: Testskript für reguläre Ausdrücke (regextest)

Reguläre Ausdrücke überprüfen

Prüfen regulärer Ausdrücke

Muster:
Text:
Ersatz:

Gierig: value="1"> Groß-/Klein: value="1"> Ersetzen? value="1">


" . htmlentities($pattern)."

"; $result = preg_match_all($pattern, $text, $matches); if ($result) { foreach($matches as $y => $match) { echo htmlentities("Match ($y): ") . "
"; if (is_array($match)) { foreach($match as $x => $submatch) { echo htmlentities(" Submatch [$x]: $submatch") . "
"; } } else echo $match; } if ($repl == 1) { $result = preg_replace($pattern, ($replace), $text);

V V V 1 2 3 4 5 6 7 8 9 10 11 12 13 14 A B C D E

326 ______________________________ 13 1000 kleine Helfer: Die PHP-Funktionen echo "
Ergebnis der Ersetzung: " . htmlentities($result); } } else { echo "Keine Übereinstimmung gefunden"; } } ?>

Dieses Skript enthält selbst keine regulären Ausdrücke. Im Prinzip werden die zulässigen Ausdrücke aus den Angaben im Formular zusammengesetzt und dann ausgeführt. Die eventuell dabei auftretenden Ergebnisse werden in Schleifen ausgegeben. Der erste Teil definiert ein Formular, dass die zu testenden Daten und Ausdrücke aufnimmt. PHP setzt in manchen Umgebungen automatisch Escape-Zeichen vor Zeichen, die eine besondere Bedeutung haben. Damit sich diese nicht selbst vervielfältigen – das Escape-Zeichen »\« wird ja selbst wieder als ein Sonderzeichen behandelt, wird stripslashes eingesetzt.



Das Feld regex speichert das Suchmuster: Muster:




Etwas größer ist der Bereich für die Musterdaten: Text:


Falls ersetzt werden soll, wird der Ersatztext in replace erfasst. Ersatz:



Nun folgen die Kontrollkästchen für die Optionen »U«, »i« und die Auswahl der Ersetzungsfunktion: Gierig: value="1"> Groß-/Klein: value="1"> Ersetzen?

13.3 Suchexperten: Reguläre Ausdrücke__________________________________ 327 value="1">


Das fertige Formular wird dann versendet:




Das Formular ruft sich selbst auf. Wurde ein regulärer Ausdruck angegeben, wird dieser ausgeführt.
Zuerst muss nach einem passenden Begrenzerzeichen gesucht werden. Bedingung ist, dass dieses nicht im Ausdruck selbst vorkommt. Eine Auswahl Begrenzungszeichen wird im Array $limiter definiert: $limiter = array("/", "#", "~", "'");

Dann werden alle Zeichen im Ausdruck gesucht. Ist ein Zeichen nicht vorhanden, kann es als Begrenzungszeichen genutzt werden. Daraus entsteht dann das vollständige Muster in der Variablen $pattern. foreach($limiter as $char) { if (!strpos($regex, $char)) { $pattern = stripslashes($char.$regex.$char); break; } }

Falls Optionen gesetzt wurden (Schalter), werden diese an das Muster angehängt: if (!$greedy == 1) $pattern .= 'U'; if ($case == 1) $pattern .= 'i';

Das fertige Muster wird angezeigt: echo "Muster: " . htmlentities($pattern)."

";

Dann wird das Muster mit den Testdaten ausgeführt. Ergebnisse werden in $matches gespeichert. Die Funktion preg_match_all ermittelt dabei alle Vorkommen in $text, die durch $pattern beschrieben werden. Fundstellen werden in $matches abgelegt. Die Funktion selbst gibt TRUE zurück, wenn etwas gefunden wurde. $result = preg_match_all($pattern, $text, $matches);

Nach der Untersuchung des Ausdrucks erfolgt die Ausgabe der Teilergebnisse. Je nach Ausdruck können dies auch verschachtelte Arrays sein, die hier mit foreach aufgelöst werden. htmlentities erlaubt die Anzeige

V V V 1 2 3 4 5 6 7 8 9 10 11 12 13 14 A B C D E

328 ______________________________ 13 1000 kleine Helfer: Die PHP-Funktionen von HTML-Tags, die der Browser sonst nicht darstellen, sondern ausführen würde. if ($result) { foreach($matches as $y => $match) { echo htmlentities("Match ($y): ") . "
"; if (is_array($match)) { foreach($match as $x => $submatch) { echo htmlentities(" Submatch [$x]: $submatch") . "
"; } } else echo $match; }

Wurde eine Ersetzung angefordert, wird auch diese ausgeführt und das Ergebnis in $result ausgegeben: if ($repl == 1) { $result = preg_replace($pattern, stripslashes($replace), $text); echo "
Ergebnis der Ersetzung: " . htmlentities($result); } } else { echo "Keine Übereinstimmung gefunden"; } } ?>

Weiterentwicklung mit Benchmark

Eine weiterentwickelte Version finden Sie unter der folgenden Adresse: http://www.php.comzept.de/regex

Dort wird neben preg_match auch mit ereg geprüft. Außerdem werden optional die Zeiten gemessen, die der Ausdruck braucht, um aufgelöst zu werden. Sie können damit den fertigen Ausdruck auch im Hinblick auf die Ausführungszeit optimieren, wenn dies erforderlich sein sollte.

13.3.3 Erstellen einfacher Muster Für die ersten Versuche ist es empfehlenswert, ein kleines Testprogramm zu verwenden. Listing 13.6 zeigt dies unter Verwendung der PCREFunktionen. Diese sind leistungsfähiger und schneller als die RegexMaschine, die PHP eingebaut hat. Die PCRE-Funktionen sind ein eigenes Modul und bilden die Funktionalität ab, die Perl bietet. HTML-Tags suchen

Das folgende Muster sucht nach dem HTML-Tag : /<title>/<br /> <br /> 13.3 Suchexperten: Reguläre Ausdrücke__________________________________ 329 Das ist nun wenig spektakulär, weil diese Aufgabe auch eine normale Suchfunktion erfüllen würde. Es zeigt aber den Aufbau eines Musters: Anfang und Ende markieren zwei Zeichen, die im Muster selbst nicht vorkommen. Die eingebauten Funktionen (ereg, eregi usw.) benötigen diese Markierung übrigens nicht. Dafür bieten die PCRE-Funktionen aber mehr Variationsmöglichkeiten und – das ist der eigentliche Grund sie zu verwenden – sie sind deutlich schneller. So ein Suchmuster wird nun von links nach rechts abgearbeitet und »gleitet« dabei über den Text, der durchsucht werden soll. Wird eine Übereinstimmung gefunden, gibt die Funktion TRUE zurück und – wenn das Muster entsprechend definiert wurde – auch Teile der Übereinstimmung. Als nächstes sollen alle Header-Tags gesucht werden. Das funktioniert Variable HTMLmit dem letzten Muster schon nicht mehr, denn die Tags treten in ver- Tags suchen schiedenen Formen auf: <h1>, <h2> usw. bis <h6>. Folgendermaßen sieht der reguläre Ausdruck aus: /<h\d>/<br /> <br /> Das Zeichen \d steht für eine Zahl. In Tabelle 13.3 finden Sie noch mehr Varianten solcher Zeichenklassen. Leider ist dieses Muster nicht perfekt, denn es findet beispielsweise auch <h8>, was es offensichtlich nicht gibt. Reguläre Ausdrücke »denken« Zeichenweise. Jedes Zeichen kann aber unterschiedlich komplex definiert werden. Was hier benötigt wird, ist eine Zeichenklasse, die die Ziffern 1 bis 6 umfasst. Zeichenklassen werden in eckige Klammern gesetzt: /<h[123456]>/<br /> <br /> Die gesamte Klasse steht dennoch nur für ein Zeichen. Eleganter ist der folgende Ansatz: /<h[1-6]>/<br /> <br /> Innerhalb der Zeichenklasse können also Bereiche definiert werden. Mit Hilfe des ^-Symbols kann der Inhalt der Zeichenklasse negiert werden. Eine Alternative zur letzten Definition sähe dann so aus: /<h[^0789]/<br /> <br /> Wie am Anfang erwähnt, gibt es oft viele Wege zum Ziel. Um diese Wege leicht testen zu können eignet sich das bereits in Listing 13.6 gezeigte Testskript ideal.<br /> <br /> 13.3.4 Vom Einfachen zum Komplexen Häufig werden reguläre Ausdrücke eingesetzt, um Eingaben aus Formularen zu überprüfen. Die Prüfung einer E-Mail-Adresse ist dabei schon eine kleine Herausforderung. Mit einem regulären Ausdruck können Sie zumindest die grundsätzliche Form überprüfen. Ein E-Mail-Name ist aus kleinen und großen Buchstaben aufgebaut. Als E-Mail-Adresse zusätzliche Zeichen sind das Minuszeichen »-«, der Unterstrich »_« und der Punkt ».« erlaubt. Groß- und Kleinschreibung spielt keine Rolle.<br /> <br /> V V V 1 2 3 4 5 6 7 8 9 10 11 12 13 14 A B C D E<br /> <br /> 330 ______________________________ 13 1000 kleine Helfer: Die PHP-Funktionen Nach dem Namen folgt das @-Zeichen und die Domain. Hier dürfen keine Unterstriche auftreten, sonst entspricht es dem Mailnamen. Es ist sinnvoll, den Ausdruck Schritt für Schritt zu entwickeln, wie es im Folgenden gezeigt wird: ^[_a-z0-9-]+<br /> <br /> Dieser Teil untersucht den Mailnamen auf gültige Zeichen. Erlaubt sind neben Ziffern und Buchstaben noch Minuszeichen und Unterstriche. Außerdem soll der Ausdruck von Beginn an untersucht werden. ^[_a-z0-9-]+(\.[_a-z0-9-]+)*<br /> <br /> Dieser Ausdruck akzeptiert auch den Punkt, allerdings nicht am Anfang oder am Ende des Namens. Die Gruppierung erlaubt die Wiederholung des zweiten Teils, er kann aber auch entfallen. Damit sind Konstruktionen wie »joerg.krause« oder »joerg« oder »joerg_krause.php-liste« erlaubt. ([a-z0-9-]+\.)[a-z]{2,3}$<br /> <br /> Hier wird nur der Domainname untersucht. Unterstriche sind nicht erlaubt, der Punkt ist zwingend und wird von 2 oder 3 Zeichen gefolgt, die wiederum nur Buchstaben sein können. Hier stellt die Gruppierung sicher, dass der Domainname aus mehreren Teilen bestehen darf. Damit sind Konstruktion wie »domain.de«, aber auch »mail.rz.unimagdeburg.de« erlaubt. Das abschließende $-Zeichen erzwingt, dass nach dem Domainnamen nichts mehr folgen darf – die zu untersuchende Zeichenkette muss hier enden. ^[_a-zA-Z0-9-]+(\.[_a-zA-Z0-9-]+)* @([a-zA-Z0-9-]+\.)[a-zA-Z]{2,3}$<br /> <br /> Das Gebilde ist nun schon recht unübersichtlich. Es ist jedoch nur eine Kombination aus dem vorderen und dem hinteren Teil, verbunden durch das @-Zeichen. Das Ergebnis noch ein Mal in voller Pracht; diese Schreibweise eignet sich übrigens auch gut zur Fehlersuche: Listing 13.7: Regulärer Ausdruck zum Prüfen der EMail-Adresse<br /> <br /> ^ [_a-zA-Z0-9-]+ (\. [_a-zA-Z0-9-]+ )* @ ( [a-zA-Z0-9-]+ \. )+ ( [a-zA-Z]{2,3} ) $<br /> <br /> Dieser Ausdruck ist gut, aber nicht perfekt. Nicht alles kann man mit regulären Ausdrücken elegant lösen. Die gezeigte Form erlaubt auch<br /> <br /> 13.3 Suchexperten: Reguläre Ausdrücke__________________________________ 331 Konstruktionen wie »___.---@---.xx«, was offensichtlicher Unfug ist. Nun kann man die Definition bis zum Exzess treiben – was meist mit drastischen Leistungseinbußen einher geht. Cleverer ist eine Kombination mit herkömmlicher Programmierung.<br /> <br /> Zur Schreibweise regulärer Ausdrücke Ausdrücke werden normalerweise als Zeichenkette direkt in der entsprechenden Funktion genutzt. Nun ist eine solche Ansammlung von Sonderzeichen extrem schwer zu lesen. Die mehrzeilige Schreibweise, wie in Listing 13.7 gezeigt, wäre da hilfreicher. Setzen Sie den Schalter /x hinzu, werden alle Whitespaces (Leerzeichen, Tabs usw.) ignoriert. Auf der anderen Seite müssen Sie diese dann als Zeichenklasse angeben, wenn danach gesucht werden soll.<br /> <br /> Zugriff auf die Teile der Suchergebnisse Der Zugriff auf Teile der untersuchten Zeichenkette erfolgt mit den Gruppen Gruppierungselementen, was die Programmierung oft stark vereinfacht. Solche Gruppen werden nämlich in Form eines PHP-Arrays zurückgegeben. Die gefundenen Zeichen einer Gruppe stehen dann direkt zur Verfügung. Die Zählung ist einfach. Jede öffnende runde Klammer beginnt eine neue Gruppen. Die Toplevel-Domain im E-Mail-Beispiel findet sich also in der dritten Gruppe wieder. Nun kann man diese Gruppe leicht mit einer Liste gültiger Domainnamen abgleichen. Ebenso wird der Name des E-Mail-Kontos durch Gruppen vom Domainnamen getrennt und kann so gesondert untersucht werden. Es besteht auch die Möglichkeit, auf die gefundenen Zeichen der Grup- Impliziter Zugriff pen direkt im selben Ausdruck zuzugreifen. Der folgende Ausdruck sucht in einem Text Wörter, die doppelt hintereinander vorkommen: \b([a-z]+)(\s)+(\1\b)<br /> <br /> Der ersten Teil beginnt mit einer Wortgrenze \b. Danach wird als Wort erkannt, was nur aus Buchstaben besteht: ([a-z]+). Selbstverständlich würde man in der Praxis noch den i-Operator anfügen, um Groß- und Kleinschreibung zu gestatten. Dann folgen Leer- oder Trennzeichen; mindestens eins oder beliebig viele (\s)+. Der zweite Teil ist der eigentliche Clou an der Sache, hier wird nämlich mit dem speziellen Operator \1 auf die erste gefundene Referenz verwiesen. Welche Ziffern man einsetzen muss, kann anhand der Anzahl der öffnenden Klammern ausgezählt werden. Danach folgt wieder eine Wortgrenze \b. Der Ausdruck findet in Sätzen wie: »Hier kommt kommt das Skript« die Doppelungen »kommt kommt« und gibt diese (und nur diese) zurück. Sind mehrere Worte doppelt, wird auch das erkannt. Sind in einem Text mehrere Wörter (hintereinander) doppelt, werden auch mehrere Gruppen zurückgegeben.<br /> <br /> V V V 1 2 3 4 5 6 7 8 9 10 11 12 13 14 A B C D E<br /> <br /> 332 ______________________________ 13 1000 kleine Helfer: Die PHP-Funktionen<br /> <br /> Von gierigen und genügsamen Ausdrücken Reguläre Ausdrücke verhalten sich normalerweise »gierig« (im engl. greedy). Der gerade untersuchte Teilausdruck versucht dabei immer, so viele Übereinstimmungen wie möglich zu finden. Dies gilt für die folgenden Metazeichen: ?, *, +, {min,max}. Der Ausdruck (\d{2}).* finden zweistellige Zahlen, die von irgendetwas gefolgt werden. Angewendet auf die Ziffernfolge »123456789« wird die 12 gefunden, der Rest erfüllt die Forderung »irgendetwas folgt« natürlich. Das ist vielleicht nicht das erwartete Verhalten. Das Sternchen ist aber gierig, es läuft bis zum Ende der Zeichenkette. Wird die Option »ungreedy« (U) gesetzt, erkennt der Ausdruck dagegen lauter Zweiergruppen von Zahlen, also 12, 34 usw. Das Sternchen akzeptiert dann auch »kein« Zeichen, wie es dies laut Definition auch soll. Abbildung 13.6: Testprogramm aus Listing 13.6 mit Ausgabe von Teilergebnissen<br /> <br /> 13.3.5 Suchen und Ersetzen Wo gesucht wird, sollte auch ersetzt werden können. Im letzten Beispiel wurde bereits gezeigt, dass Gruppen hilfreich sind, um durch Referenzen darauf zu verweisen. Das funktioniert auch beim Ersetzen. Der Ersetzungsvorgang in seiner einfachsten Form unterscheidet sich kaum vom herkömmlichen Verfahren. Der reguläre Ausdruck findet irgendwelche<br /> <br /> 13.3 Suchexperten: Reguläre Ausdrücke__________________________________ 333 Textstellen und mit der Funktion preg_replace wird der Fundort durch andere Zeichen oder eine leere Zeichenkette ersetzt. Komplizierter wird es, wenn Sie beim Beispiel der doppelten Wörter Ersatz mit diese durch ein Wort ersetzen möchten. Da sich bei jedem Fund der In- erkannten halt ändert, müssen Sie in der Ersatzzeichenkette Zugriff auf das Ergeb- Zeichen nis des regulären Ausdrucks haben. Tatsächlich können auch hier Referenzen eingesetzt werden. Das folgende Beispiel nutzt dies, um amerikanische Datumsformate in die in Deutschland üblichen umzuwandeln – mit nur einer einzige Codezeile. Zuerst wird der Ausdruck zum Suchen gezeigt: /(19|20)(\d{2})-(\d{1,2})-(\d{1,2})/<br /> <br /> Im Gegensatz zu den anderen Beispielen verhält sich dieser Ausdruck »gierig«. Als Ersatz findet folgende Konstruktion Anwendung: \4.\3.\1\2<br /> <br /> Die Ziffern zeigen auf die geklammerten Teile des regulären Ausdrucks. Andere Sonderzeichen gibt es hier nicht, die Punkte sind also tatsächlich Punkte. Die Zeichenkette »1999-05-26« wird so zu »26.05.1999«. In PHP sieht das dann so aus: <?php $pattern = "/(19|20)(\d{2})-(\d{1,2})-(\d{1,2})/"; $replace = "\4.\3.\1\2"; $text = "1999-05-26"; $result = preg_replace($pattern, $replace, $text); ?><br /> <br /> Listing 13.8: Ersetzen mit regulären Ausdrücken<br /> <br /> Aller Anfang ist schwer Es lohnt sich unbedingt, regulären Ausdrücken mehr Aufmerksamkeit zu schenken. Am Anfang werden Sie einige Misserfolge erleben. Tatsächlich gibt es auch weit mehr Möglichkeiten, als in diesem kurzen Beitrag beschrieben werden konnte. Es sollte hier auch nur der Eindruck vermittelt werden, was reguläre Ausdrücke eigentlich sind und dass sie sehr hilfreich sein können. Sie werden dann auch Mittel und Wege finden, einen passenden Ausdruck zu entwickeln.<br /> <br /> 13.3.6 Alle Metazeichen auf einen Blick Die Metazeichen, die zur Bildung der Suchmuster verwendet werden, benötigen Sie ständig. Deshalb finden Sie hier einen kompakten Überblick. Zeichen<br /> <br /> Beschreibung<br /> <br /> .<br /> <br /> Beliebiges Zeichen<br /> <br /> [^ ]<br /> <br /> Negation einer Zeichenklasse (nur, wenn das ^ an erster Stelle steht)<br /> <br /> Tabelle 13.1: Metazeichen in regulären Ausdrücken<br /> <br /> V V V 1 2 3 4 5 6 7 8 9 10 11 12 13 14 A B C D E<br /> <br /> 334 ______________________________ 13 1000 kleine Helfer: Die PHP-Funktionen Zeichen<br /> <br /> Beschreibung<br /> <br /> ^<br /> <br /> Beginn des Ausdrucks (muss am Anfang der Zeichenkette stehen)<br /> <br /> $<br /> <br /> Ende des Ausdrucks, muss am Ende des Ausdrucks stehen<br /> <br /> |<br /> <br /> Alternative (logisches Oder)<br /> <br /> ( )<br /> <br /> Gruppierung zum Anwenden der Quantifier (siehe Kasten »Quantifier«) und zum Erzeugen von Referenzen<br /> <br /> [ ]<br /> <br /> Zeichenklasse, steht für ein Zeichen ]-Klammern in der Zeichenklasse wird ein \ davor gestellt Mehrere im Zeichensatz aufeinanderfolgende Zeichen werden mit – verbunden (Beispiel: [a-z0-9])<br /> <br /> Die Quantifier werden verwendet, um das vorangegangene Zeichen oder eine komplexere Definition mehrfach zu wiederholen. Tabelle 13.2: Quantifier für reguläre Ausdrücke<br /> <br /> Zeichen<br /> <br /> Beschreibung<br /> <br /> ?<br /> <br /> Kein oder ein Zeichen<br /> <br /> *<br /> <br /> Kein oder beliebig viele Zeichen<br /> <br /> +<br /> <br /> Ein oder beliebig viele Zeichen<br /> <br /> {min, }<br /> <br /> Mindestens min Zeichen, beliebig viele Zeichen<br /> <br /> {,max}<br /> <br /> 0 bis höchstens max Zeichen<br /> <br /> {min, max}<br /> <br /> Mindestens min Zeichen, höchstens aber max<br /> <br /> Zeichenarten vereinfachen die Definition von Zeichengruppen, indem für häufiger benötigte Kombinationen feste Darstellungsformen genutzt werden. Tabelle 13.3: Zeichenarten in regulären Ausdrücken<br /> <br /> Zeichenart<br /> <br /> Beschreibung<br /> <br /> \1 ...\9<br /> <br /> Referenzen auf Gruppen<br /> <br /> \000 ... \077<br /> <br /> Oktalziffern<br /> <br /> \xHH<br /> <br /> HH sind Hexadezimalziffern<br /> <br /> \d<br /> <br /> Dezimalziffer<br /> <br /> \D<br /> <br /> keine Dezimalziffer<br /> <br /> \s<br /> <br /> Whitespace (Leerzeichen, Tabulator usw.)<br /> <br /> \S<br /> <br /> kein Whitespace<br /> <br /> \w<br /> <br /> Wortzeichen (Buchstaben, Ziffern, Unterstrich)<br /> <br /> \W<br /> <br /> kein Wortzeichen<br /> <br /> \b<br /> <br /> Wortgrenze (Anfang oder Ende eines Wortes)<br /> <br /> \B<br /> <br /> keine Wortgrenze<br /> <br /> \A<br /> <br /> Absoluter Anfang (^ kennzeichnet den Anfang innerhalb einer Zeile)<br /> <br /> 13.3 Suchexperten: Reguläre Ausdrücke__________________________________ 335 Zeichenart<br /> <br /> Beschreibung<br /> <br /> \Z<br /> <br /> Absolutes Ende ($ kennzeichnet das Ende innerhalb einer Zeile)<br /> <br /> \t<br /> <br /> Tabulator<br /> <br /> \n<br /> <br /> Zeilenumbruch<br /> <br /> \r<br /> <br /> Wagenrücklauf<br /> <br /> 13.3.7 Funktionen für reguläre Ausdrücke Die folgenden Aufzählung zeigt alle Perl-kompatiblen Funktionen, wobei perlregexmuster immer mit Begrenzungszeichen versehen sein muss, wie es am Anfang des Kapitels gezeigt wurde. Die Begrenzungszeichen sind beliebig, dürfen sich aber im Ausdruck selbst nicht wiederholen. Die folgende Funktion findet die erste Übereinstimmung und gibt, wenn dies erfolgreich war, TRUE zurück. Auswertbare Daten über die Analyse finden sich in resultarray wieder. boolean preg_match(string perlregexmuster, string suchtext, array resultarray)<br /> <br /> Syntax<br /> <br /> Mit der folgenden Funktion werden alle Übereinstimmungen gefunden, das Ergebnis-Array kann entsprechend größer ausfallen. boolean preg_match_all(string perlregexmuster, string suchtext, array resultarray)<br /> <br /> Syntax<br /> <br /> Wollen Sie nicht nur Suchen, sondern auch ersetzen, ist die folgende Funktion die beste Wahl: string preg_replace(string string string [, int<br /> <br /> perlregexmuster, ersatzmuster, zeichenkette limit])<br /> <br /> Syntax<br /> <br /> Wenn das Ersetzen keiner einfachen Logik folgt, ist eine so genannte Callback-Funktion hilfreich, die bei jedem Ersetzungsvorgang aufgerufen wird. Die Syntax sieht dann folgendermaßen aus: string preg_replace_callback(string string string [, int<br /> <br /> perlregexmuster, callbackfunction, zeichenkette, limit])<br /> <br /> Die Callback-Funktion muss einen Parameter enthalten, dem die Fundstelle übergeben wird – dies kann ein Arrays sein. Sie soll die Ersatzzeichenkette zurückgeben. Wenn Sie eine Zeichenkette anhand von Trennzeichen zerlegen und dies möglichst universell oder sicher gestalten müssen, bietet sich die folgende Funktion an:<br /> <br /> Syntax<br /> <br /> V V V 1 2 3 4 5 6 7 8 9 10 11 12 13 14 A B C D E<br /> <br /> 336 ______________________________ 13 1000 kleine Helfer: Die PHP-Funktionen Syntax<br /> <br /> array preg_split(string perlregexmuster, string zeichenkette)<br /> <br /> Arrays sind leistungsfähige Elemente in PHP. Wenn Sie viele Daten in Arrays speichern, werden Sie diese vielleicht auch durchsuchen wollen. Mit der folgenden Funktionen lassen sich reguläre Ausdrücke auf ganze Arrays anwenden: Syntax<br /> <br /> array preg_grep(string perlregexmuster, array inputarray)<br /> <br /> Optionen für die Funktionen An den mit Begrenzungszeichen versehenen Ausdruck können Sie verschiedene Optionszeichen anhängen, die das Verhalten der Funktion ändern. Der Einsatz ist in allen gezeigten Funktionen gleichermaßen möglich. Tabelle 13.4: Optionen für preg-Funktionen<br /> <br /> Option<br /> <br /> Beschreibung<br /> <br /> i<br /> <br /> ohne Berücksichtigung von Groß- und Kleinschreibung (d.h. »a« ist gleich »A«)<br /> <br /> s<br /> <br /> Das Symbol Punkt gilt auch für \n (Zeilenumbruch), wenn diese Option angegeben wurde. Normalerweise ist das nicht der Fall.<br /> <br /> x<br /> <br /> Ignoriert alle Whitespaces (damit können Sie Ausdrücke mit Kommentaren versehen)<br /> <br /> e<br /> <br /> Die Zeichen der Ersatzzeichenkette werden als PHP-Code interpretiert (wie bei der Funktion eval)<br /> <br /> m<br /> <br /> Steht für »Multiline«. Normalerweise können sich Ausdrücke über mehrere Zeilen erstrecken, ^ und $ markieren Zeilenanfang und Zeilenende, wenn m gesetzt wurde.<br /> <br /> U<br /> <br /> Unterdrückt das gierige Verhalten (siehe Kasten auf Seite 332)<br /> <br /> 13.4 Zeitwächter: Datumsfunktionen Viele Anwendungen verarbeiten Daten. Der Umgang damit ist nicht trivial. So sind neben den verschiedenen Datumsformaten, die auftreten können, auch Zeitzonen, Sommerzeit, Schaltjahre und andere Besonderheiten zu berücksichtigen. PHP5 unterstützt den Umgang mit Datumswerten durch einige spezielle Funktionen. Problematisch bleibt die Anwendung dennoch.<br /> <br /> 13.4.1 Probleme mit Datumswerten PHP läuft auf dem Webserver<br /> <br /> Vor der ersten Codezeile, die ein Datum verarbeitet, sollten Sie sich über eine Besonderheit im Klaren sein. PHP läuft auf dem Webserver – Datumsfunktionen, die das aktuelle Datum zurückgegeben, basieren auf der Serverzeit. Läuft der Server in den USA, ist dies zwangsläufig dessen Zeit. Es ist sicher nicht sehr schwer, daraus jede lokale Zeit zu berechnen – nur welche ist die korrekte lokale Zeit? Können Sie sicher feststellen, woher Ihre Benutzer kommen und in welcher Zeitzone sie damit leben?<br /> <br /> 13.4 Zeitwächter: Datumsfunktionen _____________________________________ 337 Wenn Sie die lokale Zeit des Benutzers ermitteln – beispielsweise über Lokale Zeiten JavaScript – dann ist dies auch keine zuverlässige Basis. Woher wollen ermitteln Sie wissen, dass die Zeit des Computers, auf dem der Browser läuft, korrekt ist? Ebenso schwierig sind Berechnungen der Sommerzeit, die in verschiede- Sommerzeit nen Regionen der Erde unterschiedlich gehandhabt wird. Auf der anderen Seite sollte man manche Probleme nicht überbewerten. UTC Geht es beispielsweise nur um die Feststellung eines Bestelldatums, ist die Zentralzeit UTC völlig ausreichend. Dieses Zeitnormal unterliegt nicht den Verschiebungen durch Zeitzonen.<br /> <br /> Woher kommt der Timestamp? Der Zeitstempel (engl. timestamp) wird zur internen Datierung von Dateien verwendet. Er erhöht sich im Sekundentakt und zählt die Sekunden ab dem 1.1.1970 – dem so genannten Beginn der Unix-Epoche. Bei einem vorzeichenbehafteten 32-Bit-Wert stehen Zahlen bis 231 = 2 147 483 648 zur Verfügung. Zumindest PHP kann damit bis zum 19.1.2038 rechnen.<br /> <br /> 13.4.2 Datumsfunktionen In diesem Abschnitt werden die Datumsfunktionen überblicksartig und anhand konkreter Beispiele vorgestellt. Ein Datum auf korrekte Werte überprüfen Die Funktion checkdate prüft ein Datum auf Gültigkeit. Sie gibt TRUE checkdate zurück, wenn das Datum gültig ist, sonst FALSE. Das Datum muss folgende Kriterien erfüllen: • year ist zwischen 0 und 32 767 (einschließlich). • month ist zwischen 1 und 12 (einschließlich). • day ist zwischen 1 und der durch den Monat bestimmten Anzahl. Schaltjahre werden beachtet. Das folgende Beispiel zeigt die Anwendung:<br /> <br /> <?php $date = '13.04.2003'; $d = explode('.', $date); checkdate($d[1], $d[0], $d[2]) ? print 'OK' : print "$date ?"; echo "<br>"; $date = "26.05.1964"; $d = explode('.', $date); checkdate($d[1],$d[0],$d[2]) ? print 'OK' : print "$date ?"; ?><br /> <br /> Listing 13.9: Datumswert testen (date_checkdate)<br /> <br /> V V V 1 2 3 4 5 6 7 8 9 10 11 12 13 14 A B C D E<br /> <br /> 338 ______________________________ 13 1000 kleine Helfer: Die PHP-Funktionen Das Skript zerlegt eine Datumsangabe mit explode in ein Array.<br /> <br /> $d = explode('.', $date); Auf die Elemente dieses Array greift checkdate zu.<br /> <br /> checkdate($d[1], $d[0], $d[2]) ? print 'OK' : print "$date ?"; Je nach Ergebnis wird der erste oder zweite Teil des ?-Operators ausgeführt. Beachten Sie, dass leere Zeichenketten intern, als Zahl dargestellt, zu 0 konvertiert werden und eine gültige Jahreszahl ergeben. Um damit Formulardaten zu überwachen, sind zusätzliche Tests notwendig. Abbildung 13.7: Ausgabe des Skripts aus Listing 13.9 Aktuelles Datum ermitteln oder Daten formatieren Die Funktion date formatiert eine Zeichenkette zur Ausgabe von Datum und Uhrzeit. Die auszugebene Zeit kann angegeben werden – fehlt diese Angabe, wird die aktuelle Zeit des Servers genommen. Ebenso arbeitet strftime. Diese Funktion berücksichtigt fremde Sprachen. Die Ausgabe wird anhand eines Musters erstellt, das bestimmte Platzhalter verwendet. Diese werden nachfolgende gezeigt. Tabelle 13.5: Platzhalter der Formatfunktionen<br /> <br /> date<br /> <br /> strftime<br /> <br /> Beschreibung<br /> <br /> a<br /> <br /> %p<br /> <br /> Gibt den Schriftzug »am« oder »pm« aus.<br /> <br /> A<br /> <br /> %r<br /> <br /> Ergibt den Schriftzug »AM« oder »PM«.<br /> <br /> B d<br /> <br /> Zeigt die Swatch-Internetzeit an. Diese Zeit teilt den Tag ohne Zeitzonen in 1 000 Einheiten. %d<br /> <br /> Ergibt den Tag im Monat, zwei Ziffern mit führender Null zwischen 01 bis 31 werden ausgegeben.<br /> <br /> %e<br /> <br /> Ergibt den Tag im Monat mit führendem Leerzeichen bei einstelligen Werten<br /> <br /> D<br /> <br /> %a<br /> <br /> Der Tag der Woche mit drei Buchstaben, beispielsweise »Fri«. Beachten Sie, dass date nur englische Bezeichnungen verwendet.<br /> <br /> F<br /> <br /> %B<br /> <br /> Ausgeschriebener Monatsname, beispielsweise »January«. Beachten Sie, dass date nur englische Bezeichnungen verwendet.<br /> <br /> h<br /> <br /> Die Stunde im 12-Stunden-Format zwischen 01 bis 12 mit führender Null.<br /> <br /> H<br /> <br /> Die Stunde im 24-Stunden-Format zwischen 00 bis 23 mit führender Null.<br /> <br /> g<br /> <br /> %I<br /> <br /> Ergibt die Stunde im 12-Stunden-Format ohne führende Null, also zwischen 1 und 12.<br /> <br /> 13.4 Zeitwächter: Datumsfunktionen _____________________________________ 339 date<br /> <br /> strftime<br /> <br /> Beschreibung<br /> <br /> G<br /> <br /> %H<br /> <br /> Gibt die Stunde im 24-Stunden-Format ohne führende Null aus: 00 bis 23<br /> <br /> i<br /> <br /> Die Minuten 00 bis 59 mit führender Null %M<br /> <br /> Die Minuten 0 bis 59 als Dezimalwert<br /> <br /> I<br /> <br /> Ergibt 1 in der Sommerzeit, sonst 0.<br /> <br /> j<br /> <br /> Ausgabe des Tages des Monats ohne führende Null: 1 bis 31 sind mögliche Werte.<br /> <br /> l<br /> <br /> %A<br /> <br /> L m<br /> <br /> Boolescher Wert für das Schaltjahr: 0 oder 1 %m<br /> <br /> n M<br /> <br /> Ausgeschriebener Tag der Woche: »Friday«. Beachten Sie, dass date nur englische Bezeichnungen verwendet.<br /> <br /> Ergibt den Monat des Jahres von 01 bis 12, also mit führender Null. Ergibt den Monat ohne führende Null: 1 bis 12.<br /> <br /> %b<br /> <br /> Der Monat als Abkürzung mit drei Buchstaben: »Jan«. Beachten Sie, dass date nur englische Bezeichnungen verwendet.<br /> <br /> O<br /> <br /> Zeitdifferenz zu UTC in Stunden als Differenzzeichenkette, beispielsweise »+0200«<br /> <br /> r<br /> <br /> Gibt Datum und Zeit im RFC 822-Format zurück, das folgende Form hat: »Thu, 5 Mar 2000 21:05:00 +0100«. Die RFC 822 definiert Datumsformate, wie sie in E-Mails verwendet werden.<br /> <br /> s<br /> <br /> %S<br /> <br /> Gibt die Sekunden 00 bis 59 mit führender Null zurück.<br /> <br /> S<br /> <br /> Suffix der englischen Ordnungszahlen: »th«, »nd« usw.<br /> <br /> t<br /> <br /> Anzahl der Tage des Monats: 28 bis 31. Verwechseln Sie dies nicht mit der Nummer des Tages.<br /> <br /> T<br /> <br /> Zeitzoneneinstellung des Computers, beispielsweise »EST« oder »MDT«<br /> <br /> U<br /> <br /> Die Sekunden der UNIX-Epoche (seit 1.1.1970). Entspricht der Ausgabe der Funktion time.<br /> <br /> w<br /> <br /> %w<br /> <br /> W<br /> <br /> Der Tag der Woche, beginnend mit 0 (Sonntag) bis 6 (Samstag). ISO-8601 Wochennummer des Jahres (ab erste Woche mit einem Montag drin)<br /> <br /> Y<br /> <br /> %Y<br /> <br /> Das Jahr im vierstelligen Format »2001«<br /> <br /> y<br /> <br /> %y<br /> <br /> Das Jahr im zweistelligen Format »01«<br /> <br /> z<br /> <br /> %j<br /> <br /> Der Tag im Jahr: 0 bis 365<br /> <br /> V V V 1 2 3 4 5 6 7 8 9 10 11 12 13 14 A B C D E<br /> <br /> 340 ______________________________ 13 1000 kleine Helfer: Die PHP-Funktionen date<br /> <br /> strftime<br /> <br /> Beschreibung<br /> <br /> Z<br /> <br /> %Z<br /> <br /> Ergibt den Offset der Zeitzonen gegen UTC in Sekunden von -43 200 bis 43 200 (86 400 Sekunden entspricht 1 Tag).<br /> <br /> %G<br /> <br /> Das Jahr wie %Y, aber nur bei vollen Wochen. Angefangene Wochen zählen im vorhergehenden oder im folgenden Jahr<br /> <br /> %g<br /> <br /> Wie %G, aber kurzes Jahresformat wie %y<br /> <br /> %x<br /> <br /> Zeit nach lokalen Systemeinstellungen<br /> <br /> %X<br /> <br /> Datum nach lokalen Systemeinstellungen<br /> <br /> %c<br /> <br /> Zeit + Datum nach lokalen Systemeinstellungen<br /> <br /> %D<br /> <br /> entspricht der Folge »%m/%d/%y«<br /> <br /> %U<br /> <br /> Wochennummer, beginnt mit Sonntag<br /> <br /> %V<br /> <br /> Kalenderwoche nach ISO 8601<br /> <br /> %W<br /> <br /> Wochennummer, beginnt mit Montag<br /> <br /> %R<br /> <br /> Komplette Zeit im 24-Stunden-Format<br /> <br /> %C<br /> <br /> Jahrhundert (2003 gibt »20« zurück)<br /> <br /> %t<br /> <br /> Tabulator<br /> <br /> %n<br /> <br /> Zeilenvorschub<br /> <br /> %%<br /> <br /> Prozentzeichen<br /> <br /> Alle anderen Zeichen werden unverändert ausgegeben. Da die Liste bei künftigen Versionen erweitert werden kann, sollten Sie keine Buchstaben verwenden. Listing 13.10: Formatierung von Datum und Zeit (date_form)<br /> <br /> <?php printf (' am: <b>%s</b><br>', date('D, d.m.Y')); printf (' um <b>%s</b> Uhr<br>', date('H:i:s')); printf (' Swatchzeit: <b>%04d</b>', date ('B')); ?> Das Skript nutzt lediglich die bereits gezeigten Formatanweisungen. Die Kombination mit printf verschafft weitere Formatiermöglichkeiten – so wird die Swatchzeit immer mit führenden Nullen und auf vier Stellen ergänzt angezeigt, was mit date alleine nicht möglich ist.<br /> <br /> Abbildung 13.8: Ausgabe von Listing 13.10 Lokalisierte Angaben<br /> <br /> Um Datumsangaben in anderen Sprachen zu erhalten, nutzen Sie die Funktionen setlocale und strftime. Die Einstellungen von setlocale werden von date ignoriert.<br /> <br /> 13.4 Zeitwächter: Datumsfunktionen _____________________________________ 341<br /> <br /> Was bedeutet Lokalisierung? Unter der Lokalisierung versteht man bei Software die Anpassung an bestimmte Sprachen. Wird eine Software für den internationalen Markt produziert, wird in der Regel zuerst eine englische Version erstellt und darauf aufbauend lokalisierte Varianten. Mit setlocale lässt sich dies in PHP gut realisieren.<br /> <br /> strftime formatiert eine Datumsangabe nach den Angaben der Region. Die auszugebene Zeit kann angegeben werden – fehlt diese Angabe, wird die aktuelle Zeit des Servers genommen. Es ist möglich, dass einige Systeme nicht alle Formatierungszeichen von strftime unterstützen, weil diesen eine systemeigene Bibliothek zugrunde liegt. Ein Test auf dem Zielsystem ist daher unerlässlich. Ausgaben von Monats- oder Wochentagsnamen werden nach der mit setlocale eingestellten Sprachangabe formatiert, also auch in Deutsch. Die Formatanweisungen finden Sie in Tabelle 13.5 auf Seite 338.<br /> <br /> <?php print(strftime("<b>%A</b> in setlocale (LC_TIME, "fi"); print(strftime("<b>%A</b> in setlocale (LC_TIME, "fr"); print(strftime("<b>%A</b> in setlocale (LC_TIME, "ge"); print(strftime("<b>%A</b> in ?><br /> <br /> Englisch und <br>")); Finnish<br>")); Französisch<br>"));<br /> <br /> Listing 13.11: Ausgabe von Datumswerten in verschiedenen Sprachen (date_strftime)<br /> <br /> Deutsch<br>"));<br /> <br /> Im Skript wird jeweils der Bereich der Zeitfunktionen auf verschiedene Länderkennzeichen eingestellt und anschließend erfolgt ein Zugriff mit strftime, um den Wochentag in der Landessprache auszugeben. Beachten Sie, dass PHP nicht alle Sprachen beherrscht, die theoretisch in Form entsprechender Länderkennzeichen verfügbar sind. Im europäischen Sprachraum ist die Unterstützung aber sehr gut.<br /> <br /> Die Abkürzungen für die Gebietsschemen werden unter setlocale beschrieben. Gegenüber date ist die Integration in Fließtext unproblematisch.<br /> <br /> setlocale ist betriebssystemabhängig. Windows und Linux liefern verschiedene Lokalisierungszeichenfolgen. So dürfte die für Windows funktionierende Varianten mit »de« für Deutsch unter Linux »de_DE« lauten. Probieren Sie es aus!<br /> <br /> Abbildung 13.9: Datumswerte, mit dem Skript aus Listing 13.11 erzeugt.<br /> <br /> V V V 1 2 3 4 5 6 7 8 9 10 11 12 13 14 A B C D E<br /> <br /> 342 ______________________________ 13 1000 kleine Helfer: Die PHP-Funktionen UTC ausgeben<br /> <br /> Am Anfang wurde bereits UTC als neutrale Zeitbasis angesprochen. Diese Zeit wird auch als GMT (Greenwich Mean Time15) bezeichnet. Daraus leitet sich der Name der Funktion gmstrftime ab, die eine Zeitangaben formatiert. Die Parameter entsprechen strftime. Das folgende Beispiel zeigt den Unterschied zwischen der lokalen Zeit und der UTC-Zeit:<br /> <br /> Listing 13.12: Formatierte Ausgabe der UTC-Zeit (date_utectime)<br /> <br /> <?php setlocale (LC_TIME,'de'); echo strftime ("%d.%b.%Y %H:%M:%S")."<br>"; echo gmstrftime ("%d.%b.%Y %H:%M:%S")."<br>"; ?> Die Ausgabe zeigt die lokale Zeit des Webservers und die »Grennwich Mean Time«-Zeitangabe.<br /> <br /> Abbildung 13.10: Ausgabe von Listing 13.12 gmdate<br /> <br /> Die Funktion gmdate formatiert eine UTC-Zeitangabe. Die Funktion entspricht date, nur dass als Zeitangabe immer UTC verwendet wird, auch wenn die Zeitangabe die lokale Zeit enthält. Datums- und Zeitwerte in Arrays verarbeiten<br /> <br /> getdate<br /> <br /> Die Funktion getdate ermittelt Zeit- und Datumsinformationen. Sie gibt ein assoziatives Array mit Datums- und Zeitangaben zurück. Die Elemente des Arrays werden folgendermaßen die Indizes "seconds", "minutes", "hours", "mday", "wday", "mon", "year", "yday", "weekday" und "month" adressiert.<br /> <br /> gettimeofday<br /> <br /> Ebenso arbeitet die Funktion gettimeofday, ermittelt jedoch die aktuelle Zeit. Sie gibt ein assoziatives Array mit Zeitangaben zurück. Die Elemente des Arrays werden folgendermaßen mit den folgenden Indizes adressiert: "sec", "usec" (Mikrosekunden) sowie "minuteswest" für die Sekunden westlich von Greenwich und "dsttime" für den Typ der Sommerzeitkorrektur (1 = mit Korrektur). Das folgende Beispiel zeigt die Anwendung:<br /> <br /> Listing 13.13: Untersuchung von Datumswerten (date_gettimeofday)<br /> <br /> <?php $time = gettimeofday(); echo $time["usec"] . "µs <br>"; echo date("H:m:s", $time["sec"]) . " (Zeit)<br>"; echo $time["minuteswest"]/60 . " min (Diff zu GMT)<br>"; echo (($time["dsttime"] == 1) ? "Sommerzeit" : "Winterzeit"); echo "<br>"; ?><br /> <br /> Eigentlich ist dieser Begriff veraltet, da solche volkstümlichen Versionen im Zuge der Standardisierungsbestrebungen vereinheitlicht wurden.<br /> <br /> 15<br /> <br /> 13.4 Zeitwächter: Datumsfunktionen _____________________________________ 343 Ermittelt wird in diesem Skript das aktuelle Datum. Dessen Bestandteile einschließlich der Zeitinformationen werden im Array $time abgelegt.<br /> <br /> $time = gettimeofday(); Dann werden die Bestandteile einzeln ausgelesen. Der Server, der dieses Skript ausführte, stand auf deutscher Zeit. Entsprechend ist das Element $time["minuteswest"] gleich 60 – für die Anzeige in Stunden wird der Wert durch 60 dividiert. Abbildung 13.11: Ausgabe des Skripts aus Listing 13.13 Die Funktion localtime gibt ein Array mit Zeitinformationen über die localtime Zeit zurück, die der übergebene Zeitstempel anzeigt. Wurde kein Parameter übergeben, wird die aktuelle Server-Zeit eingesetzt. Es wird ein numerisches Array erzeugt, wenn der zweite Parameter nicht angegeben wurde oder auf FALSE steht. Andernfalls wird ein assoziatives Array erzeugt. Als Schlüssel des assoziativen Arrays stehen die Indizes "tm_sec", "tm_min", "tm_hour", "tm_mday", "tm_mon", "tm_year", "tm_wday" (Wochentag), "tm_yday" (Tag des Jahres) und "tm_isdst" (Sommerzeit) zur Verfügung. Beachten Sie die Definition von tm_year. Dies bezeichnet die Anzahl der Jahre seit 1900. Für das Jahr 2000 ist der Wert 100. Sie können also nicht Zeichenketten wie "19".$array["tm_year"] bilden; in diesem Fall käme »19100« heraus. Dies ist kein Jahr-2000-Fehler, sondern eine Fehlinterpretation der Definition. Verwenden Sie den Operator »+«, um eine korrekte Ausgaben zu erzielen, wie das folgende Beispiel zeigt:<br /> <br /> <?php $time = localtime(); echo "Heute ist der "; echo $time[3] . "."; echo ++$time[4] . "."; echo $time[5] + 1900; ?> Das Skript liest die Zeitwerte in ein Array $time ein:<br /> <br /> $time = localtime(); Dann wird auf die Elemente zugegriffen. Der Wert für den Monat beginnt bei 0, muss also vor der Ausgabe inkrementiert werden:<br /> <br /> echo ++$time[4] . "."; Speziell bei der Jahreszahl wird als Operation eine Addition ausgeführt, keine Verkettung:<br /> <br /> echo $time[5] + 1900;<br /> <br /> Listing 13.14: Ausgabe von Zeitinformationen (date_localtime)<br /> <br /> V V V 1 2 3 4 5 6 7 8 9 10 11 12 13 14 A B C D E<br /> <br /> 344 ______________________________ 13 1000 kleine Helfer: Die PHP-Funktionen Abbildung 13.12: Die Ausgabe von Listing 13.14 Datumswerte auswerten strtotime<br /> <br /> Diese Funktion strtotime erwartet ein Datum mit ausgeschriebenen Namen in englischer Sprache. Zurückgegeben wird der UnixZeitstempel. Einstellungen mit setlocale haben keinen Einfluss. Andere Trennzeichen außer dem Leerzeichen sind nicht erlaubt. Das folgende Beispiel zeigt eine typische Zeichenkette und deren Umwandlung in ein anderes Sprachformat:<br /> <br /> Listing 13.15: Datumswerte erkennen<br /> <br /> <?php setlocale(LC_TIME, "ge"); $date = "may 26 2000"; $ts = strtotime($date); echo strftime("%d.%B %Y", $ts); ?> Das Skript setzt zuerst die lokale Sprache auf Deutsch. Das hat auf das Einlesen der Zeichenkette noch keinen Einfluss.<br /> <br /> setlocale(LC_TIME, "ge"); Dann wird der Wert untersucht:<br /> <br /> $date = "may 26 2000"; $ts = strtotime($date); Mit Hilfe der Funktion strftime erfolgt die lokalisierte Ausgabe, praktisch eine Übersetzung des originalen Wertes:<br /> <br /> echo strftime("%d.%B %Y", $ts); Abbildung 13.13: Ausgabe (Listing 13.15) Datumsberechnungen mktime<br /> <br /> Die Funktion mktime ermittelt den Unix-Zeitstempel für ein gegebenes Datum. Das mag auf den ersten Blick nicht sonderlich sinnvoll erscheinen – offenbart aber ein ganzes Spektrum an Möglichkeiten. Denn mit der Darstellung eines Datums in der Form des Zeitstempels können Sie sehr leicht Berechnungen anstellen. Die folgende Darstellung zeigt die Syntax der Funktion:<br /> <br /> Syntax<br /> <br /> Unix-Zeitstempel<br /> <br /> int mktime(int hour, int minute, int second, int month, int day, int year [, int is_daysave]) Der Zeitstempel entsteht durch Zählung der Sekunden seit Beginn der Unix-Epoche, dem 1.1.1970. Bedingt durch das verwendete Zahlenformat – 32 Bit – endet diese Periode Anfang 2038. Alle Berechnungen der hier vorgestellten Art funktionieren also nur zwischen 1970 und 2037 zuverlässig.<br /> <br /> 13.4 Zeitwächter: Datumsfunktionen _____________________________________ 345 Wenn year zweistellig angegeben wird, dann werden die Zahlen 70 bis 99 zu 1900 gezählt, die Zahlen 0 bis 69 dagegen zu 2000. Der höchste zulässige Wert ist auf 32-Bit-Systemen 2037. Der kleinstmögliche Wert ist 1902. Die Funktion eignet sich gut für Datumsberechnungen, weil die Werte ohne Rücksicht aufeinander angegeben werden können.<br /> <br /> <?php printf ('Es ist jetzt %s', date('H:i:s')); $time = 90; /* 90 Minuten */ $l = localtime(time()); echo '<br>'; $new = mktime($l[2], $l[1]+$time, $l[0], $l[4], $l[3], $l[5]+1900); printf ('%s min später ist es %s', $time, date('H:i:s', $new)); ?><br /> <br /> Listing 13.16: Datumsberechnungen mit mktime<br /> <br /> Das Skript nutzt localtime, um die aktuellen Teile der Zeit zu ermitteln:<br /> <br /> $l = localtime(time()); mktime werden dann neben diesen Werten auch gleich die neu berechneten übergeben: $new = mktime($l[2], $l[1]+$time, $l[0], $l[4], $l[3], $l[5]+1900); Das Skript rechnet korrekt auch über Zeitgrenzen wie den Tageswechsel hinweg. Abbildung 13.14: Ausgabe von Listing 13.16 Dieser Effekt beruht auf der internen Arbeitsweise. Alle Zeitwerte werden in das interne Format (timestamp) überführt. Dabei wird jeder einzelne durch die Anzahl Sekunden ersetzt, die ihm entsprechen. Es spielt also keine Rolle, ob Sie mit Stunden oder Tagen usw. rechnen, da intern immer Sekunden verwendet werden. Die Funktion gmmktime ermittelt den Zeitstempel nach UTC. Die Funktion gmmktime entspricht mktime, berücksichtigt aber die Differenz zu UTC. Im Zusammenhang mit mktime ist natürlich auch der Zeitstempel des time aktuellen Datums interessant. time gibt den aktuellen UNIX-Zeitstempel zurück. Die Funktion benötigt keine Parameter. Die Zeit bezieht sich auf die Betriebssystemzeit des Servers, auf dem PHP läuft. Dies ist möglicherweise nicht die Zeit, die Sie erwarten. Für lokale Zeitangaben ist es besser, auf JavaScript zurückzugreifen. Berechnungen mit hoher Genauigkeit Die Funktion microtime gibt eine Zeichenkette der Art »Mikrosekunden microtime Sekunden« zurück; die Zeitwerte sind also durch ein Leerzeichen getrennt.<br /> <br /> V V V 1 2 3 4 5 6 7 8 9 10 11 12 13 14 A B C D E<br /> <br /> 346 ______________________________ 13 1000 kleine Helfer: Die PHP-Funktionen Das folgende Beispiel zeigt den Einsatz zur Zeitmessung von Skripten: Listing 13.17: Messung der Ausführungszeit (microtime)<br /> <br /> <?php function mt() { $mt = microtime(); $at = explode(" ", $mt); return $at[1]+$at[0]; } $old = mt(); # lang dauernde Schleife for($i=0; $i<100000; $i++) {} $new = mt(); echo "Dauer: ". ($new - $old)." sec."; ?> Im Skript wird eine Funktion mt() definiert, die aus dem Array, das die eingebaute Funktion microtime zurück gibt, den vollständigen Wert ermittelt. Für eine ansprechendere Formatierung der Ausgabe eignet sich auch die Funktion printf bzw. sprintf.<br /> <br /> 13.4 Zeitwächter: Datumsfunktionen _____________________________________ 347<br /> <br /> 14 Fehlersuche und Konfiguration Wenn ein Skript nicht wie erwartet funktioniert, beginnt eine aufwändige Fehlersuche. Oft helfen die von PHP ausgegebenen Meldungen, die auch Hinweise auf den Ursprung des Problems einschließlich der Zeilennummer enthalten. Wenn keine Fehler angezeigt werden, das Skript aber dennoch nicht korrekt abläuft, wird es schwieriger. Dieses Kapitel gibt einige Tipps zur Fehlersuche. Manchmal ist auch die Konfiguration Auslöser bestimmter Schwierigkeiten. Ein Blick in die php.ini ist deshalb unerlässlich.<br /> <br /> 14<br /> <br /> Fehlersuche und Konfiguration<br /> <br /> 14.1 Die Informationszentrale ___________________________________________ 349<br /> <br /> 14.1 Die Informationszentrale PHP kann mit einer einzigen Funktion alle wichtigen Informationen über die aktuelle Konfiguration ausgeben. Dazu legen Sie das folgenden Skript auf Ihrem Webserver ab. Beim Aufruf werden dann wichtige Daten angezeigt.<br /> <br /> <?php phpinfo() ?> Der Kopf der Ausgabe klärt erst Mal über die Version auf:<br /> <br /> Listing 14.1: PHPInformationen (info) Abbildung 14.1: So meldet sich PHP 5.0.0 (RC1)<br /> <br /> Die Ausgabe erstreckt sich danach über viele Seiten. Sie ist in verschiedene Sektionen geteilt: • Kopfbereich (mit PHP-Logo) Hier stehen Informationen zum Betriebssystem, den Konfigurationsparametern und der Version • Configuration Hier sind die Einstellungen der wirksam sind.<br /> <br /> PHP.INI<br /> <br /> zu sehen, die tatsächlich<br /> <br /> Darunter folgen die installierten Module, deren Versionen und Konfigurationsparameter. • Additional Modules Hier stehen weitere externe Module, wenn diese installiert wurden. Dieser Abschnitt kann auch leer sein.<br /> <br /> V V V 1 2 3 4 5 6 7 8 9 10 11 12 13 14 A B C D E<br /> <br /> 350 ______________________________________ 14 Fehlersuche und Konfiguration • Environment Hier finden Sie alle System- und Webservervariablen. • PHP Variables Hier stehen die von PHP selbst definierten Variablen, die derzeit mit Werten belegt sind, insbesondere sie globalen HTTP-Arrays.<br /> <br /> 14.2 Konfiguration mit »php.ini« Die Einstellungen in php.ini stehen Ihnen normalerweise nicht zur Verfügung, wenn Sie PHP auf dem Server eines Providers nutzen. Sie können Sich aber mit Hilfe entsprechender Kenntnisse manche Reaktion des Servers erklären. Das erste Mal PHP.INI-DIST<br /> <br /> Wenn Sie PHP frisch installieren, finden Sie im Installationsverzeichnis die Datei php.ini-dist. Dies ist die »Distributionsform« – die Rohversion der Initialisierungsdatei. Sie müssen diese Datei in php.ini umbenennen und im Pfad für PHP verfügbar machen. Unter Windows ist es am einfachsten, die Datei ins Windows-Systemverzeichnis zu kopieren. Unter UNIX wird die Datei im aktuellen Arbeitsverzeichnis, also beispielsweise /ETC/PHP, gesucht. Sie können die Position auch festlegen, indem der Pfad in die Umgebungsvariable PHPRC geschrieben wird. Verändern Sie unter keinen Umständen die Originaldatei. Wenn Sie PHP mit falschen Einträgen funktionsunfähig machen, können Sie den Originalzustand leicht wiederherstellen, wenn die ursprüngliche Datei noch vorhanden ist. Und noch ein Tipp: Eine als »empfehlenswert« bezeichnete Form finden Sie in der Datei php.ini-recommended. Aufbau der Datei php.ini<br /> <br /> ; Kommentar [Sektion]<br /> <br /> Der Aufbau entspricht üblichen Konfigurationsdateien. Zeilen, die mit einem Semikolon beginnen, gelten als Kommentare und werden ignoriert. Sektionsabschnitte werden mit eckigen Klammern eingeleitet, beispielsweise [Sektion]. Auch solche Gebilde werden ignoriert.<br /> <br /> Groß- und Kleinschreibung<br /> <br /> Groß- und Kleinschreibung ist für die Schlüsselwörter relevant. Dies ist ein häufiger Fehler, der beim Eintragen zuvor gelöschter Schlüssel passiert. Achten Sie peinlich genau auf die Schreibweise; an vielen Stellen werden auch mitten im Wort Großbuchstaben zur optischen Auflockerung gesetzt.<br /> <br /> Wert "zwei Werte"<br /> <br /> Komplexe Werte werden in doppelte Anführungszeichen gesetzt. Ansonsten wertet PHP nur das erste Wort einer Wortkette aus.<br /> <br /> Schlüsselwörter: On, Off, Yes, No, True, False<br /> <br /> Oft werden Funktionen mit Schlüsselwörtern aktiviert oder deaktiviert. Die Schlüsselwörter sind: •<br /> <br /> On, Off<br /> <br /> 14.2 Konfiguration mit »php.ini« _________________________________________ 351 •<br /> <br /> Yes, No<br /> <br /> •<br /> <br /> TRUE, FALSE, true, false<br /> <br /> •<br /> <br /> 1, 0<br /> <br /> Bei den Schlüsselwörtern spielt Groß- und Kleinschreibung keine Rolle, YES und yes sind also identisch. Die Konfigurationsdatei im Detail Die folgenden Tabellen zeigen die einzelnen Abschnitte der Datei PHP.INI mit den möglichen Einstellungen. In der Spalte »Wert« finden Sie ein Beispiel oder den voreingestellten Standardwert. Option<br /> <br /> Wert Beschreibung<br /> <br /> engine<br /> <br /> On<br /> <br /> Aktiviert die Skriptengine unter Apache<br /> <br /> short_open_tag<br /> <br /> On<br /> <br /> erlaubt kurze Tags: <? anstatt <?php<br /> <br /> asp_tags<br /> <br /> Off<br /> <br /> erlaubt ASP-Tags <% %><br /> <br /> precision<br /> <br /> 12<br /> <br /> Genauigkeit, mit der Gleitkommazahlen verarbeitet werden<br /> <br /> y2k_compliance<br /> <br /> On<br /> <br /> Jahr 2000-Kompatibilität<br /> <br /> output_buffering<br /> <br /> Off<br /> <br /> Ausgabepufferung; wenn On, ist das Senden von Headern auch nach der Ausgabe von Daten erlaubt. Name einer Funktion, die zur Ausgabe der Seite aufgerufen wird. Schaltet output_buffering implizit ein.<br /> <br /> output_handler<br /> <br /> <br /> <br /> zlib. output_compression<br /> <br /> Off<br /> <br /> Kompression des Ausgabestroms mit dem ZIP-Kompressionsverfahren. Kann Off, On oder Puffergröße sein (Standardwert 4KB)<br /> <br /> zlib.output_handler<br /> <br /> Off<br /> <br /> Handlerprogramm, dass die Komprimierung übernimmt (standardmäßig auskommentiert)<br /> <br /> implicit_flush<br /> <br /> Off<br /> <br /> Wenn On, wird der Puffer nach jedem Block ausgegeben. Entspricht dem Aufruf von flush()<br /> <br /> <br /> <br /> unserialize _callback_func<br /> <br /> Handlerfunktion zur Deserialisierung von Klassen<br /> <br /> <br /> <br /> allow_call_time _pass_reference<br /> <br /> On<br /> <br /> Erlaubt die Übergabe von Funktionsparametern per Referenz. Ist obsolet, da diese Angabe im Funktionskopf erfolgen muss (Operator &).<br /> <br /> Der folgende Abschnitt betrifft Sicherheitsoptionen. Die Standardeinstellungen sind nicht sicher. Provider setzen oft safe_mode auf On, um ihre Server zu schützen. Deshalb gibt es einige Einschränkungen, wenn PHP im Webspace ausgeführt wird.<br /> <br /> Tabelle 14.1: Konfiguration der Sprachoptionen (mit abgekürzte Namen sind im Ganzen zu lesen)<br /> <br /> <br /> <br /> V V V 1 2 3 4 5 6 7 8 9 10 11 12 13 14 A B C D E<br /> <br /> 352 ______________________________________ 14 Fehlersuche und Konfiguration Tabelle 14.2: Sicherheitsoptionen<br /> <br /> Option<br /> <br /> Wert<br /> <br /> Beschreibung<br /> <br /> safe_mode<br /> <br /> Off<br /> <br /> On schaltet den sicheren Modus ein<br /> <br /> safe_mode_gid<br /> <br /> Off<br /> <br /> UID/GID-Prüfung bei der Dateiöffnung (User versus Group)<br /> <br /> safe_mode _include _dir<br /> <br /> <Pfad><br /> <br /> Zwingender Pfad zu Include-Dateien, wenn der Safe Mode eingeschaltet ist<br /> <br /> safe_mode_exec_dir<br /> <br /> <Pfad><br /> <br /> Erzwingt Verzeichnis zur Ausführung von Erweiterungen (DLLs/SOs)<br /> <br /> PHP_<br /> <br /> Erzwingt einen Präfix vor Umgebungsvariablen, um den Zugriff aber nicht die Nutzbarkeit einzuschränken. Der Präfix wird mit dieser Option bestimmt.<br /> <br /> LD_ LIBRARY _ PATH<br /> <br /> Kommaseparierte Liste von Umgebungsvariablen, die nicht verändert werden dürfen.<br /> <br />  <br /> <br /> safe_mode _allowed_env_vars<br /> <br />  <br /> <br /> safe_mode _protected _env_vars<br /> <br /> (Standard bei Providern)<br /> <br /> Kommaseparierte Liste von Funktionen, die nicht genutzt werden dürfen.<br /> <br /> disable_functions<br /> <br /> PHP erlaubt die Ausgabe von Code mit einer Hervorhebung von syntaktischen Einheiten. Die Farben dieser Ausgabe können Sie im nächsten Abschnitt einstellen. Die Ausgabe der Werte erfolgt in einem <font>-Tag. Tabelle 14.3: Farben für die Syntaxhervorhebung<br /> <br /> Option<br /> <br /> Wert<br /> <br /> Beschreibung<br /> <br /> highlight.string<br /> <br /> #DD0000<br /> <br /> Zeichenketten<br /> <br /> highlight.comment<br /> <br /> #FF8000<br /> <br /> Kommentare<br /> <br /> highlight.keyword<br /> <br /> #007700<br /> <br /> Schlüsselwörter<br /> <br /> highlight.bg<br /> <br /> #FFFFFF<br /> <br /> Hintergrund<br /> <br /> highlight.default<br /> <br /> #0000BB<br /> <br /> Alles andere<br /> <br /> highlight.html #000000 HTML Die folgende Option steuert die Ausgabe eines HTTP-Headers, der auf die Existenz von PHP hinweist. Diese Angabe ist aus Sicherheitsgründen unkritisch. Tabelle 14.4: Verschiedenes<br /> <br /> Option<br /> <br /> Wert<br /> <br /> Beschreibung<br /> <br /> expose_php<br /> <br /> On<br /> <br /> Wenn On, fügt PHP einen X-Header hinzu, der die Version anzeigt<br /> <br /> Die folgenden Optionen betreffen die Gesamtleistung des Systems. Wenn safe_mode = On, kann der Wert, der in max_execution_time vorgegeben wurde, nicht per Funktion verändert werden. Tabelle 14.5: Umgang mit Resourcen<br /> <br /> Option<br /> <br /> Wert<br /> <br /> Beschreibung<br /> <br /> max_execution_time<br /> <br /> 30<br /> <br /> Maximale Ausführungszeit in Sekunden<br /> <br /> 14.2 Konfiguration mit »php.ini« _________________________________________ 353 Option<br /> <br /> Wert<br /> <br /> Beschreibung<br /> <br /> memory_limit<br /> <br /> 8M<br /> <br /> Maximaler Speicherverbrauch eines Skripts (M = MegaByte)<br /> <br /> max_input_time<br /> <br /> 60<br /> <br /> Zeit, die ein Skript zum Verarbeiten der empfangenen Daten maximal zur Verfügung hat.<br /> <br /> Der nächste Abschnitt steuert die Fehlerbehandlung. Verwendet werden folgende Konstanten, die Bits eines Bitfelds repräsentieren: •<br /> <br /> E_ALL. Alle Fehler und Warnungen<br /> <br /> •<br /> <br /> E_ERROR. Nur schwerwiegende Fehler<br /> <br /> •<br /> <br /> E_WARNING. Nur Warnungen<br /> <br /> •<br /> <br /> E_PARSE. Fehler des Compilers<br /> <br /> •<br /> <br /> E_NOTICE. Nachrichten<br /> <br /> •<br /> <br /> E_CORE_ERROR. Fehler in der Startphase<br /> <br /> •<br /> <br /> E_CORE_WARNING. Warnung in der Startphase<br /> <br /> •<br /> <br /> E_COMPILE_ERROR. Schwere Compilerfehler<br /> <br /> •<br /> <br /> E_COMPILE_WARNING. Compilerwarnungen<br /> <br /> •<br /> <br /> E_USER_ERROR. Benutzergenerierte Fehler<br /> <br /> •<br /> <br /> E_USER_WARNING. Benutzergenerierte Warnungen<br /> <br /> •<br /> <br /> E_USER_NOTICE. Benutzergenerierte Nachrichten<br /> <br /> Option<br /> <br /> Wert<br /> <br /> Beschreibung<br /> <br /> error_reporting<br /> <br /> E_ALL & ~E_NOTICE<br /> <br /> Beispiel für den Einsatz der Konstanten: Alles außer Nachrichten<br /> <br /> display_errors<br /> <br /> On<br /> <br /> Schaltet die Fehlerausgabe ein<br /> <br /> display_startup _errors<br /> <br /> Off<br /> <br /> Fehler beim Startup-Prozess<br /> <br /> log_errors<br /> <br /> Off<br /> <br /> Schaltet die Protokollierung von Fehlern ein<br /> <br /> log_errors_max_len<br /> <br /> 1024<br /> <br /> <br /> <br /> Maximale Länge der protokollierten Meldung<br /> <br /> ignore_repeated _errors<br /> <br /> Off<br /> <br /> Wiederholende Fehler werden nicht protokolliert, wenn »On«<br /> <br /> ignore_repeated _source<br /> <br /> <br /> <br /> Off<br /> <br /> Ignoriert auch die Fehlerquelle, wenn wiederholende Fehler nicht protokolliert werden (siehe vorhergehende Option)<br /> <br /> report_memleaks<br /> <br /> On<br /> <br /> Berichte über Speicherlecks<br /> <br /> track_errors<br /> <br /> Off<br /> <br /> Speichert die letzte Fehlermeldung in $php_errormsg<br /> <br /> html_errors<br /> <br /> Off<br /> <br /> Entfernt HTML aus Fehlermeldungen<br /> <br /> <br /> <br /> Tabelle 14.6: Fehlerbehandlung<br /> <br /> V V V 1 2 3 4 5 6 7 8 9 10 11 12 13 14 A B C D E<br /> <br /> 354 ______________________________________ 14 Fehlersuche und Konfiguration Option<br /> <br /> Wert<br /> <br /> Beschreibung<br /> <br /> docref_root<br /> <br /> /php manual/<br /> <br /> docref_ext<br /> <br /> .html<br /> <br /> Verzweigt auf das PHP-Handbuch und legt die Erweiterung der Dateien fest, um Hinweise aus Fehlermeldungen heraus anzuzeigen. Beide Optionen sind standardmäßig auskommentiert.<br /> <br /> <br /> <br /> error_prepend _string<br /> <br /> <str><br /> <br /> Zeichenkette, die vor jedem Fehler angezeigt wird: "<font color=ff0000>"<br /> <br /> error_append _string<br /> <br /> <str><br /> <br /> Zeichenkette, die nach jedem Fehler ausgegeben wird: </font><br /> <br /> error_log<br /> <br /> <file><br /> <br /> Dateiname der Protokolldatei<br /> <br /> error_log<br /> <br /> syslog<br /> <br /> Typ der Systemprotokolldatei (gilt nicht für Windows 9x/Me)<br /> <br /> <br /> <br /> PHP erleichtert die Programmierung, indem viele Informationen, die zwischen Server und Browser übertragen werden, vorverarbeitet werden. Dieses Verhalten kann in seltenen Fällen problematisch sein. Der folgende Abschnitt erlaubt Modifikationen dieses Verhaltens. Die in früheren Versionen vorhandene Option track_vars, die das Scanverhalten aktivierte, gibt es nicht mehr. Dieses Verhalten ist jetzt immer vorhanden. Tabelle 14.7: Datenverarbeitung<br /> <br /> Option<br /> <br /> Wert<br /> <br /> Beschreibung<br /> <br /> <br /> <br /> &<br /> <br /> <br /> <br /> Wert zum Trennen von URL-Argumenten. Normalerweise deaktiviert; dann ein einfaches &-Zeichen.<br /> <br /> arg_separator .input<br /> <br /> ;&<br /> <br /> Dasselbe Trennzeichen, aber bei Auswertung eines URL. Jedes Zeichen wird beachtet. Normalerweise deaktiviert und es wird ein einfaches &-Zeichen benutzt.<br /> <br /> variables_order<br /> <br /> "EGPCS"<br /> <br /> Reihenfolge, in der externe Daten in globale Variablen überführt werden (E = Umgebung, G = GET, P = Post, C = Cookies, S = Server)<br /> <br /> register_globals<br /> <br /> Off<br /> <br /> Wenn On, werden externe, registrierte Variablen global zur Verfügung gestellt, ansonsten nur in den $HTTP_*_VARS[]bzw. $_-Arrays.<br /> <br /> register_argc_argv<br /> <br /> On<br /> <br /> Wenn On, werden Kommandozeilenargumente ausgewertet.<br /> <br /> post_max_size<br /> <br /> 8M<br /> <br /> Maximaler Platz für Formulardaten und Dateiupload (M = MegaByte)<br /> <br /> gpc_order<br /> <br /> "GPC"<br /> <br /> Obsolet, durch variables_order ersetzt (gilt jedoch für PHP 3).<br /> <br /> arg_separator .output<br /> <br /> PHP erlaubt es, Sonderzeichen automatisch mit dem Fluchtzeichen (Escape-Zeichen) Backslash zu versehen, damit diese ihre Wirkung verlieren. Die folgenden Optionen steuern dieses Verhalten.<br /> <br /> 14.2 Konfiguration mit »php.ini« _________________________________________ 355 Option<br /> <br /> Wert<br /> <br /> Beschreibung<br /> <br /> magic_quotes_gpc<br /> <br /> On<br /> <br /> <br /> <br /> Quoted (markiert Sonderzeichen) in GET, POST- und Cookie-Daten<br /> <br /> magic_quotes _runtime<br /> <br /> Off<br /> <br /> Quoted (markiert Sonderzeichen) in allen Zeichenketten<br /> <br /> magic_quotes _sybase<br /> <br /> <br /> <br /> Off<br /> <br /> Quoted (markiert Sonderzeichen) im Sybase-Format (mit '-Zeichen anstatt \Zeichen)<br /> <br /> Tabelle 14.8: Automatisches Quoten und Markieren<br /> <br /> Vor dem Start eines Skripts und danach kann PHP einen speziellen Code ausführen. Tragen Sie hier den Namen der Datei ein, die ausführbaren Skriptcode enthält. Option<br /> <br /> Wert<br /> <br /> Beschreibung<br /> <br /> auto_prepend_file<br /> <br /> <file><br /> <br /> Ausführung vor jedem Skript<br /> <br /> Ausführung nach jedem Skript auto_append_file <file> Bei der Ausgabe von Daten erzeugt PHP einen HTTP-Header, der auf den Inhalt der Seite hinweist. Die folgenden beiden Optionen kennzeichnen die Attribute dieses Headers.<br /> <br /> Option<br /> <br /> Wert<br /> <br /> Beschreibung<br /> <br /> default_mimetype<br /> <br /> "text/ html"<br /> <br /> Standard MIME-Type für den HTTPHeader<br /> <br /> Tabelle 14.9: Ausführen von Skripten/HTML vor und nach jedem Skript<br /> <br /> Tabelle 14.10: MIME-Type Header<br /> <br /> Setzt den Zeichensatz-Header ein. Soll "isokein Header gesendet werden, wird die 8859Zeile auskommentiert (Standard). 1" Bei der Ausführung können Pfade, in denen Skripte liegen, automatisch gefunden werden, wenn die folgenden Optionen konfiguriert sind. Standardmäßig muss der vollständige virtuelle Pfad angegeben werden, wenn Funktionen Datei- oder Pfadangaben erwarten.<br /> <br /> default_charset<br /> <br /> Option<br /> <br /> Wert<br /> <br /> Beschreibung<br /> <br /> include_path<br /> <br /> <path> Pfad, in dem nach Dateien gesucht wird.<br /> <br /> doc_root<br /> <br /> <path> Stammpfad (kann leer bleiben)<br /> <br /> user_dir<br /> <br /> <path> Aufrufe nach /~username landen in die-<br /> <br /> extension_dir<br /> <br /> ./<br /> <br /> Verzeichnis mit ladbaren Modulen<br /> <br /> enable_dl<br /> <br /> On<br /> <br /> Schaltet die dl()-Funktion ein<br /> <br /> cgi.force_redirect<br /> <br /> 1<br /> <br /> Schaltet CGI-Weiterleitung aus (1 = aus, 0 = ein, was etwas widersprüchlich ist). Nur für den IIS wird 0 zwingend benötigt.<br /> <br /> UNIX: "/path1:/path2" Windows: "\path1;\path2"<br /> <br /> sem Pfad<br /> <br /> Tabelle 14.11: Pfade und Verzeichnisse<br /> <br /> V V V 1 2 3 4 5 6 7 8 9 10 11 12 13 14 A B C D E<br /> <br /> 356 ______________________________________ 14 Fehlersuche und Konfiguration Option<br /> <br /> Wert<br /> <br /> Beschreibung<br /> <br /> cgi. redirect_status_env<br /> <br /> <br /> <br /> <var><br /> <br /> Eine Umgebungsvariable <var>, die der Webserver (nicht Apache) benötigen kann, um PHP zu finden.<br /> <br /> fastcgi.impersonate<br /> <br /> 1<br /> <br /> Bietet die schnellere FastCGI-Schnittstelle unter dem IIS (nicht Apache).<br /> <br /> cgi.rfc2616_headers<br /> <br /> 0<br /> <br /> Auf 1 setzen, um IIS-kompatible Header nach RFC 2616 zu senden (nicht für Apache).<br /> <br /> PHP erlaubt auf sehr einfache Weise das Hochladen von Dateien. Die folgenden Optionen steuern dieses Verhalten. Es kann jedoch zur Laufzeit mit Funktionen modifiziert werden. Tabelle 14.12: Datei-UploadVerhalten<br /> <br /> Option<br /> <br /> Wert<br /> <br /> Beschreibung<br /> <br /> file_uploads<br /> <br /> On<br /> <br /> Erlaubt Upload<br /> <br /> upload_tmp_dir<br /> <br /> <path><br /> <br /> Temporäres Verzeichnis, in dem die Daten zwischengespeichert werden<br /> <br /> <br /> <br /> Maximale Größe für hochgeladene Dateiupload_max 2M en (M = MegaByte) _filesize Die PHP-Funktion fopen ermöglicht den Zugriff auf Dateien. Spezielle Präfixe vor dem Dateinamen erlauben jedoch den Zugriff auf Dateien per HTTP oder FTP auf fremden Servern. Mit der folgender Option lässt sich dieses Verhalten deaktivieren.<br /> <br /> Tabelle 14.13: Wrapper für fopen()<br /> <br /> Option<br /> <br /> Wert<br /> <br /> Beschreibung<br /> <br /> allow_url_fopen<br /> <br /> On<br /> <br /> Erlaubt Umleitungen für fopen, beispielsweise http:// oder ftp://<br /> <br /> from<br /> <br /> <mail><br /> <br /> E-Mail-Adresse, die bei anonymen FTPZugriffen verwendet wird.<br /> <br /> user_agent<br /> <br /> PHP<br /> <br /> Name des Clients; wird zur Authentifizierung verwendet.<br /> <br /> 60<br /> <br /> Zeit in Sekunden, die maximal auf die Verbindung gewartet wird (konfigurierbar).<br /> <br /> Off<br /> <br /> Automatische Zeilenendeerkennung, wenn der Kommunikationspartner ein Mac ist.<br /> <br /> <br /> <br /> default_socket _timeout<br /> <br /> <br /> <br /> auto_detect_line _endings<br /> <br /> PHP erlaubt das Einbinden von Modulen zur Laufzeit. Diese Funktion wird vor allem unter Windows verwendet, wo die Module als DLL vorliegen. Unter Linux ist es eher üblich, Module einzukompilieren. Als SODatei vorliegende Unix-Bibliotheken lassen sich aber auch einbinden, wenn sie für PHP übersetzt wurden. Abschnitt für Module<br /> <br /> PHP besteht aus einer Vielzahl einzelner Module. Die folgenden Abschnitte zeigen Einstellungen für jeweils eines dieser Module. Die folgende Option aktiviert oder deaktiviert die Variablen, die Hinweise auf das Systemprotokoll enthalten. Die Werte können auch bei deakti-<br /> <br /> 14.2 Konfiguration mit »php.ini« _________________________________________ 357 vierter Option mit der Funktion define_syslog_variables ermittelt werden. Option<br /> <br /> Wert<br /> <br /> Beschreibung<br /> <br /> <br /> <br /> Tabelle 14.14: Modul [Syslog]<br /> <br /> Setzt Systemvariablen, Off verbessert die define_syslog Off Systemleistung _variables Die Mailfunktionen müssen nur unter Windows konfiguriert werden, wo es eine ganze Palette von SMTP-Servern gibt, an die PHP angepasst werden kann. Unter Linux nutzt PHP in jedem Fall sendmail, was standardmäßig installiert ist.<br /> <br /> Option<br /> <br /> Wert<br /> <br /> Beschreibung<br /> <br /> SMTP<br /> <br /> <host><br /> <br /> SMTP-Server (nur für Win32)<br /> <br /> sendmail_from<br /> <br /> <str><br /> <br /> Standardabsender (nur für Win32)<br /> <br /> Tabelle 14.15: Modul [mail function]<br /> <br /> Pfad zu sendmail mit Parametern (nur für Unix)<br /> <br /> sendmail_path<br /> <br /> Die folgenden beiden Optionen steuern das Verhalten des Protokollmoduls, mit dem Fehlerzustände in Protokolldateien geschrieben werden. Option<br /> <br /> Wert<br /> <br /> Beschreibung<br /> <br /> logging.method<br /> <br /> db<br /> <br /> Speichermethode für Protokolle<br /> <br /> Tabelle 14.16: Modul [Logging]<br /> <br /> Pfad zu den Protokolldateien logging.directory <path> Der folgende Abschnitt betrifft den Umgang mit Datenbankzugriffen. Es folgen dann Optionen für bestimmte Datenbanken.<br /> <br /> Option<br /> <br /> Wert<br /> <br /> Beschreibung<br /> <br /> Tabelle 14.17: [SQL]-Modul<br /> <br /> Sicherer Modus für SQL sql.safe_mode Off Das ODBC-Modul betrifft Zugriffe auf Datenbanken, die über eine ODBC-Schnittstelle verfügen. Diese Schnittstelle ist unter Windows weit verbreitet und erlaubt den Zugriff auf Datenquellen wie MS Access oder MS Excel, für die keine nativen Treiber oder Module beiliegen.<br /> <br /> Option<br /> <br /> Wert<br /> <br /> Beschreibung<br /> <br /> odbc. allow_persistent<br /> <br /> <br /> <br /> On<br /> <br /> Erlaubt persistente Verbindungen<br /> <br /> odbc. check_persistent<br /> <br /> <br /> <br /> On<br /> <br /> Prüft persistente Verbindungen vor dem Zugriff<br /> <br /> odbc. max_persistent<br /> <br /> <br /> <br /> -1<br /> <br /> Maximale Anzahl der persistenten Verbindungen, -1 ist unbegrenzt<br /> <br /> uodbc.max_links<br /> <br /> -1<br /> <br /> Maximale Anzahl der Verbindungen (egal ob persistent oder nicht), -1 ist unbegrenzt<br /> <br /> uodbc.defaultlrl<br /> <br /> 4096<br /> <br /> Behandlung von LONG-Feldern, 0 = unverändert<br /> <br /> Tabelle 14.18: [ODBC]-Modul<br /> <br /> V V V 1 2 3 4 5 6 7 8 9 10 11 12 13 14 A B C D E<br /> <br /> 358 ______________________________________ 14 Fehlersuche und Konfiguration Option<br /> <br /> Wert<br /> <br /> Beschreibung<br /> <br /> <br /> <br /> Behandlung von Binärdaten, 0 = durchreiuodbc. 1 chen, 1 = Unverändert, 2 = Konvertiert defaultbinmode MySQL ist immer noch die Standarddatenbank16 für PHP. Entsprechend umfangreich ist die Anzahl der Einstellungsmöglichkeiten. In den meisten Fällen sind die Angaben jedoch unnötig, weil diese Einstellungen bequemer vom Skript aus vorgenommen werden können oder bei aktiviertem Safe-Mode nicht erlaubt sind (betrifft default_host, default_user und default_pass).<br /> <br /> Tabelle 14.19: Modul [MySQL]<br /> <br /> Option<br /> <br /> <br /> <br /> mysql .allow_persistent<br /> <br /> Wert<br /> <br /> Beschreibung<br /> <br /> On<br /> <br /> Erlaubt persistente Verbindungen<br /> <br /> mysql.max_persistent -1<br /> <br /> Maximale Anzahl der persistenten Verbindungen, -1 ist unbegrenzt<br /> <br /> mysql.max_links<br /> <br /> -1<br /> <br /> Maximale Anzahl der Verbindungen (egal ob persistent oder nicht), -1 ist unbegrenzt<br /> <br /> mysql.default_port<br /> <br /> <port> Standardport des MySQL-Servers<br /> <br /> mysql.default_socket <sock> Socket für den MySQL-Server (bleibt normalerweise leer)<br /> <br /> mysql.default_host<br /> <br /> <host> Name des MySQL-Servers. Kann im<br /> <br /> mysql.default_user<br /> <br /> <user> Standardbenutzer. Kann im sicheren<br /> <br /> sicheren Modus nicht verändert werden. Modus nicht verändert werden.<br /> <br /> <br /> <br /> mysql .default_password<br /> <br /> <pass> Standardkennwort. Kann im sicheren Modus nicht verändert werden.<br /> <br /> Normalerweise werden Zahlenwerte im Computer in binärer Form gespeichert. Dies führt jedoch in seltenen Fällen zu Rechenfehlern, weil der Wertebereich anders als bei dezimalen Zahlen ausgebildet ist. Werden Berechnungen mit hoher Genauigkeit benötigt, hilft das BCMATHModul, dass intern mit dezimalen Zahlen rechnet. Die Anzahl der gespeicherten Dezimalstellen können Sie mit der folgenden Option angeben. Tabelle 14.20: [bcmath]-Modul<br /> <br /> Option<br /> <br /> Wert<br /> <br /> Beschreibung<br /> <br /> bcmath.scale<br /> <br /> 0<br /> <br /> Anzahl der Dezimalstellen bei bcFunktionen, 0 = Keine Vorgabe<br /> <br /> Um zu erkennen, welche Funktionen ein Browser hat, wird eine Kennungsdatei verwendet, die für alle bekannten Browser entsprechende Angaben enthält. Dies sagt jedoch nichts darüber aus, ob der Benutzer diese Funktionen auch aktiviert hat. Geben Sie mit der folgenden Option den Pfad zu einer aktuellen Version dieser Datei an.<br /> <br /> 16<br /> <br /> SQLite hat keine Konfigurationsmöglichkeiten in der PHP.INI.<br /> <br /> 14.2 Konfiguration mit »php.ini« _________________________________________ 359 Option<br /> <br /> Wert<br /> <br /> Beschreibung<br /> <br /> Tabelle 14.21: Modul [browscap]<br /> <br /> Pfad zur Browserinformationsdatei browscap <file> Das Session-Modul steuert die Verfolgung von Nutzern über mehrere Seiten hinweg. Dies ist notwendig, weil HTTP selbst statuslos arbeitet und die Verbindung nach der Auslieferung jeder Seite beendet.<br /> <br /> Die folgenden Optionen steuern das Verhalten von PHP in Bezug auf Sitzungen. Option<br /> <br /> Wert<br /> <br /> session.save_handler files<br /> <br /> Beschreibung Art der Sessionspeicherung (files = in Dateien). Kann auch user sein (eigene Funktionen erforderlich).<br /> <br /> session.save_path<br /> <br /> <path> Pfad, wo die Sessionsteuerung Daten speichert (meist /tmp)<br /> <br /> session.use_cookies<br /> <br /> 1<br /> <br /> session.name<br /> <br /> PHPSES Name der Session, wird als Cookiename oder GET-Parameter verwendet SID<br /> <br /> session.auto_start<br /> <br /> 0<br /> <br /> Erlaubt Cookies<br /> <br /> Startet Session immer auch ohne session_start-Funktion<br /> <br /> session.cookie_lifet 0 ime<br /> <br /> Lebensdauer des Cookies in Sekunden, 0 = Sessioncookie<br /> <br /> session.cookie_path<br /> <br /> /<br /> <br /> Pfad für Cookie<br /> <br /> session .cookie_domain<br /> <br /> <dom><br /> <br /> Domäne für Cookie<br /> <br /> session .serialize_handler<br /> <br /> <br /> <br /> php<br /> <br /> Art der Serialisierung der Daten (php = interne Funktion)<br /> <br /> session .gc_probability<br /> <br /> <br /> <br /> 1<br /> <br /> Steuert die Häufigkeit des Aufräumprozesses, siehe folgenden Parameter.<br /> <br /> session .gc_dividend<br /> <br /> <br /> <br /> 100<br /> <br /> <br /> <br /> Dividend für den vorhergehenden Parameter 1/100 = 1% , in einem von 100 Aufrufen startet der Garbage Collector.<br /> <br /> session .gc_maxlifetime<br /> <br /> 1440<br /> <br /> Zeit, nach der temporäre Daten gelöscht werden<br /> <br /> session .referer_check<br /> <br /> <br /> <br /> 0<br /> <br /> Prüft die Herkunft des Skripts<br /> <br /> session .entropy_length<br /> <br /> <br /> <br /> 0<br /> <br /> Anzahl Bytes, die maximal gelesen werden, 0 = unbegrenzt<br /> <br /> <br /> <br /> session.entropy_file <name> Datei, aus der Session-IDs generiert<br /> <br /> <br /> <br /> session .entropy_length<br /> <br /> werden<br /> <br /> 16<br /> <br /> Länge der Session-ID (32, wenn auskommentiert = Standard)<br /> <br /> Tabelle 14.22: [Session]-Modul<br /> <br /> V V V 1 2 3 4 5 6 7 8 9 10 11 12 13 14 A B C D E<br /> <br /> 360 ______________________________________ 14 Fehlersuche und Konfiguration Option<br /> <br /> Wert<br /> <br /> <br /> <br /> Beschreibung<br /> <br /> session .entropy_file<br /> <br /> /dev/u Quelle für den Zufallsgenerator, Stanrandom dard = auskommentiert (deaktiviert)<br /> <br /> session .cache_limiter<br /> <br /> no cache<br /> <br /> <br /> <br /> Lebensdauer des Caches im Browser (nocache, private, public}<br /> <br /> session.cache_expire 180<br /> <br /> Lebensdauer des Dokuments<br /> <br /> session .use_trans_sid<br /> <br /> 1<br /> <br /> Erlaubt transiente Übergabe der SessionID, wenn mit --enable-trans-sid compliert wurde<br /> <br /> url_rewriter.tags<br /> <br /> <str><br /> <br /> <br /> <br /> Liste der Tags, die erweitert werden, um die Session-ID automatisch anzuhängen: "a=href, area=href, frame=src, input=src, form=fakeentry"<br /> <br /> session .bug_compat_42<br /> <br /> 1<br /> <br /> session .bug_compat_warn<br /> <br /> <br /> <br /> 1<br /> <br /> Bis Version 4.2 war es möglich, Sitzungsvariablen global zu registrieren, auch wenn es für andere Variablen unmöglich war. Die Optionen schalten das Verhalten auch unter 4.3 ein und warnen ggf. vor der Verwendung.<br /> <br /> <br /> <br /> Beim Aufbau einer Verbindung per TCP/IP wird eine Kombination aus IP-Adresse und Port benutzt – ein so genanntes Socket. Dieses kann vom Betriebssystem oder von PHP verwendet werden, was dire folgende Option steuert. Tabelle 14.23: [Sockets]-Modul<br /> <br /> Option<br /> <br /> Wert<br /> <br /> Beschreibung<br /> <br /> <br /> <br /> Wenn On, wird der Systemaufruf read sockets.use On anstatt des mit PHP gelieferten genutzt _system_read Weitere Optionen für sehr seltene Datenbanksysteme und einige Bibliotheken folgen an dieser Stelle. Hier eine kurze Aufzählung:<br /> <br /> • Datenbanken: Ingres, Informix, SyBase, FrontBase, MS SQL, mSQL, PostgreSQL • COM- und Java-Modul • Printer-Modul (nur für Windows) • MbString (verarbeitet asiatische Schriftzeichen) • Crack • Exif (Konvertierung asiatischer Schriftzeichen) • Assert-Fehlerverfolgungssystem • Verisign Payflow<br /> <br /> 14.3 Tipps zur Fehlersuche _____________________________________________ 361<br /> <br /> 14.3 Tipps zur Fehlersuche Bei der Fehlersuche ist der Zustand von Variablen von großer Bedeutung. Vor allem der Zugriff auf Arrays ist aber unter Umständen lästig. Zwei Funktionen helfen, die Ausgabe sehr einfach vorzunehmen. Um zu erkennen, wie PHP Variablen zuordnet, können Sie die Funktion var_dump var_dump nutzen. Geben Sie als Argument den Namen einer Variablen an:<br /> <br /> $test = "abc"; var_dump($test); Dieser Code führt zu folgender Ausgabe;<br /> <br /> string(3) "abc"; Die Angabe von Zahlenwerten erfolgt etwas anders:<br /> <br /> $test = 123; var_dump($test); Dies führt zu der folgenden Ausgabe:<br /> <br /> int(123); Etwas umfangreicher, aber vor allem bei Arrays auch unleserlicher, sind print_r die Ausgaben, die print_r erzeugt. Beachten Sie, dass, bei der Ausgabe globaler Variablen mit einer Referenz auf sich selbst (wie $GLOBALS), die Funktion print_r in eine Endlosschleife läuft.<br /> <br /> 14.4 Typische Fehler Beim Programmieren kommt es immer wieder zu typischen Fehlern. Damit Sie nicht in dieselben Fallen tappen, wie viele andere vor Ihnen, finden Sie eine lockere Aufzählung in diesem Abschnitt.<br /> <br /> 14.4.1 Verwendung von printf und print Oft werden Funktionen eingesetzt, die an dieser Stelle zwar funktionieren, wo andere aber effektiver arbeiten. So sind in vielen Skripten Anwendungen von printf zu finden:<br /> <br /> printf("Ich bin $d Jahre alt", $alter); Das ist nicht falsch, aber völlig unnütz. Denn printf erlaubt komplexe Formatierungen. Ein einfacher Variablenersatz lässt sich einfacher folgendermaßen schreiben:<br /> <br /> print("Ich bin $alter Jahre alt"); printf ist langsamer und schwerer zu lesen und damit eine potenzielle Fehlerquelle.<br /> <br /> V V V 1 2 3 4 5 6 7 8 9 10 11 12 13 14 A B C D E<br /> <br /> 362 ______________________________________ 14 Fehlersuche und Konfiguration Verwenden Sie printf nur dann, wenn Sie die Formatierungen tatsächlich benötigen. Auf der anderen Seite sollten Sie immer printf bevorzugen, wenn Formatierungen damit möglich sind, anstatt eigene Funktionen zu schreiben.<br /> <br /> 14.4.2 Missbrauch des Variablenersatzes Die Möglichkeit, Variablen in Zeichenketten durch PHP ersetzen zu lassen, ist ebenso reizvoll wie effektiv. Missbrauch kann aber zu Fehlern führen. Das folgende Beispiel zeigt, wann der Ersatz nicht angebracht ist.<br /> <br /> $handle = fopen("data.txt", "r"); while ($line = @fgets("$handle", 1024)) { echo "$line<br>"; } Die Variable $handle enthält eine Ganzzahl, die durch den Einbau in Anführungszeichen in eine Zeichenkette umgewandelt wird. Damit kann fgets aber nichts anfangen. Die Fehlermeldung wird zudem mit @ unterdrückt – dieses Skript macht nichts und gibt auch keinen Fehler aus. Verwenden Sie die Ersetzung von Variablen in Zeichenketten nur dann, wenn dies wirklich notwendig ist. Wenn Sie Zeichenketten benötigen, verwenden Sie einfache Anführungszeichen. Achten Sie auf die Datentypen.<br /> <br /> 14.4.3 Umgang mit Variablen Es gibt einige Regeln beim Umgang mit Variablen, die die Qualität von Skripten verbessern. So sollten Sie neue Variablen nur dann einführen, wenn diese wenigstens zweimal verwendet werden.<br /> <br /> <?php $format = "H:i:s"; $time = time(); echo date($format, $time); ?> Besser ist es hier, auf Variablen zu verzichten:<br /> <br /> echo date("H:i:s", time()); Inhalt beachten<br /> <br /> Benennen Sie Variablen immer nach dem, was sie beinhalten. Variablen speichern Zuständen, entsprechend lauten gute Namen $format oder $time. Schlecht ist dagegen $formatting oder $select. Noch schlechter sind Fantasienamen wie $x23 oder $mickymouse.<br /> <br /> Syntax beachten<br /> <br /> PHP unterscheidet bei Variablennamen Groß- und Kleinschreibung. Es ist ein häufiger Fehler, dies zu vergessen.<br /> <br /> 14.4 Typische Fehler ___________________________________________________ 363<br /> <br /> 14.4.4 Paradigmen und deren Gültigkeit An Programmierparadigmen entzünden sich manchmal leidenschaftliche Diskussionen. Einige haben sich jedoch so oft bewährt, dass der Einsatz eigentlich außer Frage stehen sollte. Andere sind jedoch veraltet. Alten Code zu lesen und daraus zu lernen, kann also durchaus zu Problemen führen. Ein Problem ist die Verwendung der alternativen Syntax für die Kontrollstrukturen. Schauen Sie sich folgenden Code an:<br /> <br /> while ($line = fgets($handle, 1024)): echo "$line <br>"; if ($line == ""): break; endif; endwhile; Besser ist es, die im Buch gezeigte Standardsyntax zu verwenden und zur Verbesserung der Lesbarkeit Kommentare anzuhängen:<br /> <br /> while ($line = fgets($handle, 1024)) { echo "$line <br>"; if ($line == "") { break; } /* endif */ } /* endwhile */ Andere Programmierer, die den Code lesen, und von anderen Programmiersprachen kommen, werden von der alternativen Syntax irritiert sein.<br /> <br /> 14.4.5 Missverstandene Kontrollstrukturen Betrachten Sie den folgenden Codeausschnitt:<br /> <br /> do {<br /> <br /> echo $rs['name']; echo '<br>'; } while ($rs = mysql_fetch_assoc($handler)); Dies funktioniert nicht. Die Variable $rs wird erst am Ende des ersten Durchlaufs erzeugt, muss aber vorher schon zur Verfügung stehen. Hier könnte die while-Anweisung in Kombination mit break eine bessere Wahl sein.<br /> <br /> 14.4.6 Fehler beim Umgang mit Datenbanken Oft werden zusätzlich zum tatsächlich benötigten Code Datenbankabfra- Anzahl der gen gestartet, welche die Anzahl der Reihen ergeben. MySQL stellt in Datensätze PHP die Funktion mysql_num_rows zur Verfügung, um dies nach jeder ermitteln<br /> <br /> V V V 1 2 3 4 5 6 7 8 9 10 11 12 13 14 A B C D E<br /> <br /> 364 ______________________________________ 14 Fehlersuche und Konfiguration Abfrage zu ermitteln. Vor dem Eintritt in eine Schleife sollte geprüft werden, ob überhaupt Datensätze vorliegen:<br /> <br /> if (mysql_num_rows($handler)) { # Schleifeneintritt # ... } else { # Ausnahmenbehandlung } Möglicherweise vereinfacht sich dadurch die Konstruktion der Schleife. Auswahl der Datensätze<br /> <br /> Unsicherheit bereitet oft auch der Einsatz von SQL-Anweisungen. Versuchen Sie SQL zu erlernen. Eine Auswahl von Datensätzen mit WHERE ist signifikant einfacher und schneller als mit PHP.<br /> <br /> 14.4 Typische Fehler ___________________________________________________ 365<br /> <br /> Anhang Listings A Quickreferenz MySQL B Buchempfehlungen C Index D An den Autor E<br /> <br /> A Listings_____________________________________________________________ 367<br /> <br /> A Listings Die folgende Übersicht zeigt alle Listings im Buch. Sofort lauffähige Skripte sind durch den Dateinamen in Klammern (zzgl. .php zu lesen) gekennzeichnet.<br /> <br /> Listing 2.1: Das erste Skript zum Ausprobieren (start) ..................................................... 40 Listing 3.1: Zahlenwerte anzeigen (var_zahlen).................................................................. 50 Listing 3.2: Zahlenformate ändern (var_zahlencast)........................................................... 50 Listing 3.3: Einfache Zuweisungen (noreferences).............................................................. 52 Listing 3.4: Referenzen erzeugen (var_reference)................................................................ 52 Listing 4.1: Datumsformatierung mit sprintf (string_sprintf) .......................................... 59 Listing 4.2: Währungen aus-geben (money_format)........................................................... 61 Listing 4.3: Formatierung mit führenden Nullen ................................................................ 61 Listing 4.4: Verschiedene Formen der printf-Funktion für Prozent- und Zahlwerte (string_format) .................................................................................................. 61 Listing 4.5: Daten mit sscanf scannen (string_sscanf)......................................................... 62 Listing 4.6: Zahlen formatieren (number_format)............................................................... 63 Listing 4.7: Zeichenkette in Zweiergruppen (chunk_split)............................................... 63 Listing 4.8: Erzeugen eines Index (siteindex) ....................................................................... 64 Listing 4.9: Teil einer Zeichenkette ab Fundort (string_stristr) ........................................ 66 Listing 4.10: »Breite« einer Zahl berechnen (string_strlen)................................................ 66 Listing 4.11: Ausgabe eines formatierten Rechnungsfußes................................................ 67 Listing 4.12: Absoluten Pfad berechnen (string_strrepeat) ................................................ 67 Listing 4.13: HTML-Entities zurückwandeln (string_htmltable) ...................................... 68 Listing 4.14: Erzeugen einer Zeichentabelle (htmlspecialchars) ....................................... 69 Listing 4.15: Umbruch wortabhängig steuern (string_wordwrap) .................................... 70 Listing 4.16: Modulus für wechselnd farbige Tabellenreihen (modulus)........................ 72 Listing 4.17: Bitoperatoren anwenden (bitops) .................................................................... 74 Listing 4.18: Bessere Rundungsfunktion (math_round) ..................................................... 78 Listing 4.19: Funktionen mit beliebiger Genauigkeit (math_bctest)................................. 80 Listing 5.1: Ein einfaches Array anlegen (array_onedim) .................................................. 85 Listing 5.2: Array ohne Indexangabe erzeugen (array_onedim2).................................... 86 Listing 5.3: Indexreihenfolge beeinflussen (array_onedim3)............................................. 86 Listing 5.4: Ausgabe eines kompletten Arrays (array_foreach) ........................................ 87 Listing 5.5: Array mit Indizes ausgeben (array_foreachi) ................................................. 88 Listing 5.6: Werte mit array zuweisen (array_array)......................................................... 88 Listing 5.7: Eigene Indizes mit array angeben (array_arrayi)............................................ 88 Listing 5.8: Assoziatives Array erzeugen und ausgeben (array_assoziativ) ................... 89 Listing 5.9: Verwendung der Klammerschreibweise (array_asso2) ................................. 89<br /> <br /> V V V 1 2 3 4 5 6 7 8 9 10 11 12 13 14 A B C D E<br /> <br /> 368 ____________________________________________________________A Listings Listing 5.10: Erzeugen und ausgeben eines zweidimensionalen Arrays (array_multidim)...............................................................................................91 Listing 5.11: Ausgabe des zweidimensionalen Arrays mit foreach (array_multidim2)92 Listing 5.12: Zweidimensionales Array mit assoziativen Indizes (array_2dim).............93 Listing 5.13: Arrays konventionell auslesen (array_while)................................................96 Listing 5.14: Analysieren von ISBN-Nummern in einem Array (array_walk)................97 Listing 5.15: Element in einem Array entfernen (array_remove) ......................................98 Listing 6.1: Steuerung mit if (if_simple)..............................................................................106 Listing 6.2: if in Verbindung mit else (if_else)...............................................................107 Listing 6.3: Beispiel mit elseif (if_elseif) ..............................................................................107 Listing 6.4: Entscheidungsbäume mit switch aufbauen (switch) ....................................108 Listing 6.5: switch mit case und break (switch_case)........................................................109 Listing 6.6: Einfachste Form einer while-Schleife (while).................................................111 Listing 6.7: Notausstieg mit break (while_break) ..............................................................111 Listing 6.8: do...while-Schleife (do.while)...........................................................................112 Listing 6.9: Umgang mit continue (while_continue).........................................................113 Listing 6.10: Einfach for-Schleife (loop_for) .......................................................................114 Listing 6.11: Abbruchbedingung und Iteration nutzen verschiedene Variablen (for.2varloop)...................................................................................................115 Listing 6.12: for ohne Parameter (for_endless).................................................................115 Listing 6.13: Mehrere Ausdrücke in for (for_multi) .......................................................116 Listing 6.14: Ausgabe eines einfachen Arrays (foreach) ...................................................116 Listing 6.15: Assoziative Arrays mit Schlüssel-/Wertpaaren (foreach_hash)...............117 Listing 6.16: Verhalten lokaler und globaler Variablen beim Funktionsaufruf (function_global).............................................................................................119 Listing 6.17: Zugriff auf globale Variablen mit GLOBALS[] (function_globals)...........121 Listing 6.18: Alle globalen Variablen in einem Array sichtbar machen (function_glob2) ..............................................................................................121 Listing 6.19: Statische Variablen (function_static).............................................................122 Listing 6.20: Funktion mit referenzierten Argumenten (function_ref) ...........................122 Listing 6.21: Funktionsrückgabe mit echo ausgeben (function_echo) ............................123 Listing 6.22: Umgang mit variablen Argumentelisten (function_argv) .........................124 Listing 6.23: Funktionen mit variablen Argumentelisten (function_argv2) ..................125 Listing 6.24: Zusätzliche Auswertung des ersten Parameters (function_argv3)...........126 Listing 6.25: Rückgabe eines Arrays (function_array) ......................................................127 Listing 6.26: Rekursive Funktion: Fakultät berechnen (recursion_f) ..............................127 Listing 6.27: Ausgabe von Verzeichnisbäumen (recursion_dir)......................................129 Listing 6.28: Fehler gezielt verarbeiten (trycatch1)............................................................133 Listing 6.29: Fehler erkennen und abfangen (errorcheck) ................................................134<br /> <br /> A Listings_____________________________________________________________ 369 Listing 6.30: Fehler und Warnungen unterdrücken .......................................................... 135 Listing 6.31: Eigene Fehlerbehandlung (errorhandler)..................................................... 136 Listing 7.1: Eine Klasse definieren (class_basic) ............................................................... 140 Listing 7.2: Klassen ohne Instanziierung verwenden (classstatic) .................................. 144 Listing 7.3: Klasse mit Konstruktor (class_construct)....................................................... 145 Listing 7.4: Eine Klasse ableiten (class_extends)................................................................ 147 Listing 7.5: Eine Schnittstelle wird definiert (interface).................................................... 148 Listing 7.6: Methoden per Funktion aufrufen (classdynamic)......................................... 149 Listing 7.7: Ermitteln von definierten Methoden (calls_methods).................................. 149 Listing 7.8: Klasse zum Erzeugen eines 1x1-Pixel-GIF (giffy) ........................................ 151 Listing 7.9: Nutzung der dynamischen GIF-Erzeugung (GiffyTest1)............................. 153 Listing 7.10: Erweiterung der Mutterklasse (Ausschnitt aus giffy2) .............................. 153 Listing 7.11: Aufruf für GiffyColor (GiffyTest2)................................................................ 154 Listing 7.12: Eigene Aus-nahmeklasse (try_numexc)........................................................ 156 Listing 7.13: Eine kleine Musterbibliothek (try_numexclib)............................................ 158 Listing 7.14: Nutzung einer Bibliothek (try_numexc2)..................................................... 158 Listing 8.1: Rückgabewerte eines Moduls (include1) ....................................................... 164 Listing 8.2: modul.inc.php zu Listing 8.1............................................................................ 165 Listing 8.3: Ausgabe des Skripts aus Listing 8.2................................................................ 165 Listing 8.4: Modul mit require einbinden........................................................................... 165 Listing 8.5: Datei einlesen und ausgeben (readfile).......................................................... 167 Listing 8.6: Datei in Array einlesen und verarbeiten (fileread) ...................................... 167 Listing 8.7: Zeilenweises Lesen einer Datei (file_fgets) .................................................... 170 Listing 8.8: Die Nachrichtendatei news.txt für Listing 8.7 ............................................... 170 Listing 8.9: Formulardaten in Dateien speichern (file_formsave)................................... 171 Listing 8.10: Anzahl Zeilen einer Textdatei (file_count)................................................... 175 Listing 8.11: Löschen einer Zeile aus einer Textdatei (file_deleteline)........................... 176 Listing 8.12: Umrechnung von Byte in KB/MB (file_getreal).......................................... 177 Listing 8.13: Kopieren einer Datei mit Umbenennung (file_copy) ................................. 179 Listing 8.14: Umbenennen und Löschen von Dateien (file_unlink)................................ 180 Listing 8.15: Verzeichnis auslesen und sortieren (file_dirsort) ....................................... 182 Listing 8.16: Fremde Inhalte per HTTP auslesen (amazon) ............................................. 184 Listing 8.17: Verbindung zu einem FTP-Server herstellen (ftp_open) ........................... 188 Listing 8.18: Zugriff auf FTP-Server mit Name und Kennwort (ftp_login)................... 189 Listing 8.19: Navigation auf FTP-Servern (ftp_cdup)....................................................... 190 Listing 8.20: Erzeugen und Wechseln von Verzeichnissen (ftp_chdir) .......................... 191 Listing 8.21: Löschen von Verzeichnissen auf einem FTP-Server (ftp_rmdir) .............. 191 Listing 8.22: Ausgabe einer Verzeichnisliste mit FTP (ftp_nlist) .................................... 192<br /> <br /> V V V 1 2 3 4 5 6 7 8 9 10 11 12 13 14 A B C D E<br /> <br /> 370 ____________________________________________________________A Listings Listing 9.1: Einfaches Formular in HTML, noch ohne PHP .............................................197 Listing 9.2: Auswertung komplexer Fomulare (form_complex) .....................................199 Listing 9.3: Gruppe von Kontrollkästchen (form_checks)................................................203 Listing 9.4: Auslesen beliebiger Felder (form_post)..........................................................205 Listing 9.5: Upload per Skript empfangen (form_upload)...............................................210 Listing 9.6: Übertragung von Daten per Hyperlink (getform).........................................213 Listing 9.7: Antwort zu Listing 9.6: Die Variable $artikel wird automatisch aus der URL extrahiert (getanswer) ...........................................................................214 Listing 9.8: Daten via URL übermitteln ..............................................................................215 Listing 9.9: GET in Formularen verwenden ......................................................................216 Listing 9.10: Weitergabe von Daten per GET (getquerystring) .......................................217 Listing 9.11: Mehrfaches Auftreten gleichnamiger Variablen muss selbst analysiert werden (getquerym) .......................................................................................218 Listing 9.12: Anzeige von Servervariablen (servervariable) ...........................................219 Listing 10.1: Ausgabe der Session-ID (session_1) ..............................................................229 Listing 10.2: Sessions ohne Cookies (sessioncookless)......................................................230 Listing 10.3: Variable in Session registrieren (session_2) .................................................232 Listing 10.4: Gibt die gespeicherte Variable aus (session_3)...........................................232 Listing 10.5: Datenbankgestützte Sessionfunktionen (sessiondb)...................................235 Listing 10.6: Test der eigenen Sessionfunktionen (sessiondb2) ......................................238 Listing 10.7: Cookies mit PHP erzeugen (cookiecolor).....................................................244 Listing 10.8: Arrays in Cookies speichern (cookie_1) .......................................................246 Listing 10.9: In Cookies gespeichertes Array auslesen (Antwortskript cookie_2 zu Listing 10.8)......................................................................................................246 Listing 10.10: Auslesen aller Cookies (cookieall)...............................................................247 Listing 11.1: Tabelle für die Umfrage ..................................................................................271 Listing 11.2: Definition der Umfragewerte .........................................................................273 Listing 11.3: Zugriff auf eine MySQL-Datenbank (open.inc.php in \umfrage) ............273 Listing 11.4: umfrage.php – Das Formular .........................................................................274 Listing 11.5: Auswertung der Umfrageresultate (auswertung.php)...............................276 Listing 11.6: Ein sehr einfaches Weblog (sqliteblog) .........................................................291 Listing 12.1: JavaScript zum Versenden von Formularen verwenden ...........................300 Listing 12.2: So erkennen Sie JavaScript.............................................................................301 Listing 12.3: Formular für eine Online-Abstimmung (jsvote)..........................................302 Listing 12.4: Konsistente Ausgabe von Fehlermeldungen aus PHP und JS (jserror)....304 Listing 12.5: Tabellenstruktur der Tabelle »chat«..............................................................306 Listing 12.6: Startdatei (index)..............................................................................................307 Listing 12.7: Steuerung im Hintergrund (main)................................................................308 Listing 12.8: Ausgabe der laufenden Beiträge (show).....................................................308<br /> <br /> A Listings_____________________________________________________________ 371 Listing 12.9: Beiträge an den Chat absenden (send)......................................................... 309 Listing 13.1: Dynamische Bildauswahl ............................................................................... 316 Listing 13.2: HTML-Datei, in der ein Bild erzeugt wird (image_form).......................... 316 Listing 13.3: Erzeugung eines Bildes mit Kopfzeilen (imageheader) ............................. 317 Listing 13.4: Tabelle mit GD2 erzeugen (image_grid) ...................................................... 321 Listing 13.5: Bilddaten erkennen (imagesize)..................................................................... 322 Listing 13.6: Testskript für reguläre Ausdrücke (regextest) ............................................ 324 Listing 13.7: Regulärer Ausdruck zum Prüfen der E-Mail-Adresse ............................... 330 Listing 13.8: Ersetzen mit regulären Ausdrücken ............................................................. 333 Listing 13.9: Datumswert testen (date_checkdate) ............................................................ 337 Listing 13.10: Formatierung von Datum und Zeit (date_form)...................................... 340 Listing 13.11: Ausgabe von Datumswerten in verschiedenen Sprachen (date_strftime) ................................................................................................. 341 Listing 13.12: Formatierte Ausgabe der UTC-Zeit (date_utectime)................................ 342 Listing 13.13: Untersuchung von Datumswerten (date_gettimeofday) ............................ 342 Listing 13.14: Ausgabe von Zeitinformationen (date_localtime) .................................... 343 Listing 13.15: Datumswerte erkennen................................................................................. 344 Listing 13.16: Datumsberechnungen mit mktime.............................................................. 345 Listing 13.17: Messung der Ausführungszeit (microtime)............................................... 346 Listing 14.1: PHP-Informationen (info)............................................................................... 349<br /> <br /> V V V 1 2 3 4 5 6 7 8 9 10 11 12 13 14 A B C D E<br /> <br /> B Quickreferenz MySQL 4 ______________________________________________ 373<br /> <br /> B Quickreferenz MySQL 4 In dieser Referenz finden Sie alle MySQL-Funktionen und die Datentypen auf einen Blick, um schnell SQL-Anweisungen entwickeln zu können. Die Referenz basiert auf der Version 4 von MySQL.<br /> <br /> B.1 Datentypen Tabelle B.1: Datentypen in MySQL (Z steht für ZEROFILL, M für die Stellenzahl) Datentyp<br /> <br /> Beschreibung<br /> <br /> TINYINT [(M)] [UNSIGNED] [Z]<br /> <br /> Kleine Ganzzahlen, von 0 bis 255 oder -128 bis 127<br /> <br /> SMALLINT [(M)] [UNSIGNED] [Z]<br /> <br /> Ganzzahlen, entweder von 0 bis 65 535 oder von –32 768 bis +32 767<br /> <br /> MEDIUMINT [(M)] [UNSIGNED] [Z]<br /> <br /> Ganzzahlen, entweder von 0 bis 16 777 215 oder von – 8 388 608 bis +8 388 607<br /> <br /> INT [(M)] [UNSIGNED] [Z] INTEGER<br /> <br /> Ganzzahlen, entweder von 0 bis 4 294 967 295 oder von – 2 147 283 648 bis +2 147 283 647<br /> <br /> BIGINT [(M)] [UNSIGNED] [Z]<br /> <br /> Ganzzahlen, entweder von 0 bis 18 446 744 073 709 551 615 oder von -9 223 372 036 854 775 808 bis +9 223 372 036 854 775 807<br /> <br /> FLOAT(precision) [Z]<br /> <br /> Fließkommazahl, immer vorzeichenbehaftet. precision kann 4 oder 8 sein; 4 steht für einfache Genauigkeit, 8 für doppelte.<br /> <br /> FLOAT[(M,D)] [Z]<br /> <br /> Der Wertebereich reicht von -3,40282346638 bis -1,175494351-38, die 0 und +1,175494351-38 bis +3,40282346638<br /> <br /> DOUBLE[(M,D)] [Z] DOUBLEPRECISION[(M,D)] [Z] REAL[(M,D)] [Z]<br /> <br /> Wertebereich von -1,7976931348623157308 bis -2,2250738585072014-308, die 0 und -2,2250738585072014308 bis +1,7976931348623157308<br /> <br /> DECIMAL(M,D) [Z] NUMERIC<br /> <br /> Ungepackte Fließkommazahl, immer vorzeichenbehaftet. Zahlen werden als Zeichenkette gespeichert, jede Ziffer steht in einem Byte. Das Komma, Vorzeichen usw. belegen jeweils ein Byte.<br /> <br /> DATE<br /> <br /> Datum im Format "YYYY-MM-DD". Der Wertebereich geht von 1.1.1000 bis zum 31.12.9999.<br /> <br /> DATETIME<br /> <br /> Datum und Zeit im Format "YYYY-MM-DD hh:mm:ss".<br /> <br /> V V V 1 2 3 4 5 6 7 8 9 10 11 12 13 14 A B C D E<br /> <br /> 374 _____________________________________________ B Quickreferenz MySQL 4 Datentyp<br /> <br /> Beschreibung<br /> <br /> TIMESTAMP[(M)]<br /> <br /> Zeitstempel, Wertebereich von 1.1.1970 bis zum 31.12.2036. Für die Angabe des Anzeigebereiches M gilt: ♦<br /> <br /> 14: YYYYMMDDhhmmss<br /> <br /> ♦<br /> <br /> 12: YYMMDDhhmmss<br /> <br /> ♦<br /> <br /> 8: YYYYMMDD<br /> <br /> ♦<br /> <br /> 6: YYMMDD<br /> <br /> TIME<br /> <br /> Zeit im Wertebereich von -838:59:59 bis +838:59:59 mit dem Ausgabeformat "hh:mm:ss"<br /> <br /> YEAR<br /> <br /> Jahr, Wertebereich 1901 bis 2155, Ausgabe YYYY.<br /> <br /> CHAR(M) [BINARY]<br /> <br /> Zeichenkette fester Länge M. Wertebereich 1 bis 255. Leerzeichen am Ende werden automatisch für die Ausgabe entfernt. Sortieren und Selektieren berücksichtigt Groß- und Kleinschreibung nicht, wenn Sie nicht BINARY verwenden.<br /> <br /> VARCHAR(M) [BINARY]<br /> <br /> Zeichenkette variabler Länge, maximal M. Wertebereich 1 bis 255. Leerzeichen am Ende werden automatisch für die Ausgabe entfernt. Sortieren und Selektieren berücksichtigt Groß- und Kleinschreibung nicht, wenn Sie nicht BINARY verwenden.<br /> <br /> TINYBLOB, TINYTEXT<br /> <br /> BLOB oder TEXT mit maximal 255 Byte<br /> <br /> BLOB, TEXT<br /> <br /> BLOB oder TEXT mit maximal 65 535 Byte<br /> <br /> MEDIUMBLOB, MEDIUMTEXT<br /> <br /> BLOB oder TEXT mit maximal 16 777 215 Byte<br /> <br /> LONGBLOB, MEDIUMTEXT<br /> <br /> BLOB oder TEXT mit maximal 4 294 967 295 Byte<br /> <br /> ENUM('wert1', 'wert2', ...,)<br /> <br /> Aufzählung. Ein Feld dieses Typs kann nur eine Zeichenkette enthalten, die einem Objekt der Aufzählung entspricht.<br /> <br /> SET('wert1', 'wert2' , ...,)<br /> <br /> Wie ENUM, kann aber mehrere Werte aus der Liste enthalten.<br /> <br /> B.2 Mathematische Funktionen Tabelle B.2: Mathematische Funktionen Funktion<br /> <br /> Beschreibung<br /> <br /> ABS(x)<br /> <br /> Absoluter Betrag der Zahl x<br /> <br /> ACOS(x)<br /> <br /> Arcuskosinus<br /> <br /> ASIN(num)<br /> <br /> Arcussinus<br /> <br /> ATAN(num)<br /> <br /> Arcustangens<br /> <br /> ATN2(num1, num2)<br /> <br /> Arcustangens (Winkel) zwischen num1 und num2<br /> <br /> B Quickreferenz MySQL 4 ______________________________________________ 375 Funktion<br /> <br /> Beschreibung<br /> <br /> CEILING(x)<br /> <br /> Die kleinste Ganzzahl größer oder gleich dem Ausdruck<br /> <br /> COS(x)<br /> <br /> Kosinus<br /> <br /> COT(x)<br /> <br /> Kotangens<br /> <br /> DEGREES(x)<br /> <br /> Umrechnung Radiant in Grad<br /> <br /> EXP(x)<br /> <br /> Potenz zur Basis e<br /> <br /> FLOOR(x)<br /> <br /> Die größte Ganzzahl kleiner oder gleich dem angegebenen numerischen Ausdruck.<br /> <br /> GREATEST(x1,x2,..)<br /> <br /> Gibt den größten Wert der Liste zurück.<br /> <br /> LEAST(x1,x2,...)<br /> <br /> Gibt den kleinsten Wert der Liste zurück.<br /> <br /> LOG(x)<br /> <br /> Natürlicher Logarithmus<br /> <br /> LOG10(x)<br /> <br /> Dekadischer Logarithmus<br /> <br /> MOD(n, m)<br /> <br /> Modulus, Rest einer Ganzzahldivision<br /> <br /> PI()<br /> <br /> Konstante π<br /> <br /> POWER(x,y)<br /> <br /> Potenz<br /> <br /> RADIANS(x)<br /> <br /> Umrechnung in Radiant<br /> <br /> RAND(x)<br /> <br /> Zufallszahl, x ist optional<br /> <br /> ROUND(x, d)<br /> <br /> Rundet Werte mathematisch, Stellen d sind optional.<br /> <br /> SIGN(x)<br /> <br /> Vorzeichen (gibt –1, 0 oder 1 zurück)<br /> <br /> SIN(x)<br /> <br /> Sinus<br /> <br /> SQRT(x)<br /> <br /> Quadratwurzel<br /> <br /> TAN(x)<br /> <br /> Tangens<br /> <br /> TRUNCATE(x,d)<br /> <br /> Gibt die Zahl x zurück, gekürzt auf d Dezimalstellen.<br /> <br /> B.3 Logische Funktionen Tabelle B.3: Logische Funktionen Funktion<br /> <br /> Beschreibung<br /> <br /> ISNULL(expr)<br /> <br /> Wertet den Ausdruck expr aus und gibt 1 zurück, wenn der Ausdruck NULL ist, sonst 0.<br /> <br /> IFNULL(expr1, expr2)<br /> <br /> Wertet den Ausdruck expr1 aus und gibt expr2 zurück, wenn der Ausdruck NULL ist, sonst expr1<br /> <br /> IF(expr1,expr2,expr3)<br /> <br /> Wenn der Ausdruck expr1 Wahr ist, wird expr2 zurückgegeben, sonst expr3<br /> <br /> V V V 1 2 3 4 5 6 7 8 9 10 11 12 13 14 A B C D E<br /> <br /> 376 _____________________________________________ B Quickreferenz MySQL 4<br /> <br /> B.4 Funktionen für spaltenweise Berechnungen Tabelle B.4: Aggregat-Funktionen Funktion<br /> <br /> Beschreibung<br /> <br /> AVG<br /> <br /> Average. Der Durchschnitt der Felder.<br /> <br /> COUNT<br /> <br /> Count. Die Anzahl der Felder.<br /> <br /> COUNT (*)<br /> <br /> Repräsentiert die Anzahl aller Datensätze einer Tabelle.<br /> <br /> SUM<br /> <br /> Summary. Die Summe der Felder (Addition).<br /> <br /> MAX<br /> <br /> Maximum. Das Feld mit dem größten Wert bestimmt das Ergebnis.<br /> <br /> MIN<br /> <br /> Minimum. Das Feld mit dem kleinsten Wert bestimmt das Ergebnis.<br /> <br /> STD STDDEV<br /> <br /> Statistische Standardabweichung aller Werte der Liste<br /> <br /> BIT_OR<br /> <br /> Bitweises Oder<br /> <br /> BIT_AND<br /> <br /> Bitweises Und<br /> <br /> B.5 Funktionen für Systeminformationen Tabelle B.5: Die Systemfunktionen Funktion<br /> <br /> Beschreibung<br /> <br /> DATABASE()<br /> <br /> Gibt den Namen der aktuellen Datenbank aus.<br /> <br /> USER() SYSTEM_USER() SESSION_USER()<br /> <br /> Aktueller MySQL-Nutzername<br /> <br /> PASSWORD(str)<br /> <br /> Erzeugt ein Kennwort zur Zeichenkette str.<br /> <br /> ENCRYPT(str, seed)<br /> <br /> Erzeugt ein Kennwort zur Zeichenkette str und mit dem Startwert seed. Nutzt das Unix-Kommando crypt. Unter Windows wird NULL zurückgegeben.<br /> <br /> LAST_INSERT_ID()<br /> <br /> Gibt den zuletzt erzeugten Wert einer AUTO_INCREMENT-Spalte zurück.<br /> <br /> FORMAT(n, d)<br /> <br /> Formatiert eine Zahl n mit Kommas als Tausendergruppensymbol und Punkt als Dezimaltrennzeichen mit d Dezimalstellen.<br /> <br /> VERSION()<br /> <br /> Gibt die Versionsnummer des MySQL-Server an.<br /> <br /> GET_LOCK(str, to)<br /> <br /> Erzeugt eine Verriegelung (Lock) mit dem Namen str und dem Zeitüberschreitungswert to.<br /> <br /> RELEASE_LOCK(str)<br /> <br /> Gibt die Verriegelung str wieder frei.<br /> <br /> B Quickreferenz MySQL 4 ______________________________________________ 377<br /> <br /> B.6 Zeichenkettenfunktionen Tabelle B.6: Zeichenkettenfunktionen Funktion<br /> <br /> Beschreibung<br /> <br /> ASCII(str)<br /> <br /> Gibt den ASCII-Code des Zeichens str zurück. Hat str mehr als ein Zeichen, wird nur das erste Zeichen überprüft.<br /> <br /> CHAR(n,...)<br /> <br /> Wandelt die Zahlen n in die entsprechenden ASCII-Zeichen um. Mehrere Argumente werden zu einer Zeichenkette kombiniert.<br /> <br /> CONCAT(str,...)<br /> <br /> Verknüpft alle Argumente zu einer Zeichenkette. Wenn eines der Argumente NULL ist, wird NULL zurückgegeben.<br /> <br /> LENGTH(str)<br /> <br /> Länge der Zeichenketten str.<br /> <br /> LOCATE(sub, str) POSITION(sub IN str)<br /> <br /> Bestimmt die Position der Zeichenkette sub in der Zeichenkette str.<br /> <br /> INSTR(str, sub)<br /> <br /> Entspricht LOCATE, nur die Argumente sind vertauscht.<br /> <br /> LPAD(str,len,pad)<br /> <br /> Fügt pad links an str an, gibt jedoch nur len Zeichen zurück.<br /> <br /> RPAD(str,len,pad)<br /> <br /> Fügt pad rechts an str an, gibt jedoch nur len Zeichen zurück.<br /> <br /> LEFT(str, len)<br /> <br /> Gibt len Zeichen vom linken Ende der Zeichenkette str zurück.<br /> <br /> RIGHT(str, len)<br /> <br /> Gibt len Zeichen vom rechten Ende der Zeichenkette str zurück.<br /> <br /> MID(str, pos, len)<br /> <br /> Gibt len Zeichen von Position pos an der Zeichenkette str zurück.<br /> <br /> SUBSTRING(str FROM len SUBSTRING(str,pos,len) SUBSTRING(str FROM pos FOR len)<br /> <br /> Andere Schreibweisen für RIGHT und MID.<br /> <br /> SUBSTRING(str, pos)<br /> <br /> Gibt Teile von str ab Position pos zurück.<br /> <br /> SUBSTRING_INDEX(str, delimiter, count)<br /> <br /> Gibt den linken Teil einer Zeichenkette zurück, nachdem count mal das Zeichen delimiter aufgetreten ist.<br /> <br /> LTRIM(str)<br /> <br /> Entfernt Leerzeichen vom linken Ende.<br /> <br /> RTRIM(str)<br /> <br /> Entfernt Leerzeichen vom rechten Ende.<br /> <br /> TRIM(str)<br /> <br /> Entfernt Leerzeichen von beiden Enden der Zeichenkette str.<br /> <br /> TRIM BOTH|LEADING|TRAILING BOTH entspricht TRIM, LEADING entspricht LTRIM, TRAILING entspricht rem FROM str RTRIM, FROM ist optional, rem ist optional und steht für das zu entfernende Zeichen, str wird bearbeitet. SOUNDEX(str)<br /> <br /> Gibt die Lautfolge für str zurück.<br /> <br /> SPACE(n)<br /> <br /> Gibt n Leerzeichen zurück.<br /> <br /> REPLACE(str,from,to)<br /> <br /> Ersetzt alle Vorkommen von from in der Zeichenkette str durch to.<br /> <br /> REPEAT(str, count)<br /> <br /> Wiederholt die Zeichenkette str count mal.<br /> <br /> REVERSE(str)<br /> <br /> Dreht eine Zeichenkette um.<br /> <br /> V V V 1 2 3 4 5 6 7 8 9 10 11 12 13 14 A B C D E<br /> <br /> 378 _____________________________________________ B Quickreferenz MySQL 4 Funktion<br /> <br /> Beschreibung<br /> <br /> INSERT(str,st,len,new)<br /> <br /> Fügt len Zeichen der Zeichenkette new an der Stelle st der Zeichenkette str ein.<br /> <br /> ELT(n, str1, str2,...)<br /> <br /> Gibt die durch n bezeichnete Zeichenkette zurück: str1, wenn n=1 usw.<br /> <br /> FIELD(str,str1,str2..)<br /> <br /> Gibt die Position von str in str1, str2 usw. zurück: Wenn str2=str, wird 2 zurückgegeben.<br /> <br /> FIND_IN_SET(str, list)<br /> <br /> Gibt die Position von str in der Liste list zurück. Die Liste besteht aus kommaseparierten Werten.<br /> <br /> MAKE_SET(bits,list)<br /> <br /> Wählt die Elemente der Liste anhand der gesetzten Bits in bits aus.<br /> <br /> LCASE, LOWER(str)<br /> <br /> Wandelt in Kleinbuchstaben um.<br /> <br /> UCASE, UPPER(str)<br /> <br /> Wandelt in Großbuchstaben um.<br /> <br /> B.7 Zahlenformatierungen Tabelle B.7: Zeichenkettenfunktionen für Zahlen Funktion<br /> <br /> Beschreibung<br /> <br /> CONV(n,from,to)<br /> <br /> Konvertiert Zahlen zwischen verschiedenen Zahlenbasen. Zurückgegeben wird immer eine Zeichenkette mit der ermittelten Zahl. n ist die Zahl, from die ursprüngliche Zahlenbasis, to die Zielbasis.<br /> <br /> BIN(n)<br /> <br /> Gibt eine Zahl n als Zeichenkette im Binärformat zurück, BIN(7) "111".<br /> <br /> OCT(n)<br /> <br /> Gibt eine Zahl n als Zeichenkette im Oktalformat zurück.<br /> <br /> HEX(n)<br /> <br /> Gibt eine Zahl n als Zeichenkette im Hexadezimalformat zurück.<br /> <br /> <br /> <br /> B.8 Datums- und Zeitfunktionen Tabelle B.8: Datums- und Zeitfunktionen Funktion<br /> <br /> Beschreibung<br /> <br /> DAYOFWEEK(date)<br /> <br /> Tag der Woche, 1 ist Sonntag (1 – 7)<br /> <br /> WEEKDAY(date)<br /> <br /> Tag der Woche, 0 ist Montag (0 – 6)<br /> <br /> DAYOFMONTH(date)<br /> <br /> Tag des Monats (1 – 31)<br /> <br /> DAYOFYEAR(date)<br /> <br /> Tag des Jahres (1 – 366)<br /> <br /> MONTH(date)<br /> <br /> Monat (1 – 12)<br /> <br /> B Quickreferenz MySQL 4 ______________________________________________ 379 Funktion<br /> <br /> Beschreibung<br /> <br /> DAYNAME(date)<br /> <br /> Wochentag (englisch, ausgeschrieben)<br /> <br /> MONTHNAME(date)<br /> <br /> Monat (englisch, ausgeschrieben)<br /> <br /> QUARTER(date)<br /> <br /> Quartal (1 – 4)<br /> <br /> WEEK(date) WEEK(date, first)<br /> <br /> Woche im Jahr (0 – 52). Das optionale Argument first bestimmt, welcher Wochentag als Beginn gezählt wird. 0=Sonntag.<br /> <br /> YEAR(date)<br /> <br /> Jahr (1000 – 9999)<br /> <br /> HOUR(time)<br /> <br /> Stunde (0 – 23)<br /> <br /> MINUTE(time)<br /> <br /> Minute (0 – 59)<br /> <br /> SECOND(time)<br /> <br /> Sekunde (0 – 59)<br /> <br /> PERIOD_ADD(p,n)<br /> <br /> Addiert n Monate zur Periode p. Die Periode wird im Format YYYYMM oder YYMM erwartet. Zurückgegeben wird immer die Langform YYYYMM.<br /> <br /> PERIOD_DIFF(p1,p2)<br /> <br /> Gibt die Differenz in Monaten zwischen p1 und p2 zurück<br /> <br /> TO_DAYS(date)<br /> <br /> Zahl der Tage seit dem Jahr 0<br /> <br /> FROM_DAYS(dn)<br /> <br /> Ermittelt ein Datum aus der Tageszahl dn.<br /> <br /> CURDATE() CURRENT_DATE<br /> <br /> Das aktuelle Datum (Systemzeit des Servers)<br /> <br /> CURTIME() CURRENT_TIME<br /> <br /> Die aktuelle Zeit (Systemzeit des Servers)<br /> <br /> NOW() SYSDATE() CURRENT_TIMESTAMP<br /> <br /> Datum und Uhrzeit (Systemzeit des Servers)<br /> <br /> UNIX_TIMESTAMP<br /> <br /> Unix Timestamp (Sekunden in GMT seit den 1.1.1970, 0 Uhr). Die Funktion wird auch von der Windows-Version unterstützt.<br /> <br /> FROM_UNIXTIME(stp)<br /> <br /> Gibt ein Datum entsprechend dem Unix Timestamp stp zurück.<br /> <br /> FROM_UNIXTIME(stp, format)<br /> <br /> Gibt ein Datum entsprechend dem Unix Timestamp stp zurück. Das Datum ist entsprechend format formatiert. Formatangaben entnehmen Sie Tabelle B.9.<br /> <br /> SEC_TO_TIME(sec)<br /> <br /> Rechnet die Angabe in Sekunden in das Format HH:MM:SS um.<br /> <br /> TIME_TO_SEC(time)<br /> <br /> Rechnet eine Zeitangabe in Sekunden um.<br /> <br /> V V V 1 2 3 4 5 6 7 8 9 10 11 12 13 14 A B C D E<br /> <br /> 380 _____________________________________________ B Quickreferenz MySQL 4<br /> <br /> B.9 Datumsformatierungen Tabelle B.9: Zeittypen für Datumsberechnungen Typ-Code<br /> <br /> Bedeutung<br /> <br /> Format für expr<br /> <br /> SECOND<br /> <br /> Sekunde<br /> <br /> ss<br /> <br /> MINUTE<br /> <br /> Minute<br /> <br /> mm<br /> <br /> HOUR<br /> <br /> Stunde<br /> <br /> hh<br /> <br /> DAY<br /> <br /> Tag<br /> <br /> DD<br /> <br /> MONTH<br /> <br /> Monat<br /> <br /> MM<br /> <br /> YEAR<br /> <br /> Jahr<br /> <br /> YY<br /> <br /> MINUTE_SECONDS<br /> <br /> Minute und Sekunde<br /> <br /> "mm:ss"<br /> <br /> HOUR_MINUTE<br /> <br /> Stunde und Minute<br /> <br /> "hh:mm"<br /> <br /> DAY_HOUR<br /> <br /> Tage und Stunde<br /> <br /> "DD hh"<br /> <br /> YEAR_MONTH<br /> <br /> Jahr und Monat<br /> <br /> "YY-MM"<br /> <br /> HOUR_SECOND<br /> <br /> Stunde, Minute, Sekunde<br /> <br /> "hh:mm:ss"<br /> <br /> DAY_MINUTE<br /> <br /> Tag, Stunde, Minute<br /> <br /> "DD hh:mm"<br /> <br /> DAY_SECONDS<br /> <br /> Tag, Stunde, Minute, Sekunde<br /> <br /> "DD hh:mm:ss"<br /> <br /> Tabelle B.10: Datumsformatierungen Funktion<br /> <br /> Berechnung<br /> <br /> DATE_FORMAT(date, format)<br /> <br /> Formatiert den Wert date mit dem Format format, dessen Elemente in Tabelle B.11 beschrieben werden<br /> <br /> TIME_FORMAT(time, format)<br /> <br /> Formatiert den Wert time mit dem Format format, dessen Elemente in Tabelle B.11 beschrieben werden<br /> <br /> Tabelle B.11: Platzhalter für Datumsformatierungen Code<br /> <br /> Bedeutung (Wertebereich)<br /> <br /> Code<br /> <br /> Bedeutung (Wertebereich)<br /> <br /> %M<br /> <br /> Monatsname (January – December)<br /> <br /> %k<br /> <br /> Stunde (0 – 23) ohne führende Null<br /> <br /> %W<br /> <br /> Wochenname (Monday – Sunday)<br /> <br /> %h<br /> <br /> Stunde (01 – 12) mit führender Null<br /> <br /> %D<br /> <br /> Monat mit engl. Suffix (1st, 2nd, 3rd usw.)<br /> <br /> %I<br /> <br /> Stunde (1 – 12) ohne führende Null<br /> <br /> %Y<br /> <br /> Jahr mit 4 Stellen<br /> <br /> %l<br /> <br /> Minuten (0 – 59)<br /> <br /> %y<br /> <br /> Jahr mit 2 Stellen<br /> <br /> %i<br /> <br /> Minuten (00 – 59) mit führender Null<br /> <br /> %a<br /> <br /> Abgekürzter Wochentag (Mon – Sun)<br /> <br /> %n<br /> <br /> Zeit, 12-Stunden-Format: hh:mm:ss<br /> <br /> AM|PM<br /> <br /> B Quickreferenz MySQL 4 ______________________________________________ 381 Code<br /> <br /> Bedeutung (Wertebereich)<br /> <br /> Code<br /> <br /> Bedeutung (Wertebereich)<br /> <br /> %d<br /> <br /> Tag des Monats (00 – 31)<br /> <br /> %T<br /> <br /> Zeit, 24-Stunden-Format: hh:mm:ss<br /> <br /> %e<br /> <br /> Tag des Monats (0 – 31)<br /> <br /> %S<br /> <br /> Sekunde (00 – 59) mit führender Null<br /> <br /> %m<br /> <br /> Monat (00 – 12) mit führender Null<br /> <br /> %s<br /> <br /> Sekunde (0 – 59)<br /> <br /> %c<br /> <br /> Monat (0 – 12) ohne führende Null<br /> <br /> %p<br /> <br /> AM oder PM<br /> <br /> %b<br /> <br /> Abgekürzter Monatsname (Jan–Dec)<br /> <br /> %w<br /> <br /> Wochentag (0=Sonntag, 6=Samstag)<br /> <br /> %j<br /> <br /> Tag des Jahres (000 – 366)<br /> <br /> %U<br /> <br /> Woche, Sonntag ist der erste Tag der Woche (00 – 52)<br /> <br /> %H<br /> <br /> Stunde (00 – 23) mit führender Null<br /> <br /> %u<br /> <br /> Woche, Montag ist der erste Tag der Woche (00 – 52)<br /> <br /> %%<br /> <br /> Prozentzeichen<br /> <br /> B.10 MySQL-Anweisungen Tabelle B.12: Übersicht die Syntax aller SQL-Anweisungen, die MySQL kennt Anweisung<br /> <br /> Beschreibung<br /> <br /> CREATE DATABASE [IF NOT EXISTS] db<br /> <br /> Erzeugt eine neue Datenbank db<br /> <br /> DROP DATABASE [IF EXISTS] db<br /> <br /> Löscht eine Datenbank db<br /> <br /> CREATE [TEMPORARY] TABLE [IF NOT EXISTS] tbl [(create_def,...)] [table_options] [select_statement]<br /> <br /> Erzeugt eine neue Tabelle tbl create_def kann folgendes sein: ♦ col_name type [NOT NULL | NULL] [DEFAULT default_value] [AUTO_INCREMENT] [PRIMARY KEY] [reference_def] ♦<br /> <br /> PRIMARY KEY (index_col,...)<br /> <br /> ♦<br /> <br /> KEY [index_name] (index_col,...)<br /> <br /> ♦<br /> <br /> INDEX [index_name] (index_col,...)<br /> <br /> ♦<br /> <br /> UNIQUE [INDEX] [index_name] (index_col,...)<br /> <br /> ♦<br /> <br /> FULLTEXT [INDEX] [index_name] (index_col,...)<br /> <br /> ♦<br /> <br /> [CONSTRAINT symbol] FOREIGN KEY index_name (index_col,...) [reference_def]<br /> <br /> ♦<br /> <br /> CHECK (expr)<br /> <br /> type kann einer der Datentypen aus Tabelle B.1 sein. Für index_col_name kann folgendes eingesetzt werden: ♦<br /> <br /> col_name [(length)]<br /> <br /> V V V 1 2 3 4 5 6 7 8 9 10 11 12 13 14 A B C D E<br /> <br /> 382 _____________________________________________ B Quickreferenz MySQL 4 Anweisung<br /> <br /> Beschreibung reference_def steht für: ♦<br /> <br /> REFERENCES tbl [(index_col,...)] [MATCH FULL | MATCH PARTIAL] [ON DELETE reference_option] [ON UPDATE reference_option]<br /> <br /> reference_option wird ersetzt durch: ♦<br /> <br /> RESTRICT|CASCADE|SET NULL|NO ACTION|SET DEFAULT<br /> <br /> table_options stellt zusätzliche Optionen ein. select_statement steht für: ♦<br /> <br /> ALTER [IGNORE] TABLE tbl alter_spec [, alter_spec ...]<br /> <br /> [IGNORE | REPLACE] SELECT ... (jede gültige SELECTAnweisung; siehe dort)<br /> <br /> Ändert die Eigenschaften einer Tabelle tbl. alter_spec kann dabei eine der folgenden Werte annehmen: ♦ ADD [COLUMN] create_def [FIRST | AFTER col] [COLUMN] (create_def, create_def,...) INDEX [index_name] (index_col,...) PRIMARY KEY (index_col,...) UNIQUE [index_name] (index_col,...) FULLTEXT [index_name] (index_col,...) [CONSTRAINT symbol] FOREIGN KEY index_name (index_col,...) [ref_def] ♦<br /> <br /> ALTER [COLUMN] col {SET DEFAULT literal | DROP DEFAULT}<br /> <br /> ♦<br /> <br /> CHANGE [COLUMN] old_col create_def<br /> <br /> ♦<br /> <br /> MODIFY [COLUMN] create_def<br /> <br /> ♦<br /> <br /> DROP [COLUMN] col_name PRIMARY KEY INDEX index_name<br /> <br /> ♦<br /> <br /> RENAME [TO] new_tbl_name<br /> <br /> ♦<br /> <br /> ORDER BY col<br /> <br /> ♦<br /> <br /> table_options<br /> <br /> Die Optionen create_def und table_options finden Sie bei CREATE TABLE. RENAME TABLE old TO new<br /> <br /> Benennt eine Tabelle um old in new um<br /> <br /> DROP TABLE [IF EXISTS] tbl<br /> <br /> Löscht eine Tabelle tbl<br /> <br /> OPTIMIZE TABLE tbl, tbl2, …<br /> <br /> Optimiert die Daten von Tabellen tbl, tbl2 usw.<br /> <br /> CHECK TABLE tbl, option<br /> <br /> Prüft eine Tabelle tbl. option kann folgendes sein: ♦ QUICK | FAST | MEDIUM | EXTEND | CHANGED<br /> <br /> BACKUP TABLE tbl TP path<br /> <br /> Speichert eine Tabelle tbl auf im Pfad path<br /> <br /> RESTORE TABLE tbl FROM path<br /> <br /> Stellt eine Tabelle wieder her<br /> <br /> B Quickreferenz MySQL 4 ______________________________________________ 383 Anweisung<br /> <br /> Beschreibung<br /> <br /> ANALYZE TABLE tbl<br /> <br /> Analysiert eine Tabelle<br /> <br /> REPAIR TABLE tbl [QUICK] [EXTENDED]<br /> <br /> Repariert eine Tabelle tbl und gibt eine neue Tabelle mit Informationen über Probleme zurück<br /> <br /> DELETE [LOW_PRIORITY] FROM tbl [WHERE where_definition] [LIMIT rows]<br /> <br /> Löscht Daten in Tabelle tbl<br /> <br /> TRUNCATE TABLE tbl<br /> <br /> Leert die Tabelle tbl ohne sie zu löschen<br /> <br /> SELECT [STRAIGHT_JOIN] [HIGH_PRIORITY] [DISTINCT|DISTINCTROW|ALL] select_expression,... [INTO {OUTFILE | DUMPFILE} 'file_name' export_opt] [FROM table_references [WHERE where_def] [GROUP BY {uns_integer | col_name | formula} [ASC | DESC], ...] [HAVING where_definition] [ORDER BY {uns_integer | col_name | formula} [ASC | DESC] ,...] [LIMIT [offset,] rows] [PROCEDURE procedure_name] [FOR UPDATE | LOCK IN SHARE MODE]]<br /> <br /> Wählt Daten aus Tabellen aus. select_expression ist dabei ein gültiger Ausdruck aus Variablen, Konstanten und Spaltennamen, der die in den Anhängen B.2 bis B.9 beschriebenen Funktionen enthalten darf.<br /> <br /> tbl [CROSS] JOIN tbl2 tbl LEFT [OUTER] JOIN tbl2 tbl RIGHT [OUTER] JOIN tbl2<br /> <br /> Verbindet Tabellen bei Abfragen. Hinter der Verbindung folgt eine Bedingung: ♦ ON condition|USING (col, col, ...)<br /> <br /> INSERT [INTO] tbl [(col, col, ...)] VALUES (expr, expr, expr, ...)<br /> <br /> Fügt Daten in die Tabelle tbl ein.<br /> <br /> INSERT [INTO] tbl [(col, col, ...)] SELECT select_option<br /> <br /> Fügt Daten einer Auswahlabfrage ein. select_option wird bei SELECT beschrieben.<br /> <br /> INSERT DELAYED insert<br /> <br /> Entspricht INSERT, wobei jedoch der Client nicht auf die Ausführung der Anweisung warten mudd<br /> <br /> REPLACE insert<br /> <br /> Ersetzt Daten; arbeitet wie INSERT, ersetzt jedoch vorhandene Reihen mit gleichen Daten.<br /> <br /> ♦<br /> <br /> uns_integer ist eine vorzeichenlose Ganzzahl<br /> <br /> ♦<br /> <br /> col_name ist ein Spaltenname<br /> <br /> ♦<br /> <br /> formula ist eine Formel<br /> <br /> ♦<br /> <br /> table_references verweist auf Tabellen<br /> <br /> V V V 1 2 3 4 5 6 7 8 9 10 11 12 13 14 A B C D E<br /> <br /> 384 _____________________________________________ B Quickreferenz MySQL 4 Anweisung<br /> <br /> Beschreibung<br /> <br /> LOAD DATA [LOW_PRIORITY | CONCURRENT] [LOCAL] INFILE 'file.txt' [REPLACE | IGNORE] INTO TABLE tbl field_description<br /> <br /> Lädt Daten aus CSV-Dateien in eine Tabelle. field_description kann folgendes sein: ♦ [FIELDS [TERMINATED BY '\t'] [[OPTIONALLY] ENCLOSED BY ''] [ESCAPED BY '\\' ]] [LINES TERMINATED BY '\n'] [IGNORE number LINES] [(col,...)]<br /> <br /> UPDATE [LOW_PRIORITY] [IGNORE] tbl SET col1=expr1, [col2=expr2, ...] [WHERE where_definition] [ORDER BY ...] [LIMIT #]<br /> <br /> Aktualisiert Daten in einer Tabelle<br /> <br /> USE db<br /> <br /> Wählt die Datenbank db aus<br /> <br /> FLUSH option [, option]<br /> <br /> Leert Pufferspeicher. option kann folgendes sein: ♦ HOSTS | LOGS | PRIVILEGES ♦<br /> <br /> TABLES | TABLE tbl<br /> <br /> ♦<br /> <br /> STATUS<br /> <br /> KILL id<br /> <br /> Beendet eine Verbindung<br /> <br /> SHOW option<br /> <br /> Zeigt Systemdaten an. option kann folgendes sein (wild ist ein in SQL üblicher Platzhalter): ♦ DATABASES [LIKE wild] ♦<br /> <br /> [OPEN] TABLES [FROM db] [LIKE wild]<br /> <br /> ♦<br /> <br /> [FULL] COLUMNS FROM tbl [FROM db][LIKE wild]<br /> <br /> ♦<br /> <br /> INDEX FROM tbl [FROM db]<br /> <br /> ♦<br /> <br /> TABLE STATUS [FROM db] [LIKE wild]<br /> <br /> ♦<br /> <br /> STATUS [LIKE wild] | VARIABLES [LIKE wild]<br /> <br /> ♦<br /> <br /> LOGS | [FULL] PROCESSLIST<br /> <br /> ♦<br /> <br /> GRANTS FOR user | CREATE TABLE tbl<br /> <br /> ♦<br /> <br /> MASTER STATUS | MASTER LOGS | SLAVE STATUS<br /> <br /> EXPLAIN SELECT select_option<br /> <br /> Zeigt das Ausführungsverhalten einer SELECT-Anweisung an<br /> <br /> DESCRIBE tbl {col | wild}<br /> <br /> Gibt Daten über Spalten col der Tabelle tbl aus.<br /> <br /> BEGIN, COMMIT, ROLLBACK<br /> <br /> Transaktionssteuerung<br /> <br /> LOCK TABLES, UNLOCK TABLES<br /> <br /> Verriegeln und Freigeben von Tabellen<br /> <br /> SET [OPTION] opt=val<br /> <br /> Setzt Parameter<br /> <br /> SET TRANSACTION<br /> <br /> Transaktionssteuerung<br /> <br /> B Quickreferenz MySQL 4 ______________________________________________ 385 Anweisung<br /> <br /> Beschreibung<br /> <br /> GRANT priv_type [(col_list)] [, priv_type [(col_list)]] ON {tbl | * | *.* | db.*} TO user [IDENTIFIED BY 'password'] [, user [IDENTIFIED BY 'password']] [WITH GRANT OPTION]<br /> <br /> Vergibt Rechte an Benutzer user. priv_type kann eines der folgenden Werte ein: ALL PRIVILEGES FILE RELOAD ALTER INDEX SELECT CREATE INSERT SHUTDOWN DELETE PROCESS UPDATE DROP REFERENCES USAGE<br /> <br /> REVOKE priv_type [(col_list)] [, priv_type [(col_list)]] ON {tbl | * | *.* | db.*} FROM user<br /> <br /> Entfernt Rechte für Benutzer user. priv_type finden Sie bei GRANT.<br /> <br /> CREATE [UNIQUE|FULLTEXT] INDEX index_name ON tbl (col[(length)],... )<br /> <br /> Erzeugt einen neuen Index<br /> <br /> DROP INDEX index_name<br /> <br /> Löscht einen Index<br /> <br /> CREATE [AGGREGATE] FUNCTION function_name RETURNS {STRING|REAL|INT} SONAME library<br /> <br /> Erzeugt eine benutzerdefinierte Funktion<br /> <br /> DROP FUNCTION function_name<br /> <br /> Löscht eine benutzerdefinierte Funktion<br /> <br /> Diese Tabelle enthält nur Syntaxbeschreibungen zum schnellen Nachschlagen. Informieren Sie sich im MySQL-Handbuch über eine vollständige Beschreibung aller Optionen.<br /> <br /> V V V 1 2 3 4 5 6 7 8 9 10 11 12 13 14 A B C D E<br /> <br /> C Empfehlungen ______________________________________________________ 387<br /> <br /> C Empfehlungen Im Zusammenhang mit PHP5 benötigen Sie vermutlich früher oder später weitere Literatur, sowohl für PHP als auch für verwandte Bereiche. Die folgende Grafik zeigt einen einfachen Pfad rund um die verfügbare Primärliteratur. Weitere Empfehlungen finden Sie auf der folgenden Seite.<br /> <br /> C.1 Themen Wichtige Themen im Zusammenhang mit der Webserverprogrammierung sind: • Webserver (IIS bzw. Apache) • Protokolle (HTTP, FTP etc.) • Grundlegende Webkenntnisse (HTML, JavaScript, DHTML) • Ergänzende Sprachen (WML/WAP, Flash, PDF) • Datenbankgrundlagen (SQL, Transact-SQL, XML, XSLT) • Konkrete Datenbanken (MySQL, PostgreSQL, MS SQL)<br /> <br /> C.2 Fachbücher Diese Liste stellt nur eine kleine Auswahl der am Markt befindlichen Titel dar. Informieren Sie sich im Buchhandel nach weiteren /aktuelleren Büchern. Die Aufführung an dieser Stelle stellt keine Wertung dar. HTML und JavaScript HTML 4.0 Handbuch. HTML, JavaScript, DHTML, Perl; Stefan Münz, Wolfgang Nefzger; Franzis Verlag GmbH 2002 ISBN 3-7723-7515-4 HTML 4.0 Referenz; Stefan Münz, Wolfgang Nefzger, Franzis Verlag GmbH 2002 ISBN 3-7723-6999-5 JavaScript. Einführung, Programmierung und Referenz; Stefan Koch; dpunkt-Verlag, Heidelberg 2001 ISBN: 3-8986-4111-2 SQL SQL – Einstieg und Anwendung; Wolfgang E. Misgeld; Carl Hanser Verlag 2001, ISBN 3-446-21636-7 MySQL. Ein Tutorial für Webentwickler; Michael Kofler; Addison Wesley 2003, ISBN 3-8273-2046-1 MySQL. Zu MySQL 4, mit CD; Galileo Press 2002 ISBN: 3-8984-2188-0<br /> <br /> V V V 1 2 3 4 5 6 7 8 9 10 11 12 13 14 A B C D E<br /> <br /> 388 _____________________________________________________ C Empfehlungen Webserver Jetzt lerne ich Apache 2. Webpublishing mit Perl, PHP, MySQL, Java Server Pages und Cocoon; Markt & Technik Buch und Softwareverlag GmbH 2002 ISBN: 3-8272-6404-9 Apache Webserver 2.0 – Installation, Konfiguration, Programmierung; Addison-Wesley Longman Verlag GmbH 2002 ISBN: 3-8273-2039-9 Sonstiges Reguläre Ausdrücke; Jeffrey E. F. Friedl; OReilly/VVA 2003 ISBN 3-8972-1349-4 Theoretische Informatik kurzgefasst; Uwe Schöning; Spektrum Akademie Verlag, Heidelberg 2001 ISBN 3-8274-1099-1<br /> <br /> C.3 Programmiersysteme Ideal für alle, die wenig PHP und viel mit Design programmieren möchten, sei an dieser Stelle auf ein einzigartiges Produkt hingewiesen: phpTemple. Wenn Sie statt der üblichen Verquickung von Code und HTML mit einem Templatesystem arbeiten, lassen sich Code und Design leicht trennen und damit Arbeiten parallel ausführen. phpTemple ist ein Template-System für den Webdesigner. Sie können damit ohne Programmierkenntnisse stabile, dynamische und datenbankgestützte Websites entwerfen. Dabei muss die »Designersicht« nicht verlassen werden. Im HTML/XHTML-Code werden einfach wenige zusätzliche Tags integriert, die im Hintergrund Datenbanken abfragen, Programme starten oder Formulare behandeln. Durch die gewählte Architektur werden Sites skalierbar, das heißt, es können mehrere phpTempleSysteme parallel arbeiten und über Lastverteilungssysteme bedient werden. phpTemple ist unabhängig von Datenbanken – direkt unterstützt werden MySQL, MS SQL Server, PostgreSQL und Oracle. Alle internen Operationen basieren auf Datenbankabfragen – die Leistungsfähigkeit der Site wird wesentlich durch den Datenbankserver bestimmt. Die Datenbank wird auch eingesetzt, um Templates zu verwalten. Dadurch eignet sich phpTemple auch für Systeme mit Hunderten Templates und Tausenden daraus erstellten Seiten. phpTemple ist ein kompilierendes Templatesystem, bei dem die erstellten Vorlagen in reinen PHP-Code umgesetzt werden. Es ist deshalb kaum langsamer als reine PHPProgramme. Das Prinzip Ein einfaches Beispiel soll zeigen, wie mit phpTemple gearbeitet werden kann:<br /> <br /> <table> <ls:data sql=“SELECT name, date FROM table“> <tr> <td>${name}</td> <td>${date}</td> </tr><br /> <br /> C Empfehlungen ______________________________________________________ 389 </ls:data> </table> Diese Folge, basierend auf dem Tag <ls:data> wiederholt die Tabellenzeile sooft, wie Daten von der Datenbank geliefert werden. PHP-Code ist dazu nicht erforderlich, wird aber im Hintergrund automatisch erzeugt, sodass die Erweiterung mit PHP jederzeit möglich ist. Quelle Sie können Informationen zu phpTemple auf http://www.phpTemple.de finden. Am effizientesten lässt es sich einsetzen, wenn Sie einen dreitägigen Workshop buchen, bei dem ein konkretes Projekt umgesetzt und mit allen Techniken realisiert wird. Die Durchführung übernimmt der Autor dieses Buches persönlich. Sie erhalten also neben dem Produkt auch gleich ein fertiges Projekt. Für alle künftigen Projekte sparen Sie ca. 80% der Entwicklungszeit gegenüber der Standardprogrammierung mit PHP und HTML im klassischen Stil.<br /> <br /> V V V 1 2 3 4 5 6 7 8 9 10 11 12 13 14 A B C D E<br /> <br /> D Index ______________________________________________________________ 391<br /> <br /> D Index In diesem Index sind auch alle PHP-Funktionsnamen aufgelistet, die im Buch in irgendeiner Form Verwendung finden – mit oder ohne Erklärung, aber immer in einem praktischen Kontext. Funktionsnamen enden mit zwei runden Klammern (). Der jeweils relevante Eintrag ist fett hervorgehoben. Hinweise auf Konstanten oder Systemvariablen sind dagegen kursiv geschrieben. $ $GLOBALS 361 $HTTP_COOKIE_VARS 244 $HTTP_POST_FILES 210 $HTTP_POST_VARS 205 $HTTP_REFERER 283 $php_errormsg 134 $QUERY_STRING 216 $REMOTE_ADDR 279 $this 142 ( (boolean) 51 (double) 50 (float) 50 (integer) 50 (string) 51 @ @-Operator 133 _ __FILE__ 54 __LINE__ 54 A abstract 148 Addition 71 ALTER TABLE 260 and 104 AND 266 array() 88 array_count_values() 97 array_flip() 68 array_keys() 121 array_merge() 98 array_slice() 98 array_walk() 96 Arrays 85<br /> <br /> assoziative 88 eindimensionale 85 mehrdimensionale 90 nullbasiert 86 as Siehe foreach ASC 265 asort() 193 Auswahlboxen 202 AUTO_INCREMENT 259 B base_convert() 77 bc-Funktionen 80 Bedingungen 104 BETWEEN 266 Beziehungen 256 Bilderzeugung Fehlerausgaben 320 Bildfunktionen 315 bindec() 77 Bitoperatoren 74 NICHT 74 ODER 74 UND 74 Blöcke 103 break 108, 109, 111 for 115 switch 109 while 111 C Cache 31 call_user_method() 149 call_user_method_array() 149 case 108, 325 catch 132, 157 ceil() 77 CGI Siehe Common Gateway Interface Chat-Lösung 306<br /> <br /> V V V 1 2 3 4 5 6 7 8 9 10 11 12 13 14 A B C D E<br /> <br /> 392 _____________________________________________________________ D Index checkdate() 337 chunk_split() 63 class 140 static 143 clearstatcache() 178 Code-Konventionen 31 Common Gateway Interface 27 Compiler 29 continue 113 for 115 while 113 Cookies Definition 242 Einführung 241 copy() 179, 211 count() 96 CREATE DATABASE 259 CREATE TABLE 259 current() 95 D date() Platzhalter 338 Dateien einschließen 164 Dateierweiterungen 34 Dateisystem 163 Zugriffsrechte 209 Dateiupload 207 Größe begrenzen 209 Mehrere Dateien 210 Dateizeiger 175 Daten weiterreichen 213 Datenbanken Einführung in SQL 261 löschen 260 Datenbankobjekte 252 Datennormalisierung 253 Datentypen 48 Datumsfunktionen 336 decbin() 77 dechex() 77 decoct() 77 default 109 define 53 deg2rad() 76 Dekrement 71<br /> <br /> DELETE 267 DESC 265 Destruktor 145 die 134 dir() 181 DISTINCT 265 Division 71 do 102 do ... while 112 DROP DATABASE 260 DROP TABLE 260 E E_ALL 135 E_COMPILE_ERROR 135 E_COMPILE_WARNING 135 E_CORE_ERROR 135 E_CORE_WARNING 135 E_ERROR 54, 135 E_NOTICE 54, 135 E_PARSE 54, 135 E_USER_ERROR 135 E_USER_NOTICE 135 E_USER_WARNING 135 E_WARNING 54, 135 each() 96 else 107 elseif 107 end() 95 error_reporting() 135 Erstellen und Testen 38 Erweiterungen, DLLs 356 Exception 155 exp() 76 explode() 193, 218, 338 extends 146 F Fakultät 128 FALSE 54 fclose() 169 Fehler 41 Fehlerbehandlung 133 Fehlerunterdrückung 133 Fehlerverzweigung 134 feof() 176 fgets() 169<br /> <br /> D Index ______________________________________________________________ 393 file() 167 file_exists() 180 file_get_content 183 filemtime() 177 filesize() 177 final 148 floor() 77 Folgen 101 fopen() 168 for 40, 42, 64, 102, 114, 126 foreach 66, 87, 95, 96, 102, 116, 117, 203 Formatierzeichenkette 61 Formular Elemente auf Existenz testen 202 Formulare HTML 197 komplexe 203 Mehrfachauswahl 204 fputs() 169 fread() 169 frewind() 177 fseek() 177 ftell() 177 ftp_cdup() 191 ftp_chdir() 190 ftp_connect() 188 ftp_login() 189 ftp_pwd() 191, 192 ftp_rawlist() 192 ftp_systype() 193 FTP-Funktionen 187 FTP-Verbindungen 186 func_get_arg() 125 func_get_args() 125 func_num_args() 125 function 20, 64, 118, 177 Funktionen 118 Optionale Parameter 123 Referenzen 122 Rekursion 127 Rückgabe mehrerer Werte 126 Funktionsargumente 119 Funktionsdefinition 118 fwrite() 169<br /> <br /> G Ganzzahlen 48 Genauigkeit beliebige 80 George Boole 51 get_class() 149 get_class_methods() 149 get_html_translation_table() 68 getdate() 342 getimagesize() 322 getrandmax() 79 gettimeofday() 342 GIF 151 Gleitkommazahlen 48 Globale Servervariablen 205 gmdate() 342 gmmktime() 345 gmstrftime() 342 GROUP BY 268 H Handle 163 Hash Siehe Arrays, asoziative HAVING 268 header() 316 hexdec() 77 Hilfe im Web 23 Hinweise zum Buch 19 Hochladen von Dateien Siehe Dateiupload HTML-Formularelemente 198 htmlspecialchars() 167 I if 75, 101, 104, 106 imagecolorallocate() 317 imagecreate() 317, 321 imagedestroy() 317 imageline() 321 imagepng() 317 imagettfbbox() 317 implode() 175, 185 IN 267 include() 164 include_once() 166 ini_set 134<br /> <br /> V V V 1 2 3 4 5 6 7 8 9 10 11 12 13 14 A B C D E<br /> <br /> 394 _____________________________________________________________ D Index Inkrement 71 INSERT 261 Installation 21 Andere Server 22 LAMP 21 WAMP 22 WIMP 22 WPMP 22 interface 147 Interpreter 29 is_array() 96, 206 is_dir() 177, 182 is_file() 177 is_link() 177 is_subclass_of() 149 J JavaScript 299 Browserprobleme 306 Datenaustausch 299 Formulare 302 onclick() 305 JOIN 268 K klebrige Formulare 202 Konfiguration Groß- und Kleinschreibung 350 Konfigurationsdatei 350 Konstanten 52 Definition 53 mathematische 78 vordefinierte 54 Konstruktor 145 Kontrollkästchen 202 L LIKE 265 LIMIT 268 list() 96 localtime 343 localtime() 343 log() 76 Logische Operatoren 75, 104 Assoziativität 75 Logische Werte 51<br /> <br /> M M_1_PI 79 M_2_PI 79 M_2_SQRTPI 79 M_E 78 M_LN10 78 M_LN2 78 M_LOG10E 78 M_LOG2E 78 M_PI 78 M_PI_2 78 M_PI_4 79 M_SQRT1_2 79 M_SQRT2 79 max() 76 MAX_FILE_SIZE 209 md5() 291 Metazeichen 333 method_exists() 149 microtime() 345 MIME-Typen 212 min() 76 mktime() 344 Modulus 71 mt_getrandmax() 79 mt_rand() 79 mt_srand() 79 mt-Funktionen Siehe ZufallszahlenFunktionen Multiplikation 71 MySQL Gruppierungen 268 Mathematische Funktionen 374 PHP-Funktionen (Übersicht) 269 Praxis 271 Reguläre Ausdrücke 268 mysql_connect() 273 mysql_fetch_array() 280 mysql_fetch_assoc() 308 mysql_num_rows() 276 mysql_query() 279 mysql_select_db() 274 N Navigationshilfen 21 new 75, 142, 144, 378<br /> <br /> D Index ______________________________________________________________ 395 next() 95 Normalisierungsregeln 254 NOT NULL 260 Notationshinweise 36 NULL 54, 260 number_format() 63 O Objekte 140 octdec() 77 opendir() 212 Operatoren 71 ! 104 % 71 & 74 && 104 * 71 / 71 | 74 || 104 ~ 74 + 71 ++ 71 << 74 => (foreach) 117 >> 74 arithmetische 71 Bitweise 74 logische Siehe Logische Operatoren Zeichenketten verbinden 73 Zuweisungen 73 Optionale Parameter 123 Optionsfelder 202 or 104 OR 266 ORDER BY 265 P pack 152 PHP ausführen 33 Dateierweiterungen 34 einbinden, in HTML 35 und HTML 34 php.ini 350 php.ini-dist 350 PHP_OS 54<br /> <br /> PHP_VERSION 54 php3.ini 350 phpinfo() 349 phpMyAdmin 23 pow() 76 preg_grep 336 preg_grep() 336 preg_match() 180, 212, 335 preg_match_all() 327, 335 preg_replace() 185, 328, 333, 335 preg_split() 335 prev() 95 PRIMARY KEY 260 print_r() 361 printf() 59, 340 Programmierparadigmen 30 Proxy 31 Prozeduren 118 Punkt und Pixel 320 Q Quantifier 334 R rad2deg() 76 Radiant 76 rand() 79 RDBMS 252 read 129 readdir() 212 readfile() 166, 316 Referenzen 52 referenzierte Argumente (&) 122 REGEXP 268 Reguläre Ausdrücke 323 Greedy 332 Optionen 336 Rekursion 127 Relationen 253 rename() 180 require 165 require() 165 require_once 166 reset() 95 return 118, 119 return() 118 RLIKE 268<br /> <br /> V V V 1 2 3 4 5 6 7 8 9 10 11 12 13 14 A B C D E<br /> <br /> 396 _____________________________________________________________ D Index round() 77 rsort() 193 Rückgabe mehrerer Werte 126 Rückgabewert einer Funktion 119 S Schleifen 110 Schnittstellen 147 Schreibweisen im Buch 20 select 202 SELECT * FROM 262 SELECT ... WHERE 262 Semantik 29 Semikolon 36 Sendeschaltflächen 202 serialize() 245 Servervariablen 219 Übersicht 220 Session 225 session_modul_name() 234 session_register() 232 session_set_save_handler() 234 session_start() 231, 307 Sessions Benutzerfunktionen 233 Cookies 227 Datenspeicherung 233 Garbage Collection 229 Konfigurationsschalter 227 Müllsammelroutine 229 Sicherheit 231 Sessionvariablen 225 set_error_handler 136 setcookie() 244 setlocale() 340, 344 Skripte verbinden 213 Skriptsprache 33 Sofort ausprobieren 32 Softwarequellen 23 Späte Bindung 119 sprintf() 59, 172 SQL Siehe Structured Query Language Aggregate Funktionen 376 SQLite 251 ALTER TABLE 287 AUTOINCREMENT 285 Datentypen 285<br /> <br /> Konfiguration 287 PHP-Funktionen (Übersicht) 288 Praxis 290 SQL92 284 SQL-Dialekt 284 sqlite_master 287 TYPEOF 286 SQLLite vorbereiten 257 sqrt() 76 srand() 79 sscanf 62 static 121 Sticky Forms 202, 276 Stil 29 str_pad 172 str_pad() 66 str_repeat 152 str_repeat() 68 strftime() 341 Platzhalter 338 stripslashes() 216, 247, 326 stristr() 65 strlen() 66, 185 strncasecmp() 64 strrchr() 68 strstr() 65, 185 strtotime() 344 strtoupper() 64 strtr() 68 Structured Query Language 251 Strukturen 103 Strukturiertes Programmieren 101 substr() 64 substr_count() 68 Subtraktion 71 switch 101, 108, 171, 214 Erweiterte Syntax 109 switch() 108 Syntax 29 T Tabellen ändern 260 löschen 260 this Siehe $this throw 132, 157<br /> <br /> D Index ______________________________________________________________ 397 time() 345 Timestamp 337 trigger_error 136 Trinärer Bedingungsoperator 108 TRUE 54 try 132, 157 U ucfirst() 172 Umgebungsvariablen 219 Umwandlungsfunktionen, mathematische 77 unlink() 180, 181 unserialize() 245 unset() 175 UPDATE 267 Upload Siehe Dateiupload urldecode() 215 urlencode() 215 USE 259 UTC 342 V var_dump() 361 Variablen 47 Datentypen 48 Name 47 Referenzen 52 Verbindungen zu Servern 183 Vererbung 146 Vergleichsoperatoren 104, 105 Verweise 52<br /> <br /> Verzeichnisfunktionen 181 Verzeichnissystem 181 Verzweigungen 101 Voraussetzungen 19 W Webservervariablen Siehe Servervariablen Website zum Buch 24 WHERE Operatoren 266 while 96, 102, 110, 167 wordwrap() 70 X xor 104 Z Zahlen Schreibweise 49 Zählschleifen 114 Zeichenarten 334 Zeichenketten 37 erkennen 51 Formatierung 59 Funktionen 57 Zeichenkettenoperator 73 Zielgruppen 19 Zufallszahlen 79 Zufallszahlen-Funktionen 79 Zugriffsrechte (Unix) 192 Zuweisungsoperatoren 73<br /> <br /> V V V 1 2 3 4 5 6 7 8 9 10 11 12 13 14 A B C D E<br /> <br /> E An den Autor ________________________________________________________ 399<br /> <br /> E An den Autor Für Fragen, Anregungen aber auch Kritik und Hinweise steht Ihnen der Autor gern zur Verfügung. Dieses Buch soll einen schnellen und kompakten Einstieg in PHP5 bieten. Insofern sind Verbesserungsvorschläge und konstruktive Anmerkungen gern gesehen und finden in künftigen Auflagen sicher ihre Entsprechung. Aktuelle Informationen finden Sie im Internet Alle Skripte, Bugfixes und Korrekturen finden Sie im Internet unter der folgenden Adresse:<br /> <br /> http://www.php.comzept.de Unbedingt ansehen sollten Sie sich professionelle Template-Systeme in und für PHP:<br /> <br /> http://www.phptemple.de Den Autor selbst können Sie auf seiner Homepage näher kennen lernen:<br /> <br /> http://www.joerg.krause.net Informationen über professionelle Unterstützung Hilfe finden Sie beim Autor, wenn es um eines der folgenden »Probleme« geht: • Seminare und Schulungen auf höchstem Niveau • Workshops und Coaching zur Lösung konkreter Referenzprojekte • Entwicklung professioneller Websites jeder Größenordnung • Projektmanagement und Programmierung • Fachliche Unterstützung für Unternehmen Anfragen senden Sie bitte direkt per E-Mail an:<br /> <br /> joerg@krause.net Wichtiger Hinweis in eigener Sache Leider schaffe ich es nicht immer, jede E-Mail sofort zu beantworten. Sie können aber sicher sein, dass jede E-Mail gelesen wird. Insofern können Sie dieses Medium jederzeit nutzen, um irgendetwas los zu werden – was auch immer Sie gern mitteilen möchten. Für Hilfe beim »Skripten« wenden Sie sich an eines der vielen Foren oder werden Sie Mitglied einer Mailingliste.<br /> <br /> V V V 1 2 3 4 5 6 7 8 9 10 11 12 13 14 A B C D E<br /> <br /> </div> </div> </div> <div class="row hidden-xs"> <div class="col-md-12"> <h2></h2> <hr /> </div> <div class="col-lg-2 col-md-3"> <div class="note"> <div class="note-meta-thumb"> <a href="https://epdf.tips/spielend-programmieren-lernen.html"> <img src="https://epdf.tips/img/300x300/spielend-programmieren-lernen_5bfa81c7b7d7bcfa1f283231.jpg" alt="Spielend Programmieren lernen" /> <h3 class="note-title">Spielend Programmieren lernen</h3> </a> </div> <div class="note-action"> <a class="more-link" href="https://epdf.tips/spielend-programmieren-lernen.html">Read more</a> </div> </div> </div> <div class="col-lg-2 col-md-3"> <div class="note"> <div class="note-meta-thumb"> <a href="https://epdf.tips/programmieren-lernen-mit-java.html"> <img src="https://epdf.tips/img/300x300/programmieren-lernen-mit-java_5b982bf5b7d7bc7b0195c38e.jpg" alt="Programmieren lernen mit Java" /> <h3 class="note-title">Programmieren lernen mit Java</h3> </a> </div> <div class="note-action"> <a class="more-link" href="https://epdf.tips/programmieren-lernen-mit-java.html">Read more</a> </div> </div> </div> <div class="col-lg-2 col-md-3"> <div class="note"> <div class="note-meta-thumb"> <a href="https://epdf.tips/besser-php-programmieren-professionelle-programmiertechniken-fr-php-5-galileo-co.html"> <img src="https://epdf.tips/img/300x300/besser-php-programmieren-professionelle-programmie_5b962a72b7d7bc2859e5b0a9.jpg" alt="Besser PHP programmieren: Professionelle Programmiertechniken für PHP 5 (Galileo Computing)" /> <h3 class="note-title">Besser PHP programmieren: Professionelle Programmiertechniken für PHP 5 (Galileo Computing)</h3> </a> </div> <div class="note-action"> <a class="more-link" href="https://epdf.tips/besser-php-programmieren-professionelle-programmiertechniken-fr-php-5-galileo-co.html">Read more</a> </div> </div> </div> <div class="col-lg-2 col-md-3"> <div class="note"> <div class="note-meta-thumb"> <a href="https://epdf.tips/programmieren-lernen-mit-perl-xpertpress.html"> <img src="https://epdf.tips/img/300x300/programmieren-lernen-mit-perl-xpertpress_5baa4323b7d7bc8b0b1ae8d3.jpg" alt="Programmieren lernen mit Perl (Xpert.press)" /> <h3 class="note-title">Programmieren lernen mit Perl (Xpert.press)</h3> </a> </div> <div class="note-action"> <a class="more-link" href="https://epdf.tips/programmieren-lernen-mit-perl-xpertpress.html">Read more</a> </div> </div> </div> <div class="col-lg-2 col-md-3"> <div class="note"> <div class="note-meta-thumb"> <a href="https://epdf.tips/programmieren-lernen-mit-java-german.html"> <img src="https://epdf.tips/img/300x300/programmieren-lernen-mit-java-german_5ab08a3ab7d7bc45282f0aae.jpg" alt="Programmieren lernen mit Java GERMAN" /> <h3 class="note-title">Programmieren lernen mit Java GERMAN</h3> </a> </div> <div class="note-action"> <a class="more-link" href="https://epdf.tips/programmieren-lernen-mit-java-german.html">Read more</a> </div> </div> </div> <div class="col-lg-2 col-md-3"> <div class="note"> <div class="note-meta-thumb"> <a href="https://epdf.tips/php-5acc58768f93020c46a9f32b0d6f502fa85973.html"> <img src="https://epdf.tips/img/300x300/php-5_5b310aa0b7d7bcff49f3cbb4.jpg" alt="PHP 5" /> <h3 class="note-title">PHP 5</h3> </a> </div> <div class="note-action"> <a class="more-link" href="https://epdf.tips/php-5acc58768f93020c46a9f32b0d6f502fa85973.html">Read more</a> </div> </div> </div> <div class="col-lg-2 col-md-3"> <div class="note"> <div class="note-meta-thumb"> <a href="https://epdf.tips/php-5.html"> <img src="https://epdf.tips/img/300x300/php-5_5b310a49b7d7bc014a22343b.jpg" alt="PHP 5" /> <h3 class="note-title">PHP 5</h3> </a> </div> <div class="note-action"> <a class="more-link" href="https://epdf.tips/php-5.html">Read more</a> </div> </div> </div> <div class="col-lg-2 col-md-3"> <div class="note"> <div class="note-meta-thumb"> <a href="https://epdf.tips/php-59142a803e14c6886bb73fafd7aed709a70127.html"> <img src="https://epdf.tips/img/300x300/php-5_5bf0e341b7d7bcfa1f27fd07.jpg" alt="PHP 5" /> <h3 class="note-title">PHP 5</h3> </a> </div> <div class="note-action"> <a class="more-link" href="https://epdf.tips/php-59142a803e14c6886bb73fafd7aed709a70127.html">Read more</a> </div> </div> </div> <div class="col-lg-2 col-md-3"> <div class="note"> <div class="note-meta-thumb"> <a href="https://epdf.tips/php-562807f47db0200fc816b95dbc11f5bca24979.html"> <img src="https://epdf.tips/img/300x300/php-5_5c0aa651b7d7bcf27e6bfa44.jpg" alt="PHP 5" /> <h3 class="note-title">PHP 5</h3> </a> </div> <div class="note-action"> <a class="more-link" href="https://epdf.tips/php-562807f47db0200fc816b95dbc11f5bca24979.html">Read more</a> </div> </div> </div> <div class="col-lg-2 col-md-3"> <div class="note"> <div class="note-meta-thumb"> <a href="https://epdf.tips/programmieren-lernen-mit-perl-xpertpress-german-edition.html"> <img src="https://epdf.tips/img/300x300/programmieren-lernen-mit-perl-xpertpress-german-ed_5b049865b7d7bc7969fdd190.jpg" alt="Programmieren lernen mit Perl (Xpert.press) (German Edition)" /> <h3 class="note-title">Programmieren lernen mit Perl (Xpert.press) (German Edition)</h3> </a> </div> <div class="note-action"> <a class="more-link" href="https://epdf.tips/programmieren-lernen-mit-perl-xpertpress-german-edition.html">Read more</a> </div> </div> </div> <div class="col-lg-2 col-md-3"> <div class="note"> <div class="note-meta-thumb"> <a href="https://epdf.tips/programmieren-lernen-fr-teens-mit-c-german.html"> <img src="https://epdf.tips/img/300x300/programmieren-lernen-fr-teens-mit-c-german_5bfaa34bb7d7bcfa1f283363.jpg" alt="Programmieren lernen für Teens mit C GERMAN" /> <h3 class="note-title">Programmieren lernen für Teens mit C GERMAN</h3> </a> </div> <div class="note-action"> <a class="more-link" href="https://epdf.tips/programmieren-lernen-fr-teens-mit-c-german.html">Read more</a> </div> </div> </div> <div class="col-lg-2 col-md-3"> <div class="note"> <div class="note-meta-thumb"> <a href="https://epdf.tips/php-sicherheit-php-mysql-webanwendungen-sicher-programmieren-3-auflage.html"> <img src="https://epdf.tips/img/300x300/php-sicherheit-php-mysql-webanwendungen-sicher-pro_5a626ad9b7d7bc1a4b0f3111.jpg" alt="PHP-Sicherheit: PHP MySQL-Webanwendungen sicher programmieren, 3. Auflage" /> <h3 class="note-title">PHP-Sicherheit: PHP MySQL-Webanwendungen sicher programmieren, 3. Auflage</h3> </a> </div> <div class="note-action"> <a class="more-link" href="https://epdf.tips/php-sicherheit-php-mysql-webanwendungen-sicher-programmieren-3-auflage.html">Read more</a> </div> </div> </div> <div class="col-lg-2 col-md-3"> <div class="note"> <div class="note-meta-thumb"> <a href="https://epdf.tips/c-in-21-tagen-schritt-fr-schritt-objektorientiert-programmieren-lernen.html"> <img src="https://epdf.tips/img/300x300/c-in-21-tagen-schritt-fr-schritt-objektorientiert-_5b982bd9b7d7bc7c01398959.jpg" alt="C# in 21 Tagen. Schritt für Schritt objektorientiert programmieren lernen" /> <h3 class="note-title">C# in 21 Tagen. Schritt für Schritt objektorientiert programmieren lernen</h3> </a> </div> <div class="note-action"> <a class="more-link" href="https://epdf.tips/c-in-21-tagen-schritt-fr-schritt-objektorientiert-programmieren-lernen.html">Read more</a> </div> </div> </div> <div class="col-lg-2 col-md-3"> <div class="note"> <div class="note-meta-thumb"> <a href="https://epdf.tips/-php-54559af672bbd10f2b9eade99416a04ac61673.html"> <img src="https://epdf.tips/img/300x300/-php-5_5c0c4f1fb7d7bcfb02f5e227.jpg" alt="Самоучитель PHP 5" /> <h3 class="note-title">Самоучитель PHP 5</h3> </a> </div> <div class="note-action"> <a class="more-link" href="https://epdf.tips/-php-54559af672bbd10f2b9eade99416a04ac61673.html">Read more</a> </div> </div> </div> <div class="col-lg-2 col-md-3"> <div class="note"> <div class="note-meta-thumb"> <a href="https://epdf.tips/php-5-power-programming34749.html"> <img src="https://epdf.tips/img/300x300/php-5-power-programming_5a5d8112b7d7bc4c16b6ae37.jpg" alt="PHP 5 Power Programming" /> <h3 class="note-title">PHP 5 Power Programming</h3> </a> </div> <div class="note-action"> <a class="more-link" href="https://epdf.tips/php-5-power-programming34749.html">Read more</a> </div> </div> </div> <div class="col-lg-2 col-md-3"> <div class="note"> <div class="note-meta-thumb"> <a href="https://epdf.tips/dynamisez-php-5.html"> <img src="https://epdf.tips/img/300x300/dynamisez-php-5_5b9a57b2b7d7bcac1df10252.jpg" alt="Dynamisez PHP 5" /> <h3 class="note-title">Dynamisez PHP 5</h3> </a> </div> <div class="note-action"> <a class="more-link" href="https://epdf.tips/dynamisez-php-5.html">Read more</a> </div> </div> </div> <div class="col-lg-2 col-md-3"> <div class="note"> <div class="note-meta-thumb"> <a href="https://epdf.tips/php-5-power-programming446060bdb3fd633f7b912e4d8753730829531.html"> <img src="https://epdf.tips/img/300x300/php-5-power-programming_5a742600b7d7bcee65e33aef.jpg" alt="PHP 5 Power Programming" /> <h3 class="note-title">PHP 5 Power Programming</h3> </a> </div> <div class="note-action"> <a class="more-link" href="https://epdf.tips/php-5-power-programming446060bdb3fd633f7b912e4d8753730829531.html">Read more</a> </div> </div> </div> <div class="col-lg-2 col-md-3"> <div class="note"> <div class="note-meta-thumb"> <a href="https://epdf.tips/php-5-unleashed.html"> <img src="https://epdf.tips/img/300x300/php-5-unleashed_5ad15942b7d7bccb101e7f59.jpg" alt="PHP 5 Unleashed" /> <h3 class="note-title">PHP 5 Unleashed</h3> </a> </div> <div class="note-action"> <a class="more-link" href="https://epdf.tips/php-5-unleashed.html">Read more</a> </div> </div> </div> <div class="col-lg-2 col-md-3"> <div class="note"> <div class="note-meta-thumb"> <a href="https://epdf.tips/php-5-2687d4443c982f608f3f4567aef1af6186218.html"> <img src="https://epdf.tips/img/300x300/php-5-_5c0b8607b7d7bcfd225f5bb2.jpg" alt="PHP 5. Полное руководство" /> <h3 class="note-title">PHP 5. Полное руководство</h3> </a> </div> <div class="note-action"> <a class="more-link" href="https://epdf.tips/php-5-2687d4443c982f608f3f4567aef1af6186218.html">Read more</a> </div> </div> </div> <div class="col-lg-2 col-md-3"> <div class="note"> <div class="note-meta-thumb"> <a href="https://epdf.tips/php-5-2c2d5b92ee774f92c2160931629141fa96724.html"> <img src="https://epdf.tips/img/300x300/php-5-_5c0d3a0eb7d7bc9d677c405d.jpg" alt="PHP 5 в подлинике" /> <h3 class="note-title">PHP 5 в подлинике</h3> </a> </div> <div class="note-action"> <a class="more-link" href="https://epdf.tips/php-5-2c2d5b92ee774f92c2160931629141fa96724.html">Read more</a> </div> </div> </div> <div class="col-lg-2 col-md-3"> <div class="note"> <div class="note-meta-thumb"> <a href="https://epdf.tips/php-5-unleashed939eaeb9c3a7e8e9c56186a07ee1750a6092.html"> <img src="https://epdf.tips/img/300x300/php-5-unleashed_5bf14514b7d7bcf41f50092d.jpg" alt="PHP 5 unleashed" /> <h3 class="note-title">PHP 5 unleashed</h3> </a> </div> <div class="note-action"> <a class="more-link" href="https://epdf.tips/php-5-unleashed939eaeb9c3a7e8e9c56186a07ee1750a6092.html">Read more</a> </div> </div> </div> <div class="col-lg-2 col-md-3"> <div class="note"> <div class="note-meta-thumb"> <a href="https://epdf.tips/spring-into-php-5.html"> <img src="https://epdf.tips/img/300x300/spring-into-php-5_5a3d86beb7d7bc8413b829d3.jpg" alt="Spring Into PHP 5" /> <h3 class="note-title">Spring Into PHP 5</h3> </a> </div> <div class="note-action"> <a class="more-link" href="https://epdf.tips/spring-into-php-5.html">Read more</a> </div> </div> </div> <div class="col-lg-2 col-md-3"> <div class="note"> <div class="note-meta-thumb"> <a href="https://epdf.tips/php-5-for-dummies.html"> <img src="https://epdf.tips/img/300x300/php-5-for-dummies_5a8b5fdbb7d7bcdf582bcb1c.jpg" alt="PHP 5 for Dummies" /> <h3 class="note-title">PHP 5 for Dummies</h3> </a> </div> <div class="note-action"> <a class="more-link" href="https://epdf.tips/php-5-for-dummies.html">Read more</a> </div> </div> </div> <div class="col-lg-2 col-md-3"> <div class="note"> <div class="note-meta-thumb"> <a href="https://epdf.tips/-php-5cc4d421b04dd2c0d104c3c0d0b957c7b75493.html"> <img src="https://epdf.tips/img/300x300/-php-5_5c0c4cb9b7d7bcfc0251f253.jpg" alt="Самоучитель PHP 5" /> <h3 class="note-title">Самоучитель PHP 5</h3> </a> </div> <div class="note-action"> <a class="more-link" href="https://epdf.tips/-php-5cc4d421b04dd2c0d104c3c0d0b957c7b75493.html">Read more</a> </div> </div> </div> <div class="col-lg-2 col-md-3"> <div class="note"> <div class="note-meta-thumb"> <a href="https://epdf.tips/learning-php-5.html"> <img src="https://epdf.tips/img/300x300/learning-php-5_5a83938cb7d7bc9f0f6294b6.jpg" alt="Learning PHP 5" /> <h3 class="note-title">Learning PHP 5</h3> </a> </div> <div class="note-action"> <a class="more-link" href="https://epdf.tips/learning-php-5.html">Read more</a> </div> </div> </div> <div class="col-lg-2 col-md-3"> <div class="note"> <div class="note-meta-thumb"> <a href="https://epdf.tips/upgrading-to-php-5.html"> <img src="https://epdf.tips/img/300x300/upgrading-to-php-5_5a507beeb7d7bc057ed3f244.jpg" alt="Upgrading to PHP 5" /> <h3 class="note-title">Upgrading to PHP 5</h3> </a> </div> <div class="note-action"> <a class="more-link" href="https://epdf.tips/upgrading-to-php-5.html">Read more</a> </div> </div> </div> <div class="col-lg-2 col-md-3"> <div class="note"> <div class="note-meta-thumb"> <a href="https://epdf.tips/php-5-.html"> <img src="https://epdf.tips/img/300x300/php-5-_5bf01bcdb7d7bcf41f5000fd.jpg" alt="PHP 5 для начинающих" /> <h3 class="note-title">PHP 5 для начинающих</h3> </a> </div> <div class="note-action"> <a class="more-link" href="https://epdf.tips/php-5-.html">Read more</a> </div> </div> </div> <div class="col-lg-2 col-md-3"> <div class="note"> <div class="note-meta-thumb"> <a href="https://epdf.tips/learning-php-5323659ff9a0883976e449950e41974ad69714.html"> <img src="https://epdf.tips/img/300x300/learning-php-5_5a8393b3b7d7bc9f0f6294b9.jpg" alt="Learning PHP 5" /> <h3 class="note-title">Learning PHP 5</h3> </a> </div> <div class="note-action"> <a class="more-link" href="https://epdf.tips/learning-php-5323659ff9a0883976e449950e41974ad69714.html">Read more</a> </div> </div> </div> <div class="col-lg-2 col-md-3"> <div class="note"> <div class="note-meta-thumb"> <a href="https://epdf.tips/programming-php-2nd-edition-covers-php-5.html"> <img src="https://epdf.tips/img/300x300/programming-php-2nd-edition-covers-php-5_5a741f75b7d7bcee65e33aee.jpg" alt="Programming PHP, 2nd Edition (Covers PHP 5)" /> <h3 class="note-title">Programming PHP, 2nd Edition (Covers PHP 5)</h3> </a> </div> <div class="note-action"> <a class="more-link" href="https://epdf.tips/programming-php-2nd-edition-covers-php-5.html">Read more</a> </div> </div> </div> <div class="col-lg-2 col-md-3"> <div class="note"> <div class="note-meta-thumb"> <a href="https://epdf.tips/best-practices-php-5.html"> <img src="https://epdf.tips/img/300x300/best-practices-php-5_5a625b9cb7d7bc5c177a274f.jpg" alt="Best practices PHP 5" /> <h3 class="note-title">Best practices PHP 5</h3> </a> </div> <div class="note-action"> <a class="more-link" href="https://epdf.tips/best-practices-php-5.html">Read more</a> </div> </div> </div> </div> </div> <div class="col-lg-3 col-md-4 col-xs-12"> <div class="panel-recommend panel panel-primary"> <div class="panel-heading"> <h4 class="panel-title">Recommend Documents</h4> </div> <div class="panel-body"> <div class="row m-0"> <div class="col-md-3 col-xs-3 pl-0 text-center"> <a href="https://epdf.tips/spielend-programmieren-lernen.html"> <img src="https://epdf.tips/img/60x80/spielend-programmieren-lernen_5bfa81c7b7d7bcfa1f283231.jpg" alt="" width="100%" /> </a> </div> <div class="col-md-9 col-xs-9 p-0"> <label> <a href="https://epdf.tips/spielend-programmieren-lernen.html"> Spielend Programmieren lernen </a> </label> <div class="note-meta"> <div class="note-desc">Spielend Programmieren lernen Einführung in das kreative Programmieren mit dem Heimcomputer. Lernen Sie, Computerspiel...</div> </div> </div> <div class="clearfix"></div> <hr class="mt-15 mb-15" /> </div> <div class="row m-0"> <div class="col-md-3 col-xs-3 pl-0 text-center"> <a href="https://epdf.tips/programmieren-lernen-mit-java.html"> <img src="https://epdf.tips/img/60x80/programmieren-lernen-mit-java_5b982bf5b7d7bc7b0195c38e.jpg" alt="" width="100%" /> </a> </div> <div class="col-md-9 col-xs-9 p-0"> <label> <a href="https://epdf.tips/programmieren-lernen-mit-java.html"> Programmieren lernen mit Java </a> </label> <div class="note-meta"> <div class="note-desc">Erwin Merker Roman Merker Programmieren lernen mit JAVA Aus dem Bereich IT erfolgreich lernen Lexikon für IT-Berufe...</div> </div> </div> <div class="clearfix"></div> <hr class="mt-15 mb-15" /> </div> <div class="row m-0"> <div class="col-md-3 col-xs-3 pl-0 text-center"> <a href="https://epdf.tips/besser-php-programmieren-professionelle-programmiertechniken-fr-php-5-galileo-co.html"> <img src="https://epdf.tips/img/60x80/besser-php-programmieren-professionelle-programmie_5b962a72b7d7bc2859e5b0a9.jpg" alt="" width="100%" /> </a> </div> <div class="col-md-9 col-xs-9 p-0"> <label> <a href="https://epdf.tips/besser-php-programmieren-professionelle-programmiertechniken-fr-php-5-galileo-co.html"> Besser PHP programmieren: Professionelle Programmiertechniken für PHP 5 (Galileo Computing) </a> </label> <div class="note-meta"> <div class="note-desc">Ô·»¾» Ô»-»®·²ô ´·»¾»® Ô»-»®ô ·½¸ º®»«» ³·½¸ô ¼¿-- Í·» -·½¸ º$® »·² Þ«½¸ ª±² Ù¿´·´»± ݱ³°«¬·²¹ »²¬-½¸·»¼»² ¸¿¾»²ò Ü¿-- Í...</div> </div> </div> <div class="clearfix"></div> <hr class="mt-15 mb-15" /> </div> <div class="row m-0"> <div class="col-md-3 col-xs-3 pl-0 text-center"> <a href="https://epdf.tips/programmieren-lernen-mit-perl-xpertpress.html"> <img src="https://epdf.tips/img/60x80/programmieren-lernen-mit-perl-xpertpress_5baa4323b7d7bc8b0b1ae8d3.jpg" alt="" width="100%" /> </a> </div> <div class="col-md-9 col-xs-9 p-0"> <label> <a href="https://epdf.tips/programmieren-lernen-mit-perl-xpertpress.html"> Programmieren lernen mit Perl (Xpert.press) </a> </label> <div class="note-meta"> <div class="note-desc">Xpert. press Springer Berlin Heidelberg New York Barcelona Ho ngkong London Mailand Paris Tokio Die Reihe Xpert.pres...</div> </div> </div> <div class="clearfix"></div> <hr class="mt-15 mb-15" /> </div> <div class="row m-0"> <div class="col-md-3 col-xs-3 pl-0 text-center"> <a href="https://epdf.tips/programmieren-lernen-mit-java-german.html"> <img src="https://epdf.tips/img/60x80/programmieren-lernen-mit-java-german_5ab08a3ab7d7bc45282f0aae.jpg" alt="" width="100%" /> </a> </div> <div class="col-md-9 col-xs-9 p-0"> <label> <a href="https://epdf.tips/programmieren-lernen-mit-java-german.html"> Programmieren lernen mit Java GERMAN </a> </label> <div class="note-meta"> <div class="note-desc">Erwin Merker Roman Merker Programmieren lernen mit JAVA Aus dem Bereich IT erfolgreich lernen Lexikon für IT-Berufe...</div> </div> </div> <div class="clearfix"></div> <hr class="mt-15 mb-15" /> </div> <div class="row m-0"> <div class="col-md-3 col-xs-3 pl-0 text-center"> <a href="https://epdf.tips/php-5acc58768f93020c46a9f32b0d6f502fa85973.html"> <img src="https://epdf.tips/img/60x80/php-5_5b310aa0b7d7bcff49f3cbb4.jpg" alt="" width="100%" /> </a> </div> <div class="col-md-9 col-xs-9 p-0"> <label> <a href="https://epdf.tips/php-5acc58768f93020c46a9f32b0d6f502fa85973.html"> PHP 5 </a> </label> <div class="note-meta"> <div class="note-desc">9:55 Page 1 avec Programmez intelligent les Cahiers du Programmeur De la conception à l’exploitation, on créera un...</div> </div> </div> <div class="clearfix"></div> <hr class="mt-15 mb-15" /> </div> <div class="row m-0"> <div class="col-md-3 col-xs-3 pl-0 text-center"> <a href="https://epdf.tips/php-5.html"> <img src="https://epdf.tips/img/60x80/php-5_5b310a49b7d7bc014a22343b.jpg" alt="" width="100%" /> </a> </div> <div class="col-md-9 col-xs-9 p-0"> <label> <a href="https://epdf.tips/php-5.html"> PHP 5 </a> </label> <div class="note-meta"> <div class="note-desc">9:55 Page 1 avec Programmez intelligent les Cahiers du Programmeur De la conception à l’exploitation, on créera un...</div> </div> </div> <div class="clearfix"></div> <hr class="mt-15 mb-15" /> </div> <div class="row m-0"> <div class="col-md-3 col-xs-3 pl-0 text-center"> <a href="https://epdf.tips/php-59142a803e14c6886bb73fafd7aed709a70127.html"> <img src="https://epdf.tips/img/60x80/php-5_5bf0e341b7d7bcfa1f27fd07.jpg" alt="" width="100%" /> </a> </div> <div class="col-md-9 col-xs-9 p-0"> <label> <a href="https://epdf.tips/php-59142a803e14c6886bb73fafd7aed709a70127.html"> PHP 5 </a> </label> <div class="note-meta"> <div class="note-desc">Copyright © 2005 Micro Application 20-22, rue des Petits-Hôtels 75010 Paris 1ère Édition - Janvier 2005 Auteurs La...</div> </div> </div> <div class="clearfix"></div> <hr class="mt-15 mb-15" /> </div> <div class="row m-0"> <div class="col-md-3 col-xs-3 pl-0 text-center"> <a href="https://epdf.tips/php-562807f47db0200fc816b95dbc11f5bca24979.html"> <img src="https://epdf.tips/img/60x80/php-5_5c0aa651b7d7bcf27e6bfa44.jpg" alt="" width="100%" /> </a> </div> <div class="col-md-9 col-xs-9 p-0"> <label> <a href="https://epdf.tips/php-562807f47db0200fc816b95dbc11f5bca24979.html"> PHP 5 </a> </label> <div class="note-meta"> <div class="note-desc"></div> </div> </div> <div class="clearfix"></div> <hr class="mt-15 mb-15" /> </div> <div class="row m-0"> <div class="col-md-3 col-xs-3 pl-0 text-center"> <a href="https://epdf.tips/programmieren-lernen-mit-perl-xpertpress-german-edition.html"> <img src="https://epdf.tips/img/60x80/programmieren-lernen-mit-perl-xpertpress-german-ed_5b049865b7d7bc7969fdd190.jpg" alt="" width="100%" /> </a> </div> <div class="col-md-9 col-xs-9 p-0"> <label> <a href="https://epdf.tips/programmieren-lernen-mit-perl-xpertpress-german-edition.html"> Programmieren lernen mit Perl (Xpert.press) (German Edition) </a> </label> <div class="note-meta"> <div class="note-desc">Joachim Ziegler Programmieren lernen mit Perl Ein systematischer Grundkurs V 0.99.42 6. Februar 2002 A LGORILLA Das ...</div> </div> </div> <div class="clearfix"></div> <hr class="mt-15 mb-15" /> </div> </div> </div> </div> </div> </div> <div class="modal fade" id="report" tabindex="-1" role="dialog" aria-hidden="true"> <div class="modal-dialog"> <div class="modal-content"> <form role="form" method="post" action="https://epdf.tips/report/programmieren-lernen-in-php-5" style="border: none;"> <div class="modal-header"> <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button> <h4 class="modal-title">Report "Programmieren lernen in PHP 5"</h4> </div> <div class="modal-body"> <div class="form-group"> <label>Your name</label> <input type="text" name="name" required="required" class="form-control" /> </div> <div class="form-group"> <label>Email</label> <input type="email" name="email" required="required" class="form-control" /> </div> <div class="form-group"> <label>Reason</label> <select name="reason" required="required" class="form-control"> <option value="">-Select Reason-</option> <option value="pornographic" selected="selected">Pornographic</option> <option value="defamatory">Defamatory</option> <option value="illegal">Illegal/Unlawful</option> <option value="spam">Spam</option> <option value="others">Other Terms Of Service Violation</option> <option value="copyright">File a copyright complaint</option> </select> </div> <div class="form-group"> <label>Description</label> <textarea name="description" required="required" rows="3" class="form-control" style="border: 1px solid #cccccc;"></textarea> </div> <div class="form-group"> <div style="display: inline-block;"> <div class="g-recaptcha" data-sitekey="6Lemmz0UAAAAAANSnNH_YtG0406jaTUcUP7mxrLr"></div> </div> </div> <script src='https://www.google.com/recaptcha/api.js'></script> </div> <div class="modal-footer"> <button type="button" class="btn btn-default" data-dismiss="modal">Close</button> <button type="submit" class="btn btn-success">Send</button> </div> </form> </div> </div> </div> <footer class="footer" style="margin-top: 60px;"> <div class="container-fluid"> Copyright © 2024 EPDF.TIPS. All rights reserved. <div class="pull-right"> <span><a href="https://epdf.tips/about">About Us</a></span> | <span><a href="https://epdf.tips/privacy">Privacy Policy</a></span> | <span><a href="https://epdf.tips/term">Terms of Service</a></span> | <span><a href="https://epdf.tips/copyright">Copyright</a></span> | <span><a href="https://epdf.tips/dmca">DMCA</a></span> | <span><a href="https://epdf.tips/contact">Contact Us</a></span> | <span><a href="https://epdf.tips/cookie_policy">Cookie Policy</a></span> </div> </div> </footer> <!-- Modal --> <div class="modal fade" id="login" tabindex="-1" role="dialog" aria-labelledby="myModalLabel"> <div class="modal-dialog" role="document"> <div class="modal-content"> <div class="modal-header"> <button type="button" class="close" data-dismiss="modal" aria-label="Close" on="tap:login.close"><span aria-hidden="true">×</span></button> <h4 class="modal-title" id="add-note-label">Sign In</h4> </div> <div class="modal-body"> <form action="https://epdf.tips/login" method="post"> <div class="form-group"> <label class="sr-only" for="email">Email</label> <input class="form-input form-control" type="text" name="email" id="email" value="" placeholder="Email" /> </div> <div class="form-group"> <label class="sr-only" for="password">Password</label> <input class="form-input form-control" type="password" name="password" id="password" value="" placeholder="Password" /> </div> <div class="form-group"> <div class="checkbox"> <label class="form-checkbox"> <input type="checkbox" name="remember" value="1" /> <i class="form-icon"></i> Remember me </label> <label class="pull-right"><a href="https://epdf.tips/forgot">Forgot password?</a></label> </div> </div> <button class="btn btn-primary btn-block" type="submit">Sign In</button> </form> <hr style="margin-top: 15px;" /> <a href="https://epdf.tips/login/facebook" class="btn btn-facebook btn-block"><i class="fa fa-facebook"></i> Login with Facebook</a> </div> </div> </div> </div> <!-- Global site tag (gtag.js) - Google Analytics --> <script async src="https://www.googletagmanager.com/gtag/js?id=UA-111550345-1"></script> <script> window.dataLayer = window.dataLayer || []; function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'UA-111550345-1'); </script> <script src="https://epdf.tips/assets/js/jquery-ui.min.js"></script> <link rel="stylesheet" href="https://epdf.tips/assets/css/jquery-ui.css"> <script> $(function () { $("#document_search").autocomplete({ source: function (request, response) { $.ajax({ url: "https://epdf.tips/suggest", dataType: "json", data: { term: request.term }, success: function (data) { response(data); } }); }, autoFill: true, select: function( event, ui ) { $(this).val(ui.item.value); $(this).parents("form").submit(); } }); }); </script> <!-- cookie policy --> <div id="EPDFTIPS_cookie_box" style="z-index:99999; border-top: 1px solid #fefefe; background: #97c479; width: 100%; position: fixed; padding: 5px 15px; text-align: center; left:0; bottom: 0;"> Our partners will collect data and use cookies for ad personalization and measurement. <a href="https://epdf.tips/cookie_policy" target="_blank">Learn how we and our ad partner Google, collect and use data</a>. <a href="#" class="btn btn-success" onclick="accept_EPDFTIPS_cookie_box();return false;">Agree & close</a> </div> <script> function accept_EPDFTIPS_cookie_box() { document.cookie = "EPDFTIPS_cookie_box_viewed=1;max-age=15768000;path=/"; hide_EPDFTIPS_cookie_box(); } function hide_EPDFTIPS_cookie_box() { var cb = document.getElementById('EPDFTIPS_cookie_box'); if (cb) { cb.parentElement.removeChild(cb); } } (function () { var EPDFTIPS_cookie_box_viewed = (function (name) { var matches = document.cookie.match(new RegExp("(?:^|; )" + name.replace(/([\.$?*|{}\(\)\[\]\\\/\+^])/g, '\\$1') + "=([^;]*)")); return matches ? decodeURIComponent(matches[1]) : undefined; })('EPDFTIPS_cookie_box_viewed'); if (EPDFTIPS_cookie_box_viewed) { hide_EPDFTIPS_cookie_box(); } })(); </script> <!-- end cookie policy --> </body> </html>