indirizzo email formalmente valido e esistente

borgo italia

Super Moderatore
Membro dello Staff
SUPER MOD
MOD
4 Feb 2008
16.044
150
63
PR
www.borgo-italia.it
piccola funzione per verificare un indirizzo email.
verifica che sia formalmente corretto e, in una certa misura, verifica che esista.
in una certa misura perchè, pur esistendo il dominio, non è detto che l'indirizzo esista, comunque un certo grado di sicurezza in più la da
PHP:
<?php
function valida_email($email){
	//per prima cosa valido formalmente l'indirizzo
	if(!filter_var($email, FILTER_VALIDATE_EMAIL)){
		return false;//non formalmente valido
	}else{
		//l'indirizzo è formalmente valido e quindi lo divido
		$divisa=explode('@',$email);
		//list($prefisso, $dominio) = split("@",$email);
		//verifico che sia possibile utilizzare getmxrr e che il dominio esita
		//ho letto che su piattaforma windows getmxrr ha dei problemi
		if(function_exists("getmxrr") && getmxrr($divisa[1], $mxhosts)){
			//un elenco dei record MX trovati è posto nell'array $mxhosts.
			return true;//è stato possibile usare getmxrr e il dominio esiste
		}elseif (@fsockopen($divisa[1], 25, $err_nu, $err_str, 5)){
        	return true;//non posso usare getmxrr ma il dominio esiste
		}else{
        	return false;//il dominio non esiste
		}
	}
}
//TEST.......
//l'array: valida inesistente errata .. il dubbio
$em=array("[email protected]","[email protected]","info#borgo-italia.it","[email protected]", "[email protected]");
foreach($em as $e){
	if(valida_email($e)){
		echo "$e valida e esitente<br />";
	}else{
		echo "$e non è formalmente valida o non è esitente<br />";
	}
}
?>
come detto, provando il test, risulta:
[email protected] valida e esitente
[email protected] non è formalmente valida o non è esitente
info#borgo-italia.it non è formalmente valida o non è esitente
[email protected] valida e esitente
[email protected] valida e esitente
dove di sicuro [email protected] non esiste e [email protected] è probabile che non esista
 
