Validazione email con javascript e PHP
Seguendo alla lettera le specifiche RFC
Sempre la solita solfa!
Come fare a validare un indirizzo email con javascript?
La risposta quasi sempre è una questa semplice funzioncina:
function validEmail(email) {
return /^([a-zA-Z0-9_.-])+@([a-zA-Z0-9_.-])+.([a-zA-Z])+([a-zA-Z])+/.test(email);
}
Bene... questa è sbagliata!!! Non riesce a validare alcuni indirizzi email! non ci credete?
Facciamo dei test con i seguenti indirizzi email (clicca sul ▶ per eseguire il test):
function validEmail(email) {
return /^([a-zA-Z0-9_.-])+@([a-zA-Z0-9_.-])+.([a-zA-Z])+([a-zA-Z])+/.test(email);
}
[
`prova@example.com`,
`prova.test@example.com`,
`prova.test@example.com`,
`provà@example.com`,
`甲斐@黒川.日本`,
`prova@127.0.0.1.com`,
`prova+test@example.com`,
`!#$%&'*+-/=?^_{|}~@example.com`,
].forEach(email => {
if (validEmail(email)) {
console.log('valido: ', email);
} else {
console.error('errato: ', email);
}
});
Ora molti diranno... È ovvio che gli ultimi non vengano validati! Sono pieni di caratteri strani, incomprensibili! Sono certamente errati!
E qui casca l'asino.
Tutti gli indirizzi qui sopra sono validi! Non mi credete? Analizziamoli passo a passo
Email con caratteri accentati / non latini
Le email citate prima ( provà@example.com e 甲斐@黒川.日本 ) sono assolutamente valide, poiché da settembre 2009 è stata data la possibilità di registrare domini con caratteri anche non latini, detti domini internazionalizzati.
Email che contengono simboli
Spulciando le specifiche dell'email (per semplicità date un'occhiata alla wikipedia inglese) ho scoperto che in realtà in esse non sono definiti i caratteri validi, ma quelli non validi. E non sono tanti come si possa immaginare! Quindi email caratteri come parentesi grafe, asterischi, tilde, dollari ecc. sono assolutamente da ritenersi valide.
La funzione di validazione email definitiva
Girando per internet sono riuscito a trovarla! Craig Cockburn modificando la funzione di Sandeep V. Tamhankar!, ha creato una funzione che segue alla lettera le specifiche riguardanti le email, così da non dover aver più nessun problema in futuro! (almeno finché non cambiano le specifiche :D )
function emailCheck(emailStr) {
const emailPat = /^(.+)@(.+)$/;
const specialChars = `\\(\\)<>@,;:\\\\\\\"\\.\\[\\]`;
const validChars = `[^\\s` + specialChars + `]`;
const quotedUser = `("[^"]*")`;
const ipDomainPat = /^\[(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})\]$/;
const atom = validChars + `+`;
const word = `(` + atom + `|` + quotedUser + `)`;
const userPat = new RegExp(`^` + word + `(\\.` + word + `)*$`);
const domainPat = new RegExp(`^` + atom + `(\\.` + atom + `)*$`);
const matchArray = emailStr.match(emailPat);
if (matchArray == null) {
console.error(`L'email sembra essere sbagliata: (controlla @ e .)`);
return false;
}
const user = matchArray[1];
const domain = matchArray[2];
if (user.match(userPat) == null) {
console.error(`La parte dell'email prima di '@' non sembra essere valida!`);
return false;
}
const IPArray = domain.match(ipDomainPat);
if (IPArray != null) {
for (var i = 1; i <= 4; i++) {
if (IPArray[i] > 255) {
console.error(`L'IP di destinazione non è valido!`);
return false;
}
}
return true;
}
const domainArray = domain.match(domainPat);
if (domainArray == null) {
console.error(`La parte dell'email dopo '@' non sembra essere valida!`);
return false;
}
const atomPat = new RegExp(atom, `g`);
const domArr = domain.match(atomPat);
const len = domArr.length;
if (domArr[domArr.length - 1].length < 2 ||
domArr[domArr.length - 1].length > 6) {
console.error(`Il dominio di primo livello (es: .com e .it) non sembra essere valido!`);
return false;
}
if (len < 2) {
console.error(`L'indirizzo manca del dominio!`);
return false;
}
return true;
}
[
`prova@example.com`,
`prova.test@example.com`,
`prova.test@example.com`,
`prova.test@international.com`,
`provà@example.com`,
`甲斐@黒川.日本`,
`prova@127.0.0.1.com`,
`prova+test@example.com`,
`!#$%&'*+-/=?^_{|}~@example.com`,
].forEach(email => {
if (emailCheck(email)) {
console.log('valido: ', email);
} else {
console.error('errato: ', email);
}
});
Conclusioni
Le email con caratteri strani e lettere accentate non hanno ancora preso piede e devo dire per esperienza personale che è alquanto difficile utilizzare una email con simboli "non consoni": mi ero fatto un indirizzo #chalda#@example.com e non vi dico le difficoltà nell'utilizzarlo in giro, poiché tutti i sistemi automatici utilizzano validazioni come quella qui sopra. E allora vai di segnalazioni al webmaster
Inoltre quando operatori telefonici mi richiedevano un indirizzo email il 25% sbagliava a scriverlo, il 25% mi diceva che non poteva essere valido e l'altro 50% non riusciva ad inserirlo nel sistema. Un buon metodo anti spam devo dire. :D
Tutta questa male informazione penso sia stata creata da Hotmail, Yahoo, Gmail e affini: questi servizi, inserendo delle limitazioni nella possibilità di scegliere l'indirizzo email, hanno fatto supporre a tutti i loro utenti (che sono una gran fetta del mercato) che le email devono per forza essere fatte a quella maniera.
Ora sapete che non è così. :)
Validazione con PHP1
In php invece esiste già una funzione nativa per validare le email:
filter_var($email, FILTER_VALIDATE_EMAIL);
Ma anche in questo caso non funziona con la parte locale e con i domini con caratteri accentati.
La soluzione è quella di utilizzare l'opzione di filter_var FILTER_FLAG_EMAIL_UNICODE e convertire il nome del dominio in Punycode .
La funzione corretta quindi è la seguente:
function validEmail($email){
$atPos = strrpos($email, '@');
if ($atPos === false) return false;
$local = substr($email, 0, $atPos);
$domain = substr($email, $atPos + 1);
$asciiDomain = idn_to_ascii($domain, IDNA_NONTRANSITIONAL_TO_ASCII, INTL_IDNA_VARIANT_UTS46);
return filter_var($local . '@' . $asciiDomain, FILTER_VALIDATE_EMAIL, FILTER_FLAG_EMAIL_UNICODE);
}
Commenti
Rileggendo il mio post e considerando il fatto che non sono riuscito a trovare una funzione equivalente in PHP, ho pensato di convertire la funzione io stesso.
Finalmente l'ho trovato, grazie!
Scusate la domanda, Magari parlo da ignorantissimo essendo nuovo dell'ambito ma perchè uccidersi a fare una funzione così lunga quando si potrebbe semplicemente impostare che la chiocciola debba essere posizionata al secondo carattere? O meglio, se la mail deve accettare praticamente ogni simbolo o carattere , perchè non dirgli direttamente di accettare tutto a patto che la chiocciola sia inserita in una posizione realistica per una mail?
@Fabrizio: Semplicemente per avere una funzione che segue le specifiche, così sei sicuro di avere email valide :-)
Grazie per la segnalazione! io fino ad oggi ho usato:
E sinceramente credo di continuare ad usare questa per la sua semplicità e leggerezza anche perchè fino ad oggi mi è servita in controlli dove l'utenza media di provenienza esclusivamente italiana non va oltre a nome.congnome@miodiminio.com e non sa e forse è meglio così di poter usare caratteri ""strani"" quindi mi ""tolgo"" il problema dei domini internazionalizzati, però mi lascia perplesso la possibilità di ammettere email nella forma: !#$%&'*+-/=?^_`{|}~@example.com nel senso come le maneggi in sicurezza delle mail che hanno caratteri che in php sarebbero fatali?
Ciao,
bisogna anche tener presente un'altra cosa: esistono gli alias o mail temporanee che uno può crearsi come vuole, è per questo che ho messo la reg così e un codice a parte che la limita a 320 caratteri totali
In questo modo uno può inserire quello che vuole ed ha solo 3 obblighi: la chiocciola, il punto prima del dominio e dominio da 2-6 caratteri minuscoli
Guida inutile direi, chi è che utilizza email con simboli? nessuno e credo anche che non sia possibile usarli. La stessa cosa vale per i caratteri accentati, quasi nessuno ce l'ha.
Sarà anche inutile, ma qui non stavo valutando l'utilità, ma la funzionalità. Le specifiche esistono, poi se i provider si limitano a "solo lettere e numeri" quella è un'altra cosa!
Grazie x l 'informazioni
Lascia un commento