Transcript
Page 1: Internettechnologien, LE 3: PHP, SQL und HTMLhaegar.fh-swf.de/TBW/Internettechnologien/Internettechno...PHP-Modul muss also PHP-Code als HTML-Code ausgeben und durch denWebserverandenBrowsersenden

Inhaltsverzeichnis

Inhaltsverzeichnis

Vorbemerkungen zu dieser Lerneinheit ..... . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2

1 Datenbankzugriffe übers Web: HTML & PHP & SQL ...... .. 3

1.1 Zugriff von PHP auf MySQL ..... .. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4

1.2 Anzeigen von Daten im Browser...... . . . . . . . . . . . . . . . . . . . . . . . . . 10

1.3 Informationen über gerade abgesetzte SQL-Befehle...... . 13

1.4 SQL Injection entschärfen mit escape_string . . . . . . . . . . . . . . . 13

1.5 Zusammenfassung ..... .. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14

2 Datenbankinteraktionen mit dem Browser ....... . . . . . . . . . . . 15

2.1 Eintragen-Skript mit unformatierten Ausgaben ..... ... . . . . . 16

2.2 Eintragen-Skript mit Funktionen und Formatierungen..... 19

2.3 Zusammenfassung ...... . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23

3 Übungsaufgaben ...... .. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24

4 Lösungen der Aufgaben ...... .. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27

Abbildungsverzeichnis..... .. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41

1

Page 2: Internettechnologien, LE 3: PHP, SQL und HTMLhaegar.fh-swf.de/TBW/Internettechnologien/Internettechno...PHP-Modul muss also PHP-Code als HTML-Code ausgeben und durch denWebserverandenBrowsersenden

Inhaltsverzeichnis

Vorbemerkungen zu dieser Lerneinheit

Die vorliegende Lerneinheit ist die vom Seitenumfang her kleinste desLehrbriefs zu Internettechnologien, vom Zeitaufwand der Programmie-rung ihrer Aufgabenlösungen aber die größte. Sie ist in gewisser Weisedas Herzstück des gesamten Lehrbriefs. Hier werden die in den vorher-gehenden Lerneinheiten dargestellten Webtechniken HTML und PHPmit einer Datenbank kombiniert, so dass interaktive Datenbankzugriffeüber den Browser ermöglicht werden. Es ist genau diese Kombinationbekannter Konzepte, die knappe und gebrauchstaugliche Handlungs-anleitungen gegenüber einer breiten theoretischen Diskussion odergrundlegenden Erläuterungen in den Vordergrund treten lassen.Damit setzt allerdings das Verständnis dieser Lerneinheit auch Kennt-nisse und Programmiererfahrungen in HTML, PHP und SQL voraus. Dasgrößte Problem für den Einsteiger in die Webprogrammierung ist er-fahrungsgemäß, Struktur in diesen kleinen Zoo von Programmierkon-zepten und Techniken zu erlangen und deren einzelne Stärken undGrenzen zu erkennen und einzusetzen. Das erfordert aber hauptsäch-lich Praxis, weniger Theorie.Zur Lösung und Programmierung der Aufgaben ist zudem ein Server-system mit einem Webserver und einem Datenbankserver notwendig.Für eine einfache Installation sei dazu das frei verfügbare Paket XAMPPempfohlen, das aktuell mit dem Apache HTTP-Server und der quelloffe-nen Datenbank MariaDB ausgeliefert wird. Grundsätzlich können aberauch andere, PHP integrierende Serverdistributionen verwendet wer-den, so dass die Inhalte dieser Lerneinheit weitgehend unverändert an-wendbar bleiben.

Hagen,im Dezember 2016 Andreas de Vries

2

Page 3: Internettechnologien, LE 3: PHP, SQL und HTMLhaegar.fh-swf.de/TBW/Internettechnologien/Internettechno...PHP-Modul muss also PHP-Code als HTML-Code ausgeben und durch denWebserverandenBrowsersenden

1 Datenbankzugriffe übers Web: HTML & PHP & SQL

In diesem Kapitel werden wir die verschiedenen Fäden, die wir in denvergangenen Kapiteln gesponnen haben, zu einer Gesamtheit zusam-men knüpfen. Wir haben PHP als eine Programmiersprache kennen ge-lernt, die auf einem Webserver läuft und dessen Ressourcen nutzenkann. Als Modul des Webservers kann PHP insbesondere die Schnitt-stellen zu einem Client des Webservers nutzen, d.h. einem Browser. Das

Abb. 1.1: Die drei Schichten einer datenbankbasierten Webanwendung

PHP-Modul muss also PHP-Code als HTML-Code ausgeben und durchden Webserver an den Browser senden.

Nun wollen wir unser HTML-PHP-System erweitern und eine relatio-nale Datenbank anbinden. Die Programmiersprache für Zugriffe auf ei-ne solche Datenbank ist SQL. Jetzt kehren sich die Rollen in unseremSystem gewissermaßen um, PHP ist nunmehr der Client für den Daten-bankserver, der auf SQL-Befehle reagiert und mit Daten antwortet.

Abb. 1.2: PHP als Schnittstelle, die über reinen Text kommuniziert

Somit stellt PHP eine Schnittstelle zwischen Browser (WebClient) undeiner MySQL Datenbank (DB-Server) dar. In einem PHP-Skript kann na-türlich weder HTML- noch SQL-Code verarbeitet werden. Beides kannnur dynamisch als String erzeugt werden und entweder per echo an denBrowser oder, nach geeigneteter Vorbereitung, per $mysqli->query() andie Datenbank geschickt werden.

3

Page 4: Internettechnologien, LE 3: PHP, SQL und HTMLhaegar.fh-swf.de/TBW/Internettechnologien/Internettechno...PHP-Modul muss also PHP-Code als HTML-Code ausgeben und durch denWebserverandenBrowsersenden

1 Datenbankzugriffe übers Web: HTML & PHP & SQL

1.1 Zugriff von PHP auf MySQL

Um auf Daten einer allgemeinen Datenbank zuzugreifen, also nicht nurauf eine lokale Datenbank wie Access, sondern auch einen Datenbank-server wie MariaDB, MySQL, Oracle oder MSSQL, benötigt man im We-sentlichen die folgenden Schritte.

1. Verbindung zur Datenbank eines Datenbankservers erstellen;

2. Abfrage (query) zur Datenbank per SQL absetzen;

3. Datensätze von Auswahlabfragen (result) aus der Datenbank ineine geeignete Datenstruktur von PHP umformen.

Für eine Webanwendung in PHP, die Zugriffe auf eine MySQL-Datenbank aus dem Web ermöglichen soll, müssen wir diese Schrit-te programmieren können. Dazu stehen in PHP Funktionen zur Verfü-gung, die wir im folgenden kennen lernen werden. Listen wir hier ein-mal die Schritte für einen Datenzugriff auf und erwähnen die dazu ver-wendeten PHP-Funktionen; in den nächsten Abschnitten werden wirsie näher betrachten.

Aktionsschritt PHP-Anweisung1. Verbindung zur Datenbank er-

stellen$mysqli = new mysqli(...)

2. SQL-Abfrage zur Datenbank sen-den

$result = $mysqli->query(...)

3a. Abfrageergebnis als Objekt inPHP einlesen

$result->fetch_object()

3b. Abfrageergebnis als assoziativesArray in PHP einlesen

$result->fetch_assoc()

3c. Abfrageergebnis als numerischesArray in PHP einlesen

$result->fetch_row()

Die Schritte 3a, 3b und 3c der Ergebniseinlesung nach PHP sind hier-bei als Alternativen anzusehen, sie unterscheiden sich lediglich in derDatenstruktur, in der die Datensätze der Ergebnismenge der Datenban-kabfrage in PHP gespeichert werden.Hat man die Verbindung zu einer Datenbank eingerichtet, so hat manu.a. die folgenden Abfragefunktionen über SQL zur Verfügung:

1. Eintragen von Daten mit INSERT. Die Syntax dazu lautet:

INSERT INTO tabelle (spalte1, spalte2, ...)

VALUES (’wert1’, ’wert2’, ...)

oder

4

Page 5: Internettechnologien, LE 3: PHP, SQL und HTMLhaegar.fh-swf.de/TBW/Internettechnologien/Internettechno...PHP-Modul muss also PHP-Code als HTML-Code ausgeben und durch denWebserverandenBrowsersenden

1.1 Zugriff von PHP auf MySQL

INSERT INTO tabelle SET

spalte1 = ’wert1’,

spalte2 = ’wert2’,

...

2. Ansehen gespeicherter Daten mit SELECT:

SELECT spalte_x, spalte_y FROM tabelle # WHERE bedingung

...

Will man alle Daten einer Tabelle erhalten, so kann man statt dereinzelnen Spaltennamen auch einfach die Wildcard * angeben.

3. Ändern von gespeicherten Daten mit UPDATE:

UPDATE tabelle SET

spalte1 = ’neuerWert1’,

spalte2 = ’neuerWert2’,

...

WHERE Primärschlüssel = ’x’

4. Löschen gespeicherter Daten mit DELETE:

DELETE FROM tabelle WHERE bedingungen

(Achten Sie auf die WHERE-Klausel, sonst ist alles gelöscht . . . )

1.1.1 Verbindung zum Datenbanksystem: new mysqli(...)

Der Verbindungsaufbau zu einer einer Datenbank geschieht durchdie Erzeugung eines mysqli-Objekts, $mysqli = new mysqli(...), einesStandardobjekts in PHP:

$mysqli = new mysqli("localhost", "user", "passwort", "db");

Der Konstruktor des PHP-Objekts mysqli erwartet vier Eingabeparame-ter:

1. Den Namen des Datenbankservers: Dies ist hier "localhost".Hiermit wird der Rechner, auf dem das PHP-Programm selberläuft, angesprochen. Alternativ kann hier die IP-Adresse eines an-deren Rechners stehen; allerdings muss das Serversystem dazuentsprechend konfiguriert sein.

2. Den Namen des Benutzers, hier "user". Hier kann der Name einesjeden beim Datenbankserver registrierten Nutzers stehen.

3. Das Passwort des Benutzers, hier: "passwort".

4. Den Namen der Datenbank, hier "db".

5

Page 6: Internettechnologien, LE 3: PHP, SQL und HTMLhaegar.fh-swf.de/TBW/Internettechnologien/Internettechno...PHP-Modul muss also PHP-Code als HTML-Code ausgeben und durch denWebserverandenBrowsersenden

1 Datenbankzugriffe übers Web: HTML & PHP & SQL

Optional kann als fünfter Parameter der Port des Datenbankservers an-gegeben werden, sein Standardwert ist 3306 und funktioniert dement-sprechend bei den üblichen Datenbankinstallationen.Es ist zu empfehlen, zur besseren Übersicht und zur vereinfachten Ein-stellung bei etwaig geänderten Datenbankzugriffen die Aufrufparame-ter in Variablen zu speichern:

$server = "localhost";

$user = "user";

$password = "passwort";

$database = "datenbank";

$mysqli = new mysqli($server, $user, $password, $database);

$mysqli->set_charset("utf8");

Die letzte Anweisung ist sehr ratsam und lässt die Datenbank Text inder UTF8-Kodierung zu speichern. Natürlich muss dazu Text aus einemHTML-Formular, der über PHP in der Datenbank gespeichert werdensoll, dieselbe Kodierung haben, d.h. die Webseiten zur Eingabe solltenentsprechend das <meta>-Element

<meta charset="utf-8"/>;

enthalten.Um Fehler beim Zugriff ausgeben zu lassen, was gerade bei der Pro-grammierung eines Datenbankzugriffs sehr hilfreich sein kann, sollteman nach Erzeugung des mysqli-Objekts und vor Einstellung der Ko-dierung das Attribut $mysqli->connect_errno verwenden:

$server = "localhost";

$user = "user";

$password = "passwort";

$database = "datenbank";

$mysqli = new mysqli($server, $user, $password, $database);

if ($mysqli->connect_errno) {

echo "Fehler beim Zugriff auf MySQL: (" .

$mysqli->connect_errno . ") " . $mysqli->connect_error;

}

$mysqli->set_charset("utf8");

