Um Formulardaten als E-Mail zu versenden, hat mailto:
mangels Browserunterstützung längst ausgedient und kann u.U. noch über mein Javascript eingesetzt werden. Besser ist hingegen ein serverseitiger Versand, der meist über ein PHP-Script erfolgt. Im Internet gibt es Tausende davon, aber die meisten sind leider unsicher und können über Manipulation der Header-Daten als „Spamschleuder“ missbraucht werden und Tausende von Spam-Mails an beliebige Empfänger versenden mit der Folge, dass die Seite vom Provider gesperrt wird oder gar Schadenersatzforderungen von Mitbenutzern des Mailservers aufgrund der Eintragung desselben in eine Spam-Blacklist gestellt werden.
Die PHP-mail()
-Funktion erwartet mindestens drei Parameter: 1. Empfängeradresse, 2. Betreff, 3. Mailtext. Über einen zusätzlichen 4. Parameter ist meist noch eine Absenderadresse anzugeben. Die ersten beiden und ggfls. der 4. Parameter werden, durch einen Zeilenumbruch getrennt, als Mailheader gesendet. Vor dem dritten Parameter setzt die Funktion einen doppelten Zeilenumbruch, der die Mailheader vom Mailbody (dem Inhalt) trennt. Wenn nun Formulardaten ungeprüft in die Mailheader übernommen werden und einen Zeilenumbruch enthalten, können weitere Mailheader (und damit auch Empfängeradressen) eingeschmuggelt werden. Ein sicheres Script prüft daher die Formulardaten oder versendet sie ausschließlich im Mailbody und trägt in den anderen Parametern eigene Werte ein.
Hierzu reicht im Prinzip folgendes Script schon aus:
<?php
if(!empty($_POST))
mail("mail@example.org", "Nachricht",
"Folgende Daten wurden übermittelt im Formular-".print_r($_POST,true),
"From: formmailer@example.org");
?>
Dieses Script muss lediglich in die PHP-Seite eingetragen werden, an die die Formulardaten gesandt werden, was auch durchaus dieselbe Seite sein kann, die das Formular enthält. Man spricht in diesem Fall von einem „Affenformular“.
Die E-Mail wird dann an »mail@example.org« mit dem Betreff »Nachricht« und dem Absender »formmailer@example.org« verschickt. Der Inhalt des $_POST
-Arrays, das alle übermittelten Formulardaten enthält, wird im Mailbody in dieser Form geschrieben:
Folgende Daten wurden übermittelt im Formular-Array
(
[Name] => Ingo
[Nachricht] => Test des Formmailers
)
Die Ausgabe ist zwar ungewohnt, aber übersichtlich und eingetragene Seiten- oder Mailadressen werden vom Mailprogramm meist auch automatisch verlinkt.
Was noch fehlt, sind einige der folgenden Überprüfungen und Rückmeldungen:
Diese Funktion liefert dann true
zurück:
function Formular_abgeschickt() {
return !empty($_POST);
}
Diese Funktion liefert dann true
zurück:
function Formular_Daten() {
foreach ($_POST as $key => $val) {
if(trim($val)) return true;
}
return false;
}
Leider wurde in früheren PHP-Versionen ein Automatismus zur Verfügung gestellt, der einfache und doppelte Anführungszeichen in über GET, POST oder COOKIE übertragenen Daten maskiert, um unbedarfte Programmierer vor Manipulationen in Sonderfällen zu bewahren. Da sich diese üble Funktion nicht bei jedem Provider z.B. über den Eintrag php_flag magic_quotes_gpc Off
in der Apache-Konfigurationsdatei .htaccess
abschalten lässt, sollte ein universelles Script die Daten in diesem Fall bereinigen. Der folgende Code ersetzt außerdem die vorherigen Funktionen und stellt stattdessen Variablen zur Verfügung:
if($Formular_abgeschickt = !empty($_POST)) {
$Formular_leer = true; ini_set('magic_quotes_runtime',0);
$_POST = array_map('Formular_Daten', $_POST);
}
function Formular_Daten($val) {
global $Formular_leer;
if(is_array($val)) return array_map('Formular_Daten', $val);
if(ini_get('magic_quotes_gpc')) $val = stripslashes($val);
if($val = trim($val)) $Formular_leer = false;
return $val;
}
Für diese Funktion muss zuvor über $Pflichtfelder=array();
ein Array angelegt sein, in das bei Bedarf die Namen der zu prüfenden Pflichtfelder eingetragen werden. Sie liefert einen Leerstring oder entsprechende Fehlermeldungen zurück:
function Formular_Pflichtfelder() {
global $Pflichtfelder;
$Fehler = '';
foreach ($Pflichtfelder as $Feld) {
$key = str_replace(' ','_',$Feld);
if(!(isset($_POST[$key]) && trim($_POST[$key])!=='')) {
if($Fehler) $Fehler .= '<br />';
$Fehler .= 'Pflichtfeld "' . $Feld . '" nicht ausgefüllt.';
}
}
return $Fehler;
}
Um dies zu vermeiden, werden oft Sessions eingesetzt oder eine Weiterleitung genutzt, die dem Prinzip des „Affenformulars“ widerspricht, das alle Funktionen zur Formularausgabe, -Auswertung und -Rückmeldung sinnvoll vereinigt. Ich nutze hierzu eine ganz simple Methode, für die dem Verzeichnis allerdings Schreibrechte eingeräumt werden muss.
Diese Funktion liefert bei wiederholtem Versenden false
zurück:
function Formular_neu($log='.htPOSTdata.txt') {
if(file_exists($log) && is_readable($log)
&& file_get_contents($log) == print_r($_POST,true))
return false;
if($handle=@fopen($log, 'w')) {
fwrite($handle, print_r($_POST,true)); fclose($handle);
}
return true;
}
Ohne Schreibrechte wird immer true
zurück geliefert; um in diesem Fall doppeltes Versenden zu vermeiden, könnte man z.B. auch den Betreff in einer Session speichern und abfragen.
Übrigens keine Sorge, dass Außenstehende die letzte verschickte Mail einsehen können - ein Apache-Server ist standardmäßig so konfiguriert, dass er den Zugriff auf Dateien, deren Name mit ".ht" beginnt (wie insb. ".htaccess") verweigert.
Diese Funktion nutzt die vorherigen und liefert Fehlermeldungen oder einen Leerstring zurück:
function Formular_Check() {
global $Formular_leer;
if($Formular_leer) $Fehler = 'Keine Daten eingetragen.';
elseif(!$Fehler = Formular_Pflichtfelder()) {
if(!Formular_neu()) $Fehler = 'Nachricht war bereits verschickt.';
}
return $Fehler;
}
Diese Funktion wird mit dem name
-Attribut des Feldes im Formular dort aufgerufen, wo eine evtl. erfolgte Eingabe ausgegeben werden soll:
function Formular_Eingabe($Feldname, $def='') {
if(isset($_POST[$Feldname]) && $_POST[$Feldname]!=='')
echo htmlspecialchars($_POST[$Feldname],ENT_COMPAT,'ISO-8859-15');
// ggfls. Zeichenkodierung anpassen (Vorgabe ist seit PHP 5.4 UTF-8!)
else echo $def; // ggfls. übergebenen Vorgabewert ausgeben
}
Um auch für diese (im einfachen Kontaktformuar nicht vorkommenden) Sonderfälle die Auswahl zu übernehmen, dient diese Funktion. Ihr wird außer dem name
-Attribut auch der Wert
des Feldes übergeben sowie "checked"
für Radio-Buttons und Checkboxen oder "selected"
für Options und optional als letzter Parameter true
für ein vorselektiertes Element:
function Formular_Auswahl($Feldname,$Wert,$Auswahl,$def=false) {
if(
(empty($_POST[$Feldname]) && $def) ||
(!empty($_POST[$Feldname]) && // Achtung: $Wert darf nicht "0" sein!
($_POST[$Feldname]==$Wert ||
(is_array($_POST[$Feldname]) && in_array($Wert,$_POST[$Feldname]))
)
)
) echo ' ', $Auswahl, '="', $Auswahl, '"';
}
# Beispielaufruf dieser Funktion für eine Checkbox:
<input name="AGB" type="checkbox" value="Ja" <?php
Formular_Auswahl('AGB','Ja','checked'); ?> />
<label for="AGB">Ich akzeptiere die AGB.</label>
# Beispielaufruf dieser Funktion für Radio-Buttons:
<input type="radio" id="Herr" name="Anrede" value="Herr"
<?php Formular_Auswahl('Anrede','Herr','checked');
?>><label for="Herr">Herr</label>
<input type="radio" id="Frau" name="Anrede" value="Frau"
<?php Formular_Auswahl('Anrede','Frau','checked',true); // Vorauswahl
?>><label for="Frau">Frau</label>
# Beispielaufruf dieser Funktion für eine Auswahlliste:
<label for="Anrede">Wie darf ich Sie ansprechen?</label>
<select id="Anrede" name="Anrede">
<option <?php Formular_Auswahl('Anrede','Herr','selected'); ?>>Herr</option>
<option <?php Formular_Auswahl('Anrede','Frau','selected','true'); ?>>Frau</option>
</select>
Diese Funktionen sollten zu einer sicheren Auswertung eines Kontaktformulars ausreichen, aber da sich dieser Tipp auch an Anfänger richtet, die bisher unsichere PHP-Scripte aus dem Internet genutzt haben, biete ich nachfolgend den kompletten Code für ein sicheres Kontaktformular an - in der Hoffnung, die „Spam-Schleudern“ im Internet zu reduzieren.
Um die Regeln der RFC einzuhalten, werden in diesem Script Umlaute und Sonderzeichen ab PHP 5.3.0 maskiert. Wenn eine ältere PHP-Version installiert ist und der Mail-Server nicht RFC-konforme Mails abweisen sollte (was allerdings nur sehr selten vorkommen soll), könnten Sie auf eine Mailer-Klasse wie PHPMailer zurückgreifen, wobei mit der class.phpmailer.php jedoch rund 137 KB PHP-Code eingebunden und Anpassungen vorgenommen werden müssen.
<?php
define ('MAILTO', "mail@example.org"); // Empfänger hier eintragen
define ('MAILFROM', "Kontaktformular@example.org"); // ggfls. Absender hier eintragen
define ('SUBJECT', "Nachricht vom Kontaktformular"); // ohne Sonderzeichen
define ('CHARSET', "ISO-8859-15"); // Zeichenkodierung ggfls. anpassen
$Pflichtfelder = array('Nachricht'); // ggfls. weitere Pflichtfelder angeben
define ('MailAnzeige', true); // Nachricht nach Versand angezeigen
define ('FormularLink', true); // nach Versand Link auf neues Formular ausgeben
define ('FormularAnzeige', false); // keine Formularausgabe nach Versand
define ('LF', chr(13).chr(10)); // Zeilenumbruch
$AddHeader = (MAILFROM) ? 'From: '.MAILFROM.LF : "";
if(function_exists('quoted_printable_encode')) { // ab PHP 5.3.0 für RFC-Konformität
$AddHeader .= 'MIME-Version: 1.0';
$AddHeader .= LF.'Content-Type: text/plain; charset='.CHARSET;
$AddHeader .= LF.'Content-Transfer-Encoding: quoted-printable';
}
else $AddHeader .= 'Content-Type: text/plain; charset='.CHARSET;
if($Formular_abgeschickt = !empty($_POST)) {
$Formular_leer = true;
if(ini_get('magic_quotes_runtime')) ini_set('magic_quotes_runtime',0);
$_POST = array_map('Formular_Daten', $_POST);
}
function Formular_Daten($val) {
global $Formular_leer;
if(is_array($val)) return array_map('Formular_Daten', $val);
if(ini_get('magic_quotes_gpc')) $val = stripslashes($val);
if($val = trim($val)) $Formular_leer = false;
return $val;
}
function Formular_Pflichtfelder() {
global $Pflichtfelder;
$Fehler = '';
foreach ($Pflichtfelder as $Feld) {
$key = str_replace(' ','_',$Feld);
if(!(isset($_POST[$key]) && trim($_POST[$key])!=='')) {
if($Fehler) $Fehler .= '<br />';
$Fehler .= 'Pflichtfeld "' . $Feld . '" nicht ausgefüllt.';
}
}
return $Fehler;
}
function Formular_neu($log='.htPOSTdata.txt') {
if(file_exists($log) && is_readable($log)
&& file_get_contents($log) == print_r($_POST,true))
return false;
if($handle=@fopen($log, 'w')) {
fwrite($handle, print_r($_POST,true)); fclose($handle);
}
return true;
}
function Formular_Check() {
global $Formular_leer;
if($Formular_leer) $Fehler = 'Keine Daten eingetragen.';
elseif(!$Fehler = Formular_Pflichtfelder()) {
if(!Formular_neu()) $Fehler = 'Nachricht war bereits verschickt.';
}
return $Fehler;
}
function Formular_Eingabe($Feldname, $def='') {
if(isset($_POST[$Feldname]) && $_POST[$Feldname]!=='')
echo htmlspecialchars($_POST[$Feldname],ENT_COMPAT,CHARSET);
else echo $def;
}
function Formular_Nachricht($HTML=false) {
$msg=''; $vor=''; $nach=': ';
foreach ($_POST as $key => $val) {
if($key != 'abschicken' && trim($val)) { // if(true) um alle Felder auszugeben
if($HTML) {
$msg .= '<strong>'.$vor.$key.$nach.'</strong>'
.htmlspecialchars($val,ENT_COMPAT,CHARSET).'<br />';
}
else {
if(function_exists('quoted_printable_encode')) {
$val = quoted_printable_encode($val);
}
$msg .= $vor.$key.$nach.$val.LF.LF;
}
}
}
return $msg;
}
$Meldung = ""; $id = "";
if($Formular_abgeschickt) {
if($Formular_Fehler = Formular_Check()) {
$Meldung = $Formular_Fehler; $id = 'Fehler';
}
elseif(@mail(MAILTO, SUBJECT, Formular_Nachricht(), $AddHeader)) {
$Meldung = 'Nachricht verschickt.'; $id = 'OK';
}
else {
$Meldung = 'Server-Fehler !'; $id = 'Fehler';
}
}
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="de" lang="de">
<head>
<title>Kontaktformular</title>
<meta http-equiv="Content-Type" content="text/html; charset=<?php echo CHARSET; ?>" />
</head>
<body>
<h1 id="Kontakt">Kontakt</h1>
<?php
if($Meldung) echo '<p class="Meldung" id="',$id,'">',$Meldung,'</p>';
if($id=='OK') {
if(MailAnzeige) echo '<p id="Nachricht">',Formular_Nachricht(true),'</p>';
if(FormularLink) {
echo '<p id="FormularLink">
<a href="'.$_SERVER['SCRIPT_NAME'].'">neues Formular?</a>
</p>';
}
}
if(FormularAnzeige || $id != 'OK'): ?>
<form action="<?php echo $_SERVER['SCRIPT_NAME']; ?>#Kontakt" method="post"
enctype="multipart/form-data" accept-charset="<?php echo CHARSET; ?>">
<fieldset><legend>Kontaktformular</legend>
<p>
<label for="Name">Ihr Name:</label>
<input name="Name" id="Name" size="66"
value="<?php Formular_Eingabe('Name'); ?>" />
</p>
<p>
<label for="Nachricht">Nachricht:</label>
<textarea name="Nachricht" id="Nachricht" rows="5" cols="50"><?php
Formular_Eingabe('Nachricht'); ?></textarea>
</p>
<p><input type="submit" value="abschicken" /></p>
</fieldset>
</form>
<?php endif; ?>
</body>
</html>
Zur besseren Übersicht habe ich die PHP-Codebereiche farblich hervorgehoben. Damit diese ausgeführt und nicht im HTML-Quelltext ausgegeben werden, muss die Datei auf einem PHP-fähigen Webspace liegen und sollte mit der Endung ".php" benannt sein.
Sie können das Script auf zwei Arten in Ihre Seite integrieren:
chr(160)
übernommen werden.In beiden Fällen muss zumindest die Zeile »define ('MAILTO', "mail@example.org");
« angepasst und ggf. auch die Formularfelder geändert oder weitere hinzugefügt werden.
Wenn Ihr Kontaktormular erst nach Scrollen erreicbar ist, sollte dessen Überschrift wie hier mit einer id
versehen und das Ziel des Formulars mit einem Ankersprung hierauf erweitert werden, damit die Rückmeldungen direkt ersichtlich sind.
Wenn Sie z.B. eine E-Mail-Adresse als Pflichtfeld hinzufügen und diese auf grobe Tippfehler prüfen möchten, gehen Sie wie folgt vor:
$Pflichtfelder = array('Nachricht', 'eMail');
checkEmail()
aus meinem Tipp »E-Mail-Adressen prüfen« zwischen die übrigen Funktionen.
function Formular_Check() {
global $Formular_leer;
if($Formular_leer) $Fehler = 'Keine Daten eingetragen.';
elseif(!$Fehler = Formular_Pflichtfelder()) {
if(!checkEmail($_POST['eMail'])) $Fehler = 'E-Mail fehlerhaft.';
elseif(!Formular_neu()) $Fehler = 'Nachricht war bereits verschickt.';
}
return $Fehler;
}
<p>
<label for="eMail">Ihre E-Mail:</label>
<input name="eMail" id="eMail" size="64"
value="<?php Formular_Eingabe('eMail'); ?>" />
</p>
Wenn Sie wie oben beschrieben die Abfrage einer E-Mail-Adresse als geprüftes Pflichtfeld hinzugefügt haben und diese als Absender der Mail eintragen möchten, gehen Sie wie folgt vor:
define ('MAILFROM', "");
@mail(MAILTO, SUBJECT, Formular_Nachricht(), 'From: '.$_POST['eMail'].LF.$AddHeader)
checkEmail()
die Funktion checkEmailRFC()
aus meinem Tipp »E-Mail-Adressen prüfen« zwischen die übrigen Funktionen und tragen diesen Funktionsnamen statt checkEmail
in der Funktion Formular_Check()
ein.Der Mailserver könnte fremde Absenderangaben allerdings möglicherweise nicht akzeptieren.
Hierzu müssen Sie zunächst das HTML-Formular erweitern, z.B. so:
<p>
<label for="Datei">Datei anfügen:</label>
<input id="Datei" name="Datei" type="file" size="70" />
</p>
Außerdem erweitern Sie den PHP-Code am Anfang:
$AddHeader = 'MIME-Version: 1.0'.LF;
$boundary = strtoupper(md5(uniqid(time())));
$AddHeader .= 'Content-Type: multipart/mixed; boundary='.$boundary.' charset='.CHARSET;
Wird fortgesetzt... das Prinzip für den restlichen Code wird aber z.B. aufhttps://www.teialehrbuch.de/Kostenlose-Kurse/PHP/9404-Versenden-einer-E-Mail-mit-Anhang.html
recht gut erklärt.