Nicht selten muss innerhalb eines PHP-Projektes die Gültigkeit einer E-Mail-Adresse verifiziert werden. Mit älteren PHP-Version half hier oft ein Regulärer Ausdruck (Regex) aus, mittlerweile steht uns PHP-Entwicklern aber die (oftmals) praktische Funktion filter_var zur Verfügung. Die Benutzung dieser Funktion im Falle der E-Mail-Validierung sieht wie folgt aus:
var_dump(filter_var('admin@mysite.org', FILTER_VALIDATE_EMAIL) !== false);; // ergibt bool(true)
var_dump(filter_var('notexist.org', FILTER_VALIDATE_EMAIL) !== false);; // ergibt bool(false)
Dies funktioniert eigentlich hervorragend, wäre da nicht der kleine, aber feine Unterschied bei der Gültigkeit von E-Mail-Adressen. Laut offiziellem Standard ist nämlich auch so eine E-Mail-Adresse valide:
admin@localhost
test@wurstbrot (und so weiter...)
Im Praxisfall ist so eine Art von E-Mail natürlich nutzlos – das wage ich jetzt einfach mal zu behaupten. Für solche Fälle habe ich eine kleine Funktion erstellt, die eine String als E-Mail-Adresse verifiziert. Dabei wird auch gleichzeitig geprüft, ob die Domain existiert – das macht Eintragungen wie asdasdasd@asdasdasd.asd obsolet.
Und hier ist sie:
function validateMail($email, $checkdns = true) {
if(preg_match("/^[a-zA-Z0-9_.-]+@[a-zA-Z0-9][a-zA-Z0-9-.]+\.([a-zA-Z]{2,6})$/" , $email) && filter_var($email, FILTER_VALIDATE_EMAIL) !== false ) {
$tmp = explode('@', $email);
$domain = $tmp[1];
if($checkdns && @dns_get_record($domain) === false) {
return false;
}
} else {
return false;
}
return true;
}
Hier eine kurze Erläuterung: Zuerst wird die Adresse anhand eines regulären Ausdrucks geprüft (wie in alten Zeiten) und, um sicherzustellen, wird auch die filter_var-Funktion zu Rate gezogen. Das wäre eigentlich überflüssig, allerdings ist es möglich, dass mein regulärer Ausdruck nicht ganz perfekt ist und hole mir so sicherheit durch die PHP-interne Funktion.
Danach wird die Domain aus der E-Mail-Adresse extrahiert und auf Existenz geprüft, sofern der zweite Parameter der Funktion nicht auf false gesetzt wurde.
Noch eine kleine Anmerkung bezüglich der unterdrückten Fehlermeldung in Zeile 3: dns_get_record gibt nicht einfach nur false zurück, wenn die Domain nicht existiert – es meldet sich dann in diesem Falle lautstark mit einer Notice, was wir natürlich nicht möchten. Ansonsten sollte man natürlich tunlichst auf so eine Praxis vermeiden, jedoch geht es hier nicht anders.
Schlägt eine der Prüfungen fehl, so gibt die Funktion false zurück, andernfalls (wie könnte es auch ander sein) true.
Achtung…
Ich benutze diese Funktion sehr gerne, allerdings gibt es hier eine kleine Stolperfalle: Mittlerweile existieren bekanntlich sogenannte Umlaut-Domains, beispielsweise www.günstige-schöne-mähdrescher.de – die filter_var- und die dns_get_record-Funktion lehen Umlaute aber strikt ab, weshalb auch meine Funktion die E-Mail-Adresse nicht verifiziert.
Als “Workaround” könnte man hier noch eine Prüfung auf vorhandene Umlaute implementieren. Wenn dies der Fall ist, findet keine DNS-Prüfung statt und ein leicht veränderter regulärer Ausdruck wird zur Prüfung angewandt.
function validateMail($email, $checkdns = true, $consider_umlauts = true) {
if(preg_match('/^[a-zA-Z0-9_.-]+@[a-zA-Z0-9][a-zA-Z0-9-.]+\.([a-zA-Z]{2,6})$/' , $email) && filter_var($email, FILTER_VALIDATE_EMAIL) !== false ) {
$tmp = explode('@', $email);
$domain = $tmp[1];
if($checkdns && @dns_get_record($domain) === false) {
return false;
}
} elseif($consider_umlauts && preg_match('/^[a-zA-Z0-9äöüÄÖÜ_.-]+@[a-zA-Z0-9äöüÄÖÜ][a-zA-Z0-9-äöüÄÖÜ.]+\.([a-zA-Z]{2,6})$/', $email)) {
// Workaround for german Umlauts
return true;
} else {
return false;
}
return true;
}
Testlauf
So, und jetzt wollen wir doch einmal die Funktion testen:
$testArray = array(
'test@test.de',
'mailaddress@googlemail.com',
'test.test.test',
'a@b.c',
'admin@localhost',
'user@äöüäöü.de', //DNS Prüfung wird ignoriert
'mail@umlaut.dä', //DNS Prüfung wird ignoriert
'asdf@asdfasdasd.asd',
'@.de'
);
foreach($testArray as $email) {
echo $email . ':<br />';
var_dump(validateMail($email, true, false));
echo '<br /><br />';
}
Hier die Ausgabe:
test@test.de: bool(true)
mailaddress@googlemail.com: bool(true)
test.test.test: bool(false)
a@b.c: bool(false)
admin@localhost: bool(false)
user@äöüäöü.de: bool(false)
mail@umlaut.dä: bool(false)
asdf@asdfasdasd.asd: bool(false)
@.de: bool(false)



Coole Sache! Vielen Dank für den guten Artikel!
http://www.günstige-schöne-mähdrescher.de
sehr schön – wie lange hast du dafür gebraucht!? ;P
Ich denke aber, man sollte mal von ein paar guten Code den Regex überprüfen lassen und das filter_var dann raus nehmen, weil im Grunde wird dann ja zwei mal das Gleiche gemacht – das ist doch irgendwie unschön.
Habe filter_var dringelassen, weil ich meinem eigenen Regex nicht vertraue. Irgendwie ist es aber doch doppelt gemoppelt, da hast du Recht.
Zu den Umlautdomains:
Umlaute sind nach wie vor nicht erlaubt und werden auch nie erlaubt sein. Was aktuell geschieht ist die Kodierung solcher Domains durch den Punycode
schön => schn-7qa
Diesen Code könntest du aber ganz leicht implementieren für DNS-Abfragen.
Danke für den Hinweis. Man lernt nie aus :)