Das öffentliche Attribut $mysqli->connect_errno gibt die Fehlernummerder aktuellen Datenbankverbindung an und ist null, wenn der Zugrifferfolgreich war; in der if-Anweisung wird dies von PHP als false be-trachtet und die echo-Anweisung daher nicht ausgeführt. Ist jedoch einFehler aufgetreten, so ergibt in PHP die if-Anweisung true und das At-tribut $mysqli->connect_error enthält eine Beschreibung des eingetre-tenen Fehlers. (Eine solche Fehlerausgabe sollte man bei produktiv ein-gesetzten und veröffentlichten Systemen selbstverständlich deaktivie-ren, denn ein gutwilliger Anwender kann damit nichts anfangen, und

6

Page 7: Internettechnologien, LE 3: PHP, SQL und HTMLhaegar.fh-swf.de/TBW/Internettechnologien/Internettechno...PHP-Modul muss also PHP-Code als HTML-Code ausgeben und durch denWebserverandenBrowsersenden

1.1 Zugriff von PHP auf MySQL

ein böswilliger Hacker kann wertvolle Informationen erlangen.) Weite-re Hinweise und Informationen finden Sie auf php.net unter dem Stich-wort mysqli.1

Eine weitere Empfehlung ist, die Konfigurationsdaten des Zugriffsauf den Datenbankserver in eine eigene Datei auszulagern, z.B.db_login.inc.php, und zu Beginn eines PHP-Skripts per require_once

einzulesen. So können mehrere PHP-Skripte die Einstellungen zentraleinlesen und bei etwaigen Änderungen der Zugriffsparameter die ak-tuellen Werte erhalten, ohne dass sie selbst geändert werden müssen.Da meist verschiedene PHP-Skripte eines Webauftritts zwar auf den-selben Datenbankserver zugreifen sollen, aber auf verschiedene Daten-banken, sollte in der Zugriffsdatei zentral eine Funktion definiert wer-den, die den Namen der Datenbank als Parameter erfordert und dasmysqli-Objekt der Datenbankverbindung zurück gibt:

1 <!-- Dateiname: db_login.inc.php -->

2 <?php

3 /** Erstellt eine Datenbankverbindung mit zentralen

4 * Konfigurationsdaten des DB-Servers.

5 * @param $database die Datenbank

6 * @return mysqli-Objekt der Datenbankverbindung

7 */

8 function login($database) {

9 $server = "localhost";

10 $user = "user";

11 $password = "passwort";

12

13 $mysqli = new mysqli($server,$user,$password,$database);

14 if ($mysqli->connect_errno) {

15 echo "Keine DB-Verbindung: ({$mysqli->connect_errno}) "

16 . $mysqli->connect_error;

17 exit(); // beendet das Programm

18 }

19

20 $mysqli->set_charset("utf8");

21 return $mysqli;

22 }

23 ?>

Diese Funktion kann dann von einem beliebigen PHP-Skript importiertwerden, um eine Datenbankverbindung zu erstellen:

require_once("db_login.inc.php");

$mysqli = login("AdressDB");

Danach ist bei erfolgreichem Zugriff auf den Datenbankserver und dieDatenbank ein mysqli-Objekt über die Variable $mysqli verfügbar. Bei

1 http://php.net/manual/de/mysqli.quickstart.connections.php [2016-11-11]

7

Page 8: Internettechnologien, LE 3: PHP, SQL und HTMLhaegar.fh-swf.de/TBW/Internettechnologien/Internettechno...PHP-Modul muss also PHP-Code als HTML-Code ausgeben und durch denWebserverandenBrowsersenden

1 Datenbankzugriffe übers Web: HTML & PHP & SQL

einem Verbindungsfehler allerdings wird hier wegen der Funktion exit

das Skript sofort abgebrochen.

1.1.2 Abfragen mit $mysqli->query

Mit der Objektmethode $mysqli->query wird ein SQL-Kommando an dieDatenbank geschickt und dort ausgeführt. Die Methode erwartet alsEingabeparameter das SQL-Kommando, das vom Datenbank-Systemausgeführt werden soll, in Form eines Strings. Ein Beispiel für das Ab-schicken einer SELECT-Anweisung:

$result = $mysqli->query("SELECT * FROM adressen");

Der SQL-Befehl selektiert alle Datensätze der Tabelle adressen. Natür-lich ist der SQL-Befehl für PHP lediglich ein String, also ohne weitereBedeutung. Ähnlich wie PHP ein HTML-Dokument auch nur als einenString aufbaut und per echo an den Browser schickt, muss ein SQL-Befehl als String an die Datenbank geschickt werden. Genau das macht$mysql->query: es schickt die Abfrage an die Datenbank, die sie dort alsSQL interpretiert und ausführt. Die Ergebnismenge (result set) wird üb-licherweise in einer Variablen $result gespeichert.Eine weitere Variante, die oft in der Literatur oder in Programmbei-spielen zu sehen ist, ist die Methode mysqli_query() nach dem „pro-zeduralen Stil“. Sie hat als obligatorischen Paraeter eine gültige Da-tenbankverbindung und erlaubt damit den Zugriff auf mehrere Da-tenbanken innerhalb eines PHP-Skripts, ohne sie immer wieder neuaufbauen zu müssen. Weitere Informationen dazu siehe unter http:

//php.net/manual/en/mysqli.query.php.

1.1.3 Übernahme der Daten nach PHP

Es gibt mehrere Objektmethoden der Ergebnismenge $result einer er-folgreichen Auswahlabfrage einer Datenbank, um auf deren Datensätzezuzugreifen. Die wichtigsten sind:

$result->fetch_object()

und

$result->fetch_assoc()

Die erste Methode liefert die Ergebnismenge der Datenbankabfrage alsObjekt zurück, die zweite als assoziatives Array. Hierbei wird der je-weils nächste Datensatz der Ergebnismenge $result gelesen und in ei-nem Objekt mit den Spalten als Attributnamen bzw. einem assoziativenArray mit den Bezeichnungen der Tabellenspalten als Schlüssel gespei-chert.Die beiden Methoden sind hierbei als Alternativen anzusehen. Ihre Wir-kung ist fast gleich und am besten anhand eines einfachen Beispiels zu

8

Page 9: Internettechnologien, LE 3: PHP, SQL und HTMLhaegar.fh-swf.de/TBW/Internettechnologien/Internettechno...PHP-Modul muss also PHP-Code als HTML-Code ausgeben und durch denWebserverandenBrowsersenden

1.1 Zugriff von PHP auf MySQL

erklären: Hat man nach einer Datenbankabfrage eine Ergebnismenge$result mit der Spalte spalte und dem Eintrag $eintrag, so erzeugt dieAnweisung $result->fetch_object() je Datensatz ein Objekt

$wert = $a->spalte

Entsprechend erzeugt die Anweisung $result->fetch_assoc() je Daten-satz ein assoziatives Array

$wert = $a["spalte"]

Wir werden im Folgenden oft die früher weit verbreitete Variante mitassoziativen Arrays verwenden, auch wenn die objektorientierte Vari-ante eleganter und beim Programmieren leichter hinzuschreiben ist.

Eine weitere Möglichkeit der Konvertierung der Ergebnismen-ge einer Auswahlabfrage der Datenbank ist mit der Anweisung$result->fetch_row()

$result->fetch_row()

gegeben, die ein numerisches Array liefert, in dem jedoch die Spalten-namen der Datenbanktabelle nicht mehr verfügbar sind. Der Zugriff aufdie Datenbankinhalte geschieht hier über Indizes 0, 1, . . . . Die assozia-tive Variante bzw. die fetch_object-Methode sind flexibler, da sie auchnach späteren eventuellem Einfügen neuer Felder in die Datenbankta-belle korrekte Resultate liefern.

Um nach einem SELECT-Befehl die Ergebnismenge zu durchlaufen, kannman eine der folgenden Schleifenkonstrukte verwenden:

while ($datensatz = $result->fetch_object()) {

$datensatz->spalte ... // $datensatz ist ein Objekt

}

oder

while ($datensatz = $result->fetch_assoc()) {

$datensatz["spalte"] ... // $datensatz ist ein assoz. Array

}

oder

while ($datensatz = $result->fetch_row()) {

$datensatz[0] ... // $datensatz ist ein numerisches Array

}

Bei allen Varianten wird jeweils der nächste Datensatz in der Ergebnis-menge $result als Objekt bzw. Array eingelesen, solange es einen sol-chen gibt. Nach dem letzten Datensatz liefert die Zuweisung ein leeresErgebnis, d.h. sie ist false, und die Schleife wird beendet. Ist die Ergeb-nismenge leer oder enthält sie eine Fehlermeldung, so wird die Schleifegar nicht erst begonnen.

9

Page 10: Internettechnologien, LE 3: PHP, SQL und HTMLhaegar.fh-swf.de/TBW/Internettechnologien/Internettechno...PHP-Modul muss also PHP-Code als HTML-Code ausgeben und durch denWebserverandenBrowsersenden

1 Datenbankzugriffe übers Web: HTML & PHP & SQL

1.2 Anzeigen von Daten im Browser

Das folgende Programmbeispiel erweitert das obige Adressbeispiel, in-dem es die verfügbaren Adressen aus einer Datenbank liest und an-zeigt. Voraussetzung ist, dass bereits eine Datenbank mit einigen Ein-trägen existiert, siehe Abb. 1.3. Um den Inhalt der Datenbank als Tabelle

Abb. 1.3: Die Struktur der Adressdatenbank (links) und einige Einträge (rechts), mitphpMyAdmin betrachtet.

im Browser darzustellen, muss also mit einem SELECT-Befehl als SQL-Statement auf die Datenbank zugegriffen werden, die Ergebnismengemit $mysqli->fetch_assoc als Array in PHP transformiert und in HTMLals Tabelle erzeugt werden.

Wir werden zwei Versionen eines PHP-Skripts betrachten. Die erstezeigt den Datenbankinhalt einfach zeilenweise im Browser an und er-läutert konkret die notwendigen Programmzeilen eines allgemeinenPHP-Skripts zur Datenanzeige. Das zweite wird dann eine formatierteAnzeige in einer Tabelle vornehmen und die Feldnamen als Spaltenbe-zeichnung verwenden. Ferner wird die foreach-Schleife eingesetzt, umdie Datensatzfelder automatisch zu durchlaufen.

Listing 1: Einträge einer Datenbank anzeigen

1 <!-- Adressen aus DB. Dateiname: adresseDB.php -->

2 <?php

3 $mysqli = new mysqli("localhost", "user", "c5dDC8VJemscKPQS",

"AdressDB");

4 if ($mysqli->connect_errno) {

5 echo "Failed to connect to MySQL: ({$mysqli->connect_errno

}) $mysqli->connect_error";

6 }

7 $result = $mysqli->query("SELECT * FROM adressen");

8 while ($adresse = $result->fetch_assoc()) {

9 echo "$adresse[name], $adresse[vorname], $adresse[email]<

br/>";

10 }

11 ?>

10

Page 11: Internettechnologien, LE 3: PHP, SQL und HTMLhaegar.fh-swf.de/TBW/Internettechnologien/Internettechno...PHP-Modul muss also PHP-Code als HTML-Code ausgeben und durch denWebserverandenBrowsersenden

1.2 Anzeigen von Daten im Browser

1.2.1 Die wesentlichen Schritte des PHP-Skripts

Schauen wir uns die wesentlichen Programmschritte an, um den aktu-ellen Inhalt einer Datenbank im Browser darzustellen. Zunächst wirddie Verbindung zur Datenbank AdressDB auf dem Datenbankserverlocalhost erstellt. Die if-Abfrage bewirkt hier, dass im Falle eines Feh-lers bei der Verbindungserstellung eine Fehlermeldung erscheint. Alsnächstes wird eine SQL-Anweisung, hier ein SELECT, an den Datenbank-server geschickt und das das Ergebnis in der Variable $result gespei-chert. Somit enthält $result die vollständige Ergebnismenge der SQL-Anweisung. Die Ergebnismenge kann je nach Abfrage und Datenbanktausende von Einträgen enthalten, oder vielleicht leer sein, oder abereinen Fehlercode liefern. Die für die Anzeige der Datensätze aus derDatenbank nächste wesentliche Anweisung ist die folgende Schleife:

