Autenticare gli utenti con PHP
Costruiamo un semplice ma efficace script per autenticare gli utenti estraendone i dati da un database.
Quello dell’autenticazione degli utenti è da sempre un problema molto sentito da parte di tutti i webmaster. Inibire l’accesso a determinate aree del proprio sito può essere necessario per molteplici motivi. I siti che offrono servizi a pagamento, ad esempio, devono disporre di zone accessibili soltanto agli utenti registrati. Chi crea delle aree di amministrazione per il proprio sito (cosa molto comune, in PHP) avverte chiaramente l’esigenza di proteggere le pagine con cui gestisce tutto il sito.
Per questi e per tanti altri motivi gli sviluppatori web si adoperano da sempre creando script o sfruttando le caratteristiche dei vari web server (Apache in primis) per proteggere files e cartelle dei propri siti. Anche il PHP interagisce al meglio con i web server (creando ad esempio dei file .htaccess di Apache) e, cosa di cui tratteremo in queste pagine, può inviare degli header HTTP al browser che richiedano nome e password dell’utente. Sfrutteremo questa caratteristica del PHP per richiedere i dati dell’utente, che cercheremo poi in un database. Se l’utente esiste permetteremo l’accesso, altrimenti ne consentiremo l’iscrizione inserendo i nuovi dati nel DB stesso. Per provare l’esempio di queste pagine ci sarà bisogno di un webserver Apache, del PHP e di MySQL. Troverete tutti i software necessari nella sezione “Il meglio” del CD-Rom di questo mese.
A La tabella utenti
Visto che conserveremo in un database i dati degli utenti, la prima cosa da fare è di sicuro quella di creare il DB stesso e la tabella che conterrà tali dati. La struttura della tabella sarà molto semplice, formata da soli sei campi:
# Id – il campo che fungerà da contatore
# Nome – lo username scelto dall’utente in fase di registrazione
# Email – la sua e-mail, che servirà anche per inviare la password
# Password – il campo che conterrà la password
# Data – la data di registrazione
# Ip – l’indirizzo IP dell’utente al momento della registrazione

Dopo aver avviato il server MySQL (si può fare riferimento all’altro articolo di pratica presente in questo numero) apriamo una sessione di DOS e, dalla sottocartella bin di MySQL, lanciamo il client digitando mysql.
Il codice SQL da digitare per creare la nostra tabella (che chiameremo anagrafica) è il seguente:

CREATE database utenti;
USE utenti;
CREATE TABLE anagrafica (
id int(3) NOT NULL auto_increment,
nome char(8) NOT NULL default '',
email char(255) NOT NULL default '',
password char(8) NOT NULL default '',
data char(255) NOT NULL default '',
ip char(15) NOT NULL default '',
PRIMARY KEY (id),
UNIQUE KEY id (id),
KEY id_2 (id) ) TYPE=MyISAM;


è possibile copiare il codice esattamente come lo si vede; battere il tasto invio alla fine di ogni riga, non dimenticando di digitare il punto e virgola alla fine, per dire a mysql che l’istruzione stessa è terminata. I nomi da attribuire al DB e alla tabella possono essere cambiati a seconda delle prorie esigenze; l’importante è specificarli nel file di configurazione che creeremo tra poco. 

Si comincia col PHP
Ora che abbiamo la tabella nella quale memorizzare i dati, possiamo iniziare a scrivere un po’ di codice PHP. Stabiliamo, per essere ordinati, che creeremo tre piccoli script PHP, in tre diversi file. Il primo conterrà semplicemente i dati di connessione al database, mentre il secondo invierà gli header, ed il terzo permetterà di iscriversi agli utenti che ancora non compaiono nella tabella. La struttra dei tre file è molto semplice; vediamo dapprima di scrivere il codice del file di configurazione da includere negli altri due, e che chiameremo conf.inc.php:

<?
$data = date ("d/m/Y H:i");

con l’istruzione date ricaveremo facilmente la data nel formato GG/MM/AAAA (giorno, mese, anno). Scriviamo ora i fondamentali dati per connettersi correttamente al server MySQL:

$server = "localhost";
$utente = "root";
$db_pass = "";
$datab = "gol61";
$tabella = "anagrafica";

oltre all’indirizzo dell’host e i dati dell’utente, abbiamo conservato in due variabili quelli con il nome del database da utilizzare e quello della tabella. Volendo personalizzare questi dati sarà sufficiente intervenire sulle due variabili. Com’è ormai nostra abitudine, creeremo una piccola funzione al’interno di questo file, chiamata errore_server(). Questa funzione servirà semplicemente ad informarci minuziosamente su eventuali errori in fase di connessione e di interrogazione.

