Die Datei index.php
soll die Anfragen an die einzelnen Kommandos weiterleiten. Ist kein Kommando angegeben, so soll eine Weiterleitung an das Read-Kommando durchgeführt werden. Unser Front-Controller wird an der oben markierten Stelle wie folgt erweitert.
Es wird zunächst ein Array angelegt, in welchem alle gültigen Kommandos mit der Datei, die aufgrund dieses Kommandos geladen wird, verzeichnet sind. Dann wird, wenn das Kommando gefunden wird, die entsprechende .php
-Datei eingefügt. Es wird ein Array mit allen Kommandos genutzt und nicht direkt die Datei eingebunden, um einem Angreifer keine Möglichkeit zu geben, ein nicht-definiertes Kommando aufzurufen und damit fremden Code in unserem System auszuführen.
Hier der vollständige Einschub:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
// ... if ($loginSuccessfull){ $commandlist = ['create' => 'create.php', 'read' => 'read.php', 'update' => 'update.php', 'delete' => 'delete.php' ]; if (!isset($_GET['command'])) include($commandlist['read']); else include($commandlist[$_GET['command']]); } else { // ... |
Da das Read-Kommando das Standardkommando ist, wird dieses zuerst entwickelt. Eine Datei read.php
wird angelegt und mit folgendem Inhalt befüllt:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
<?php if (!isset($frontcontrollerVisited) || $frontcontrollerVisited == false) die(); ?><!DOCTYPE html> <html lang="de"> <head> <meta charset="utf-8"> <title>Adressverwaltung</title> <style> table {border-collapse: collapse;} table, td, th {border: 1px solid black;} th {background-color: green; color: white;} tr:hover {background-color: lightgrey;} </style> </head> <body> <h1>Adressverwaltung</h1> <table> <tr> <th>Vorname und Name</th> <th>Straße und Hausnummer</th> <th>PLZ und Ort</th> <th>Aktionen</th> </tr> <?php $pdo = new PDO("mysql:host=$dbhost;dbname=$dbname", $dbuser, $dbpasswd); $statement = $pdo->prepare("SELECT `id`,`name`,`strasse`,`ort` FROM `addresses`"); if($statement->execute()){ while ($row = $statement->fetch()) { echo ("<tr><td>$row[1]</td>". "<td>$row[2]</td>". "<td>$row[3]</td>". "<td><a href='?command=update&id=$row[0]' >Aktualisieren</a>,". "<a href='?command=delete&id=$row[0]' >Löschen</a></td>". "</tr>"); } } else { echo ("SQL Fehler"); } $statement->closeCursor(); ?> </table> <a href="?command=create">Neue Adresse anlegen</a> </body> </html> |
Die read.php
blockt in der ersten Zeile wieder den direkten Zugriff, so dass das Read-Kommando immer über den Front-Controller aufgerufen werden muss. Ist alles okay, so wird eine HTML-Seite ausgegeben. Um eine schönere Tabelle zu erzeugen, beinhaltet diese HTML-Datei etwas CSS. Letztendlich stellt sie eine große Tabelle dar. Die Inhalte der Tabelle werden Zeile für Zeile mit Hilfe eines Iterieren über die Ergebnisse eines PDO-Statements generiert. Besonders wichtig ist hier die letzte Spalte der Tabelle. Hier befinden sich Links zu dem Aktualisieren- und Löschen-Kommando, die mit Hilfe dem Statement generiert werden. Unter der Tabelle befindet sich ein Link, welcher es ermöglicht, das Create-Kommando aufzurufen.
Die Datei create.php
für das Create-Kommando sieht wie folgt aus:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
<?php if (!isset($frontcontrollerVisited) || $frontcontrollerVisited == false) die(); if (!isset($_POST['name'])) { // GET: Formular ausgeben ?><!DOCTYPE html> <html lang="de"> <head> <meta charset="utf-8"> <title>Adressverwaltung: Adresse anlegen</title> </head> <body> <h1>Adressverwaltung: Adresse anlegen</h1> <form action="?command=create" method="POST"> Vorname und Nachname:<br> <input type="text" name="name"> <br> Straße und Hausnummer:<br> <input type="text" name="strasse"> <br> Postleitzahl und Ort:<br> <input type="text" name="ort"> <br><br> <input type="submit" value="Anlegen"> </form> </body> </html> <?php } else { // POST: Anlegen der Adresse in der Datenbank $name = htmlspecialchars($_POST['name']); $strasse = htmlspecialchars($_POST['strasse']); $ort = htmlspecialchars($_POST['ort']); $pdo = new PDO("mysql:host=$dbhost;dbname=$dbname", $dbuser, $dbpasswd); $statement = $pdo->prepare("INSERT INTO `addresses` (`name`, `strasse`, `ort`) VALUES (?,?,?)"); if(!$statement->execute([$name,$strasse,$ort])) { echo ("SQL Fehler"); } $statement->closeCursor(); header ('Location: .'); } ?> |
In der ersten Zeile der Datei findet sich wieder die Sperre, dass die Datei nur über den Front-Controller aufgerufen werden darf. Was dann folgt ist eine If-Verzweigung zwischen zwei Möglichkeiten: Einmal die Anforderung der Seite mit einer GET-Anfrage und einmal das Schicken der neuen Werte mit einem POST-Request. Unterschieden wird zwischen beiden Möglichkeiten, indem geprüft wird, ob das $_POST
-Array das Feld name
enthält:
- Wird die Seite mit einem
GET
aufgerufen, so wird ein Formular ausgegeben. Das Formular wird über ein POST abgeschickt, wobei über einen GET-Parameter noch angegeben wird, dass das Create-Kommando weiterhin genutzt werden soll. - Wird die Seite mit einem
POST
aufgerufen, werden zunächst die POST-Variablen mit der Funktionhtmlspecialchars()
} in Strings die HTML-sicher sind verwandelt, so dass kein Hacker fremden Code in die Seite einschleusen kann. Mittels eines PDO-Prepared-Statements werden diese Variablen dann in die Datenbank geschrieben. Die ID des Datensatzes wird vom Datenbankserver selbst erzeugt. Die letzte Zeile des Else-Zweiges leitet den Browser über den HTTP-Header auf die Hauptseite der Adressverwaltung um, wo der Nutzer daraufhin die neu eingegebene Adresse sehen wird.
Die beiden weiteren Kommandos sind Anpassungen der schon vorhandenen Kommandos. Das Aktualisieren-Kommando ließt zuvor die Daten aus der Datenbank, um die Formularfelder vorzubelegen. Weiterhin wird kein INSERT INTO
-SQL-Statement verwendet, sondern ein UPDATE
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 |
<?php if (!isset($frontcontrollerVisited) || $frontcontrollerVisited == false) die(); if (!isset($_POST['name'])) { // GET: Formular mit vorbelegten Variablen ausgeben $id = htmlspecialchars($_GET['id']); $pdo = new PDO("mysql:host=$dbhost;dbname=$dbname", $dbuser, $dbpasswd); $statement = $pdo->prepare("SELECT `id`,`name`,`strasse`,`ort` FROM `addresses` WHERE `id`= ?"); if(!$statement->execute([$id])) { echo ("SQL Fehler"); } else { $row = $statement->fetch(); $name = $row['1']; $strasse = $row['2']; $ort = $row['3']; ?><!DOCTYPE html> <html lang="de"> <head> <meta charset="utf-8"> <title>Adressverwaltung: Adresse aktualisieren</title> </head> <body> <h1>Adressverwaltung: Adresse aktualisieren</h1> <form action="?command=update&id=<?=$id?>" method="POST"> Vorname und Nachname:<br> <input type="text" name="name" value="<?=$name?>"> <br> Straße und Hausnummer:<br> <input type="text" name="strasse" value="<?=$strasse?>"> <br> Postleitzahl und Ort:<br> <input type="text" name="ort" value="<?=$ort?>"> <br><br> <input type="submit" value="Aktualisieren"> </form> </body> </html> <?php } $statement->closeCursor(); } else { // POST: Update der Adresse in der Datenbank $id = htmlspecialchars($_GET['id']); $name = htmlspecialchars($_POST['name']); $strasse = htmlspecialchars($_POST['strasse']); $ort = htmlspecialchars($_POST['ort']); $pdo = new PDO("mysql:host=$dbhost;dbname=$dbname", $dbuser, $dbpasswd); $statement = $pdo->prepare("UPDATE `addresses` SET `name`= ?, `strasse`= ?, `ort` = ? WHERE `id`= ?"); if(!$statement->execute([$name,$strasse,$ort,$id])) { echo ("SQL Fehler"); } $statement->closeCursor(); header ('Location: .'); } ?> |
Das Löschen-Kommando ist an das Aktualisieren-Kommando angelehnt. Es stellt eine Sicherheitsfrage, ob der Datensatz gelöscht werden soll. Dazu werden seine Werte nochmals angezeigt:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 |
<?php if (!isset($frontcontrollerVisited) || $frontcontrollerVisited == false) die(); if (!isset($_POST['sicherheitsfrage'])) { // GET: Sicherheitsfrage $id = htmlspecialchars($_GET['id']); $pdo = new PDO("mysql:host=$dbhost;dbname=$dbname", $dbuser, $dbpasswd); $statement = $pdo->prepare("SELECT `id`,`name`,`strasse`,`ort` FROM `addresses` WHERE `id`= ?"); if(!$statement->execute([$id])) { echo ("SQL Fehler"); } else { $row = $statement->fetch(); $name = $row['1']; $strasse = $row['2']; $ort = $row['3']; ?><!DOCTYPE html> <html lang="de"> <head> <meta charset="utf-8"> <title>Adressverwaltung: Adresse löschen</title> </head> <body> <h1>Adressverwaltung: Adresse löschen</h1> <form action="?command=delete&id=<?=$id?>" method="POST"> <input type="hidden" name="sicherheitsfrage" value="ok"> Vorname und Nachname:<br> <?=$name?> <br> Straße und Hausnummer:<br> <?=$strasse?> <br> Postleitzahl und Ort:<br> <?=$ort?> <br><br> Wirklich löschen? <br><br> <input type="submit" value="Löschen"> </form> </body> </html> <?php } $statement->closeCursor(); } else { // POST: Löschen der Adresse in der Datenbank $id = htmlspecialchars($_GET['id']); $pdo = new PDO("mysql:host=$dbhost;dbname=$dbname", $dbuser, $dbpasswd); $statement = $pdo->prepare("DELETE FROM `addresses` WHERE `id`= ?"); if(!$statement->execute([$id])) { echo ("SQL Fehler"); } $statement->closeCursor(); header ('Location: .'); } ?> |