while ( $adresse = mysql_fetch_assoc($result) ) {

echo "$adresse[Name] ... <br/>";

}

Die while-Schleife wiederholt sich hier, solange noch ein nächster Da-tensatz in der Ergebnismenge $result existiert. Falls nicht, so gibt dieAnweisung in der while-Klammer nämlich false zurück, und der Schlei-fenrumpf wird nicht weiter ausgeführt.Während eines Schleifendurchlaufs steht also in der Variablen $adresse

ein bestimmter Datensatz aus der Datenbank als assoziatives Array, mitden Feldnamen der Datenbanktabelle als Schlüssel und den Datenbank-einträgen des Datensatzes als Inhalte.

1.2.2 Formatierte Ausgabe

Zum Anzeigen der Daten reichen die obigen Anweisungen völlig aus.

Beispiel 1.1 Formatierte Ausgabe von Adressen aus Datenbank ♦

1 <!-- Adressen aus DB. Dateiname: adresseDB1.php -->

2 <?php

3 $mysqli = new mysqli("localhost", "user", "c5dDC8VJemscKPQS",

"AdressDB");

4 if ($mysqli->connect_errno) {

5 echo "Failed to connect to MySQL: ({$mysqli->connect_errno

}) $mysqli->connect_error";

6 }

7 ?>

8

9 <h2>Adressen als 2-dimensionales Array</h2>

10 <table border="1">

11 <?php

12 $result = $mysqli->query("SELECT * FROM adressen");

11

Page 12: Internettechnologien, LE 3: PHP, SQL und HTMLhaegar.fh-swf.de/TBW/Internettechnologien/Internettechno...PHP-Modul muss also PHP-Code als HTML-Code ausgeben und durch denWebserverandenBrowsersenden

1 Datenbankzugriffe übers Web: HTML & PHP & SQL

13

14 // Tabellenkopf mit den Feldnamen als Spaltenbezeichnungen:

15 echo " <tr>\n";

16 while ( $field = $result->fetch_field() ) {

17 echo " <th>$field->name</th>\n";

18 }

19 echo " </tr>\n";

20

21 // Tabelleneinträge aus der Datenbank, spezielle Ausgabe für

email und web:

22 while ( $adresse = $result->fetch_object() ) {

23 echo " <tr>\n";

24 foreach ( $adresse as $key => $value ) {

25 if ( $key === "email" ) {

26 echo " <td><a href=\"mailto:$value\">$value</a></

td>\n";

27 } else if ( $key === "web" ) {

28 echo " <td><a href=\"http://$value\">$value</a></

td>\n";

29 } else {

30 echo " <td>$value</td> \n";

31 }

32 }

33 echo " </tr>\n";

34 }

35 ?>

36 </table>

Im Unterschied zum vorigen Beispiel werden hier die Datensätze in ei-ner Tabelle ausgegeben. Die foreach-Schleife läuft das Array sukzessi-ve durch und ermöglicht den Zugriff auf die Inhalte über die Variable$value. In dem Beispiel wird der Wert von $value in ein <td>-Tag vonHTML gepackt, so dass jeder Datensatz in <tr>-Elementen steht und soals eine Tabellenzeile im Browser angezeigt wird.

Ermittlung der Feldnamen aus der Datenbank

Möchte man zusätzlich, so wie in diesem Beispiel, die Feldnamen derDatenbank als Spaltenbezeichner anzeigen, so muss man irgendwie andie Bezeichnungen der Felder aus der Datenbank gelangen. Die Infor-mation ist aber bereits in der Ergebnismenge einer erfolgreich abge-schlossenen SELECT-Anweisung enthalten, in unserem Falle also in derVariablen $result. Der eleganteste Weg, an diese Information zu kom-men, ist mit Hilfe der Funktion $result->fetch_field(). Sie liefert einObjekt zurück, dessen Attribute die Metadaten des jeweils nächstenFeldes der Datenbanktabelle(n) ist, wie z.B. Feldname oder Feldtyp. So

12

Page 13: Internettechnologien, LE 3: PHP, SQL und HTMLhaegar.fh-swf.de/TBW/Internettechnologien/Internettechno...PHP-Modul muss also PHP-Code als HTML-Code ausgeben und durch denWebserverandenBrowsersenden

1.3 Informationen über gerade abgesetzte SQL-Befehle

kann man sich also mit der Anweisung

while ($spaltenname = $result->fetch_field()->name) {

echo "$spaltenname<br/>";

}

die Feldnamen anzeigen lassen.

1.3 Informationen über gerade abgesetzte SQL-Befehle

In diesem Abschnitt werden zwei sehr nützliche öffentliche Attributedes mysqli-Objekts bzw. der Ergebnismenge vorgestellt, die Informa-tionen über den jeweils letzten abgesetzte SQL-Befehl speichern.

• $mysqli->affected_rows speichert die Anzahl der durch die je-weils letzte SQL-Anfrage an den Server betroffenen Datensätze.Beispielsweise findet man wie folgt die Anzahl gelöschter Daten-sätze heraus:

$mysqli->query("DELETE FROM mytable WHERE id < 10");

$anzahl = $mysqli->affected_rows;

echo "$anzahl Datensätze gelöscht";

Die prozedurale Variante davon, mysqli_affected_rows($link),ist eine Funktion und benötigt als Parameter die Ver-bindungskennung $link; Näheres dazu siehe unterhttp://php.net/manual/de/mysqli.affected-rows.php.

• $result->num_rows speichert die Anzahl der Datensätze einer Er-gebnismenge $result. Dieses Attribut ist nur gültig nach einemSELECT-Befehl.

$result = $mysqli->query("SELECT * FROM table1");

$num_rows = $result->num_rows;

echo "$num_rows Zeilen\n";

Direkt nach einer SELECT-Anfrage mit $mysqli->query() ergibt$result->num_rows dasselbe wie $mysqli->affected_rows.

1.4 SQL Injection entschärfen mit escape_string

Ein Sicherheitsrisiko jeder Webdatenbank ist die „SQL-Injektion“, al-so der Versuch eines Angreifers, über eine Formulareingabe die Da-tenbank abzufragen oder gar zu manipulieren. Ein Schutz vor sol-chen Angriffen ist nicht trivial, allerdings bietet PHP mit der Funkti-on escape_string einen einfachen Abwehrmechanismus an, siehe http:

//php.net/manual/en/mysqli.real-escape-string.php; die Funktion istein Alias der Funktion real_escape_string. Sie durchläuft den überge-benen String und ersetzt sicherheitskritische Zeichen, die zu einer SQL-Injektion führen könnten. Man sollte generell alle Eingaben analog fol-gendem Mechanismus entschärfen:

13

Page 14: Internettechnologien, LE 3: PHP, SQL und HTMLhaegar.fh-swf.de/TBW/Internettechnologien/Internettechno...PHP-Modul muss also PHP-Code als HTML-Code ausgeben und durch denWebserverandenBrowsersenden

1 Datenbankzugriffe übers Web: HTML & PHP & SQL

$eingabe = $mysqli->escape_string($_POST["eingabe"]);

// irgendeine SQL-Anweisung:

$sql = "SELECT * FROM tabelle WHERE spalte=’$eingabe’";

$result = $mysqli->query($sql); // zur Datenbank senden

1.5 Zusammenfassung

• Ein netzwerkbasiertes System, das Datenbankzugriffe über dasInternet ermöglicht, kann mit HTML, PHP und SQL programmiertwerden.

• Insgesamt stellt PHP eine Schnittstelle zwischen Browser (Web-Client) und einer MySQL Datenbank (DB-Server) dar.

• Merke: In einem PHP-Skript kann weder HTML- noch SQL-Codeverarbeitet werden. Beides muss als String erzeugt werden undentweder per echo an den Browser oder per $mysqli->query an dieDatenbank geschickt werden.

• Die Funktionen zur Durchführung der drei wesentlichen Schrittezum Datenzugriff auf eine Datenbank via PHP sind:

1. $mysqli = new mysqli(...) — erstellt die Verbindung zurDatenbank auf einem Datenbankserver

2. $mysqli->query(...) — sendet SQL-Befehle zur Datenbank(SELECT, INSERT, UPDATE, DELETE)

3. $result->fetch_object(), $result->fetch_assoc(), $result->fetch_row() — liest die Ergebnismenge einer SQL-Abfrageals Objekt bzw. als assoziatives oder numerisches Array inPHP ein

• Der Zugriff auf eine Datenbank sollte der Übersichtlichkeit undWartbarkeit halber mit Variablen parametrisiert werden:

$server = "localhost";

$user = "user";

$password = "passwort";

$database = "datenbank";

$mysqli = new mysqli($server, $user, $password,

$database);

$mysqli->set_charset(’utf8’);

14

Page 15: Internettechnologien, LE 3: PHP, SQL und HTMLhaegar.fh-swf.de/TBW/Internettechnologien/Internettechno...PHP-Modul muss also PHP-Code als HTML-Code ausgeben und durch denWebserverandenBrowsersenden

Zudem sollten diese Anweisungen in eine eigene Datei ausgela-gert werden, so dass mehrere PHP-Skripte die Einstellungen ein-lesen können.

• Zum Anzeigen von Informationen aus einer Datenbanktabelle be-nötigt man mindestens die zwei Schritte

$result = $mysqli->query("SELECT * FROM Tabelle");

zur Selektion der Daten und die Schleife

1 while ( $eintrag = $result->fetch_assoc() ) {

2 foreach ($eintrag as $value) {

3 echo "$value<br/>";

4 }

5 }

2 Datenbankinteraktionen mit dem Browser

Üblicherweise besteht eine Webanwendung aus einer Interaktion miteiner Datenbank, also aus enem komplexen Ablauf von Aus- und Ein-gabeaktionen, die jeweils von den vorherigen Aktionen abhängen. Ab-lauf und Logik aus Sicht des Anwenders müssen aufgrund der star-ren Request-Response-Architektur des Webs in dem PHP-Skript umge-schrieben werden. Die Schwierigkeit von PHP liegt abstrakt gesprochendarin, dass PHP nur auf einen einkommenden Request reagieren kann,aber keinen permanenten Prozess darstellt, der den Ablauf begleitet.Ein PHP-Skript muss also den aktuellen Zustand des Ablaufs jedesmalvon Neuem feststellen. Oft ist dazu die Information notwendig, welchenButton der Anwender eigentlich gedrückt hat. Mit dieser Problematikbeschäftigen wir uns in diesem Kapitel.Wir möchten dazu im Folgenden ein Skript schreiben, das nicht nur dasAnsehen der Daten in der Adressdatenbank ermöglicht, sondern auchdas Eintragen neuer Daten über den Browser. Grob soll dabei folgenderAblauf stattfinden:

1. Beim ersten Aufruf soll der aktuelle Inhalt der Datenbank gezeigtwerden. Allerdings soll es nun einen Submit-Button geben, sieheAbb. 2.4 (links).

2. Anklicken dieses Buttons ruft dasselbe Skript auf, das nun aberein Eingabeformular zeigt, in das die neuen Daten eingetragenwerden können, siehe Abb. 2.4 (rechts).

3. Das Anklicken des Submit-Buttons soll erneut das Skript aufru-fen, um nun die Formulardaten in die Datenbank zu speichern.

15

Page 16: Internettechnologien, LE 3: PHP, SQL und HTMLhaegar.fh-swf.de/TBW/Internettechnologien/Internettechno...PHP-Modul muss also PHP-Code als HTML-Code ausgeben und durch denWebserverandenBrowsersenden

2 Datenbankinteraktionen mit dem Browser

Abb. 2.4: Die Seite beim Aufruf und beim Drücken des Eintragen-Buttons.

2.1 Eintragen-Skript mit unformatierten Ausgaben

Wir werden zunächst ein PHP-Skript betrachten, das zwar alle gefor-derten Funktionalitäten liefert, aber die Browserausgaben nicht forma-tiert.

Beispiel 2.1 Adressen aus Datenbank, mit Einfügemöglichkeit ♦

1 <!-- Adressen in DB eintragen. Dateiname: adresseDB2.php -->

2 <form action="<?php echo $_SERVER[’PHP_SELF’]?>" method="POST">

3 <?php

