PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : PHP E-Mail-Validation mit IDN (Internationalized domain name) Support


Atomic
13.07.2009, 16:52
Internationale Domain Namen (IDN) - Was ist das?
Seit 2004 dürfen *.de-Domains (und auch einige andere Top-Level-Domains) Umlaute (äöü...) enthalten.

Das Problem: Während man nun seit 5 Jahren solche Domain-Namen registrieren kann ist die Unterstützung in Web-Software (CMS, Services, Websites) katastrophal. Ich möchte hier einen kleinen Beitrag leisten.

Und zwar möchte ich erstens zeigen wie man mit IDN-Domains umgeht. Und zweitens möchte ich zeigen wie man E-Mail Adressen mit IDN-Domains validiert.

Was man über IDN-Domains wissen muss, ist folgendes:
IDN-Domains werden in Unicode DARGESTELLT.
Da man Unicode so schlecht verarbeiten kann gibt es eine Art "Codex", welcher den Domain-Namen so umschreibt, dass er nur noch ASCII-Zeichen enthält:

Aus http://süße.de wird xn--httpssse-b6a.de

Diese neue "Schreibweise" nennt sich Punycode.
( Punycode ? Wikipedia (http://de.wikipedia.org/wiki/Punycode) )

Den "Codex" um zwischen Punycode und Unicode hin und her zu übersetzen gibt es z.B. bei PEAR: Net_IDNA (http://pear.php.net/package/Net_IDNA)
Oder einfach im Anhang dieses Posts.
Für den folgenden Code ist es zwingend notwendig die Version im Anhang dieses Postes zu verwenden! (Klassennamen habe ich abgeändert.)

Die Validierungsfunktion habe ich von http://www.linuxjournal.com/article/9585 übernommen und erweitert mit IDN-Domains Support. Guter Artikel!

/*
* Make sure you got the version from http://hx3.de/software-webentwicklung-23/php-e-mail-validation-idn-internationalized-domain-name-support-17398/
*/
include_once("IDNA.php");


/**
* PHP Validation
*
* @author Douglas Lovell (http://www.linuxjournal.com/article/9585) Thanks!
* @return string the error message if an error occures else return void
*/
function validate($email){
$email = trim($email);

//Minimum lenght
$min_lenght=5;

//Maximimum lenght your database acceppts (VARCHAR(265))
$max_lenght=265;

$isValid = true;
$atIndex = strrpos($email, "@");

if(empty($email)){

$error="Field is empty";

} else if ($atIndex===null||$atIndex===false){

$isValid = false;

} else if(strlen($email)<$min_lenght){

$error=$min_lenght." chars are required!";

} else if(strlen($email)>$max_lenght){

$error="Only ".$max_lenght." chars are allowed!";

} else {
$domain = substr($email, $atIndex+1);

if (strrpos($domain, ' ')!==false) {
$error="EMail-Adress is not valid!";
} else {
/*
* Lets encode the domain-name to punycode
*/
$idna_converter = new convert_IDNA();
//try{
$domain = $idna_converter->encode($domain);
//} catch(exception $e){
//$isValid=false;
//}
$local = substr($email, 0, $atIndex);
$localLen = strlen($local);
$domainLen = strlen($domain);
if ($localLen < 1 || $localLen > 64){
// local part length exceeded
$isValid = false;
} else if ($domainLen < 1 || $domainLen > 255) {
// domain part length exceeded
$isValid = false;
} else if ($local[0] == '.' || $local[$localLen-1] == '.') {
// local part starts or ends with '.'
$isValid = false;
} else if (preg_match('/\\.\\./', $local)) {
// local part has two consecutive dots
$isValid = false;
} else if (!preg_match('/^[A-Za-z0-9\\-\\.]+$/', $domain)) {
// character not valid in domain part
$isValid = false;
} else if (preg_match('/\\.\\./', $domain)) {
// domain part has two consecutive dots
$isValid = false;
} else if (!preg_match('/^(\\\\.|[A-Za-z0-9!#%&`_=\\/$\'*+?^{}|~.-])+$/', str_replace("\\\\","",$local))){
// character not valid in local part unless
// local part is quoted
if (!preg_match('/^"(\\\\"|[^"])+"$/', str_replace("\\\\","",$local))){
$isValid = false;
}
}
if ($isValid && !(checkdnsrr($domain,"MX") || checkdnsrr($domain,"A"))) {
// domain not found in DNS
$error="EMail-Adress seems to not exist!";
} else if(!$isValid){
$error="EMail-Adress is not valid!";
}
}
}

if(isset($error)) return $error;
else return;
}


/**
* Encode E-Mail to Punycode
*
* @param string email-adress
* @author Herbert Walde
* @see http://hx3.de/software-webentwicklung-23/php-e-mail-validation-idn-internationalized-domain-name-support-17398/
* @return string punycode of email
*/
function encodeEMail($unicode_email){
$atIndex = strrpos($unicode_email, "@");
$domain = encodeDomain(substr($unicode_email, $atIndex+1));
$local = substr($unicode_email, 0, $atIndex);
return $local."@".$domain;
}


/**
* Decode E-Mail to Unicode
*
* @param string email-adress
* @author Herbert Walde
* @see http://hx3.de/software-webentwicklung-23/php-e-mail-validation-idn-internationalized-domain-name-support-17398/
* @return string email in unicode
*/
function decodeEMail($punycode_email){
$atIndex = strrpos($punycode_email, "@");
$domain = decodeDomain(substr($punycode_email, $atIndex+1));
$local = substr($punycode_email, 0, $atIndex);
return $local."@".$domain;
}


/**
* Encode IDN-Domain to Punycode
*
* @param string domain
* @author Herbert Walde
* @see http://hx3.de/software-webentwicklung-23/php-e-mail-validation-idn-internationalized-domain-name-support-17398/
* @return string domain in punycode
*/
function encodeDomain($unicode_domain){
$idna_converter = new convert_IDNA();
return $idna_converter->encode($unicode_domain);
}


/**
* Decode Punycode-Domain to IDN-Domain
*
* @param string domain
* @author Herbert Walde
* @see http://hx3.de/software-webentwicklung-23/php-e-mail-validation-idn-internationalized-domain-name-support-17398/
* @return string domain in unicode
*/
function decodeDomain($punycode_domain){
$idna_converter = new convert_IDNA();
return $idna_converter->decode($punycode_domain);
}


//////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////// BEISPIELE /////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////


$email = " customer/department=shipping@süßes.com ";

$error = validate($email);
if(isset($error)){
echo "An error occured: ".$error;
} else {
//save $email to database:
$sql = "INSERT INTO users (email) VALUES (\"".$pdo->quote($email)."\");";
$pdo->query($sql);
//.........

//send email to user:
$punycode_email = encodeDomain($email);
mail($punycode_email, "Test Mail", "Dies ist ein Test.");
}

Kleinere Bugs vorbehalten. (Ich musste den Code umschreiben.)

Der Quellcode von PEAR_IDNA steht unter der GPL.