Eine Mailadresse prüfen, dass muss jeder Entwickler mal in seinem Code machen. Dass dabei eine Menge schief gehen kann, davon kann sicherlich jeder PHP-Programmierer ein Lied singen. Gemacht werden muss es aber, nur wie? Ich stelle die PHP eigene Funktion filter_var() gegen die Filterfunktion des Zend Frameworks und schaue mal, welche der beiden Lösungen denn „Praxistaugliche“ Antworten erzeugt.
Für die PHP eigenen Funktionen lasse ich filter_var mit Filteroption FILTER_VALIDATE_EMAIL antreten. Zur einfachen Übersicht baue ich eine Funktion „isEMailValid“. Diese soll bei korrekter Mailadresse true zurückliefern, ansonsten false; also eher trivial.
function isEMailValid($mail)
{
return (filter_var($mail, FILTER_VALIDATE_EMAIL) !== FALSE);
}
Für die Frameworks tritt das Zend Framework an und speziell dessen Zend_Validate_EmailAddress Klasse. Diese besitzt eine Funktion isValid, die das gleiche Verhalten zeigt wie unsere eigene „isEMailValid“ Funktion.
Als Beispiel gebe ich 4 ähnliche Mailadressen an, nur die erste ist eine „echte“ Mailadresse, bei allen anderen fehlt was bzw. ist ein Teil unvollständig. Sicherlich prüft das ganze nicht alle möglichen Fälle von Mailadressen ab, aber es zeigt einen (sinngemäßen) Fall, der mir Probleme bereitete und mich nun zum Wechsel von meiner „filter_var plus regex“-Methode zum ZendFramework bewegen konnte.
function isEMailValid($mail)
{
return (filter_var($mail, FILTER_VALIDATE_EMAIL) !== FALSE);
}
$mail1 = 'max.muster-mann@eine.beispieldomain.com';
$mail2 = 'max.muster-mann@com';
$mail3 = 'max.muster-mann eine.beispieldomain.com';
$mail4 = 'max.muster-manneine.beispieldomain.com';
printf('php-filter:'."\n");
var_dump(isEMailValid($mail1));
var_dump(isEMailValid($mail2));
var_dump(isEMailValid($mail3));
var_dump(isEMailValid($mail4));
printf('zend:'."\n");
require_once 'Zend/Validate.php';
require_once 'Zend/Validate/EmailAddress.php';
$mailvalidator = new Zend_Validate_EmailAddress();
var_dump($mailvalidator->isValid($mail1));
var_dump($mailvalidator->isValid($mail2));
var_dump($mailvalidator->isValid($mail3));
var_dump($mailvalidator->isValid($mail4));
Die Ausgabe:
php-filter:
bool(true)
bool(true)
bool(false)
bool(false)
zend:
bool(true)
bool(false)
bool(false)
bool(false)
Wie man sieht, die „normale“ filter_var() Funktion von PHP schlägt fehl und meldet die zweite Mailadresse als korrekt, was nicht richtig ist.
Allein das zeigt mir nun, dass ich mich auf die Ergebnisse der PHP eigenen Prüfung nicht verlassen kann. Ich werde das ganze weiterhin beobachten, allerdings wird das nächste Projekt dann Funktionen aus dem Zend Framework benutzen. Das schöne ist, dass ich nur einmal in meiner Prüfungsmethode meiner Validatorklasse die Prüfung ändern muss, damit Projektweit die „richtige“ Prüfung benutzt wird. OOP ist toll 😉
PHP-Version: 5.2.13
Nachtrag vom 24.09.2010
Die ersten 5 Kommentare brachten mich auf andere Wege und zu mehr „Erkentnis“ des ganzen. Danke an IchBinIch und SkaveRat für die Hinweise!
Nimmt man noch ein paar andere Abwandlungen der Mailadressen zeigt sich ein Bild, dass man erklären sollte, denn filter_var und Zend arbeiten anscheinend völlig unterschiedlich. Oder doch nicht?
Was soll man nun benutzen? filter_var oder doch die Zend-Funktionen?
Die Antwortet lautet: Es kommt drauf an!
Je nachdem, was man mit der Prüfung erreichen will, benötigt man entweder das eine oder das andere. Hier die beiden Möglichkeiten:
- 1. Prüfung für den Mailversand!
Der wohl häufigste Fall. Man möchte wissen, ob eine Mailadresse dazu taugt, etwas per SMTP dort auch hinsenden zu können (Zugangsdaten, Newsletter, …). Hier lautet die Antwort: Zend-Framework, denn das prüft, ob ein String eine versendbare Mailadresse nach RFC 5321 beinhaltet (siehe auch Kommentar 3 von SkaveRat). - 2. Prüfung, ob es ganz generell eine Mailadresse sein könnte!
Hier ist die Antwort: filter_var, denn diese Funktion prüft die generelle Syntax des Strings, nicht dessen Nutzbarkeit. Dabei können auch Global-Parts wie ‚localhost‘ eingesetzt werden, allerdings werden auch Mailadressen wie ‚a@com‘ durchgelassen, da diese ja theoretisch auch Mailadressen sind.
Man sieht, dass es durchaus auf den Anwendungsfall ankommt, will man sich für eine Filterklasse entscheiden. Ich werde das auf jeden Fall bei der nächsten Prüfung berücksichtigen.
Hey,
bist du kannst sicher, das „max.muster-mann@com“ falsch ist?
„example@localhost“ wäre doch Ok, der zweite Teil ist der Domain-Part, der könnte ja auch einfach ein IP sein – oder sehe ich das falsch?
mfg
IchBinIch
PS: Ich habe eben erst die PHP Filter bei mir eingebaut, ich fände es sehr schade, wenn das jetzt doch nicht so tolle wäre, wie ich dachte …
@IchBinIch: Habe mal 2 weitere Prüfungen eingebaut und bin etwas ratlos.
Habe noch
$mail5 = ‚max.muster-mann@localhost‘;
$mail6 = ‚max.muster-mann@192.168.69.1‘;
hinzugefügt und nun lautet die Ausgabe für diese beiden true bei den php-filter-Funktionen und beide false bei den Zend-Filtern.
Im Prinzip gebe ich dir recht, man kann im Global-Part auch localhost oder IP angeben. Aber nun habe ich (als Entwickler) das Problem, dass ich mich nun weder auf die Ergebnisse von filter_var, noch auf die Zend-Filter verlassen kann. Hat einer eine Idee?
foobar@localhost funktioniert, ist aber laut RFC5321 nicht erlaubt.
Siehe Kommentar der Methode ab Zeile 499:
http://svn.php.net/viewvc/php/php-src/trunk/ext/filter/logical_filters.c?view=markup
Okay, das bringt mich nun zu diesem Punkt: Will ich Mailadressen prüfen mit dem Ziel, diese als Mailadresse für SMTP zu benutzen, dann benutze ich Zend, prüfe ich Mailadressen darauf, ob diese generell „so hinhauen“ könnten, dann bleiben die filter-Methoden stehen.
Für mich: Ich benutze Zend, denn ich will ja was an die Mailadressen senden.
Danke @SkaveRat für den Quellenhinweis!
„Allein das zeigt mir nun, dass ich mich auf die Ergebnisse der PHP eigenen Prüfung nicht verlassen kann.“ – Höchst kritische Aussage… Was heißt den „nicht verlassen“? Das bedeutet imho das es für mich nicht berechenbar bzw. Fehlerhaft ist, ist hier aber nicht der Fall. Der Sinn der Funktion ist es eben eine eMail-Adresse (auch local) zu validieren und damit funktioniert die Funktion korrekt, nur dein Ziel ist damit eben nicht abgedeckt. Wie man damit umgeht, ist ja dann wieder eine plausible Fragestellung, aber zu sagen, man könnte sich nicht darauf verlassen ist eine Aussage, auf die ich mich nicht verlassen kann 😉
Gruß Seb
So, habe den Text entsprechend ergänzt; vielen Dank an alle für die Hilfe!
Eine gültige Email-Adresse bei der Zend auf die Nase fällt ist „i@an“. Ja, diese Adresse gibt es wirklich. Sonderfall, klar.
Wenn es nötig wird, das ich einmal eine e-Mailadresse überprüfen muss, mache ich 2 Dinge:
1. Mit Hilfe von filter_var die e-Mailadresse validieren lassen.
2. Mittels checkdnsrr frage ich ab, ob ein MX-, A-, oder CNAME-Record zu der jeweiligen Domain (also dem Teil hinter dem @) existiert.
Eure Meinung?