4 $mysqli = new mysqli("localhost", "user", "c5dDC8VJemscKPQS",

"AdressDB");

5 if ($mysqli->connect_errno) {

6 echo "Failed to connect to MySQL: ({$mysqli->connect_errno

}) $mysqli->connect_error";

7 }

8 $mysqli->set_charset("utf8");

9

10 if (isset($_POST[’eintragen’])) { // -- Eingabeform und

Speichern-Button erstellen -

11 ?>

12 Vorname: <input type="text" name="vorname"/><br/>

13 Name: <input type="text" name="name"/><br/>

14 PLZ: <input type="text" name="plz" size="7"/>

15 Ort: <input type="text" name="ort"/> <br/>

16 Strasse: <input type="text" name="strasse"/><br/>

17 Web: <input type="text" name="web"/><br/>

18 e-mail: <input type="text" name="email"/><br/>

19 <input type="submit" name="speichern" value="Speichern"/>

16

Page 17: Internettechnologien, LE 3: PHP, SQL und HTMLhaegar.fh-swf.de/TBW/Internettechnologien/Internettechno...PHP-Modul muss also PHP-Code als HTML-Code ausgeben und durch denWebserverandenBrowsersenden

2.1 Eintragen-Skript mit unformatierten Ausgaben

20 <?php

21 } else {

22 if (isset($_POST[’speichern’])) { // -- Formulardaten

speichern --

23 $name = $mysqli->escape_string($_POST["name"]);

24 $vorname = $mysqli->escape_string($_POST["vorname"]);

25 $plz = $mysqli->escape_string($_POST["plz"]);

26 $ort = $mysqli->escape_string($_POST["ort"]);

27 $strasse = $mysqli->escape_string($_POST["strasse"]);

28 $web = $mysqli->escape_string($_POST["web"]);

29 $email = $mysqli->escape_string($_POST["email"]);

30

31 $sql = "INSERT INTO adressen ";

32 $sql .= "(name, vorname, plz, ort, strasse, web, email)

";

33 $sql .= " VALUES ";

34 $sql .= "(’$name’,’$vorname’,’$plz’,’$ort’,’$strasse’,’

$web’,’$email’)";

35 $mysqli->query($sql); // an Datenbank abschicken

36 } // -- Ende speichern ------------------------------

37

38 //auflisten + Eintragen-Button:

39 $sql = "SELECT * FROM adressen ORDER BY Name";

40 $result = $mysqli->query($sql);

41

42 while ($adresse = $result->fetch_assoc()) {

43 echo "$adresse[name], $adresse[vorname], $adresse[email

]<br/>";

44 }

45 ?>

46 <input type="submit" name="eintragen" value="Adresse

eintragen"/>

47 <?php

48 } //-- Ende else ------------------------------------

49 ?>

50 </form>

51 </body>

52 </html>

Zunächst fällt auf, dass das gesamte Skript durch ein Form-Tag um-schlossen wird, so dass es sich beim Submit selbst wieder aufruft.

2.1.1 Der Ablauf des Skripts

Der eigentliche Ablauf des Skripts aus Sicht des Benutzers wird durchdie if-Anweisungen gesteuert. Sie haben die folgende Struktur:

17

Page 18: Internettechnologien, LE 3: PHP, SQL und HTMLhaegar.fh-swf.de/TBW/Internettechnologien/Internettechno...PHP-Modul muss also PHP-Code als HTML-Code ausgeben und durch denWebserverandenBrowsersenden

2 Datenbankinteraktionen mit dem Browser

1 if (isset($_POST[’eintragen’])) {

2 ... Eingabeformular und Speichern-Button erstellen ...

3 } else {

4 if (isset($_POST[’speichern’])) {

5 ... Eingabedaten in DB speichern ...

6 }

7 ... DB-Inhalt auflisten und Eintragen-Button erstellen

...

8 }

Wie läuft das Skript also aus Benutzersicht ab? Ruft er es das ersteMal auf, so ist sind $_POST["eintragen"] und $_POST["speichern"] unde-finiert. In dem Skript werden also nur die nach dem inneren if-Zweigausgeführt, so dass der Benutzer den aktuellen Datenbankinhalt undden Eintragen-Button sieht.

Klickt er nun auf den Eintragen-Button, so wird das Skript erneutaufgerufen, doch diesmal ist der Inhalt von $_POST["eintragen"] defi-niert (wesentlich ist hierbei, dass der Eintragen-Button auch den Na-men eintragen hat!). Somit werden die Anweisungen des äußeren if-Zweigs ausgeführt und das Eingabeformular für die Daten sowie derSpeichern-Button angezeigt.

Schickt der Benutzer nun dieses Formular ab, so wird das Skript eindrittes Mal aufgerufen, diesmal ist jedoch $_POST mit den Eingabedatengefüllt und $_POST["speichern"] ist nun ebenfalls definiert. Daher wirdder innere if-Zweig ausgeführt, der Benutzer sieht den aktuellen Standder Datenbank.

2.1.2 Das Eingabeformular

Das Eingabeformular wird aufgebaut, wenn zuvor der Submit-Buttonnamens eintragen gedrückt worden ist. Jedes Input-Element hat alsNamen den entsprechenden Feldnamen aus der Datenbanktabelle. Da-mit hat man stets eine direkt verständliche Verbindung zwischen denFeldern und den Textfeldern und erleichtert so die Programmierungund spätere Verwaltung aufgrund etwaiger Änderungen der Daten-bankstruktur.

Wesentlich für den korrekten Ablauf des Skripts ist, dass der Submit-Button dieses Eingabeformulars speichern heißt, denn die steuerndenif-Anweisungen benötigen zum korrekten Ablauf des Skripts diesenNamen.

2.1.3 Das Abspeichern der Daten

Zum Abspeichern der Daten aus dem Eingabeformular muss ein INSERT-Befehl in SQL auf die Datenbank abgesetzt werden. (Hier erkennt maneinen der Vorteile, wenn man die Input-Elemente des Formulars gleich

18

Page 19: Internettechnologien, LE 3: PHP, SQL und HTMLhaegar.fh-swf.de/TBW/Internettechnologien/Internettechno...PHP-Modul muss also PHP-Code als HTML-Code ausgeben und durch denWebserverandenBrowsersenden

2.2 Eintragen-Skript mit Funktionen und Formatierungen

nennt wie die Felder der Tabelle!) Ein häufig gemachter Fehler ist dasFehlen der Apostrophs bei der Wertzuweisung.Der SQL-Befehl wird zunächst in eine String-Variable $sql gespeichert.(Zu beachten sind dabei die Leerzeichen bei Zeilenumbrüchen!). Dashat einerseits den Vorteil, dass man den relativ langen Befehl über-sichtlich aufbauen kann. Andererseits kann man im Fehlerfall leichtden SQL-Befehl anzeigen („debuggen“) lassen, um zu prüfen, ob es sichum einen SQL-Fehler handelt. Debugging ist das zeilenweise Verfol-gen der Werte eines Programms während der Laufzeit. Es gibt dafür,ähnlich wie für andere Programmiersprachen, einige ausgereifte Tools,jedoch in so einfachen Umfeldern wie hier reicht auch ein einfachesAusgeben der Werte. Damit kann man sich also in unserem Falle wäh-rend des Skriptablaufs anzeigen lassen, welches SQL-Statement genauabgesetzt worden ist. Oft kann man auf diese Weise Syntaxfehler inSQL schnell entdecken, insbesondere das Vergessen der Apostrophs (’).Empfehlenswert ist in diesem Zusammenhang auch das Debuggen mitetwaigen Fehlerausgaben der Funktion mysqli_error nach einer SQL-Anfrage:

$result = $mysqli->query($sql);

if ($mysqli->error) {

echo "SQL error: " . $mysqli->error;

}

Mit der if-Bedingung wird die echo-Anweisung nur im Fehlerfall aufge-rufen.Wie auch immer, am Ende muss ein SQL-Befehl natürlich auch mit$mysqli->query an die Datenbank gesendet werden. Genau dieser Fehlerwird erfahrungsgemäß oft gemacht, dass eine geniale SQL-Anweisungerzeugt wird, sie aber nicht abgesetzt wird. Denken Sie immer an Ab-bildung 1.2, PHP ist nur das Medium!

2.1.4 Die Anzeige

Die Anzeige des aktuellen Inhalts der Datenbank wird angezeigt durcheine SELECT-Anweisung. Sie lautet in unserem Beispiel 2.1

SELECT * FROM adressen ORDER BY Name

und liefert eine nach Namen sortierte Ergebnismenge $result.

2.2 Eintragen-Skript mit Funktionen und Formatierungen

Mit Funktionen kann man das eigentliche PHP-Skript, im folgendenauch „Hauptskript“ genannt, relativ kurz gestalten.

Beispiel 2.2 Adressen aus Datenbank, mit Einfügemöglichkeit ♦

19

Page 20: Internettechnologien, LE 3: PHP, SQL und HTMLhaegar.fh-swf.de/TBW/Internettechnologien/Internettechno...PHP-Modul muss also PHP-Code als HTML-Code ausgeben und durch denWebserverandenBrowsersenden

2 Datenbankinteraktionen mit dem Browser

1 <!-- Adressen in DB eintragen. Dateiname: adresseDB3.php -->

2 <form action="<?php echo $_SERVER[’PHP_SELF’]?>" method="POST">

3 <?php

4 require("./adressDBFunktionen.inc.php");

5

6 $mysqli = new mysqli("localhost", "user", "c5dDC8VJemscKPQS",

"AdressDB");

7 if ($mysqli->connect_errno) {

8 echo "Failed to connect to MySQL: ({$mysqli->connect_errno

}) $mysqli->connect_error";

9 }

10 $mysqli->set_charset("utf8");

11

12 if (isset($_POST[’eintragen’])) {

13 eintragen($mysqli);

14 } else {

15 if (isset($_POST[’speichern’])) {

16 speichern($mysqli, "adressen", $_POST);

17 }

18 auflisten($mysqli);

19 }

20 ?>

21 </form>

Im Wesentlichen wird also ein Formular erzeugt und nach dem Auf-bau der Datenbankverbindung je nach Inhalt der $_POST-Variablen eineder Funktionen auflisten, eintragen oder speichern aufgerufen. DieseFunktionen sind ausgelagert in der Datei

adressDBFunktionen.inc.php

in der gleichen Verzeichnisebene wie das PHP-Skript, zu erkennen amPfad des require-Befehls. Bevor wir uns diese näher anschauen, be-trachten wir den Ablauf des Skripts eingehender.Betrachten wir nun die aufgerufenen Funktionen etwas näher.

Beispiel 2.3 Funktionen der Adressdatenbank ♦

1 <!-- Funktionen der Adress-DB. Dateiname: adressDBFunktionen.

inc.php //->

2 <?php

3 function auflisten($mysqli) {

4 ?>

5 <h2>Adressen als 2-dimensionales Array</h2>

6 <table border="1">

7 <?php

8 $sql = "SELECT * FROM adressen ORDER BY Name";

9 $result = $mysqli->query($sql);

20

Page 21: Internettechnologien, LE 3: PHP, SQL und HTMLhaegar.fh-swf.de/TBW/Internettechnologien/Internettechno...PHP-Modul muss also PHP-Code als HTML-Code ausgeben und durch denWebserverandenBrowsersenden

2.2 Eintragen-Skript mit Funktionen und Formatierungen

10

11 // Tabellenkopf mit den Feldnamen als Spaltenbezeichnungen:

12 echo " <tr>\n";

13 while ( $attribut = $result->fetch_field() ) {

14 echo " <th>$attribut->name</th>\n";

15 }

16 echo " </tr>\n";

17

18 // Tabelleneinträge aus der Datenbank, spezielle Ausgabe

für email und web:

19 while ( $adresse = $result->fetch_assoc() ) {

20 echo " <tr>\n";

21 foreach ( $adresse as $key => $value ) {

22 if ( $key == "email" ) {

23 echo " <td><a href=\"mailto:$value\">$value</a></

td>\n";

24 } else if ( $key == "web" ) {

25 echo " <td><a href=\"http://$value\">$value</a></

td>\n";

26 } else {

27 echo " <td>$value</td> \n";

28 }

29 }

30 echo " </tr>\n";

31 }

32 ?>

33 </table>

34 <p style="text-align:center">

35 <input type="submit" name="eintragen" value="Adresse

eintragen"/>

36 </p>

37 <?php

38 } // Ende function auflisten

