Quakenet/#php Tutorial

Hinweis: Wenn sie diese Seite von einer externen URL aufgerufen haben achten sie darauf das alle Kapitel aufeinander aufbauen. Stellen sie daher sicher dass sie alle vorherigen Kapitel gelesen haben, da sie sonst relevante Informationen übersehen.

Gästebuch

  1. Eigenes Gästebuch schreiben
  2. Aufbaue der Tabelle in MySQL
  3. Aufbau des PHP-Skriptes
  4. Code zum Anzeigen der Beiträge
  5. Code zum hinzufügen von neuen Beiträgen
  6. Nachteile vom Gästebuch-Skript

1. Eigenes Gästebuch schreiben

Ein Gästebuch ist vergleichbar mit einem Newsskript nur dass die Beiträge von den Benutzern kommen, nicht vom Administrator der Seite. Jedoch liegen auch hier die Probleme denn die Benutzer können jeden Text eingeben den sie wollen. Dies kann dazu führen das in den Gästebucheinträgen Texte stehen die man lieber nicht haben möchte. Daher müssen alle Eingaben die vom Benutzer kommen geprüft werden. Des Weiteren muss man sich auch gegen Spam schützen.

2. Aufbaue der Tabelle in MySQL

Die Tabelle in MySQL wird einen vergleichbaren Aufbau wie die News-Tabelle haben. Neben den eigentlichen Text wird der Name und das Datum gespeichert. Daher wird die Tabelle 4 Spalten besitzen.

  1. ID - Die normale Identifikationsspalte vom Typ INT.

  2. Datum - Der Zeitpunkt wann der Eintrag hinzugefügt wurde. Typ ist entsprechend DATETIME.

  3. Autor - Der Name desjenigen der den Eintrag geschrieben hat. Ein VARCHAR(50) wird wohl reichen.

  4. Inhalt - Der eigentliche Text des Eintrags. Dieser wird entsprechend in einem TEXT-Feld gespeichert.

Der entsprechende SQL-Query sieht wie folgt aus.

CREATE TABLE Guestbook (
    ID INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
    Autor VARCHAR(50) NOT NULL,
    Datum DATETIME NOT NULL,
    Inhalt TEXT NOT NULL
);

Analog kann man auch über phpMyAdmin die Tabelle hinzufügen.

3. Aufbau des PHP-Skriptes

Das PHP-Skript vom Gästebuch muss zwei Aufgaben durchführen. Einmal muss es aus der Datenbank die Datensätze auslesen. Des Weiteren muss es Daten aus einem Formular verarbeiten und entsprechend neue Datensätze in die Datenbank eintragen. Dies unterscheiden wir anhand der $_SERVER['REQUEST_METHOD']-Variable. Bei einem POST-Request versuchen wir die Daten aus dem Formular in die Datenbank hinzuzufügen, bei allen anderen Requesttypen (insbesondere GET-Requests) zeigen wir das Gästebuch und ein Formular für neue Gästebucheinträge an.

<?php
error_reporting
(E_ALL);
ini_set('display_errors'1);

if (
'POST' == $_SERVER['REQUEST_METHOD']) {
    
// Code zum hinzufügen in der DB
} else {
    
// Anzeigen von Gästebuchbeiträgen und dem Formular.
}
?>

Da wir natürlich mit MySQL arbeiten wollen bauen wir eine Verbindung zur Datenbank auf. Außerdem laden wir noch HTML-Header- und HTML-Footer-Code via include oder besser via readfile.

<?php
error_reporting
(E_ALL);
ini_set('display_errors'1);

$db = @new mysqli('localhost''username''password''database');
if (
mysqli_connect_errno()) {
    die(
'Konnte keine Verbindung zur Datenbank aufbauen: '.mysqli_connect_error().'('.mysqli_connect_errno().')');
}

readfile('header.html'); // enthält auch das <body>-tag

if ('POST' == $_SERVER['REQUEST_METHOD']) {
    
// Code zum hinzufügen in der DB
} else {
    
// Anzeigen von Gästebuchbeiträgen und dem Formular.
}

readfile('footer.html');
?>

Nun können wir mit den Teilbereichen anfangen.

4. Code zum Anzeigen der Beiträge

Der PHP-Code zum Anzeigen der Beiträge ist vergleichbar mit dem Code aus dem Newsskript. Daher gibt es nicht viel zu erklären.

