E-Mail-Validierung für IDN-Domains in HTML5, PHP und Javascript

Tach,

ich habe mich heute mal (wieder) informiert, wie man am besten E-Mail-Adressen auf korrektes Format validiert.

Die Situation

Bisher habe ich in PHP immer den mit Version 5.2.0 eingeführten E-Mail-Filter und in Javascript einen regulären Ausdruck verwendet:

PHP:

function checkEmail($email){
	return filter_var($email, FILTER_VALIDATE_EMAIL) !== false;
}

Javascript:

function checkEmail(email){
	return email.match(/^[-a-z0-9~!$%^&*_=+}{\'?]+(\.[-a-z0-9~!$%^&*_=+}{\'?]+)*@([a-z0-9_][-a-z0-9_]*(\.[-a-z0-9_]+)*\.(aero|arpa|biz|com|coop|edu|gov|info|int|mil|museum|name|net|org|pro|travel|mobi|[a-z][a-z])|([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}))(:[0-9]{1,5})?$/i);
}

HTML5:

Auch HTML5 bietet die Möglichkeit, ein Eingabefeld des Typs E-Mail zu erzeugen:

<!DOCTYPE html>
<html lang="de">
    <head>
        <title>E-Mail-Validierung</title>
    </head>
    <body>   
        <form>
            <input type="email">
            <input type="submit">
        </form>   
    </body>
</html>

Demo für HTML5 und Javascript.

Das Problem

Das Problem ist nun, dass keine der drei Lösungen IDN-Domains bei E-Mail-Adressen akzeptiert (siehe [1] und [2]). Das heißt Adressen wie foo@bär.de, die durchaus gültig sind, werden als ungültig erkannt.

Die Lösung

Als Lösung muss man also den Domain-Teil in Punycode konvertieren, um danach das Format prüfen zu können.

PHP:

Für PHP kann man hierzu auf das Modul intl bzw. speziell auf die Funktion idn_to_ascii
zurückgreifen.

function checkEmail($email){
	$parts = explode('@', $email);
	return count($parts) == 2 && filter_var($parts[0].'@'.idn_to_ascii($parts[1]), FILTER_VALIDATE_EMAIL) !== false;
}

Javascript:

Für Javascript bin ich auf eine tolle Bibliothek von Mathias Bynens gestoßen. Damit lässt sich das Problem analog zu PHP lösen.

function checkEmail(email){
	var parts = email.split('@');
	if(parts.length != 2){
		return false;
	}
	var converted = parts[0] + '@' + punycode.toASCII(parts[1]);

	return converted.match(/^[-a-z0-9~!$%^&*_=+}{\'?]+(\.[-a-z0-9~!$%^&*_=+}{\'?]+)*@([a-z0-9_][-a-z0-9_]*(\.[-a-z0-9_]+)*\.(aero|arpa|biz|com|coop|edu|gov|info|int|mil|museum|name|net|org|pro|travel|mobi|[a-z][a-z])|([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}))(:[0-9]{1,5})?$/i);
}

Das Fazit

Mit etwas mehr Aufwand ist es in PHP und Javascript also durchaus möglich IDN-E-Mail-Adressen korrekt zu erkennen. Meiner Meinung nach sollten die PHP-Entwickler ihren E-Mail-Filter erweitern, damit er IDN-Domains akzeptiert.

Für HTML5 gibt es dafür keine Lösung, solange die Browser-Entwickler es nicht berücksichtigen. Eingabefelder vom Typ „url“ können übrigens mit IDN-Domains umgehen. Warum also nicht auch E-Mail-Felder?

Da davon auszugehen ist, dass sich „Umlautdomains“ (wie man so schön sagt) in Zukunft weiter verbreiten werden, wäre es wichtig, dass Browser jetzt schon im vollen Umfang darauf vorbereitet wären.

[1] http://www.php.net/manual/en/filter.filters.validate.php#102398
[2] http://barrow.io/posts/email-validation-of-double-byte-domains/

Deutsches Datum bei Facebook

Kurz ein kleines Greasemonkey Script um deutsche Datumsanzeigen bei Facebook zu erzeugen.

Mit Datumsanzeigen mein ich den title-Tag der Angaben bei „Vor X Minuten“ usw.

datum

// ==UserScript==
// @name           FacebookDate
// @namespace      bla
// @include        http://www.facebook.com/*
// ==/UserScript==

function xpath(src,query) {
	var res = document.evaluate(query, src, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null);
	res.length = res.snapshotLength;
	res.item = res.snapshotItem;
	return (res.snapshotLength > 0) ? res : false;
}

var res = xpath(document,"//abbr[@class='timestamp']");
if(res){
	for(var i=0; i < res.length; i++){
		var d = new Date(Date.parse(res.item(i).title));
		res.item(i).title = d.getDate() + "." + ((d.getMonth() + 1) % 12) + "." + d.getFullYear() + " " + d.getHours() + ":" + d.getMinutes() + ":" + d.getSeconds();
	}
}

Hier das Script zum Download facebookdate.user.

gzip komprimierte Javascript- und CSS-Dateien

Hi,

im letzten Post habe ich über eine komprimierte Variante der neuesten Prototype-Version geschrieben. Wie versprochen werde ich in diesem Post erklären, wie man so eine mit gzip-komprimierte Datei möglichst elegant und flexibel in seine Seite einbindet.

Dazu legt man einfach eine .htaccess-Datei mit folgendem Inhalt an:

RewriteCond %{HTTP:Accept-Encoding} .*gzip.*
RewriteCond %{REQUEST_FILENAME} ^.+\.(js|css)$
RewriteCond %{REQUEST_FILENAME}.gz -f
RewriteRule ^(.+) $1.gz [QSA,L]
RemoveType .gz
AddEncoding x-gzip .gz

Wichtig: der Apache muss mod_rewrite aktiviert haben!

Jetzt muss man nur noch für alle Dateien, die man komprimiert ausliefern will eine entsprechende Variante mit dem Suffix .gz im gleichen Verzeichnis in dem das Original liegt anlegen.

Ist eine solche gzip Datei vorhanden wird diese anstatt der unkomprimierten Variante übertragen, ansonsten ändert sich nichts.

Hinweis: folgende Zeile war bei mir zwingend nötig um die globale Einstellung vom Apache zu überschreiben. Keine der Lösungen, die im Netz gefunden habe, weist darauf hin!

RemoveType .gz

Unterstützt ein Browser keine Komprimierung (sowas gibts hoffentlich nicht mehr, selbst der IE4 kann das) werden die Regeln einfach ignoriert.

Das wars auch schon. Mit dieser kleinen, aber feinen Lösung verkürzt man die Ladezeit seiner Seite erheblich.

object doesn’t support this property or method

Hi,

bin grad mal wieder über ein total dämliches Problem mit dem Internet Explorer gestolpert.

element = document.getElementById('element');

Das wird einen Fehler werfen, sobald ihr auf element zugreifen wollt.
Warum? Tja, eigentl eine gute Frage. Die Antwort ist umso schockierender.

Der Internet Explorer scheint sich intern für jedes Element mit einer eindeutigen ID bereits eine Variable zu reservieren. Ergo, der Versuch diese zu überschreiben schlägt fehl und somit auch alle späteren Versuche darauf zuzugreifen.

Abhilfe schafft hier einfach das Wählen eines anderen Variablennamens.