39

40 function eintragen($mysqli) {

41 ?>

42 <table border="0">

43 <tr><td>Vorname: </td><td><input type="text" name="

vorname"/></td></tr>

44 <tr><td>Name: </td><td><input type="text" name="name"

/></td></tr>

45 <tr>

46 <td>PLZ/Ort: </td>

47 <td>

48 <input type="text" name="PLZ" size="7"/>

49 <input type="text" name="Ort"/>

21

Page 22: Internettechnologien, LE 3: PHP, SQL und HTMLhaegar.fh-swf.de/TBW/Internettechnologien/Internettechno...PHP-Modul muss also PHP-Code als HTML-Code ausgeben und durch denWebserverandenBrowsersenden

2 Datenbankinteraktionen mit dem Browser

50 </td>

51 </tr>

52 <tr><td>Strasse: </td><td><input type="text" name="

strasse"/></td></tr>

53 <tr><td>Web: </td><td><input type="text" name="web"/></

td></tr>

54 <tr><td>e-mail: </td><td><input type="text" name="email"

/></td></tr>

55 </table>

56 <p><input type="submit" name="speichern" value="Speichern"

/></p>

57 <?php

58 } // Ende function eintragen

59

60 function speichern($mysqli, $tabelle, $daten) {

61 $spalten = array();

62 $werte = array();

63 foreach ( $daten as $key => $value ) {

64 if ( $key != "speichern" ) {

65 $spalten[] = $key;

66 $werte[] = "’" . $mysqli->escape_string($value) . "’"

;

67 }

68 }

69 $sql = "INSERT INTO $tabelle ";

70 $sql .= "(" . implode(",", $spalten ) . ")";

71 $sql .= " VALUES ";

72 $sql .= "(" . implode(",", $werte ) . ")";

73 $mysqli->query($sql);

74 }

75 ?>

Die Funktion auflisten entspricht im Wesentlichen dem Beispielskript1. Einzige Änderungen sind das SELECT-Statement, das jetzt

SELECT * FROM adressen ORDER BY Name

lautet und eine nach Namen sortierte Ergebnismenge $result liefert.Außerdem ist nun ein Submit-Button namens eintragen eingefügt, deran sich nichts anderes bewirkt, als dass das Hauptskript wieder auf-gerufen wird. Die $_POST-Variable enthält nun als einziges Datenfeld$_POST[eintragen], ist also nicht mehr leer.Damit wird nun in dem Skript der zweite if-Zweig durchlaufen, d.h. dieFunktion eintragen aufgerufen. Diese Funktion baut nun ein einfachesEingabeformular auf, in dem die Adressdaten eingegeben werden kön-nen. Der Submit-Button heißt hier nun speichern, und damit wird nachAnklicken das Hauptskript wieder aufgerufen.

22

Page 23: Internettechnologien, LE 3: PHP, SQL und HTMLhaegar.fh-swf.de/TBW/Internettechnologien/Internettechno...PHP-Modul muss also PHP-Code als HTML-Code ausgeben und durch denWebserverandenBrowsersenden

2.3 Zusammenfassung

Diesmal wird der dritte if-Zweig durchlaufen und die Funktionspeichern aufgerufen. Diese Funktion übernimmt die Dateninhalteder $_POST-Variablen des Eingabeformulars, um daraus ein INSERT-Statement zu bilden. Mit $mysqli->query wird dieser SQL-Befehl an dieDatenbank geschickt, in der dann der Datensatz gespeichert wird. Die-se Variante bildet zwei Arrays, je eins mit den Spaltennamen und einsmit den Inhalten, und verwendet den implode-Befehl, um daraus dieKlammerausdrücke für ein INSERT zu erzeugen. Nachdem dieser INSERT-Befehl als String gebildet worden ist, wird er mit $mysqli->query an dieDatenbank geschickt, dort von dem Datenbanksystem als SQL interpre-tiert und ausgeführt (wenn denn kein Syntaxfehler in SQL vorliegt ...).Danach wird direkt die Funktion auflisten aufgerufen, die die nun ak-tualisierte Tabelle an den Browser schickt. Violà!

2.3 Zusammenfassung

• Der Ablauf eines Skripts, das sich mehrmals selbst aufruft, wirdmit if-Anweisungen gesteuert, die den Inhalt der Submit-Buttonsprüfen. Wesentlich ist also in diesem Fall, dass jeder Submit-Button einen eigenen Namen trägt.

• Der zeitliche Ablauf des Skripts aus Sicht des Benutzers ent-spricht nicht der Struktur der if-Anweisungen, denn zuerst wer-den spezielle Belegungen der Submit-Buttons abgefragt, dannerst kommt der allgemeine Teil.

• Die Anzeige des aktuellen Datenbankinhalts sollte erst am Endedes Skripts erfolgen, nachdem etwaige Änderungen in der Daten-bank erfolgt sind. Würde man in Beispiel 2.1 die Anzeige der Da-tenbankinhalte vor der Speicherung der Eingabedaten program-mieren, wäre zwar der neue Eintrag korrekt in der Datenbank ge-speichert, der Anwender sähe aber irreführenderweise noch denalten Stand der Datenbank.

• Man sollte die Namen der <input>-Tags in einem Eingabeformulargenauso nennen wie die entsprechenden Feldnamen der Daten-banktabelle. Das erleichtert einerseits die Programmübersicht,andererseits die Synchronisation und Verwaltung bei Änderun-gen der Datenbankstruktur.

• Erstellt man ein SQL-Statement als einen String (z.B. namens$sql), so muss er irgendwann mit $mysqli->query an die Daten-bank gesendet werden. ;-)

23

Page 24: Internettechnologien, LE 3: PHP, SQL und HTMLhaegar.fh-swf.de/TBW/Internettechnologien/Internettechno...PHP-Modul muss also PHP-Code als HTML-Code ausgeben und durch denWebserverandenBrowsersenden

3 Übungsaufgaben

3 Übungsaufgaben

Aufgabe 3.1 (Anmeldetracking) (a) Erstellen Sie mit phpmyadmin eineDatenbank aufgabe_3_1 mit einer Tabelle, die folgende Spalten enthält:

Spaltenname Datenformat Standardwertanmeldename VARCHAR (10)ip VARCHAR (39)anzahl INT 1

Der Anmeldename soll hier der Primärschlüssel sein. Tragen Sie,ebenfalls mit phpmyadmin, zwei Datensätze ein. (Die Spalte ip sollhierbei eine IP-Adresse nach IPv4 oder IPv6 darstellen, also z.B.„193.174.68.9“.)

(b) Schreiben Sie ein PHP-Skript, das bei jedem Aufruf die Daten derDatenbankeinträge auflistet sowie ein Textfeld für einen Anmeldena-men und einen Button „Anmelden“ anzeigt. Durch Anklicken des But-tons soll das Skript wieder aufgerufen werden und der übermittelte An-meldename in die Datenbank eingetragen werden. Beim Eintragen solldie in dem PHP-Array $_SERVER["REMOTE_ADDR"] enthaltene IP-Adressedes Browsers gespeichert werden.

(c) Erweitern Sie das Skript, so dass für den Fall, dass der Anmeldenamein der Datenbank bereits vorhanden ist, sein Betrag im Feld anzahl umeins erhöht wird.

Programmiertipp. Speichern Sie in PHP erzeugte SQL-Anweisungen ineiner eigenen Variablen und geben Sie sie zunächst per echo als Textaus und testen sie per SQL-Eingabe in phpmyadmin. Auf diese Weisekönnen Sie mögliche SQL-Fehler leichter erkennen.

Aufgabe 3.2 (Pizzabestellung) Programmieren Sie ein PHP-Skript, dasdas untenstehende Formular anzeigt und die eingegebenen Daten ineine Datenbanktabelle schreibt. Erstellen Sie in der Datenbank nebeneiner Tabelle für die Kundenanmeldung lediglich eine weitere für dieBestellungen, verwenden Sie passend VARCHAR, ENUM, SET, INT und TEXT

als Datentypen für die Tabelle und definieren Sie einen sinnvollen Pri-märschlüssel.

24

Page 25: Internettechnologien, LE 3: PHP, SQL und HTMLhaegar.fh-swf.de/TBW/Internettechnologien/Internettechno...PHP-Modul muss also PHP-Code als HTML-Code ausgeben und durch denWebserverandenBrowsersenden

Aufgabe 3.3 (Werbebanner) (a) Sie arbeiten bei einem Portalanbieter.Die Geschäfte laufen gut und die Anzahl der zur Verfügung stehendenWerbeflächen ist erschöpft. Ihr Chef kommt auf die Idee, eine Werbeflä-che, d.h. eine bestimmte Position der Webseite zu geringeren Preisenmehrfach zu vermieten.Dazu werden Sie beauftragt, ein geeignetes PHP-Skript zu programmie-ren. Dabei muss sichergestellt sein, dass während eines Zyklusses (Pe-riode der Seitenaufrufe = Anzahl der Werbebanner) alle Banner gleichhäufig angezeigt werden. Weiterhin sollen alle entscheidenden Datenaus einer Datenbank kommen, das Skript soll also bei neuen oder ge-kündigten Bannern nicht modifiziert, sondern es soll nur der Daten-bankinhalt per phpMyAdmin angepasst werden.

(b) Das Konzept ist so erfolgreich, dass mehrere Positionen nun mehr-fach vermietet werden sollen. Wie muss die Datenbank und das Skripthierfür angepasst werden?

Aufgabe 3.4 (a) Programmieren Sie für den Administrator einer Adress-datenbank eine Bedienoberfläche für den Browser. Die Anwendung sollfolgende Funktionalitäten und Eigenschaften haben:

• In der Datenbank werden Name, Vorname und Ort gespeichert(wenn Sie wollen, auch Straße, Stadt, Email, Telefon, Handy, . . . ).

• Um die Verwaltung nutzen zu können, muss man sich anmel-den. Die Passwörter der Anwender sollen in der Datenbank mitSHA-1 gehasht gespeichert werden, verwenden Sie zum Spei-chern der initialen Nutzerdaten die Hilfsfunktion unter http:

//haegar.fh-swf.de/sha1.php.

• Der Admin soll Datensätze anlegen, ändern und löschen können.Erstellen Sie dazu ein PHP-Skript, das die Bearbeitung der Daten-banktabelle gemäß folgender Abbildung ermöglicht.

(b) Programmieren Sie ein zweites Skript, mit dem sich ein User anmel-den und seine eigenen Daten editieren kann (d.h. ändern und löschen).Zudem soll er durch Eingabe von Vornamen oder Nachname nach dendazu verfügbaren Einträgen suchen und sich die vollständigen Datendazu anzeigen lassen können.

25

Page 26: Internettechnologien, LE 3: PHP, SQL und HTMLhaegar.fh-swf.de/TBW/Internettechnologien/Internettechno...PHP-Modul muss also PHP-Code als HTML-Code ausgeben und durch denWebserverandenBrowsersenden

3 Übungsaufgaben

(c) Sofern der Client-Rechner Cookies zulässt, kann man auf Wunschpermanent angemeldet bleiben.

26

Page 27: Internettechnologien, LE 3: PHP, SQL und HTMLhaegar.fh-swf.de/TBW/Internettechnologien/Internettechno...PHP-Modul muss also PHP-Code als HTML-Code ausgeben und durch denWebserverandenBrowsersenden

4 Lösungen der Aufgaben

Aufgabe 3.1 Die Datenbank hat die folgende Struktur:

1 -- phpMyAdmin SQL Dump

2 -- version 4.6.1

3 -- http://www.phpmyadmin.net

4 --

5 -- Host: localhost

6 -- Erstellungszeit: 13. Nov 2016 um 14:56

7 -- Server-Version: 5.7.16-0ubuntu0.16.04.1

8 -- PHP-Version: 7.0.9-1+deb.sury.org trusty+1

9

10 SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";

11 SET time_zone = "+00:00";

12

13 /*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;

14 /*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;

15 /*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;

16 /*!40101 SET NAMES utf8mb4 */;

17

18 --