Per rendere "più sicuro" un indirizzo email il sito di PHP consiglia questa procedura:
PHP:
$c = '([email protected])';
$sanitized_c = filter_var($c, FILTER_SANITIZE_EMAIL);
if (filter_var($sanitized_c, FILTER_VALIDATE_EMAIL)) {
echo "Email sicura: $sanitized_c";     //   [email protected]
}
In pratica prima si "sanitizza" un indirizzo email alla ricerca di eventuali caratteri spuri come ad esempio parentesi tonde, dopo il filtro di sanitizzazione l'indirizzo sarà reso senza parentesi, ma potevano essere altri caratteri non compresi nell'elenco dell'RFC relativa ( vedi: http://www.faqs.org/rfcs/rfc2822.html ).
Poi una volta tolto tutto ciò che non ci deve essere si verifica se ciò che resta è ancora valido.
Nell'esempio di cui sopra preso dalla pagina di esempi di PHP l'email è resa semplicemente senza parentesi e valida.
Quindi la prima parte del tuo esempio lo modificherei così:
PHP:
function valida_email($email){ 
    //per prima cosa valido formalmente l'indirizzo 
    $email =  filter_var($email, FILTER_SANITIZE_EMAIL);
    if(!filter_var($email, FILTER_VALIDATE_EMAIL)){ 
        return false;  //non formalmente valido 
    }else{
Mentre sulla verifica dei records MX io non mi pronuncio dato che l'argomento è vasto, resta il fatto che è purtroppo semplice mascherarli, però è anche vero che una persona reale che intende contattarci per un motivo reale (incontrarci, chiederci/offrirci un lavoro) di solito non fa queste cose, di solito semplicemente sbaglia a scrivere il proprio indirizzo :D
Magari un upgrade alla funzione potrebbe essere uno che evidenzi gli errori di battitura, purtroppo però SANITIZE_EMAIL non ha un feedback relativamente ai caratteri inseriti malamente, li toglie e basta.
Magari con un approccio diverso, magari tramite regex si può fare.
 
piccola funzione per verificare un indirizzo email.
verifica che sia formalmente corretto e, in una certa misura, verifica che esista.
in una certa misura perchè, pur esistendo il dominio, non è detto che l'indirizzo esista, comunque un certo grado di sicurezza in più la da
PHP:
<?php
function valida_email($email){
	//per prima cosa valido formalmente l'indirizzo
	if(!filter_var($email, FILTER_VALIDATE_EMAIL)){
		return false;//non formalmente valido
	}else{
		//l'indirizzo è formalmente valido e quindi lo divido
		$divisa=explode('@',$email);
		//list($prefisso, $dominio) = split("@",$email);
		//verifico che sia possibile utilizzare getmxrr e che il dominio esita
		//ho letto che su piattaforma windows getmxrr ha dei problemi
		if(function_exists("getmxrr") && getmxrr($divisa[1], $mxhosts)){
			//un elenco dei record MX trovati è posto nell'array $mxhosts.
			return true;//è stato possibile usare getmxrr e il dominio esiste
		}elseif (@fsockopen($divisa[1], 25, $err_nu, $err_str, 5)){
        	return true;//non posso usare getmxrr ma il dominio esiste
		}else{
        	return false;//il dominio non esiste
		}
	}
}
//TEST.......
//l'array: valida inesistente errata .. il dubbio
$em=array("[email protected]","[email protected]","info#borgo-italia.it","[email protected]", "[email protected]");
foreach($em as $e){
	if(valida_email($e)){
		echo "$e valida e esitente<br />";
	}else{
		echo "$e non è formalmente valida o non è esitente<br />";
	}
}
?>
come detto, provando il test, risulta:

dove di sicuro [email protected] non esiste e [email protected] è probabile che non esista

Per sapere se esiste un indirizzo email, la miglior cosa da fare è inviarsi un avviso. Visto che quando non esiste di solito torna un MAILER-DAEMON, si può fare anche il contrario, credo.

Si può prendere spunto da questo http://www.verificaemail.com/verifica_email.php
 
Riporto una considerazione in proposito che scrissi in un altro topic.
Credo sia inutile eseguire tutta questa caterva di controlli che rischiano solo di bloccare utenti che fanno soltanto uso di mail provider che, magari, gestiscono le caselle di alias in un modo non proprio verificabile (vedi esempio @tin.it), anche perché servizi di mail temporanee come 10minutemail sono ormai ingrado di superare da un pò di tempo questo tipo di controlli e le blacklist servono a poco se non sono continuamente aggiornate.

Chiaro, dipende dalle esigenze, ma se si vuol evitare di ricevere spam ci sono sempre alternative come il captcha (o altri escamotage più accessibili) per difendersi dagli invii di dati a puro fine di spam.

Detto questo, c'è anche da considerare che per l'iscrizione ad un servizio, un altro valido mezzo è l'attivazione dell'account tramite link spedito via email. Se dopo ti inondano di spam il problema tange relativamente poiché periodicamente gli account mai attivati possono essere eliminati senza problemi da un job pianificato in automatico.

A questo punto, personalmente, la soluzione che in genere adotto e/o che mi sento di consigliare è un qualcosa che si limiti a:
  • verificare l'esistenza del record MX del DNS della email;
  • verificare la validità sintattica della email;
  • sanitizzare la stringa dell'email.
Riassunta al volo, la funzione risultante potrebbe essere qualcosa di simile a questa:
PHP:
function is_email($email) {

	$mailSplit = explode('@', $email);
	$sanitizedEmail = filter_var($email, FILTER_SANITIZE_EMAIL);

	return checkdnsrr(array_pop($mailSplit), 'MX') && 
		filter_var($email, FILTER_VALIDATE_EMAIL) == $sanitizedEmail?
			$sanitizedEmail : false;
}



var_dump(is_email('[email protected]'));  // string(10) "[email protected]"
var_dump(is_email('[email protected]'));  // string(18) "[email protected]"
var_dump(is_email('[email protected]'));  // bool(false)
var_dump(is_email('invalìd"[email protected]'));  // bool(false)

Nota a margine: fate attenzione, perché l'output generato è si sanitizzato ma i caratteri ammessi dalla RFC 2822 possono far alterare la formulazione delle vostre richieste SQL se non fate uso dei prepared statements.
 
Beh, allora posso continuare ad usare il mio che dalle prove che ho fatto sembra affidabile:

PHP:
//Valida email (Campo non obbligatorio)
if ($suoemail) { 
if (!preg_match("/^[^.-]([.]?[^.-]+)*([-][^.-])?([.]?[^.-])*@(.*)[^.](\.[a-z]{2,6})$/",$suoemail)) {  
echo "Inserire un'email valida";
 }
}
 
A dire il vero no, la tua funzione presenta alcuni problemi di validazione.
Sotto questo aspetto il filter_var di PHP agisce in maniera impeccabile e ti consiglio di usare, se non la funzione che ho esposto io, qualcosa di molto simile logicamente parlando in quanto esegue un ottima validazione sintattica ed unisce un controllo base quantomeno sulla presenza del record MX nei DNS.

Se vuoi invece scrivere da te il parser di validazione allora la tua funzione non centra alcuni punti, come la corretta lunghezza delle stringhe e il corretto range di caratteri ammessi (a questo fine dovresti ben documentarti leggendo le specifiche elencate nella RFC 2822 linkata nel mio post precedente).
 
A dire il vero no, la tua funzione presenta alcuni problemi di validazione.
Sotto questo aspetto il filter_var di PHP agisce in maniera impeccabile e ti consiglio di usare, se non la funzione che ho esposto io, qualcosa di molto simile logicamente parlando in quanto esegue un ottima validazione sintattica ed unisce un controllo base quantomeno sulla presenza del record MX nei DNS.

Se vuoi invece scrivere da te il parser di validazione allora la tua funzione non centra alcuni punti, come la corretta lunghezza delle stringhe e il corretto range di caratteri ammessi (a questo fine dovresti ben documentarti leggendo le specifiche elencate nella RFC 2822 linkata nel mio post precedente).

Vediamo un attimo, la lunghezza totale della mail la controllo con questa:
PHP:
if (strlen($suoemail) > 320) { 
echo "EMAIL: max 320 caratteri";
}

poi, i caratteri accettati sono quelli normalmente accettati, ma non tutti i server sono uguali:

In base allo standard RFC-2822 l’username dev’essere:

1.Username: [^.-]([.]?[^.-]+)*([-][^.-])?([.]?[^.-])*

1. minimo un solo carattere iniziale
2. accetta il punto . molte volte ma non consecutive, non vicino al trattino e non all'inizio o alla fine
3. accetta il trattino - una sola volta, non vicino al punto e non all'inizio o alla fine

2. "@"

3. Dominio: così accetta qualsiasi cosa: (\.[a-z]{2,6})
 
Vediamo un attimo, la lunghezza totale della mail la controllo con questa:
PHP:
if (strlen($suoemail) > 320) { 
echo "EMAIL: max 320 caratteri";
}

Già questa presenta il problema che non ti dice se effettivamente la parte locale dell'indirizzo è lunga massimo i suoi 64 caratteri, puoi facilmente ritrovarti come valide email con parte locale lunga 90 caratteri e dominio lungo 10 (ma può succedere anche il problema inverso).

In base allo standard RFC-2822 l’username dev’essere:
..
1. minimo un solo carattere iniziale
2. accetta il punto . molte volte ma non consecutive, non vicino al trattino e non all'inizio o alla fine
3. accetta il trattino - una sola volta, non vicino al punto e non all'inizio o alla fine

la gestione del punto è corretta quella del trattino no ( [email protected] è considerata sintatticamente valida ) e gli unici caratteri speciali che la parte locale (o lo username) può contenere sono: ! # $ % & ' * + – / = ? ^ _ ` { | } ~

La tua funzione invece prende come valida anche un email di questo tipo: ciao€@email.it

Sono tutti controlli e implementazioni già disponibili nel filter_var, personalmente trovo poco sensato riscriverli.
 
Già questa presenta il problema che non ti dice se effettivamente la parte locale dell'indirizzo è lunga massimo i suoi 64 caratteri, puoi facilmente ritrovarti come valide email con parte locale lunga 90 caratteri e dominio lungo 10 (ma può succedere anche il problema inverso).



la gestione del punto è corretta quella del trattino no ( [email protected] è considerata sintatticamente valida ) e gli unici caratteri speciali che la parte locale (o lo username) può contenere sono: ! # $ % & ' * + – / = ? ^ _ ` { | } ~

La tua funzione invece prende come valida anche un email di questo tipo: ciao€@email.it

Sono tutti controlli e implementazioni già disponibili nel filter_var, personalmente trovo poco sensato riscriverli.

Dal 11 luglio 2012 chiunque voglia registrare un dominio contenente un carattere accentato può farlo. I caratteri ammessi sono : (opzione valida solo per i domini .IT)

Riguardo al trattino multiplo non credo che tutti i server lo accettino, per sicurezza nell'user ne ho messo uno.

Il controllo della lunghezza lo faccio in js:
PHP:
//Conta lunghezza username 
function contaUser(user) {
var max = 64;
var at = user.value.indexOf("@");
var tmp = user.value.split("@");
if( tmp[0].length > max ) {
user.value = tmp[0].substring(0,max) + ( tmp[1] ? "@" + tmp[1] : at >= 0 ? "@" : "" );
document.getElementById('contaUser').innerHTML = "&bull;&nbsp;&nbsp;Username: max 64 caratteri";
return false;
}
else {
document.getElementById('contaUser').innerHTML = "";
}
return true;
}

Questi sono indirizzi validi, anche se può sembrare strano:

[email protected]
[email protected]
[email protected]
[email protected]
• user@[IPv6:2001:db8:1ff::a0b:dbd0]
• "much.unusual"@example.com
• "[email protected]"@example.com
• "very.(),:;<>[]\".VERY.\"very@\\ \"very\".unusual"@strange.example.com
• 0@a
• postbox@com(top-level domains are valid hostnames)
• !#$%&'*+-/=?^_`{}|[email protected]
• "()<>[]:,;@\\\"!#$%&'*+-/=?^_`{}|~?^_`{}|~.a"@example.org
• ""@example.org
 
Ultima modifica:
Mai fidarsi dei controlli lato client, sono tutti facilmente aggirabili.

Gli indirizzi che citi non hanno nulla di strano, rientrano nelle specifiche previste dove è scritto chiaramente che la parte locale può essere una dot-atom con le regole che ti ho esposto prima (prendo un esempio dal tuo elenco)
o una quoted string:
"()<>[]:,;@\\\"!#$%&'*+-/=?^_`{}|~?^_`{}|~.a"@example.org

Per la dot-atom sono valide delle regole, per la quoted string lo sono delle altre e la tua funzione non fa distinzione: ammette caratteri non validi nella dot-atom e non controlla la validità sintattica di una quoted string (che ad esempio chiede le quotes obbligatorie all'inizio e alla fine).

Ripeto: secondo me ha poco senso reinventare da se la ruota quando PHP ha già un implementazione nativa per questo genere di controlli.
 
Ultima modifica:
Mai fidarsi dei controlli lato client, sono tutti facilmente aggirabili.

Gli indirizzi che citi non hanno nulla di strano, rientrano nelle specifiche previste dove è scritto chiaramente che la parte locale può essere una dot-atom con le regole che ti ho esposto prima (prendo un esempio dal tuo elenco)

o una quoted string:


Per la dot-atom sono valide delle regole, per la quoted string lo sono delle altre e la tua funzione non fa distinzione: ammette caratteri non validi nella dot-atom e non controlla la validità sintattica di una quoted string (che ad esempio chiede le quotes obbligatorie all'inizio e alla fine).

Ripeto: secondo me ha poco senso reinventare da se la ruota quando PHP ha già un implementazione nativa per questo genere di controlli.

Il controllo lunghezza l'ho messo in js perché non lo fare in php.

Proverò FILTER_VALIDATE_EMAIL. Addirittura gmail e yahoo non accettano nemmeno un trattino.


 

Discussioni simili