ärger mit regulärem ausdruck
azok
- php
0 Dennis0 Tobias Kloth0 Dennis
hi!
ich habe vor kurzem eine kleine "funktion" zum überprüfen von email adressen geschrieben. nur heute ist mir ein fehler aufgefallen, wo ich nicht mehr weiter weiß. die "funktion" sieht mal so aus:
ereg("/^([a-zA-Z0-9]+([.]?|[-]?|[_]?)?)(-|_|.)([a-zA-Z0-9]+([.]?[_]?)?)@([a-z0-9]+([.]?|[-]?)?)*[a-z0-9]+.{1}[a-z]{2,6}$/i",$email)
nun, sie funktioniert auch ganz gut... aber leider bei meiner eigenen(!) emailadresse nicht. ich verstehe nicht warum... bei heinrich_peter@hotmail.com liefert sie mir "false"...
kann mir jemand von euch weiter helfen?
lg
azok
Hi azok,
ereg("/^([a-zA-Z0-9]+([.]?|[-]?|[_]?)?)(-|_|.)([a-zA-Z0-9]+([.]?[_]?)?)@([a-z0-9]+([.]?|[-]?)?)*[a-z0-9]+.{1}[a-z]{2,6}$/i",$email)
Puh, ich vermute mal, diese Mühe, die du dir hier machst, ist vollständig überflüssig. Ich kann dir trotzdem eine E-Mail Adresse unterjubeln, die gar nicht existiert...
nun, sie funktioniert auch ganz gut... aber leider bei meiner eigenen(!) emailadresse nicht. ich verstehe nicht warum... bei heinrich_peter@hotmail.com liefert sie mir "false"...
Nun, RegEx sind standardmäßig gierig, deshalb glaube ich das Phänomen wie folgt erklären zu können:
([a-zA-Z0-9]+([.]?|[-]?|[_]?)?)(-|_|.)([a-zA-Z0-9]+([.]?[_]?)?)
| | | | |
Buchstaben (1 und mehr) -, _ oder sonst was -, _ oder sonst was
| |
-, _ oder sont was Buchstaben (1 oder mehr)
Das dürfte dein RegEx bis zum @ Zeichen sein.
Jetzt nehmen wir mal die E-Mail heinrich_peter:
Das heinrich matcht alles noch in den ersten Teil (die Buchstaben), der Unterstrich wird dann allerdings von dem zweiten Teil "gefressen" (der ja 0 oder 1 mal vorkommen soll) und somit bleibt für den dritten Teil keines der Zeichen "(-|_|.)" mehr übrig.
Womit der RegEx dann als ganzes nicht mehr matchen würde.
Ok, dein Problem ist festgestellt, jetzt mal zu deinem Ansatz:
Dein RegEx würde folgende E-Mail nicht als richtig erkennen:
vorname_zweitname_nachname@domain.de
Ferner setzt du durch vorraus, dass der Teil vor dem @ mindestens 3 Zeichen lang sein muss - ist dem denn wirklich so? Kann ich @meinerdomain denn nicht auch nur zwei Zeichen machen?
Dann, was soll das:
([.]?|[-]?|[_]?)?
Ich weiß nicht, was du durch das escapen des Punkte bewirken willst. In einer Zeichenklasse, also zwischen [ und ] hat ein . immer seine normale Bedeutung und gilt nicht "als Platzhalter für ein beliebiges Zeichen (außer Whitespace)", für was er sonst gilt.
Dann ist deine Logik da auch falsch. Da blickt doch keiner mehr durch, mach das lieber so:
([.]|-|_)?
Sollte eigentlich genau das gleiche bewirken: Entweder ein -, oder ein _, oder ein beliebiges Zeichen, oder gar nichts.
Die restlichen logischen Fehler (die sich einander ähneln) lasse ich jetzt mal außer Acht.
Ach ja, einer noch: Woher willst du wissen, ob es nicht schon bald TLD's mit mehr als 6 Zeichen gibt? Mache also lieber {2,} um das zukunftssicher zu halten.
Trotzdem mal noch ein Lösungsansatz für deinen RegEx: Du könntest den Modifier U (für ungreedy, also "unhungrig"/nicht gefräßig) verwenden.
Allerdings will ich dich nicht dazu anstiften einen eh schon vermurksten RegEx noch weiter zu bearbeiten. RegExen ist - wie man zu weilen zu Recht sagt - eine Kunst, also versuche immer, alles so einfach wie möglich zu machen, ein Beispiel habe ich dir schon gegeben.
Und dann habe ich hier mal noch eine experimentelle Funktion, die ich mir (auf einenem bestehenden Code basierend) zur überprüfung gebaut habe.
Mir ist bewusst, dass diese Funkion nur auf entsprechend Konfigurierten Server laufen kann und auch dort der Erfolg nicht immer gewährleistet ist.
//Funktion Check E-Mail Absender
function check_email($email, $check_host = false)
{
$nonascii = "\x80-\xff"; # Non-ASCII-Chars are not allowed
$nqtext = "[^\\$nonascii\015\012"]";
$qchar = "\\[^$nonascii]";
$protocol = '(?:mailto:)';
$normuser = '[a-zA-Z0-9][a-zA-Z0-9_.-]*';
$quotedstring = ""(?:$nqtext|$qchar)+"";
$user_part = "(?:$normuser|$quotedstring)";
$dom_mainpart = '[a-zA-Z0-9][a-zA-Z0-9._-]*\.';
$dom_subpart = '(?:[a-zA-Z0-9][a-zA-Z0-9._-]*\.)*';
$dom_tldpart = '[a-zA-Z]{2,}';
$domain_part = "$dom_subpart$dom_mainpart$dom_tldpart";
$correct_opt = preg_match("/^$protocol?$user_part@($domain_part)$/",$email,$treffer);
//Wenn die E-Mail Adresse optisch schon verkehrt ist abbrechen
if(!$correct_opt) return false;
//Überprüfung auf Host,
//der folgende Teil ist experimentell!!!
if($check_host)
{
//Sonst überprüfen, ob es die Domain in der Adresse gibt
$correct_nopt = @fopen("http://www.".$treffer[1],"r");
//Wenn nicht abbrechen
if(!$correct_nopt) return false;
//Sonst E-Mail Adresse als gültig durchlasen
fclose($correct_nopt);
}
//Und True zurückliefern
return true;
}
Was ich versuche ist, den Host aus dem Domain Teil anzusprechen. Dass da natürlich auch richtige E-Mails verweigert werden können, weil der Server z.B. grade down ist, ist klar.
Na ja, da müsste man sicherlich noch was dran machen....
MfG, Dennis.
Hallo Dennis,
Ferner setzt du durch vorraus, dass der Teil vor dem @ mindestens 3 Zeichen lang sein muss - ist dem denn wirklich so?
nein, ich habe auch eine E-Mailadresse die mit »to@« anfängt.
In einer Zeichenklasse, also zwischen [ und ] hat ein . immer seine normale Bedeutung und gilt nicht "als Platzhalter für ein beliebiges Zeichen (außer Whitespace)", für was er sonst gilt.
der Punkt erkennt lediglich keine Zeilenumbrüche (außer man verwendet den Modifikator »s«)
Dann ist deine Logik da auch falsch. Da blickt doch keiner mehr durch, mach das lieber so:
([.]|-|_)?
»[._-]?« sollte es auch tun (ggf. noch runde Klammern um die eckigen um das gefundene Zeichen "festzuhalten")
Sollte eigentlich genau das gleiche bewirken: Entweder ein -, oder ein _, oder ein beliebiges Zeichen, oder gar nichts.
mhh... ein paar Zeilen weiter oben behauptest du noch, dass ein »[.]« nur einen Punkt findet und nicht ein beliebiges Zeichen (was afaik auch richtig ist) - und jetzt soll »[.]« beliebige Zeichen finden (in dem Fall wäre es übrigends relativ sinnlos »-« und »_« noch extra aufzuführen - sie würden ja auch vom Punkt gefunden :-))
Die restlichen logischen Fehler (die sich einander ähneln) lasse ich jetzt mal außer Acht.
zu erwähnen wäre vielleicht noch ».{1}« was das gleiche ist wie ».« :-)
Trotzdem mal noch ein Lösungsansatz für deinen RegEx: Du könntest den Modifier U (für ungreedy, also "unhungrig"/nicht gefräßig) verwenden.
ich würde den RegEx gleich wegwerfen - in E-Mailadressen sind nämlich noch _wesentlich_ mehr Zeichen erlaubt (schon alleine die Umlaute in Umlautdomains, siehe http://aktuell.de.selfhtml.org/tippstricks/programmiertechnik/email/)
$correct_nopt = @fopen("http://www.".$treffer[1],"r");
woher willst du wissen, das
a) die Domain per http ereichbar ist? (bei dem Domain-Teil meiner FH-Adresse (»student.fh-nuernberg.de«) würdest du hier auf Granit beißen)
b) die Subdomain "www" eingerichtet ist
?
Was ich versuche ist, den Host aus dem Domain Teil anzusprechen. Dass da natürlich auch richtige E-Mails verweigert werden können, weil der Server z.B. grade down ist, ist klar.
selbst wenn der Test erfolgreich ist, ist immernochnicht sicher, dass die E-Mailadresse auch existiert ...
Na ja, da müsste man sicherlich noch was dran machen....
ja, z.B. einen ganz einfachen regulären Ausdruck wie »~^.+@.+..{1,20}$~« nehmen: so prüfst du auf den grundlegensten Syntax (zeichen@zeichen.zeichen) - und wirklich auf Gültigkeit und Existenz(!) kannst du sowieso nicht testen.
Grüße aus Nürnberg
Tobias
Hi Tobias,
Ferner setzt du durch vorraus, dass der Teil vor dem @ mindestens 3 Zeichen lang sein muss - ist dem denn wirklich so?
nein, ich habe auch eine E-Mailadresse die mit »to@« anfängt.
Das war mehr eine rethorische Frage, aba trotzdem danke, dass du mir das noch mal bestätigst ;-)
In einer Zeichenklasse, also zwischen [ und ] hat ein . immer seine normale Bedeutung und gilt nicht "als Platzhalter für ein beliebiges Zeichen (außer Whitespace)", für was er sonst gilt.
der Punkt erkennt lediglich keine Zeilenumbrüche (außer man verwendet den Modifikator »s«)
ah, stimmt, das hatte ich vergessen. Klar, Es werden nur Zeilenumbrüchen und ich glaube auch Wagenrückläufe (oder wie hieß das?, dieses \r unter Windows) nicht erkannt.
Dann ist deine Logik da auch falsch. Da blickt doch keiner mehr durch, mach das lieber so:
([.]|-|_)?
»[._-]?« sollte es auch tun (ggf. noch runde Klammern um die eckigen um das gefundene Zeichen "festzuhalten")
Stimmt, so gehts natürlich noch einfacher.
Sollte eigentlich genau das gleiche bewirken: Entweder ein -, oder ein _, oder ein beliebiges Zeichen, oder gar nichts.
mhh... ein paar Zeilen weiter oben behauptest du noch, dass ein »[.]« nur einen Punkt findet und nicht ein beliebiges Zeichen (was afaik auch richtig ist) - und jetzt soll »[.]« beliebige Zeichen finden (in dem Fall wäre es übrigends relativ sinnlos »-« und »_« noch extra aufzuführen - sie würden ja auch vom Punkt gefunden :-))
Uuups, da hab ich mich aber verlaufen ;-))
Du hast natürlcih recht, ich war irgendwie durch diesen ewig langen RegEx und an der Stelle durch diese ?-Kombination irgendwie etwas durcheinander ;-)
Die restlichen logischen Fehler (die sich einander ähneln) lasse ich jetzt mal außer Acht.
zu erwähnen wäre vielleicht noch ».{1}« was das gleiche ist wie ».« :-)
richtig.
Trotzdem mal noch ein Lösungsansatz für deinen RegEx: Du könntest den Modifier U (für ungreedy, also "unhungrig"/nicht gefräßig) verwenden.
ich würde den RegEx gleich wegwerfen - in E-Mailadressen sind nämlich noch _wesentlich_ mehr Zeichen erlaubt (schon alleine die Umlaute in Umlautdomains, siehe http://aktuell.de.selfhtml.org/tippstricks/programmiertechnik/email/)
Das wollte ich eigentlich auch so vermitteln, habe es dann aber nicht so direkt gesagt, in Anbedacht der Mühe, mit der der OP den RegEx erstellt hat :-P
$correct_nopt = @fopen("http://www.".$treffer[1],"r");
woher willst du wissen, das
a) die Domain per http ereichbar ist? (bei dem Domain-Teil meiner FH-Adresse (»student.fh-nuernberg.de«) würdest du hier auf Granit beißen)
das war ja das, was ich unten noch angemerkt habe, natürlich muss nicht jede Domain über http:// erreichnbar sein.
b) die Subdomain "www" eingerichtet ist
gut, dass habe ich wirklich übersehen. aber ich denke mal, ich lasse diesen gedanken eh wieder verfallen.
Was ich versuche ist, den Host aus dem Domain Teil anzusprechen. Dass da natürlich auch richtige E-Mails verweigert werden können, weil der Server z.B. grade down ist, ist klar.
selbst wenn der Test erfolgreich ist, ist immernochnicht sicher, dass die E-Mailadresse auch existiert ...
natürlich, aber wenn der Test erfolgreich ist, existiert wenigstens die Domain.
Na ja, da müsste man sicherlich noch was dran machen....
ja, z.B. einen ganz einfachen regulären Ausdruck wie »~^.+@.+..{1,20}$~« nehmen: so prüfst du auf den grundlegensten Syntax (zeichen@zeichen.zeichen) - und wirklich auf Gültigkeit und Existenz(!) kannst du sowieso nicht testen.
Hm, mehr wird man wohl nicht machen können. Die einzige Methode zu prüfen ob eine E-Mail Adresse existiert, wird wohl auch weiterhin bleiben, eine E-Mail mit irgendeinem zufällig generiertem String dahinzu schicken, den der Besucher dann fernen benötigt (Freischaltcode, Passwort...)
MfG, Dennis.