function errore_server() 
{
echo "<b>Il database MySql sembra
non rispondere...</b><br>MySql 
dice:<br><font color=red>";
echo mysql_error();
echo "</font><br>pregasi 
<a href=\"mailto:iltuo@indirizzo.com\">
segnalare</a> il problema"; 


A questo punto non dobbiamo fare altro che connetterci al server e selezionare, direttamente in questa fase, il database da utilizzare.

$connessione = @mysql_connect ($server, $utente, $db_pass)
or die (errore_server ());
$db = mysql_select_db ($datab, $connessione) 
or die (errore_server ());
?>

Salviamo il file conf.inc.php in una cartella del nostro webserver, e pensiamo a creare quello che sarà l’indice della cartella stessa.

Sei autorizzato? Controlliamo…
Il file index.php avrà l’importantissimo compito di inviare gli headers e, una volta che l’utente abbia inserito i dati richiesti, di verificare che questi siano presenti nel database. Per fare una prova, e visualizzare tutti gli headers di una richiesta http, possiamo prendere in prestito un’esempio direttamente dal manuale PHP:

<?
$headers = getallheaders();
while (list ($header, $value) = each ($headers)) {
echo "$header: $value<br />\n";
}
echo $REMOTE_ADDR;
?>

Questo piccolo ciclo while approfitta dell’istruzione getallheaders() per restituire i valori dell’array definito dall’istruzione stessa. Gli headers sono in realtà di molteplici tipi, e quello che ci interessa si chiama $PHP_AUTH_USER. Ricordiamo che gli headers vanno inviati al browser prima di qualsiasi altra cosa, anche di un solo semplice carattere, onde evitare spiacevoli errori. Ecco quindi le prime righe del nostro file index.php

<?
if (!isset($PHP_AUTH_USER)) {
header('WWW-Authenticate: Basic realm="Area privata"');
header('HTTP/1.0 401 Unauthorized');
echo 'Richiesta autorizzazione.';
exit; }
Queste poche istruzioni controllano che il valore $PHP_AUTH_USER non sia presente nell’ambiente (if (!isset…) e lanciano la classica finestrella di autenticazione http, dove si dovranno inserire lo username e la password. In caso di errore ci si limiterà a stampare a video la frase Richiesta autorizzazione. Qualora l’utente abbia inserito i dati richiesti, ricorreremo ad un else che ne controllerà l’esistenza nel DB.

else {
include ("conf.inc.php");

ovviamente includeremo all’inizio di questo ciclo il file che contiene le configurazioni. Subito dopo penseremo a creare la query e ad eseguirla sul database:

$sql = "SELECT id FROM $tabella WHERE nome='$PHP_AUTH_USER'
and password='$PHP_AUTH_PW'";
$query = mysql_query($sql) or die (errore_server());

la query può fornire un solo risultato o riga (il nome utente deve infatti essere necessariamente univoco). Controlliamo quindi il suo valore, grazie all’istruzione mysql_num_rows

$num = mysql_numrows($query);
if ($num == 1) {
echo "<P>Ok, sei autorizzato<br>";
echo "Il tuo nome utente è <b>$PHP_AUTH_USER</b><br>";
echo "La tua passwd è <b>$PHP_AUTH_PW</b></p>";
}

Se il risultato è uguale ad 1 il nome utente esiste, e corrisponde alla password digitata. Nell’esempio abbiamo semplicemente mostrato a video i dati digitati, ma è proprio qui (all’interno del bracket) che potrete inserire il codice riservato agli utenti presenti nel DB. È anche plausibile pensare di includere un file invece di scrivere tutto il codice che serve; si dia un’occhiata al boxino di queste pagine per approfondire.

else if ($num == 0)
{
echo "Nome utente o password non validi<br>";
echo "<a href=\"iscriviti.php\">iscriviti</a>";
}}

Se invece il risultato della query è uguale a zero visualizzeremo un link che rimanda al file per iscriversi nel database.

L’iscrizione degli utenti.
Memorizzare gli utenti nel database è meno difficile di quello che sembra.
Il file iscriviti.php non dovrà far altro che visualizzare un form HTML e, dopo aver controllato che lo username inserito non sia già presente, inserire i dati nella tabella stessa. Dopo avere svolto questo compito, invieremo due distinte e-mail: una a chi si è appena iscritto, e un’altra al proprietario del sito stesso, per informarlo della presenza di un nuovo utente. Creeremo un ciclo if che controlli inizialmente la presenza della variabile $invia (il nome del pulsante del form HTML). Se questa non esiste, si visualizza subito il form:

<?
include ("conf.inc.php");
if (!$invia){ 
echo <<
Il tuo nome utente non è stato trovato nel database
<br>Registrati<br> </h1>
<form method=post>
<table width=85% border=1 align=center> <tr><td>Nome</td> 
<td> <input type="text" name="nome"> </td></tr> 
<tr> <td>Email</td>
<td><input type="text" name="email"></td> </tr> <tr>
<td>passwd</td>
<td><input type="password" name="passwd"></td>
</tr>
<tr>
<td align=right><input type="submit" name="invia"></td>
<td align=left><input type="reset"></td>
</tr>
</table>
</form>
EOD;
}

Da notare che, usando questa “tecnica”, non abbiamo neanche bisogno di specificare l’action del form stesso. Se il pulsante viene premuto potremo proseguire con i controlli del caso e l’eventuale inserimento; vediamo prima se il nome utente esiste:

else {
$sql = "select * from $tabella where nome='$nome'";
$query =mysql_query ($sql) or die (errore_server());
$num = mysql_numrows($query);
if ($num == 1) {
echo "nome utente già occupato<br>";
echo "<a href=\"javascript:history.back()\">ritenta</a>
con un altro username";
}
Utilizzando la solita istruzione mysql_numrows controlleremo il risultato della query e, qualora esso sia maggiore di 0, rimanderemo indietro l’utente per farlo riprovare con un altro nick.

else {
$ip = $REMOTE_ADDR;
$sql="INSERT INTO anagrafica (id,nome,email,password,
data,ip) VALUES ('', '$nome', '$email',
'$passwd', '$data', '$ip')";

$query = mysql_query ($sql) or die (errore_server());
echo "dati inseriti correttamente<br>";




E Inviamo le e-mail
Dopo aver inserito tutti i dati dell’utente nel nostro bravo database, possiamo pensare a inviare le due e-mail. La prima, come dicevamo, sarà indirizzata all’utente e conterrà i suoi dati, a mò di promemoria, e l’altra arriverà al webmaster del sito. Vediamo il codice della prima mail:

$from_mail = "iltuo@indirizzo.tld";
$To="$email";
$Headers ="From: $from_mail";
$Soggetto="[Inserire nome del sito] I tuoi dati di accesso";
$Corpo.="Ciao!\n\n";
$Corpo.="Sono il programma Sendmail di http://$HTTP_HOST\n";
$Corpo.=" La tua iscrizione è stata accettata!\n\n";
$Corpo.=" Questi sono i tuoi dati:\n\n";
$Corpo.=" Il tuo nome utente: $nome\n";
$Corpo.=" La tua password: $passwd\n\n";
$Corpo.=" A presto!\n\n";
$Corpo.="--------------------------------------------\n";
$Corpo.="$from_mail\n";
$Corpo.="http://$HTTP_HOST\n";
$Corpo.="--------------------------------------------\n";

La variabile $from_mail conterrà l’indirizzo che verrà visualizzato come mittente dell’e-mail, e che inseriremo negli headers della mail (occhio, non sono quelli uguali http…:) ). In $To lo script prenderà l’indirizzo dell’utente per utilizzarlo come destinatario, mentre in $Soggetto il testo (personalizzabile) dell’oggetto della mail. Per quanto riguarda il contenuto del messaggio, esso verrà creato concatenando la variabile $Corpo, in modo da inviare un messaggio composto da più righe ordinate. Abbiamo inserito nel corpo anche la variabile d’ambiente $HTTP_HOST, giusto per includere nel messaggio anche il nome del sito.

mail($To, $Soggetto, $Corpo, $Headers);
echo "ti è stata inviata una mail all'indirizzo 
$email con i tuoi dati";

Praticamente la stessa cosa sarà da farsi con l’e-mail da inviare al webmaster del sito.

$webmaster = "iltuo@indirizzo.tld";
$email1 ="$email";
$mailTo1="$webmaster";
$mailHeaders1="From: $email1";
$mailSubject1="[Inserire il nome del sito]
Nuovo UTENTE registrato";
$mailBody1.="Ciao!\n\n";
$mailBody1.="Un nuovo utente si è registrato!\n\n";
$mailBody1.="Questi sono i suoi dati:\n\n";
$mailBody1.="Username: $nome\n";
$mailBody1.="passwd: $passwd\n";
$mailBody1.="Email: $email1\n";
mail($mailTo1, $mailSubject1, $mailBody1, $mailHeaders1);
}}

Abbiamo approfittato per chiudere i cicli ancora aperti; il compito dello script, in realtà, è terminato.