19 -- Datenbank: ‘aufgabe_3_1‘

20 --

21 -- -------------------------------------

22 --

23 -- Tabellenstruktur für Tabelle ‘besucher‘

24 --

25 CREATE TABLE ‘besucher‘ (

26 ‘anmeldename‘ varchar(10) NOT NULL,

27 ‘ip‘ varchar(15) NOT NULL,

28 ‘anzahl‘ int(11) NOT NULL DEFAULT ’1’

29 ) ENGINE=InnoDB DEFAULT CHARSET=utf8;

30 --

31 -- Daten für Tabelle ‘besucher‘

32 --

33 INSERT INTO ‘besucher‘ (‘anmeldename‘, ‘ip‘) VALUES

34 (’anna’, ’192.168.0.100’),

35 (’hugo’, ’localhost’),

36 (’otto’, ’194.94.2.20’);

37 --

38 -- Indizes für die Tabelle ‘besucher‘

39 --

40 ALTER TABLE ‘besucher‘

41 ADD PRIMARY KEY (‘anmeldename‘);

42 /*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;

43 /*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;

44 /*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;

Das PHP-Skript kann nach den Aufgabenstellungen (a) bis (c) lauten:

1 <!DOCTYPE html>

2 <html lang="de-DE">

3 <head>

4 <meta charset="UTF-8">

5 <title>Anmeldetracking</title>

6 </head>

7 <body>

27

Page 28: Internettechnologien, LE 3: PHP, SQL und HTMLhaegar.fh-swf.de/TBW/Internettechnologien/Internettechno...PHP-Modul muss also PHP-Code als HTML-Code ausgeben und durch denWebserverandenBrowsersenden

4 Lösungen der Aufgaben

8 <form action="<?php echo $_SERVER[’PHP_SELF’];?>" method="POST">

9 <input type="text" name="anmeldename" placeholder="Anmeldename"/>

10 <input type="submit" value="Anmelden" />

11 </form>

12

13 <?php

14 $server = "localhost";

15 $user = "user";

16 $password = "passwort";

17 $database = "aufgabe_3_1";

18

19 $mysqli = new mysqli($server, $user, $password, $database, 3306);

20 $mysqli->set_charset("utf8");

21

22 if (isset($_POST["anmeldename"])) {

23 $sql = "SELECT COUNT(*) FROM besucher

24 WHERE anmeldename = ’$_POST[anmeldename]’";

25 //echo $sql; exit();

26 $result = $mysqli->query($sql);

27 if ($result->fetch_assoc()["COUNT(*)"] === "0") { // Anmeldename nicht da

28 $sql = "INSERT INTO besucher

29 (anmeldename, ip)

30 VALUES

31 (’$_POST[anmeldename]’, ’$_SERVER[REMOTE_ADDR]’)";

32 //echo $sql; exit();

33 $result = $mysqli->query($sql);

34 } else { // Anmeldename vorhanden

35 $sql = "UPDATE besucher SET anzahl = anzahl + 1

36 WHERE anmeldename = ’$_POST[anmeldename]’";

37 //echo $sql; exit();

38 $result = $mysqli->query($sql);

39 }

40 }

41

42 // Auflisten der DB-Einträge:

43 echo "<h3>Eingetragene Anmeldenamen:</h3><ol>";

44 $sql = "SELECT * FROM besucher";

45 //echo $sql; exit();

46 $result = $mysqli->query($sql);

47 while ($eintrag = $result->fetch_assoc()) {

48 echo "<li>" .

49 $eintrag["anmeldename"] . ": " .

50 $eintrag["anzahl"] . " Besuche, " .

51 "IP: " . $eintrag["ip"] .

52 "</li>";

53 }

54 ?>

55 </body>

56 </html>

Beachten Sie dabei die auskommentierten Anweisungen echo $sql;

exit(); in den Zeilen 25, 32, 37 und 45, die zum Debuggen der jeweili-gen SQL-Anweisungen eingesetzt werden können, um sie in phpmyad-min direkt zu testen. Die Funktion exit bricht das Skript sofort ab.

Aufgabe 3.2 Das Formular lässt sich wie folgt implementieren:

28

Page 29: Internettechnologien, LE 3: PHP, SQL und HTMLhaegar.fh-swf.de/TBW/Internettechnologien/Internettechno...PHP-Modul muss also PHP-Code als HTML-Code ausgeben und durch denWebserverandenBrowsersenden

1 <!DOCTYPE html>

2 <html lang="de-DE">

3 <head>

4 <meta charset="UTF-8"/>

5 <title>Pizzabestellung</title>

6 <style>

7 .spalte1 {width: 15ex; margin: 1.5ex;}

8 .spalte1u {width: 15ex; margin: 1.5ex; margin-bottom: -0.75ex;}

9 .spalte2 {margin: 1.5ex;}

10 .spalte2u {margin: 1.5ex; margin-bottom: -0.75ex;}

11 </style>

12 </head>

13 <body>

14 <form action="./bestellen.php" method="POST">

15 <div style="display:flex;">

16 <div class="spalte1">Pizza</div>

17 <div class="spalte2">

18 <select name="pizza">

19 <option>Tonno</option>

20 <option>Salami</option>

21 <option>Prosciuto</option>

22 <option>Funghi</option>

23 </select>

24 </div>

25 </div>

26 <div style="display:flex;">

27 <div class="spalte1">Größe</div>

28 <div class="spalte2">

29 <input type="radio" name="groesse" value="groß" checked="checked"/>

30 groß<br/>

31 <input type="radio" name="groesse" value="mittel"/>

32 mittel<br/>

33 <input type="radio" name="groesse" value="klein"/>

34 klein

35 </div>

36 </div>

37 <div style="display:flex;">

38 <div class="spalte1">Extra Beilagen</div>

39 <div class="spalte2">

40 <input type="checkbox" name="zutaten[]" value="Käse"/>

41 Käse<br>

42 <input type="checkbox" name="zutaten[]" value="Zwiebeln"/>

43 Zwiebeln<br>

44 <input type="checkbox" name="zutaten[]" value="Tomaten"/>

45 Tomaten

46 </div>

47 </div>

48 <div style="display:flex;">

49 <div class="spalte1">Bemerkungen</div>

50 <div class="spalte2"><textarea name="bemerkung" rows="5"></textarea></div>

51 </div>

52 <div style="margin-top: 1.5ex;">

53 <div style="display:flex;">

54 <div class="spalte1u">Anmeldename</div>

55 <div class="spalte2u"><input type="text" name="anmeldename"></div>

56 </div>

29

Page 30: Internettechnologien, LE 3: PHP, SQL und HTMLhaegar.fh-swf.de/TBW/Internettechnologien/Internettechno...PHP-Modul muss also PHP-Code als HTML-Code ausgeben und durch denWebserverandenBrowsersenden

4 Lösungen der Aufgaben

57 <div style="display:flex;">

58 <div class="spalte1u">Passwort</div>

59 <div class="spalte2u"><input type="password" name="passwort"></div>

60 </div>

61 </div>

62 <br/>

63 <div class="spalte1">

64 <input type="submit" name="submit" value="Bestellen"/>

65 </div>

66 </form>

67 </body>

68 </html>

Entsprechend lautet das PHP-Skript bestellen.php im selben Verzeich-nis:

1 <?php

2 $server = "localhost";

3 $user = "root";

4 $password = "fbtbw1234";

5 $database = "pizzeria";

6

7 $mysqli = new mysqli($server, $user, $password, $database);

8 $mysqli->set_charset(’utf8’);

9

10 if (isset($_POST["anmeldename"])) {

11 $sql = "SELECT COUNT(*) FROM kunden

12 WHERE anmeldename = ’$_POST[anmeldename]’

13 AND passwort = ’$_POST[passwort]’";

14 #echo $sql;

15 $result = $mysqli->query($sql);

16 if ($treffer = $result->fetch_assoc()) {

17 if ($treffer["COUNT(*)"] === "0") {

18 echo "Log-in gescheitert! (Anwendername oder Passwort falsch)";

19 exit();

20 }

21 if ($treffer["COUNT(*)"] !== "1") {

22 echo "SQL-Injection: " . $treffer["COUNT(*)"] . " gleiche Anwender!";

23 exit();

24 }

25 } else {

26 echo "Log-in gescheitert: Datenbankfehler: Wir arbeiten dran ...";

27 exit();

28 }

29

30 // Ab hier geht es nur nach einem erfolgreichen Log-in weiter ...

31 $sql = "INSERT INTO ‘bestellungen‘

32 (‘kunde‘, ‘pizza‘, ‘groesse‘, ‘beilagen‘, ‘bemerkung‘)

33 VALUES (’$_POST[anmeldename]’, ’$_POST[pizza]’, ’$_POST[groesse]’,

’";

34 for ($i = 0; $i < sizeof($_POST["beilagen"]); $i++) {

35 $sql .= $_POST["beilagen"][$i];

36 if ($i < sizeof($_POST["beilagen"]) - 1) {

37 $sql .= ",";

38 }

39 }

40 $sql .= "’, ’$_POST[bemerkung]’)";

30

Page 31: Internettechnologien, LE 3: PHP, SQL und HTMLhaegar.fh-swf.de/TBW/Internettechnologien/Internettechno...PHP-Modul muss also PHP-Code als HTML-Code ausgeben und durch denWebserverandenBrowsersenden

41 #echo "$sql";

42 $result = $mysqli->query($sql);

43 if ($result) {

44 echo "Ihre Bestellung wurde erfolgreich gespeichert:";

45 echo "<pre>"; print_r($_POST); echo "</pre>";

46 } else {

47 echo "Bei Ihrer Bestellung lief etwas schief! Wir arbeiten dran ...";

48 }

49 }

50 ?>

1 SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";

2 SET time_zone = "+00:00";

3

4

5 /*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;

6 /*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;

7 /*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;

8 /*!40101 SET NAMES utf8mb4 */;

9

10 --

11 -- Datenbank: ‘pizzeria‘

12 --

13

14 -- -------------------------------------

15

16 --

17 -- Tabellenstruktur für Tabelle ‘bestellungen‘

18 --

19

20 CREATE TABLE ‘bestellungen‘ (

21 ‘bestellid‘ int(11) NOT NULL,

22 ‘kunde‘ varchar(10) NOT NULL COMMENT ’Referenzschlüssel’,

23 ‘pizza‘ enum(’Tonno’,’Salami’,’Prosciuto’,’Funghi’) NOT NULL,

24 ‘groesse‘ enum(’groß’,’mittel’,’klein’) NOT NULL,

25 ‘beilagen‘ set(’Käse’,’Zwiebeln’,’Tomaten’) NOT NULL,

26 ‘bemerkung‘ text NOT NULL

27 ) ENGINE=InnoDB DEFAULT CHARSET=utf8;

28

29 -- -------------------------------------

30

31 --

32 -- Tabellenstruktur für Tabelle ‘kunden‘

33 --

34

35 CREATE TABLE ‘kunden‘ (

36 ‘anmeldename‘ varchar(10) NOT NULL,

37 ‘passwort‘ varchar(20) NOT NULL

38 ) ENGINE=InnoDB DEFAULT CHARSET=utf8;

39

40 --

41 -- Daten für Tabelle ‘kunden‘

42 --

43

44 INSERT INTO ‘kunden‘ (‘anmeldename‘, ‘passwort‘) VALUES

45 (’anna’, ’123’),

46 (’otto’, ’abc’);

31

Page 32: Internettechnologien, LE 3: PHP, SQL und HTMLhaegar.fh-swf.de/TBW/Internettechnologien/Internettechno...PHP-Modul muss also PHP-Code als HTML-Code ausgeben und durch denWebserverandenBrowsersenden

4 Lösungen der Aufgaben

47

48 --

49 -- Indizes der exportierten Tabellen

50 --

51

52 --

53 -- Indizes für die Tabelle ‘bestellungen‘

54 --

55 ALTER TABLE ‘bestellungen‘

56 ADD PRIMARY KEY (‘bestellid‘);

57

58 --

59 -- Indizes für die Tabelle ‘kunden‘

60 --

61 ALTER TABLE ‘kunden‘

62 ADD PRIMARY KEY (‘anmeldename‘);

63

64 --

65 -- AUTO_INCREMENT für exportierte Tabellen

