of 41/41
Inhaltsverzeichnis Inhaltsverzeichnis Vorbemerkungen zu dieser Lerneinheit ...................................... Datenbankzugrie übers Web: HTML & PHP & SQL ........ . Zugri von PHP auf MySQL ..................................... . Anzeigen von Daten im Browser ............................... . Informationen über gerade abgesetzte SQL-Befehle ....... . SQL Injection entschärfen mit escape _ string ............... . Zusammenfassung ............................................... Datenbankinteraktionen mit dem Browser .................. . Eintragen-Skript mit unformatierten Ausgaben ............. . Eintragen-Skript mit Funktionen und Formatierungen..... . Zusammenfassung ............................................... Übungsaufgaben ................................................. Lösungen der Aufgaben ......................................... Abbildungsverzeichnis...........................................

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

  • View
    2

  • Download
    0

Embed Size (px)

Text of Internettechnologien, LE 3: PHP, SQL und...

  • 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

  • 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

    https://www.apachefriends.org/https://httpd.apache.org/https://mariadb.org/

  • 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

  • 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

  • 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

  • 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 -Element

    ;

    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

  • 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_onceeinzulesen. 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

    2

    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

    http://php.nethttp://php.net/manual/de/mysqli.quickstart.connections.php

  • 1 Datenbankzugriffe übers Web: HTML & PHP & SQL

    einem Verbindungsfehler allerdings wird hier wegen der Funktion exitdas 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

    http://php.net/manual/en/mysqli.query.phphttp://php.net/manual/en/mysqli.query.php

  • 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

  • 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

    2

    10

  • 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] ...
    ";

    }

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

    2

    8

    9 Adressen als 2-dimensionales Array

    10

    11

  • 1 Datenbankzugriffe übers Web: HTML & PHP & SQL

    13

    14 // Tabellenkopf mit den Feldnamen als Spaltenbezeichnungen:

    15 echo " \n";

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

    17 echo " $field->name\n";

    18 }

    19 echo " \n";

    20

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

    email und web:

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

    23 echo " \n";

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

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

    26 echo " $value\n";

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

    28 echo " $value\n";

    29 } else {

    30 echo " $value \n";

    31 }

    32 }

    33 echo " \n";

    34 }

    35 ?>

    36

    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 -Tag vonHTML gepackt, so dass jeder Datensatz in -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

  • 1.3 Informationen über gerade abgesetzte SQL-Befehle

    kann man sich also mit der Anweisung

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

    echo "$spaltenname
    ";

    }

    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

    http://php.net/manual/de/mysqli.affected-rows.phphttp://php.net/manual/en/mysqli.real-escape-string.phphttp://php.net/manual/en/mysqli.real-escape-string.php

  • 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

  • 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
    ";

    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

  • 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

    2

  • 2.1 Eintragen-Skript mit unformatierten Ausgaben

    20

    46

    47

    50

    51

    52

    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

  • 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

  • 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

  • 2 Datenbankinteraktionen mit dem Browser

    1

    2

  • 2.2 Eintragen-Skript mit Funktionen und Formatierungen

    10

    11 // Tabellenkopf mit den Feldnamen als Spaltenbezeichnungen:

    12 echo " \n";

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

    14 echo " $attribut->name\n";

    15 }

    16 echo " \n";

    17

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

    für email und web:

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

    20 echo " \n";

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

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

    23 echo " $value\n";

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

    25 echo " $value\n";

    26 } else {

    27 echo " $value \n";

    28 }

    29 }

    30 echo " \n";

    31 }

    32 ?>

    33

    34

    35

    36

    37

    42

    43 Vorname:

    44 Name:

    45

    46 PLZ/Ort:

    47

    48

    49

    21

  • 2 Datenbankinteraktionen mit dem Browser

    50

    51

    52 Strasse:

    53 Web:

    54 e-mail:

    55

    56

    57

    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

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

  • 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 TEXTals Datentypen für die Tabelle und definieren Sie einen sinnvollen Pri-märschlüssel.

    24

    https://tools.ietf.org/html/rfc791https://tools.ietf.org/html/rfc4291

  • 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

    http://haegar.fh-swf.de/sha1.phphttp://haegar.fh-swf.de/sha1.php

  • 3 Übungsaufgaben

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

    26

  • 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 @[email protected]@CHARACTER_SET_CLIENT */;

    14 /*!40101 SET @[email protected]@CHARACTER_SET_RESULTS */;

    15 /*!40101 SET @[email protected]@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 [email protected]_CHARACTER_SET_CLIENT */;

    43 /*!40101 SET [email protected]_CHARACTER_SET_RESULTS */;

    44 /*!40101 SET [email protected]_COLLATION_CONNECTION */;

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

    1

    2

    3

    4

    5 Anmeldetracking

    6

    7

    27

  • 4 Lösungen der Aufgaben

    8

  • 1

    2

    3

    4

    5 Pizzabestellung

    6

    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

    12

    13

    14

    15

    16 Pizza

    17

    18

    19 Tonno

    20 Salami

    21 Prosciuto

    22 Funghi

    23

    24

    25

    26

    27 Größe

    28

    29

    30 groß

    31

    32 mittel

    33

    34 klein

    35

    36

    37

    38 Extra Beilagen

    39

    40

    41 Käse

    42

    43 Zwiebeln

    44

    45 Tomaten

    46

    47

    48

    49 Bemerkungen

    50

    51

    52

    53

    54 Anmeldename

    55

    56

    29

  • 4 Lösungen der Aufgaben

    57

    58 Passwort

    59

    60

    61

    62

    63

    64

    65

    66

    67

    68

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

    1

  • 41 #echo "$sql";

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

    43 if ($result) {

    44 echo "Ihre Bestellung wurde erfolgreich gespeichert:";

    45 echo ""; print_r($_POST); echo "";

    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 @[email protected]@CHARACTER_SET_CLIENT */;

    6 /*!40101 SET @[email protected]@CHARACTER_SET_RESULTS */;

    7 /*!40101 SET @[email protected]@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

  • 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 [email protected]_CHARACTER_SET_CLIENT */;

    74 /*!40101 SET [email protected]_CHARACTER_SET_RESULTS */;

    75 /*!40101 SET [email protected]_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 @[email protected]@CHARACTER_SET_CLIENT */;

    14 /*!40101 SET @[email protected]@CHARACTER_SET_RESULTS */;

    15 /*!40101 SET @[email protected]@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

  • 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

  • 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 [email protected]_CHARACTER_SET_CLIENT */;

    90 /*!40101 SET [email protected]_CHARACTER_SET_RESULTS */;

    91 /*!40101 SET [email protected]_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

    (b) Das PHP-Skript lautet

    1

  • 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 "

    25 ";

    26 ?>

    Aufgabe 3.4 (a) und (b) Die Datenbank1 -- 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 @[email protected]@CHARACTER_SET_CLIENT */;

    14 /*!40101 SET @[email protected]@CHARACTER_SET_RESULTS */;

    15 /*!40101 SET @[email protected]@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

  • 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

  • 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 [email protected]_CHARACTER_SET_CLIENT */;

    97 /*!40101 SET [email protected]_CHARACTER_SET_RESULTS */;

    98 /*!40101 SET [email protected]_COLLATION_CONNECTION */;

    Das Startskript ist die folgende Datei login.php:

    1

    40

  • 4 Lösungen der Aufgaben

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

    1

    2

    3

    4

    5 Editierung einer Datenbank

    6

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

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

    9

    10

    11

    12

    13

  • 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

    85 ID

    86 Vorname

    87 Nachname

    88 Ort

    89

    90

    91

  • 4 Lösungen der Aufgaben

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

    105

    106

    107

    108

    109

    110 ";

    111 }

    112 echo "

    113

    114

    115

    116

    117

    118

    119

    120

    121

    122

    123 ";

    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

  • 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

    http://php.net/manual/de/http://sandbox.onlinephpfunctions.comhttp://www.w3c.org/http://www.edition-w3c.de/http://www.edition-w3c.de/http://www.w3c.de/http://www.w3c.at/

    Vorbemerkungen zu dieser LerneinheitDatenbankzugriffe übers Web: HTML & PHP & SQLZugriff von PHP auf MySQLAnzeigen von Daten im BrowserInformationen über gerade abgesetzte SQL-BefehleSQL Injection entschärfen mit escape_stringZusammenfassung

    Datenbankinteraktionen mit dem BrowserEintragen-Skript mit unformatierten AusgabenEintragen-Skript mit Funktionen und FormatierungenZusammenfassung

    ÜbungsaufgabenLösungen der AufgabenAbbildungsverzeichnis