Kontaktformular Tutorial

  • Hallo zusammen,


    wir, Stef und JR Cologne, haben uns dazu entschieden, gemeinsam ein paar Tutorials zu verfassen. Für das erste Tutorial haben wir uns überlegt, uns mit der Erstellung eines einfachen Kontaktformulars mit PHP auseinanderzusetzen.


    Wir hoffen, euer Interesse wecken zu können und würden uns sehr freuen, wenn wir dem einen oder anderen hiermit ein wenig helfen können.

    Anforderungen

    Schwierigkeitsgrad: leicht

    Kenntnisse: HTML & PHP Basics

    Abhängigkeiten: PHPMailer in Version 6

    Setup/Einrichtung

    Wir starten mit einer kurzen Einrichtung: Für unser Kontaktformular benötigen wir die Mailer-Klasse PHPMailer, welche wir für die Versendung der E-Mail nutzen werden.


    Um den PHPMailer nutzen zu können, müssen wir diesen erstmal herunterladen, damit wir die Abhängigkeit dann im Code einbinden können. Auch wenn die Möglichkeit einer Installation über Composer zur Verfügung steht, nutzen wir diese der Einfachheit halber nicht.


    Stattdessen laden wir uns die aktuelle Version einfach im Zip-Format von GitHub herunter.

    Auf der Übersichtsseite mit allen Releases müssen wir nur die gewünschte Version auswählen und dann den Quellcode des PHPMailers herunterladen. In unserem Beispiel nutzen wir die Version 6.0.3.


    Innerhalb unseres Projektordners erstellen wir anschließend einen Ordner für den PHPMailer, sodass unsere Ordnerstruktur ungefähr so aussieht:



    Nur die Dateien datenUeberpruefung.php und kontaktformular.php sind dabei unsere eigenen Dateien. Der Rest kommt vom PHPMailer und sollte möglichst nicht angerührt werden.


    So, das wäre es dann auch schon. Wir sind startklar.

    Was gibt es allgemein zu beachten?

    Bevor wir mit unserem Formular starten, müssen wir erst noch ein paar allgemeine Dinge klären:


    Formulardaten können über zwei Kanäle empfangen werden. Über GET und POST. Der Kanal, über den das Formular abgesendet wird, legt man mit dem Attribut method fest. Diesem geben wir entweder post oder get als Wert mit. Für Kontaktformulare sollte immer POST verwendet werden, mehr dazu gleich.


    Des Weiteren muss jede Usereingabe als potentiell gefährlich angesehen werden. Ebenso muss man darauf achten, dass man die Formulardaten immer mit der geeigneten Funktion filtern muss, um z.B. XSS-Attacken zu verhindern. Meistens ist das htmlspecialchars().

    Unterschied POST/GET

    Der wesentliche Unterschied zwischen den beiden Methoden für die Übermittlung von Formulardaten GET und POST ist, dass POST-Daten praktisch verdeckt übermittelt werden und nicht direkt für den User sichtbar sind.


    Bei der Methode GET werden die Daten hingegen über die URL übertragen und sind damit in der Adresszeile einsehbar. Dies ist in den meisten Fällen nicht erwünscht, weshalb im Zweifel immer POST verwendet werden sollte.


    Lediglich bei Anwendungsfällen, wie z.B. einer Suchfunktion, macht es Sinn, die Daten über den GET-Kanal zu übertragen. Ansonsten sollte man bei Formularen stets die Finger von GET lassen.


    Unabhängig von Formularen haben sogenannte GET-Parameter, auch URL-Parameter genannt, zwar noch andere Anwendungsfälle, aber diese sind dann meist abseits von Formularen. Von daher gehen wir darauf jetzt nicht näher ein.


    Stattdessen schauen wir uns noch kurz ein Beispiel für die Nutzung der beiden Kanäle an.

    Achtung: Die Beispiele sind aufs Wesentliche heruntergebrochen und sollten so nicht verwendet werden.

    GET:

    PHP: get.php
    1. <?php
    2. if (isset($_GET['query'])) {
    3. echo 'Du hast nach ' . $_GET['query'] . ' gesucht.';
    4. }
    5. ?>
    6. <form action="" method="get">
    7. <input type="text" name="query">
    8. <input type="submit" name="submit" value="Suchen">
    9. </form>


    URL: http://example.com/get.php?query=test



    POST:


    PHP: post.php
    1. <?php
    2. if (isset($_POST['query'])) {
    3. echo 'Du hast nach ' . $_POST['query'] . ' gesucht.';
    4. }
    5. ?>
    6. <form action="" method="post">
    7. <input type="text" name="query">
    8. <input type="submit" name="submit" value="Suchen">
    9. </form>


    URL: http://example.com/post.php


    Der wesentliche Unterschied ist direkt an der URL zu erkennen. Bei POST findet sich keinerlei Hinweis auf die versendeten Daten, bei GET schon.

  • kontaktformular.php

    Nun starten wir endlich mit unserem Kontaktformular und der Datei kontaktformular.php. Diese Datei stellt praktisch die Seite dar, welche das Kontaktformular anzeigt und auch verarbeitet, allerdings haben wir die Verarbeitung in die separate Datei datenUeberpruefung.php ausgelagert.


    Diese binden wir ganz am Anfang der Datei kontaktformular.php ein:


    PHP: kontaktformular.php
    1. <?php
    2. require_once 'datenUeberpruefung.php';
    3. ?>


    Anschließend folgt dann das HTML gemischt mit ein wenig PHP zur Darstellung des Kontaktformulars. Wichtig zu erwähnen ist hierbei, dass wir Bootstrap 4 für das Design der Seite nutzen, damit es halbwegs nach was aussieht.


    Hier ist der gesamte Inhalt der Datei kontaktformular.php:


    In Zeile 11 wird wie angesprochen Bootstrap 4 über den CDN eingebunden.


    Darauf stehen uns dann zahlreiche Klassen zur Verfügung. Zuersteinmal ist das die container-Klasse, welche für die horizontale Zentrierung unseres Kontaktformulars sorgt.


    Damit das Formular nach oben und unten ebenfalls ein wenig Platz bekommt, nutzen wir die Klasse py-5. Innerhalb des Formulars befinden sich dann jeweils div-Container mit der Klasse form-group, welche immer ein Formularfeld enthalten.


    Dieses besteht aus einem label sowie dem entsprechenden input-Feld. Letzteres bekommt die Klasse form-control.


    Abgeschlossen wird unser Formular mit einem Submit-Button mit der Klasse btn sowie btn-primary.


    Dies alles sorgt letztendlich dafür, dass wir dank Bootstrap eine relativ schlichte aber schicke Darstellung unseres Formulars erreichen, ohne auch nur eine Zeile CSS geschrieben haben zu müssen.


    Ansonsten fällt bei den Formularfeldern noch auf, dass wir stets ein wenig PHP-Code innerhalb des value-Attributs eines input-Feldes bzw. innerhalb die textarea geschrieben haben. Dieser sieht immer ungefähr so aus, in dem Fall kommt er vom Formularfeld für den Namen:


    PHP: kontaktformular.php
    1. <?php echo !empty($name) ? $name : '' ?>


    Dieser sorgt schlicht und ergreifend dafür, dass wir nach dem Absenden des Formulars alle ausgefüllten Daten behalten und nicht alles nochmal neu eingeben müssen, sollte noch irgendwo ein Fehler bestehen.


    Um genau zu sein, versteckt sich dahinter der sogenannte Ternary-Operator, welcher eine Abkürzung für eine normale if-Abfrage darstellt.


    Der obige Code ist im Prinzip also exakt mit folgendem Code gleichzusetzen:

    PHP
    1. <?php
    2. if (!empty($name)) {
    3. echo $name;
    4. } else {
    5. echo '';
    6. }
    7. ?>


    Noch ein weiterer kleiner PHP-Code lässt sich nach dem Formular innerhalb des Containers finden:

    PHP: kontaktformular.php
    1. <?php
    2. if (!empty($errors) && count($errors) > 0 && !$success) {
    3. echo implode('', $errors);
    4. } else if (!empty($success) && count($errors) === 0) {
    5. echo $success;
    6. }
    7. ?>


    Dieser ist für die Ausgabe von möglichen Fehlern bzw. Erfolgsmeldungen zuständig.

    Zu Beginn überprüfen wir, ob überhaupt Einträge in unserem Fehler-Array vorhanden sind und ob die Variable $success einen Wert beinhaltet, der von PHP als false behandelt wird.


    Ist dies der Fall, werden die Einträge des Arrays als String aneinandergekettet und ausgegeben.


    Trifft die eben besprochene Bedingung nicht zu, geht es mit der nächsten Bedingung weiter, die durch das else if gekennzeichnet wird. Hierbei überprüfen wir, ob die Variable $success nicht leer ist und ob die Anzahl der Einträge des Fehler-Arrays gleich 0 ist, wir also keine Fehler vorliegen haben.


    Hinweis: Der PHP-Code wird erstmal ohne jeglichen Kontext ein wenig unverständlich sein. Zum kompletten Verständnis der Datei kontaktformular.php ist also ein Blick in die Datei datenUeberpruefung.php zu werfen.

  • datenUeberpruefung.php

    Alles klar, nun geht es weiter mit der Datei datenUeberpruefung.php, welche die Formulardaten verarbeitet.


    Dort wird zuerst der PHPMailer eingebunden und Konstanten für die spätere Fehlerausgabe angelegt. Dies wurde vorgenommen, um das HTML später nicht tausendmal wiederholen zu müssen.


    Zuallererst müssen wir überprüfen, ob das Formular abgesendet wurde. Dies erreichen wir mit der Überprüfung, ob $_POST['submit'] existiert. Dafür verwenden wir die Funktion isset().


    PHP
    1. if (isset($_POST['submit'])) {}


    Existiert $_POST['submit'], wurde das Formular erfolgreich abgesendet. Ist dies der Fall, müssen wir die Formulareingaben in Variablen ablegen und diese filtern, bzw. Sonderzeichen in HTML-Code umwandeln. Dies müssen wir machen, damit das Formular vor XSS-Attacken geschützt ist.

    Dafür verwenden wir die Funktion htmlspecialchars(). Diese wandelt alle Sonderzeichen in ungefährlichen HTML-Code um. Darüber hinaus entfernen wir noch alle Leerzeichen, am Anfang und Ende der Zeichenkette, aus den Eingaben. Dazu verwenden wir die Funktion trim().


    PHP: datenUeberpruefung.php
    1. $name = htmlspecialchars(trim($_POST['name']));
    2. $email = htmlspecialchars(trim($_POST['email']));
    3. $subject = htmlspecialchars(trim($_POST['subject']));
    4. $message = htmlspecialchars(trim($_POST['message']));
    5. $receiver = htmlspecialchars(trim($_POST['receiver'])); // nur zum Testen


    Ist dies erfolgt, müssen wir nun überprüfen, ob die Eingaben unsere gewünschten Kriterien erfüllen. Ist dies nicht der Fall, werden Fehlermeldungen in einem Array gespeichert. Für die Fehlermeldung verwenden wir die Konstanten, welche den HTML-Code der Fehlermeldung beinhalten. Erst mal überprüfen wir, ob die Variablen leer sind. Ist dies der Fall, wird eine Fehlermeldung in das Array hinzugefügt. Ist dies nicht der Fall, überprüfen wir noch die Länge des Strings in den Variablen mit der Funktion strlen(). Erfüllt eine Variable die angeforderte Länge nicht, wird eine Fehlermeldung in das Array hinzugefügt. Bei der E-Mail überprüfen wir zusätzlich, ob die eingegebene E-Mail eine gültige E-Mail-Adresse ist. Dies erreichen wir mit der Funktion filter_var() und dem dazugehörigen Filter FILTER_VALIDATE_EMAIL.



    Nun überprüfen wir nach der Fehlerbehandlung und der Kriterienprüfung, ob das Array, welches die Fehlermeldungen speichert, leer ist. Dies erreichen wir, wenn wir auf das Array die Funktion count() anwenden und überprüfen, ob das Ergebnis, also die Anzahl der Einträge, gleich 0 ist.

    PHP
    1. if (count($errors) === 0) {}


    Liegen keine Fehler vor, erfolgt der Mailversand. Zum Mailversand verwenden wir den PHPMailer. Da wir den PHPMailer bereits am Anfang der Datei eingebunden haben, können wir nun eine Instanz der PHPMailer-Klasse erstellen und setzen den Charset, den Absender sowie Empfänger, den Betreff und den Inhalt der E-Mail. Darüber hinaus überprüfen wir zum Schluss noch, ob der Mailversand erfolgreich war. Ist dies der Fall wird eine Erfolgsmeldung ausgegeben, ist dies aber nicht der Fall wird eine Fehlermeldung ausgegeben.


  • Hier ist nochmal der komplette Code:


    Das ist das Ergebnis : http://stef97.bplaced.net/kont…mular/kontaktformular.php

  • Sehr ausführlich beschrieben. Und obwohl ich mich nicht gerade als Einsteiger bezeichne, hätte ich doch eine Frage:

    Warum wird die PHP-Mailer-Klasse benötigt? Was spricht gegen die Verwendung von mail() ? Ganz besonders unter dem Aspekt eines einfachen Kontaktformulars.

  • Hey,


    danke. Wir machen das gerne (Wissen weitergeben).


    Jav :

    Zitat

    Warum wird die PHP-Mailer-Klasse benötigt? Was spricht gegen die Verwendung von mail() ? Ganz besonders unter dem Aspekt eines einfachen Kontaktformulars

    Die mail-function finde ich selbst garnicht schlecht. Nur muss man sich da selbst um die korrekte Formatierung nach den RFC-Standards kümmern. Darüber benötigt man schon etwas Wissen in den benötigten RFC's. Wenn man darüber dann nichts weiß oder wenn man keine Lust hat die RFC's zu lernen gibt es Mailerklassen welche den Mailversand bereits RFC konform durchführen. Das heißt wir brauchen uns darum nicht zu kümmern und können beruhigt, ohne eigentlich was falsch machen zu können, ein Mailversand programmieren.

  • Wenn man es so formuliert, klingt es komplizierter als es ist.

    Die anzuwendenden RFCs besagen:

    - verwende nur gültige Emailadressen

    - verwende nur gültige Strings


    Also nichts, worauf nicht auch sonst geachtet werden müsste. Und ob die RFCs dazu "auswendig" gelernt wurden - nunja.


    Aber danke für die Antwort, Stef . Und schön, dass überhaupt noch jemand das Thema Tutorials in Angriff nimmt :)

  • Jav Mal abgesehen davon, dass der PHPMailer alles ein wenig schöner macht, hast du im Prinzip recht. Hätten auch genauso gut die mail()-Funktion nutzen können.


    Anders gesagt: Es geht uns nicht darum, den PHPMailer als toll darzustellen, sondern einen möglichst einfachen und gleichzeitig relativ schönen Weg aufzuzeigen, um ein Kontaktformular umzusetzen.

  • Genau. Besse kann man es nicht sagen.


    Jav : Es wissen bestimmt nicht alle Anfänger was sie da beachten müssen. Und um diese Fehler vorzubeugen nimmt man eine Mailerklasse, wo schon alles programmiert ist und man einfach seine Daten eintragen muss. Ist im Prinzip das selbe wie ein CMS. Man braucht kein Hintergrundwissen um dies zu erstellen, für was man eigentlich Programmiererfahrungen braucht.

  • Beides gute Punkte. Letzteres lässt sich ja sehr leicht noch hinzufügen.


    Bei dem Thema Spam muss ich sagen, dass ich damit bisher so gut wie keine Erfahrungen gemacht habe. Obwohl auf meiner Website die E-Mail in großen Buchstaben im Klartext aufzufinden ist und mein Kontaktformular keinen Schutz beinhaltet, habe ich bisher kaum bis gar keine Spam-Mails erhalten. Würde von daher zum aktuellen Zeitpunkt ungerne was darüber schreiben.


    Meiner Meinung nach macht es ohnehin mehr Sinn, das Thema gesondert anzusprechen, da es je nachdem durchaus etwas komplexer ist.

    Man könnte dann ja in diesem Tutorial darauf verweisen und umgekehrt.


    Vielleicht hat ja jemand anderes Lust, ein solches Tutorial zu verfassen.

  • Kompliment erstmal an den/die Verfasser des Tutorial.

    Ist denke ich für jeden gut verständlich beschrieben.


    Ein wenig mehr EVA Einhaltung hätte ich schöner gefunden, aber das handhabt jeder halt wie er es selber am sinnvollsten findet.


    Ich möchte allerdings unabhängig vom eigentlichen Tutorial etwas ins rechte Licht rücken:

    Das ist aus meiner Sicht grob fahrlässig simplifiziert!


    Was genau kennst Du über die RFC's? Dir sagt der Begriff Mail Header was? Vermutlich kennst Du alle Faktoren, die für korrekte Mail Header nötig sind?

    Und wie sieht es mit dem Mail Transport aus? Glaubst Du mail() kümmert sich darum? Nein, zumindest die Vorbereitungen musst Du als Entwickler treffen.


    Nun, für all diejenigen, die nicht Dein Experten-Level haben sind das wichtige Informationen, um gültige E-Mails zu versenden. RFCs muss man nicht auswendig lernen, aber man sollte bestimmte Informationen daraus wissen, wenn man Mails ohne Mailerklassen versenden will.

    Und das unter den Tisch zu kehren halte ich für absolut falsch.


    Mailerklassen nehmen Dir den Großteil dieser Dinge ab und sorgen dafür, dass die E-Mail RFC konform aufgebaut und versendet werden.


    Und genau das spricht - wie Stef in #7 schreibt - für Mailerklassen, wie PHPMailer! mail() roh sollten nur Entwickler einsetzen, die wirklich wissen, wie eine E-Mail nach RFC aufgebaut und transportiert werden sollte!


    Nur am Rande ohne Bezug auf das Thema: Es gibt übrigens auch noch den SwiftMailer, den ich persönlich schicker finde.


    Soll nicht böse rüberkommen, ich finde es nur wichtig, dass Anfänger mail() nicht ahnungslos anwenden, daher lieber Mailerklassen!


    Gruß Arne

  • Okay.

    Zitat

    Die Verarbeitung von Daten gehört für mich halt nicht in den HTML-Text, aber wie gesagt, rein subjektiv.

    Die Verarbeitung erfolgt ja nicht im HTML. Es wird nur überprüft ob Fehler vorhanden sind und ob die Erfolgsmeldung vorhanden ist. Und wenn ja wird dies ausgegeben.


    Wenn man dies im PHP-Teil machen würde, müsste man im HTML-Teil trotzdem überprüfen ob die Ausgabe vorhanden ist mittels if-else.

  • Nein, genau das müsste man nicht, einfaches Beispiel ( basierend auf Deinem Beispiel, minimiert! )

    Keine Logik im HTML-Text!


    Ich würde sogar soweit gehen, das HTML im Vorwege zu rendern und anschließend komplett auszugeben, aber das wäre noch ein Schritt weiter in Richtung Templating.

  • Moin,


    okay. So kann man das natürlich auch machen. Ist sogar doch besser beim genauern hinschauen. Dann hat man keine Abfragen mehr im HTML sondern nur die Variablen. Mit Templating hatte ich bisher noch nichts zu tun.


    Muss man, wenn man eine Variable als Value eines Feldes speichertm nicht diese Variable mit echo ausgeben?


    Grüße,

    Stef