66 --

67

68 --

69 -- AUTO_INCREMENT für Tabelle ‘bestellungen‘

70 --

71 ALTER TABLE ‘bestellungen‘

72 MODIFY ‘bestellid‘ int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=10;

73 /*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;

74 /*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;

75 /*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;

Aufgabe 3.3 Für beide Aufgabenteile (a) und (b) wird auf dieselbe Da-tenbank zugegriffen, die die folgende Struktur besitzt:

1 -- phpMyAdmin SQL Dump

2 -- version 4.5.1

3 -- http://www.phpmyadmin.net

4 --

5 -- Host: 127.0.0.1

6 -- Erstellungszeit: 10. Nov 2016 um 14:42

7 -- Server-Version: 10.1.9-MariaDB

8 -- PHP-Version: 5.6.15

9

10 SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";

11 SET time_zone = "+00:00";

12

13 /*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;

14 /*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;

15 /*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;

16 /*!40101 SET NAMES utf8mb4 */;

17

18 --

19 -- Datenbank: ‘werbebanner‘

20 --

21 -- -------------------------------------

22 --

23 -- Tabellenstruktur für Tabelle ‘aufgabe_3_2_a‘

24 --

32

Page 33: Internettechnologien, LE 3: PHP, SQL und HTMLhaegar.fh-swf.de/TBW/Internettechnologien/Internettechno...PHP-Modul muss also PHP-Code als HTML-Code ausgeben und durch denWebserverandenBrowsersenden

25 CREATE TABLE ‘aufgabe_3_2_a‘ (

26 ‘bannerID‘ int(10) UNSIGNED NOT NULL,

27 ‘file‘ varchar(50) NOT NULL,

28 ‘ranking‘ tinyint(3) UNSIGNED NOT NULL

29 ) ENGINE=InnoDB DEFAULT CHARSET=latin1;

30

31 --

32 -- Daten für Tabelle ‘aufgabe_3_2_a‘

33 --

34 INSERT INTO ‘aufgabe_3_2_a‘ (‘bannerID‘, ‘file‘, ‘ranking‘) VALUES

35 (1, ’schroeder.jpg’, 1),

36 (2, ’de-vries.jpg’, 2),

37 (3, ’erniebert.jpg’, 0);

38

39 -- -------------------------------------

40

41 --

42 -- Tabellenstruktur für Tabelle ‘aufgabe_3_2_b‘

43 --

44 CREATE TABLE ‘aufgabe_3_2_b‘ (

45 ‘bannerID‘ int(10) UNSIGNED NOT NULL,

46 ‘file‘ varchar(50) NOT NULL,

47 ‘ranking‘ tinyint(3) UNSIGNED NOT NULL,

48 ‘position‘ tinyint(3) UNSIGNED NOT NULL

49 ) ENGINE=InnoDB DEFAULT CHARSET=latin1;

50

51 --

52 -- Daten für Tabelle ‘aufgabe_3_2_b‘

53 --

54 INSERT INTO ‘aufgabe_3_2_b‘ (‘bannerID‘, ‘file‘, ‘ranking‘, ‘position‘) VALUES

55 (1, ’schroeder.jpg’, 2, 0),

56 (2, ’de-vries.jpg’, 2, 0),

57 (3, ’erniebert.jpg’, 0, 0),

58 (4, ’bogart.jpg’, 3, 1),

59 (5, ’dean.jpg’, 0, 1),

60 (6, ’taylor.jpg’, 3, 1),

61 (7, ’monroe.jpg’, 1, 1);

62

63 --

64 -- Indizes für die Tabelle ‘aufgabe_3_2_a‘

65 --

66 ALTER TABLE ‘aufgabe_3_2_a‘

67 ADD PRIMARY KEY (‘bannerID‘);

68

69 --

70 -- Indizes für die Tabelle ‘aufgabe_3_2_b‘

71 --

72 ALTER TABLE ‘aufgabe_3_2_b‘

73 ADD PRIMARY KEY (‘bannerID‘);

74

75 --

76 -- AUTO_INCREMENT für exportierte Tabellen

77 --

78

79 --

80 -- AUTO_INCREMENT für Tabelle ‘aufgabe_3_2_a‘

33

Page 34: Internettechnologien, LE 3: PHP, SQL und HTMLhaegar.fh-swf.de/TBW/Internettechnologien/Internettechno...PHP-Modul muss also PHP-Code als HTML-Code ausgeben und durch denWebserverandenBrowsersenden

4 Lösungen der Aufgaben

81 --

82 ALTER TABLE ‘aufgabe_3_2_a‘

83 MODIFY ‘bannerID‘ int(10) UNSIGNED NOT NULL AUTO_INCREMENT, AUTO_INCREMENT

=4;

84 --

85 -- AUTO_INCREMENT für Tabelle ‘aufgabe_3_2_b‘

86 --

87 ALTER TABLE ‘aufgabe_3_2_b‘

88 MODIFY ‘bannerID‘ int(10) UNSIGNED NOT NULL AUTO_INCREMENT, AUTO_INCREMENT

=8;

89 /*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;

90 /*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;

91 /*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;

Die Namen der Bilddateien sind in den Zeilen 55 bis 61 angegeben undmüssen in einem Unterverzeichnis ./banner vorhanden sein.

(a) Das PHP-Skript lautet

1 <?php

2 //DB connect

3 $mysqli = new mysqli("localhost","user","password","werbebanner");

4

5 // select banner:

6 $sql = "SELECT bannerID, file FROM aufgabe_3_2_a

7 ORDER BY ranking DESC LIMIT 1";

8 $result = $mysqli->query($sql);

9 $banner = $result->fetch_assoc();

10

11 // increase / decrease ranking:

12 $sql = "UPDATE aufgabe_3_2_a SET ranking = ranking+1

13 WHERE bannerID <> $banner[bannerID]";

14 $mysqli->query($sql);

15

16 $sql = "UPDATE aufgabe_3_2_a SET ranking=0

17 WHERE bannerID = $banner[bannerID]";

18 $mysqli->query($sql);

19

20 // Show Banner

21 echo "<img src=\"./banner/".$banner[’file’]."\" />";

22 ?>

(b) Das PHP-Skript lautet

1 <?php

2 //DB connect

3 $mysqli = new mysqli("localhost","user","password","werbebanner");

4

5 // select banner:

6 for ($p = 0; $p < 2; $p++) { // enumerate positions $p

7 $sql = "SELECT bannerID, file FROM aufgabe_3_2_b

8 WHERE position = $p ORDER BY ranking DESC LIMIT 1";

9 $result = $mysqli->query($sql);

10 $banner[$p] = $result->fetch_assoc();

11 }

12

13 // increase / decrease ranking:

14 for ($p = 0; $p < 2; $p++) { // enumerate positions $p

34

Page 35: Internettechnologien, LE 3: PHP, SQL und HTMLhaegar.fh-swf.de/TBW/Internettechnologien/Internettechno...PHP-Modul muss also PHP-Code als HTML-Code ausgeben und durch denWebserverandenBrowsersenden

15 $sql = "UPDATE aufgabe_3_2_b SET ranking = ranking + 1

16 WHERE position = $p AND bannerID <> " . $banner[$p]["bannerID"];

17 $mysqli->query($sql);

18 $sql = "UPDATE aufgabe_3_2_b SET ranking = 0

19 WHERE position = $p AND bannerID = ".$banner[$p]["bannerID"];

20 $mysqli->query($sql);

21 }

22

23 // Show Banner:

24 echo "<img src=\"./banner/" . $banner[0]["file"] . "\" />

25 <img src=\"./banner/" . $banner[1]["file"] . "\" />";

26 ?>

Aufgabe 3.4 (a) und (b) Die Datenbank

1 -- phpMyAdmin SQL Dump

2 -- version 4.6.1

3 -- http://www.phpmyadmin.net

4 --

5 -- Host: localhost

6 -- Erstellungszeit: 29. Nov 2016 um 13:40

7 -- Server-Version: 5.7.16-0ubuntu0.16.04.1

8 -- PHP-Version: 7.0.9-1+deb.sury.org trusty+1

9

10 SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";

11 SET time_zone = "+00:00";

12

13 /*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;

14 /*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;

15 /*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;

16 /*!40101 SET NAMES utf8mb4 */;

17

18 --

19 -- Datenbank: ‘AdressDB‘

20 --

21 -- -------------------------------------

22 --

23 -- Tabellenstruktur für Tabelle ‘adressen‘

24 --

25

26 CREATE TABLE ‘adressen‘ (

27 ‘id‘ int(11) NOT NULL,

28 ‘vorname‘ varchar(20) NOT NULL DEFAULT ’’,

29 ‘name‘ varchar(20) NOT NULL DEFAULT ’’,

30 ‘email‘ varchar(30) NOT NULL DEFAULT ’’,

31 ‘web‘ varchar(50) NOT NULL DEFAULT ’’,

32 ‘strasse‘ varchar(20) NOT NULL DEFAULT ’’,

33 ‘plz‘ varchar(30) NOT NULL DEFAULT ’’,

34 ‘ort‘ varchar(30) NOT NULL DEFAULT ’’,

35 ‘nutzer‘ varchar(10) DEFAULT NULL COMMENT ’Fremdschlüssel’

36 ) ENGINE=InnoDB DEFAULT CHARSET=utf8;

37

38 --

39 -- Daten für Tabelle ‘adressen‘

40 --

41

42 INSERT INTO ‘adressen‘ (‘id‘, ‘vorname‘, ‘name‘, ‘email‘, ‘web‘, ‘strasse‘, ‘

plz‘, ‘ort‘, ‘nutzer‘) VALUES

35

Page 36: Internettechnologien, LE 3: PHP, SQL und HTMLhaegar.fh-swf.de/TBW/Internettechnologien/Internettechno...PHP-Modul muss also PHP-Code als HTML-Code ausgeben und durch denWebserverandenBrowsersenden

4 Lösungen der Aufgaben

43 (1, ’Andreas’, ’de Vries’, ’[email protected]’, ’haegar.fh-swf.de/

deVries.html’, ’Haldener Straße 182’, ’D-58095’, ’Hagen’, ’’),

44 (2, ’Ingo’, ’Schröder’, ’[email protected]’, ’www3.fh-swf.de/fbtbw/

Schroeder.htm’, ’Haldener Straße 182’, ’D-58095’, ’Hagen’, ’’),

45 (4, ’Volker’, ’Weiß’, ’[email protected]’, ’www3.fh-swf.de/fbtbw/Weiss.

htm’, ’Haldener Straße 182’, ’D-58095’, ’Hagen’, ’’),

46 (5, ’Bernd’, ’Blümel’, ’[email protected]’, ’hochschule-bochum.de/fbw

/personen/bluemel.html’, ’Lennershofstraße 140’, ’D-44801’, ’Bochum’, ’’)

,

47 (7, ’Otto’, ’Klein’, ’’, ’’, ’’, ’’, ’Iserlohn’, ’otto’);

48

49 -- -------------------------------------

50 --

51 -- Tabellenstruktur für Tabelle ‘nutzer‘

52 --

53

54 CREATE TABLE ‘nutzer‘ (

55 ‘name‘ varchar(10) NOT NULL,

56 ‘rolle‘ set(’admin’,’user’) NOT NULL DEFAULT ’user’,

57 ‘passwort‘ varchar(40) NOT NULL COMMENT ’SHA-1 hashed’,

58 ‘angemeldet‘ tinyint(1) NOT NULL DEFAULT ’0’,

59 ‘seit‘ timestamp NULL DEFAULT CURRENT_TIMESTAMP

60 ) ENGINE=InnoDB DEFAULT CHARSET=utf8;

61

62 --

63 -- Daten für Tabelle ‘nutzer‘

64 --

65

66 INSERT INTO ‘nutzer‘ (‘name‘, ‘rolle‘, ‘passwort‘, ‘angemeldet‘, ‘seit‘)

VALUES

67 (’admin’, ’admin’, ’beccee1a5ed045c43b71ccbeb1bab5c632e2bd25’, 0, ’2016-11-29

12:29:17’),

68 (’devries’, ’admin’, ’beccee1a5ed045c43b71ccbeb1bab5c632e2bd25’, 1, ’

2016-11-29 11:13:38’),