<?php
// [...]

} else {
    
$sql 'SELECT
                Datum,
                Autor,
                Inhalt
            FROM
                Guestbook
            ORDER BY
                Datum DESC'
;
    
$result $db->query($sql);
    if (!
$result) {
        die(
'Der Query konnte nicht ausgeführt werden: '.$db->error);
    }
    if (
$result->num_rows) {
        while (
$row $result->fetch_assoc()) {
            echo 
'<div class="beitrag">'."\n";
            echo 
'    <span class="autor">'.htmlspecialchars($row['Autor'])."</span>\n";
            echo 
'    <span class="datum">'.$row['Datum']."</span>\n";
            echo 
"    <p>\n";
            echo 
nl2br(htmlspecialchars(preg_replace('~\S{30}~''\0 '$row['Inhalt'])));
            echo 
"    </p>\n";
            echo 
"</div>\n";
        }
    } else {
        echo 
'<p class="info">Es sind keine Gästebucheinträge vorhanden</p>';
    } 
    
readfile('formular.html');
}

// [...]
?>

Die Funktion htmlspecialchars dient dazu besondere HTML-Zeichen wie < zu escapen damit sie als Text angezeigt werden und nicht irgendwie unseren HTML-Code durcheinander bringen. Dies ist nötig da die Daten von Benutzer kommen und die sehr kreativ sind wenn es darum geht ein Gästebuch mit Müll zu füllen. Die Funktion nl2br fügt hinter jedem Zeilenumbruch im Beitrag ein HTML-Zeilenumbruch <br /> ein. Dies ist nötig da der Text in der Datenbank nur normale Zeilenumbrüche mittels \n enthält. Der preg_replace-Ausdruck ist nicht einfach zu erklären da er ein regulären Ausdruck enthält. Reguläre Ausdrücke wird jedoch erst in einem späteren Kapitel durchgenommen. Um es kurz zu machen: dieser preg_replace Ausdruck fügt in Wörter die länger als 30 Zeichen sind hinter jedem 30. Zeichen ein Leerzeichen ein. Damit verhindern wir dass Spaßvögel sowas wie AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA... eingeben und die Internetseite unnötig breit machen.

Die formular.html-Datei enthält den Code für ein Formular damit die Besucher etwas ins Gästebuch schreiben können.

<form action="guestbook.php" method="post">
    <fieldset>
        <legend>Ins Gästebuch Eintragen</legend>
        <label>Name: <input type="text" name="Autor" /></label>
        <label>Text: <textarea name="Inhalt" rows="6" cols="40"></textarea></label>
        <label>{FRAGE}: <input type="text" name="Antwort"/></label>
        <input type="submit" name="formaction" value="Eintragen" />
    </fieldset>
</form>

Wie man sieht gehen wir davon aus dass das Gästebuch unter der Datei guestbook.php erreichbar ist. Der Bereich {FRAGE} dient dazu Spam im Gästebuch zu verhindern, dazu später mehr.

Es ist klar dass das Gästebuch noch leer ist und wir beim testen nur die Anzeige Es sind keine Gästebucheinträge vorhanden bekommen. Daher nun der Code zum hinzufügen von Beiträgen.

5. Code zum hinzufügen von neuen Beiträgen

Aus dem Formular kriegen wir die Felder Autor, Inhalt, Antwort und formaction. Daher prüfen wir zuerst ob wir diese Daten auch wirklich bekommen, denn es könnte sein dass ein Benutzer ein eigenes Formular verwendet.

<?php
// [...]

