Nel realizzare un qualsiasi form di registrazione, o un’area di accesso in cui l’utente esterno dovrà inserire la sua login, dobbiamo prevedere la possibilità che il visitatore possa dimenticare la sua password. Non è una cosa poco frequente, soprattutto se l’utente utilizza password diverse per accedere ai suoi vari account: ricordarle tutte può diventare un’impresa.
Ecco allora che ci tornerà utile uno script per recuperare la password dimenticata.
I tipi di approccio sono molteplici: quello che vi vado a presentare è solo uno dei tanti e può essere adattato (e migliorato) in base all’esigenza, magari inserendo la classica “domanda” a cui l’utente dovrà rispondere per ricevere la password direttamente al suo indirizzo email.
In questo tutorial ho preparato alcune classi di esempio per formattare i campi tramite css: dovrete occuparvi voi di creare il dovuto foglio di stile, in base al layout del vostro sito.
Si dà per scontato che abbiate delle conoscenze, almeno di base, nell’uso delle funzioni php e nell’invio email con questo linguaggio. Inoltre è utile una conoscenza dell’uso dei database: nell’esempio, infatti, presuppongo che abbiate gli utenti salvati in un database di tipo mysql. Non è un passaggio obbligatorio – potete anche avere user e password elencati in un file – ma si tratta senz’altro di uno strumento più efficacie e immediato. In caso contrario, dovrete adattare lo script.
Potete anche prendere lo script così com’è e modificare soltanto l’essenziale. Ogni parte è dovutamente commentata.
Se siete invece interessati ad approfondire il tema del login, potete dare un’occhiata all’articolo che ho scritto a questo indirizzo.
Download script
Il form di login
Il nostro form di login, ridotto all’essenziale, avrà questa forma:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
<!-- Il form è solo di esempio. Cliccando sul link in basso si va al file “recupero.php”, che si occupa di recuperare la password. --> <form action="#form" method="post" id="login"> <div class="campo_contatti"> <div class="voce_campo">* email</div> <input type="text" name="email" value="<?=@$_POST['email']?>" class="campo" <?php if(!$email || !$password) echo $errore; ?> /> </div> <div class="campo_contatti"> <div class="voce_campo">* password</div> <input type="password" name="password" value="" class="campo" <?php if(!$email || !$password) echo $errore; ?> /> </div> <div class="clear"></div> <div class="campo_contatti"> <input type="submit" value="Accedi" /> </div> <div class="clear"></div> <div class="campo_contatti"> Hai dimenticato la password? Clicca <a href="recupero.php" style="color: red">qui</a> </div> <div class="clear"></div> </form> |
Nell’esempio l’utente deve inserire l’email e la password per accedere: avremo quindi il dato “email” già a disposizione in caso di smarrimento password. Nel caso in cui l’accesso avvenga invece per nickname, durante la registrazione dovrete aver predisposto un ulteriore campo per l’inserimento dell’email, un dato indispensabile per il recupero della password.
In caso di smarrimento della password, l’utente potrà cliccare sul link sottostante al form e verrà indirizzato al file recupero.php
.
Form di recupero della password
Nel file di recupero della password avremo due passaggi chiave:
– creazione di un form, dove l’utente scriverà la sua email (che corrisponde all’user di accesso) in cui riceverà la nuova password;
– l’invio dell’email che conterrà il link a una nuova pagina, dove confermerà la richiesta di una nuova password. La conferma ci è necessaria per evitare che un qualsiasi intruso possa richiedere la password di un utente semplicemente conoscendo il suo indirizzo email, digitandolo come indirizzo nel browser.
Come valore univoco per identificare l’utente, prenderemo l’id con cui è salvato nel database.
Per chi ha meno dimestichezza, consiglio di dare un’occhiata prima alla parte del form e quindi alla parte riguardante l’invio email.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
/* PARTE DELL’INVIO EMAIL. Si controlla che l'email (=user) sia presente nel db. Estraggo quindi id e password dell'utente e li unisco in un'unica stringa ($hash) da passare nel $_GET. La stringa su cui cliccare è inviata per email, come conferma, e rinvia al file “nuova_password.php”. */ if(isset($_POST['email'])){ $errore=0; //variabile di controllo errori (se rimane a 0 non ci sono errori) if($_POST['email']==""){ $errore=1; }else{ $result=mysql_query("select id, password from utenti where email='".$_POST['email']."' limit 0,1", $db); if(mysql_num_rows($result)>0){ $row=mysql_fetch_array($result); //l’hash ci servirà per recuperare i dati utente e confermare la richiesta //la password nel database si presume criptata, con md5 o altro algoritmo //al posto di questi due dati, se ne possono usare altri legati all’utente, purché univoci $hash=$row['password']."".$row['id']; }else $errore=1; } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
//se non ci sono stati errori, invio l’email all’utente con il link da confermare if($errore==0){ $header= "From: sito.it <info@sito.it>\n"; $header .= "Content-Type: text/html; charset=\"iso-8859-1\"\n"; $header .= "Content-Transfer-Encoding: 7bit\n\n"; $subject= "sito.it - Nuova password utente"; $mess_invio="<html><body>"; $mess_invio.=" Clicca sul <a href=\"http://www.sito.it/nuova_password.php?hash=".$hash."\">link</a> per confermare la nuova password.<br /> Se il link non è visibile, copia la riga qui sotto e incollala sul tuo browser: <br /> http://www.sito.it/nuova_password.php?hash=".$hash." "; $mess_invio.='</body><html>'; //invio email if(@mail($_POST['email'], $subject, $mess_invio, $header)){ echo "<div class=\"campo_contatti\" style=\"margin-left: 20px; height: 300px\">"; echo "Email inviata con successo. Controlla la tua email<br /><br />"; echo "</div> <div class=\"clear\"></div>"; unset($_POST); //elimino le variabili post, in modo che non appaiano nel form } } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
<!-- FORM BASE L'utente inserisce la sua email (che dovrà corrispondere a quella salvata nel database). --> <form action="" method="post" id="login"> <div class="campo_contatti"> <div class="voce_campo">Inserisci la tua email per ricevere la nuova password</div> <input type="text" name="email" value="<?=@$_POST['email']?>" class="campo" /> </div> <div class="clear"></div> <div class="campo_contatti"> <input type="submit" value="invia" /> </div> <div class="clear"></div> </form> |
Conferma della password
Una volta ricevuta l’email e cliccato sul link di conferma password, l’utente sarà indirizzato alla pagina nuova_password.php
, dove sarà passata anche una variabile get contenente la vecchia password (criptata) e l’id dell’utente salvato nel database.
Anche qui i passaggi sono pochi:
– divido la variabile $hash nei suoi due componenti (vecchia password e id)
– creo una nuova password a random e la salvo nel database al posto di quella vecchia
– invio all’email dell’utente la nuova password creata
1 2 3 4 5 6 7 8 9 10 |
<?php //funzione che crea una password random function random($lunghezza=12){ $caratteri_disponibili ="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890"; $codice = ""; for($i = 0; $i<$lunghezza; $i++){ $codice = $codice.substr($caratteri_disponibili,rand(0,strlen($caratteri_disponibili)-1),1); } return $codice; } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
<?php //il controllo del get evita errori di pagina if(isset($_GET['hash'])){ $hash=$_GET['hash']; $id=substr($hash, 32); $password_old=substr($hash, 0, 32); $password=random(8); //nuova password di 8 caratteri //controllo che i valori dell’hash corrispondano ai valori salvati nel database $result=mysql_query("SELECT * FROM utenti WHERE id=".$id." AND password='".$password_old."'", $db); if(mysql_num_rows($result)>0){ $row=mysql_fetch_array($result); $email=$row['email']; //salvo la nuova password al posto della vecchia (in md5) $result=mysql_query("update utenti set password='".md5($password)."' where id=".$id." and password='".$password_old."'", $db); $header= "From: sito.it <info@sito.it>\n"; $header .= "Content-Type: text/html; charset=\"iso-8859-1\"\n"; $header .= "Content-Transfer-Encoding: 7bit\n\n"; $subject= "sito.it - Nuova password utente"; $mess_invio="<html><body>"; $mess_invio.=" La sua nuova password utente è ".$password."<br /> Ora puoi accedere all'area <a href=\"http://www.sito.it/login.php\" style=\"color: red\">Login</a>. "; $mess_invio.='</body><html>'; if(@mail($email, $subject, $mess_invio, $header)){?> La password è stata cambiata con successo. Controlla la tua email.<br /><br /> <?php } } } //if(isset($_GET['hash'])) ?> |
Ottimo script funge perfettamente. grazie
Non c’è di che 😉
a me non succede nulla quando premo invia ,
Prova a controllare innanzitutto che lo script dell’email ti funzioni (anche se dovrebbe darti un errore a video, in caso contrario).
Se premendo invio non succede niente, significa che il form non viene inviato
e devo capire perché il form non viene inviato
Forse essendo che sto testando l’invio in locale con xaamp , l’invio della mail non parte?
@Antonio
In locale l’email non viene inviata, devi essere online per poterla inviare
Per tesare con le email in locale puoi installare fakeSMTP.
ciao.. non riesco a far funzionare il sistema.. ho provato ad aggiungere i dati di connessione al db …ma niente.. help me please !! 😀
Ciao LaD,
l’email te la invia?
Se non è così (e sei online) prova a vedere se l’errore è in una delle query: stampala a video e inseriscila manualmente nel database (per esempio usando phpmyadmin), così ti rendi conto se il problema è solo di sintassi
Con questo script se scrivo nel browser http://www.sito.it/nuova_password.php?hash=000000000000000000000000000000001234 e “1234” corrisponde ad un ID utente ecco che il link di conferma verrebbe baypassato non essendoci alcun controllo lato script (gli zeri possono essere sostituiti con qualsiasi carattere random per 32 volte).
Ok, come non detto… ho visto ora il controllo sulla query SELECT….
Ho provato il codice e funziona perfettamente. L’unico problema è che all’utente che chiede il recupero della password, gli appare nella posta: “messaggio da Apache”…
E’ possibile modificare il codice per indicare il nominativo che gli spedisce il messaggio con la password dimenticata?
GRAZIE PER LA RISPOSTA
Ciao Tony,
con la riga dell’header dovresti poter gestire il mittente:\n”;
$header= “From: sito.it
Grazie, Manuel Marangoni, ho provato e funziona perfettamente.
GRAZIE MILLE
Figurati 😉
Salve, non capisco come questa parte del codice di recupero: <input type="text" name="email" value="” class=”campo” />
L’argomento del value cosa sarebbe? Non trovo altri esempi per capire, e il modulo non invia nulla all’indirizzo di posta elettronica che scrivo. Credo occorra passare in PHP il contenuto del campo value, ma in questa forma non l’ho mai visto.
Grazie.
Intendi il POST[‘email’] con la chiocciola davanti? Indica di recuperare il valore dell’input “email” nel caso il form sia già stato inviato. La chiocciola indica di ignorare gli eventuali messaggi di errore, per esempio se non trova il valore dell’email inviata.
Lascia pure il value vuoto, se ti confonde, non è essenziale. Il concetto è questo:
– in quel campo input l’utente digita l’email e invia il form
– il codice prende l’email digitata dall’utente e gli invia (appunto) un’email con il link per il recupero della password
Tieni conto che questo script è un esempio minimale per capire il procedimento e, tra l’altro, l’ho scritto 9 anni fa quando ero ai primi tempi della mia “carriera” di programmatore: oggi strutturerei il codice in modo ben più efficiente. La chiocciola davanti alle variabili per esempio non riesco più a digerirla, esistono modi migliori per gestire gli errori 🙂
Il mio problema è che non riesco a fare inviare la mail, anzi la funzione pare proprio non andare (per qualche mia svista probabilmente) dato che non svolge l’echo per mostrare che l’email è stata spedita. Credo cercherò un’altra via, dato che vorrei anche mettere qualche controllo di sicurezza.
Scusa, nel
if(isset($_POST[‘invia’]))
che apre il codice del controllo email nel db, invia è, come credo, il value del submit del form di richiesta?
Sì, controlla che il form sia inviato. Sarebbe più corretto controllare l’esistenza del campo email, visto che è quello che ci interessa. Ho modificato l’esempio con:
if (isset($_POST[‘email’]))
All’interno in ordine:
– controlla che l’email ricevuta dal form esista nel db
– se non ci sono errori, invia l’email all’utente (con il link per modificare la password)
Mi va in errore a questo controllo if(mysql_num_rows($result)>0)
Quindi come se $result fosse vuoto, ma credo punti bene al db, tenuto conto che la mia tabella si chiama amministrazione:
$result=mysql_query(“SELECT id, password from amministrazione where email='”.$_POST[‘email’].”‘ limit 0,1″, $db);
Poi mi chiedo: non dovrebbe esserci un’istruzione tipo mysql_select_db(‘my_database’) per far indirizzare PHP?
L’esempio non tiene conto del codice che riguarda la connessione al db, presuppone che sia già stato implementato. Mostra solo la parte che riguarda il procedimento di recupero password.
Per capire se la tua query ha un errore prova a stamparla a video e vedi cosa risulta, cioè:
echo “SELECT id, password from amministrazione where email='”.$_POST[‘email’].”‘ limit 0,1″;
Uff! Risolto aggiungendo la banale sessione di accesso al db…
Ora c’è un nuovo inghippo: il link che trovo nella mail apre una pagina bianca, oltre a essere ritenuto un link “sospetto” da Gmail.
La password vecchia deve essere criptata nel db?
Per la sicurezza, le password devono essere sempre criptate nel db.
Sono d’accordissimo, stranamente al corso che ho seguito le password le ho sempre viste mettere “in chiaro”, mentre qui l’hai dato per scontato.
Sto procedendo con i vari “aggiustamenti”: ora ricevo le due mail (link per nuova password e assegnazione con invito al nuovo login, ma… la password nuova pare non funzionare, credo per problemi di confronto tra stringa in chiaro e in md5.
La prima parte sempre funzionare bene però quando vengo rindirizzato a nuova_password.php non ricevo nessuna email con la nuova password
Può essere che la select incaricata di controllare i valori nell’hash non trovi una corrispondenza nel database. Un modo semplice per controllare è stampare a video la query e inserirla nel database a mano.
Se ti restituisce 0 risultati, allora c’è un errore nel recupero dell’hash (per esempio l’hash nel GET è sbagliato).
Se invece ti restituisce un risultato, allora dovrebbe entrare nella condizione. In questo caso credo che il problema sia nella query di update: forse c’è un errore di sintassi che ti blocca il procedimento.