69 (’otto’, ’user’, ’beccee1a5ed045c43b71ccbeb1bab5c632e2bd25’, 1, ’2016-11-29

12:37:35’);

70

71 --

72 -- Indizes der exportierten Tabellen

73 --

74

75 --

76 -- Indizes für die Tabelle ‘adressen‘

77 --

78 ALTER TABLE ‘adressen‘

79 ADD PRIMARY KEY (‘id‘);

80

81 --

82 -- Indizes für die Tabelle ‘nutzer‘

83 --

84 ALTER TABLE ‘nutzer‘

85 ADD PRIMARY KEY (‘name‘);

86

87 --

88 -- AUTO_INCREMENT für exportierte Tabellen

89 --

36

Page 37: Internettechnologien, LE 3: PHP, SQL und HTMLhaegar.fh-swf.de/TBW/Internettechnologien/Internettechno...PHP-Modul muss also PHP-Code als HTML-Code ausgeben und durch denWebserverandenBrowsersenden

90

91 --

92 -- AUTO_INCREMENT für Tabelle ‘adressen‘

93 --

94 ALTER TABLE ‘adressen‘

95 MODIFY ‘id‘ int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=8;

96 /*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;

97 /*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;

98 /*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;

Das Startskript ist die folgende Datei login.php:

1 <?php

2 require_once("../db_login.inc.php");

3 $mysqli = login("AdressDB");

4

5 if (isset($_POST["name"]) && isset($_POST["passwort"])) {

6 $name = $mysqli->escape_string($_POST["name"]);

7 $passwort = sha1($_POST["passwort"]); // gehashtes Passwort

8 $sql = "SELECT COUNT(*) FROM nutzer

9 WHERE name = ’$name’

10 AND passwort = ’$passwort’";

11 $result = $mysqli->query($sql);

12 if ($treffer = $result->fetch_assoc()) {

13 if ($treffer["COUNT(*)"] === "0") {

14 echo "Log-in gescheitert! (Anmeldename oder Passwort falsch)<br/>";

15 echo "Versuchen Sie es <a href=\"$_SERVER[PHP_SELF]\">noch mal!</a>";

16 exit();

17 }

18 if ($treffer["COUNT(*)"] !== "1") {

19 error_log("Möglicher Cyberangriff: "

20 . $treffer["COUNT(*)"] . " gleiche Anwender!"

21 . " user: " . $_POST["name"]

22 . " passwort: " . $_POST["passwort"]

23 );

24 exit();

25 }

26 } else {

27 echo "Log-in gescheitert: Datenbankfehler: Wir arbeiten dran ...";

28 }

29

30 // Log-in erfolgreich ...

31 $sql = "UPDATE ‘nutzer‘ SET angemeldet = TRUE, seit = CURRENT_TIMESTAMP

WHERE name=’$name’";

32 $mysqli->query($sql);

33 header("Location: ./editieren.php?name=$name&pwd=$passwort");

34 exit();

35 }

36 if (isset($_POST["name"]) XOR isset($_POST["passwort"])) {

37 "Bitte Anmeldename und Passwort eingeben!";

38 }

39 ?>

40 <form action="<?php echo $_SERVER["PHP_SELF"]; ?>" method="POST">

41 <input type="text" name="name" />

42 <input type="password" name="passwort" />

43 <input type="submit" value="Anmelden" />

44 </form>

37

Page 38: Internettechnologien, LE 3: PHP, SQL und HTMLhaegar.fh-swf.de/TBW/Internettechnologien/Internettechno...PHP-Modul muss also PHP-Code als HTML-Code ausgeben und durch denWebserverandenBrowsersenden

4 Lösungen der Aufgaben

Nach erfolgreichem Login werden Anmeldename und das geshashtePasswort per URI und GET an das Skript editieren.php geschickt:

1 <!DOCTYPE html>

2 <html lang="de-DE">

3 <head>

4 <meta charset="UTF-8">

5 <title>Editierung einer Datenbank</title>

6 <style>

7 .idspalte {width: 5ex; margin: 0.1ex; border: 1px solid gray;}

8 .spalte {width: 20ex; margin: 0.1ex; border: 1px solid gray;}

9 </style>

10 </head>

11 <body>

12 <h1></h1>

13 <?php

14 require_once("../db_login.inc.php");

15 $mysqli = login("AdressDB");

16

17 // Bei jedem Aufruf dieser Seite Log-in erneut prüfen:

18 $nutzer = ""; // Nutzer in Nutzertabelle

19 $rolle = ""; // Nutzerrolle: admin dar alles editieren, user nur seine Daten

...

20

21 if (isset($_GET["name"]) && isset($_GET["pwd"])) {

22 $nutzer = $mysqli->escape_string($_GET["name"]);

23 $pwd = $mysqli->escape_string($_GET["pwd"]);

24

25 $sql = "SELECT COUNT(*), rolle FROM nutzer WHERE name=’$nutzer’ AND

passwort=’$pwd’ AND angemeldet=1";

26 $result = $mysqli->query($sql);

27 $anzahl = 0;

28 if ($treffer = $result->fetch_row()) {

29 $anzahl = $treffer[0];

30 $rolle = $treffer[1];

31 }

32

33 if ($anzahl != 1) { // Login fehlerhaft, Sitzung abbrechen

34 $sql = "UPDATE nutzer SET angemeldet=false WHERE name=’$name’";

35 $mysqli->query($sql);

36 header("Location: ./login.php");

37 exit();

38 }

39 } else { // Login fehlerhaft, Sitzung abbrechen

40 header("Location: ./login.php");

41 exit();

42 }

43

44 // Hier gelangt man nur mit gültigen Anmeldedaten hin!

45

46 // UPDATE:

47 if (isset($_POST["aendern"])) {

48 $id = $mysqli->escape_string($_POST["id"]);

49 $vorname = $mysqli->escape_string($_POST["vorname"]);

50 $name = $mysqli->escape_string($_POST["name"]);

51 $ort = $mysqli->escape_string($_POST["ort"]);

52

38

Page 39: Internettechnologien, LE 3: PHP, SQL und HTMLhaegar.fh-swf.de/TBW/Internettechnologien/Internettechno...PHP-Modul muss also PHP-Code als HTML-Code ausgeben und durch denWebserverandenBrowsersenden

53 $sql = "UPDATE adressen

54 SET vorname = ’$vorname’, name=’$name’, ort=’$ort’

55 WHERE id=$id";

56 if ($rolle != "admin") {

57 $sql .= " AND nutzer=’$nutzer’";

58 }

59 $mysqli->query($sql);

60 }

61 // DELETE:

62 if (isset($_POST["loeschen"])) {

63 $id = $mysqli->escape_string($_POST["id"]);

64 $sql = "DELETE FROM adressen WHERE id=$id";

65 if ($rolle != "admin") {

66 $sql .= " AND nutzer=’$nutzer’";

67 }

68 $mysqli->query($sql);

69 }

70 // INSERT:

71 if (isset($_POST["hinzufuegen"])) {

72 $vorname = $mysqli->escape_string($_POST["vorname"]);

73 $name = $mysqli->escape_string($_POST["name"]);

74 $ort = $mysqli->escape_string($_POST["ort"]);

75

76 $sql = "INSERT INTO adressen

77 (vorname, name, ort, nutzer)

78 VALUES

79 (’$vorname’, ’$name’, ’$ort’, ’$nutzer’)";

80 $mysqli->query($sql);

81 }

82 // SELECT:

83 ?>

84 <div style="display:flex;">

85 <div class="idspalte" style="font-weight:bold;">ID</div>

86 <div class="spalte" style="font-weight:bold;">Vorname</div>

87 <div class="spalte" style="font-weight:bold;">Nachname</div>

88 <div class="spalte" style="font-weight:bold;">Ort</div>

89 <div class="spalte" style="font-weight:bold;"></div>

90 </div>

91 <?php

92 $sql = "SELECT id, vorname, name, ort FROM adressen";

93 if ($rolle != "admin") {

94 $sql .= " WHERE nutzer=’$nutzer’";

95 }

96 $result = $mysqli->query($sql);

97 while ($eintrag = $result->fetch_row()) {

98 echo "

99 <form action=\"$_SERVER[PHP_SELF]?name=$_GET[name]&pwd=$_GET[pwd]\" method=\"

POST\">

100 <div style=\"display:flex;\">

101 <div class=\"idspalte\">$eintrag[0]<input type=\"hidden\" name=\"id\" value

=\"$eintrag[0]\"/></div>

102 <div class=\"spalte\"><input type=\"text\" style=\"width:20ex;\" name=\"

vorname\" value=\"$eintrag[1]\" /></div>

103 <div class=\"spalte\"><input type=\"text\" style=\"width:20ex;\" name=\"name

\" value=\"$eintrag[2]\" /></div>

104 <div class=\"spalte\"><input type=\"text\" style=\"width:20ex;\" name=\"ort

39

Page 40: Internettechnologien, LE 3: PHP, SQL und HTMLhaegar.fh-swf.de/TBW/Internettechnologien/Internettechno...PHP-Modul muss also PHP-Code als HTML-Code ausgeben und durch denWebserverandenBrowsersenden

4 Lösungen der Aufgaben

\" value=\"$eintrag[3]\" /></div>

105 <div class=\"spalte\">

106 <input type=\"submit\" name=\"aendern\" value=\"Ändern\"/>

107 <input type=\"submit\" name=\"loeschen\" value=\"Löschen\"/>

108 </div>

109 </div>

110 </form>";

111 }

112 echo "

113 <form action=\"$_SERVER[PHP_SELF]?name=$_GET[name]&pwd=$_GET[pwd]\" method=\"

POST\">

114 <div style=\"display:flex;\">

115 <div class=\"idspalte\"></div>

116 <div class=\"spalte\"><input type=\"text\" style=\"width:20ex;\" name=\"

vorname\" /></div>

117 <div class=\"spalte\"><input type=\"text\" style=\"width:20ex;\" name=\"name

\" /></div>

118 <div class=\"spalte\"><input type=\"text\" style=\"width:20ex;\" name=\"ort

\" /></div>

119 <div class=\"spalte\">

120 <input type=\"submit\" name=\"hinzufuegen\" value=\"Hinzufügen\"/>

121 </div>

122 </div>

123 </form>";

124 ?>

(c) Bevor nach erfolgreichem Login das Editieren-Skript in Zeile 33 desSkripts login.php aufgerufen wird, können zwei Cookies gesetzt wer-den, die den Anwendernamen und das gehashte Passwort speichern. ImEditierskript können die beiden Cookies dann statt der GET-Parameterabgefragt und verwendet werden.

40

Page 41: Internettechnologien, LE 3: PHP, SQL und HTMLhaegar.fh-swf.de/TBW/Internettechnologien/Internettechno...PHP-Modul muss also PHP-Code als HTML-Code ausgeben und durch denWebserverandenBrowsersenden

Abbildungsverzeichnis

Internetquellen

[PHP] http://php.net/manual/de/ – PHP-Handbuch

[PS] http://sandbox.onlinephpfunctions.com – PHP Sandbox, Möglich-keit zum Testen von PHP-Quelltextfragmenten (Snippets). DieSandbox wird bereitgestellt von Jereon (John) Post, die Websiteliefert Informationen und Tutorials über PHP.

[W3C] http://www.w3c.org/ – World Wide Web Consortium, Gremiumzur Standardisierung der Web-Techniken; eine deutsche Überset-zung wichtiger Teile dieses Webauftritts findet man unter http:

//www.edition-w3c.de/, auf die auch das Deutsch-ÖsterreichischeBüro W3C.DE/AT http://www.w3c.de/ bzw. http://www.w3c.at/

verlinkt.

Abbildungsverzeichnis

1.1 Die drei Schichten einer datenbankbasierten Webanwendung . . . . . 31.2 PHP als Schnittstelle, die über reinen Text kommuniziert . . . . . . . . 31.3 Die Struktur der Adressdatenbank (links) und einige Einträge (rechts),

mit phpMyAdmin betrachtet. . . . . . . . . . . . . . . . . . . . . . . . . 102.4 Die Seite beim Aufruf und beim Drücken des Eintragen-Buttons. . . . 16

41


Recommended