if ('POST' == $_SERVER['REQUEST_METHOD']) {
    if (!isset(
$_POST['Autor'], $_POST['Inhalt'], $_POST['Antwort'], $_POST['formaction'])) {
        die (
'Benutzen sie nur Formulare von der Homepage.');
    }
} else {

// [...]
?>

Nun machen wir einfache Textabfragen indem wir gucken ob der Benutzer überhaupt was eingegeben hat. Dazu verwenden wir einmal die Funktion trim um Leerzeichen vor und nach der Eingabe zu löschen und vergleichen den Rückgabewert mit '' und wissen dann ob was eingegeben wurde oder nicht.

<?php
// [...]

if ('POST' == $_SERVER['REQUEST_METHOD']) {
    if (!isset(
$_POST['Autor'], $_POST['Inhalt'], $_POST['Antwort'], $_POST['formaction'])) {
        die (
'Benutzen sie nur Formulare von der Homepage.');
    }
    if ((
'' == $autor trim($_POST['Autor'])) or 
            (
'' == $inhalt trim($_POST['Inhalt'])) or
            (
'' == $antwort trim($_POST['Antwort']))) {
        die (
'Bitte füllen sie das Formular vollständig aus.');
    }
} else {

// [...]
?>

Nun prüfen wir das Antwort-Feld. Dabei erwarten wir eine bestimmte Antwort von dem Benutzer. Der {FRAGE}-Teil in dem Formular muss entsprechend geändert werden. Dies ist vergleichbar mit einem CAPTCHA jedoch viel simpler. Anhand dieser Eingabe schließen wir Spam-Bots aus die Gästebücher mit Müll zuspammen. Hier reicht es wenn man nach einen einzelnen Wort fragt, dass der Benutzer eintragen soll.

<?php
// [...]

if ('POST' == $_SERVER['REQUEST_METHOD']) {
    if (!isset(
$_POST['Autor'], $_POST['Inhalt'], $_POST['Antwort'], $_POST['formaction'])) {
        die (
'Benutzen sie nur Formulare von der Homepage.');
    }
    if ((
'' == $autor trim($_POST['Autor'])) or 
            (
'' == $inhalt trim($_POST['Inhalt'])) or
            (
'' == $antwort trim($_POST['Antwort']))) {
        die (
'Bitte füllen sie das Formular vollständig aus.');
    }
    if (
'' != $antwort) { // entsprechend Anpassen, sowie den {FRAGE}-Teil im Formular
        
die ('Sie müssen die Frage richtig beantworten.');
    }
} else {

// [...]
?>

Beachtet dass man den Besuchern nicht zu viel abverlangt, insbesondere Groß- und Kleinschreibungen. Für den Fall dass man dann doch Spam im Gästebuch hat hat man ganz andere Probleme als Spam im Gästebuch, denn dann hat jemand speziell ein Skript geschrieben um genau dieses Gästebuch zuzuspammen und dann ist es etwas persönliches gegen euch und hat nichts mehr mit dem Hintergrundrauschen von Spam im Internet zu tun.

Nun können wir die Daten in die Datenbank speichern. Am einfachsten wäre es den INSERT-Befehl mit Stringverkettung aus Strings und den Variablen zusammenzubauen. Dies wird problematisch da die Variablen beliebigen Inhalt haben können, insbesondere '-Zeichen die den SQL-Query kaputt machen. Dies nennt man auch SQL-Injection, da die Besucher auch versuchen SQL-Befehle wie DROP TABLE Guestbook; einzuschleusen. Daher muss man die Daten irgendwie verändern/schützen. In der mysql-Extension wurde dies mit der mysql_real_escape_string-Funktion gemacht.

<?php
$sql 
'INSERT INTO
            Guestbook(Autor,Datum,Inhalt)
        VALUES
            ("'
.mysql_real_escape_string($autor).'",
             NOW(),
             "'
.mysql_real_escape_string($inhalt).'");';
?>

In MySQLi verwenden wir dafür Prepared Statements. Dies sind SQL-Queries die Platzhalter enthalten (einfache ?-Zeichen). Durch entsprechende Funktionen werden diese Platzhalter dann mit Werten gefüllt. Diese Funktionen sorgen dann dafür dass die Inhalte entsprechend verarbeitet werden damit sie keinen Unsinn anstellen und den SQL-Query nicht zerstören.

Um so ein prepared statement zu erstellen wird die Methode prepare() verwendet (mysqli_prepare). Dabei geben ?-Zeichen die Platzhalter an, die wir dann später mit Daten füllen.

<?php
// [...]

if ('POST' == $_SERVER['REQUEST_METHOD']) {
    if (!isset(
$_POST['Autor'], $_POST['Inhalt'], $_POST['Antwort'], $_POST['formaction'])) {
        die (
'Benutzen sie nur Formulare von der Homepage.');
    }
    if ((
'' == $autor trim($_POST['Autor'])) or 
            (
'' == $inhalt trim($_POST['Inhalt'])) or
            (
'' == $antwort trim($_POST['Antwort']))) {
        die (
'Bitte füllen sie das Formular vollständig aus.');
    }
    if (
'' != $antwort) { // entsprechend Anpassen, sowie den {FRAGE}-Teil im Formular
        
die ('Sie müssen die Frage richtig beantworten.');
    }
    
$sql 'INSERT INTO
                Guestbook(Autor, Datum, Inhalt)
            VALUES
                (?, NOW(), ?)'
;
    
$stmt $db->prepare($sql);
    if (!
$stmt) {
        die (
'Es konnte kein SQL-Query vorbereitet werden: '.$db->error);
    }
} else {

// [...]
?>

Da auch ein prepare() fehlschlagen kann müssen wir ihn auf Fehler überprüfen. Die Methode liefert wenn alles gut ist ein MySQLi_STMT-Objekt zurück, mit denen wir dann arbeiten. Für unsere Zwecke sind dies die bind_param()- und execute()-Methoden.

<?php
// [...]

if ('POST' == $_SERVER['REQUEST_METHOD']) {
    if (!isset(
$_POST['Autor'], $_POST['Inhalt'], $_POST['Antwort'], $_POST['formaction'])) {
        die (
'Benutzen sie nur Formulare von der Homepage.');
    }
    if ((
'' == $autor trim($_POST['Autor'])) or 
            (
'' == $inhalt trim($_POST['Inhalt'])) or
            (
'' == $antwort trim($_POST['Antwort']))) {
        die (
'Bitte füllen sie das Formular vollständig aus.');
    }
    if (
'' != $antwort) { // entsprechend Anpassen, sowie den {FRAGE}-Teil im Formular
        
die ('Sie müssen die Frage richtig beantworten.');
    }
    
$sql 'INSERT INTO
                Guestbook(Autor, Datum, Inhalt)
            VALUES
                (?, NOW(), ?)'
;
    
$stmt $db->prepare($sql);
    if (!
$stmt) {
        die (
'Es konnte kein SQL-Query vorbereitet werden: '.$db->error);
    }
    
$stmt->bind_param('ss'$autor$inhalt);
    if (!
$stmt->execute()) {
        die (
'Query konnte nicht ausgeführt werden: '.$stmt->error);
    }
    echo 
'<p class="info">Gästebucheintrag hinzugefügt. <a href="guestbook.php">Zurück zum Gästebuch</a>.</p>';
} else {

// [...]
?>

Die zwei s-Zeichen geben an das 2 Strings Variablen folgen (für die Spalten Autor und Inhalt). Für die Methode bind_param() existieren noch die Zeichen i für Integerzahlen, d für Floatzahlen (double) und b für Binärdaten. Wir werden Hauptsächlich nur i und s verwenden. Danach wird mit der execute()-Methode der Query ausgeführt und dann geben wir nur noch ein Infotext aus. Da auch die execute()-Methode fehlschlagen kann wird hier der Rückgabewert geprüft. Ist dieser false wird entsprechend eine Fehlermeldung ausgegeben.

Beim Testen kann es passieren dass wir einen Webserver mit magic quotes haben. Da wir selber uns um das richtige escapen kümmern laden wir in unserem PHP-Skript den Code der die Backslashes von magic quotes löscht. Dies machen wir so weit oben wie möglich.

<?php
error_reporting
(E_ALL);
ini_set('display_errors'1);

include 
'magic_quotes_remove_slashes.php'// oder wie man seine Datei genannt hat
// oder den Quellcode direkt einfügen.

// [...]
?>

Somit ist unser Skript nun fertig.

6. Nachteile vom Gästebuch-Skript

Auch wenn es viele Angriff abwehrt ist es nicht total sicher. Insbesondere kann ein Benutzer mehrere Gästebucheinträge auf einmal hinzufügen. Dies kann man versuchen zu unterbinden wenn die IP-Adresse mitgespeichert wird und vorm Eintragen geprüft wird ob ein Datensatz bereits existiert oder nicht. Außerdem fehlt eine Blätterfunktion und alle Einträge werden auf einer Seite dargestellt.

Fragen zum Kapitel

Keine Fragen zum Kapitel vorhanden

Zurück zu Weiter zu
Copyright © bei den OPs von #php.de/QuakeNet Valid XHTML 1.0 Strict Valid CSS!