Documenti di Didattica
Documenti di Professioni
Documenti di Cultura
Con questo articolo, e con gli altri che seguiranno, iniziamo una serie di tutorial per introdurre
ai lettori i concetti fondamentali riguardanti la gestione degli utenti all'interno di un sito web o
di un'applicazione internet. Tratteremo argomenti relativi all'autenticazione, alla gestione dei
permessi, alla sicurezza ed alla registrazione, in modo da presentare un'analisi completa delle
problematiche che si devono affrontare durante la stesura di un sistema simile.
Gli script proposti implementano una struttura procedurale abbastanza frammentata, in modo
da permettere la semplice modifica per adattarli alle proprie esigenze.
Prima di iniziare esorto i lettori a leggere gli articoli riguardanti i Tutto sui cookie e le Sessioni
alternative in Php presenti su freephp.html.it, anche se non essenziali per la corretta
comprensione degli articoli.
I file utilizzati in questo articolo possono essere subito scaricati. Vanno tenuti presenti in modo
particolare poiché faremo riferimento ad essi per ogni commento al codice interno all'articolo.
• Effettuare il logout
Il sistema, una volta verificata la correttezza dei dati passati, inizializzerà una sessione
all'interno del nostro database, ed utilizzerà un ID univoco come riferimento a questa. Questo
ID verrà passato tra le pagine sfruttando o i cookie o la query string dell'URL, in base alle
scelte del programmatore.
Prima di iniziare, prepariamo il nostro database: creiamo una tabella per gestire le sessioni con
il seguente comando:
• Il campo uid conterrà l'ID univoco che identificherà la sessione di riferimento per un
utente autorizzato. Verrà utilizzato per reperire l'ID dell'utente nella tabella 'utenti', e
come controllo per sapere se l'utente è autorizzato o meno
• Il campo user_id conterrà l'ID della tabella 'utenti' al quale la sessione fa riferimento
• Il campo creation_date conterrà la data (espressa in secondi) di creazione della
sessione; verrà utilizzato per controllare se la sessione è scaduta o meno.
Dato che il processo di registrazione verrà analizzato nei prossimi articoli, riempiremo ora la
tabella utenti manualmente:
L'unica cosa da appuntare è l'utilizzo della funzione MD5 (facente parte del core di funzioni di
MySQL): data una stringa in input, questa funzione restituisce un valore di 32 bit irreversibile
che rappresenta univocamente la stringa data. Salvando nel database le password attraverso
MD5 aumentiamo leggermente la sicurezza: difatti, anche avendo accesso manuale al
database, non si avrà alcun modo per conoscere la password relativa ad un dato utente.
Il processo di autenticazione
La semplice applicazione che creeremo avrà la seguente struttura nel filesystem:
autenticazione
|
|-------- Directory: include
| |
| |-------- File: config.php
| |
| |-------- File: auth.lib.php
|
|-------- File: home.php
|
|-------- File: login.php
|
|-------- File: logout.php
|
|-------- File: pagina1.html
|
|-------- File: pagina2.php
|
|-------- File: pagina3.php
|
|-------- File: pagina4.php
Cominciamo creando il file di configurazione (config.php): questo file conterrà alcune costanti
predefinite che utilizzeremo all'interno dei nostri script (il loro significato vi verrà spiegato in
seguito), i parametri di connessione al DB, alcune opzioni e le funzioni per effettuare la
connessione a MYSQL. Nel file config.php contenuto nella cartella include potete visualizzare il
codice necessario.
Continuiamo iniziando a scrivere il file auth.lib.php, che conterrà tutte le funzioni che
utilizzeremo per effettuare il processo di autenticazione dell'utente. Sempre per motivi di
spazio, non vi mostro il listato del codice, che potete comunque trovare all'interno del file
auth.lib.php nella cartella include.
Questa libreria implementa le funzionalità necessarie affinché il nostro script sia capace di
autenticare un utente. Vediamola in dettaglio.
L'array $_AUTH contiene le opzioni capaci di cambiare il comportamento della libreria. Per ora
solo un'opzione è stata inserita che serve ad identificare il metodo con il quale passare tra le
varie pagine l'ID di sessione; le opzioni possibili sono AUTH_USE_LINK, AUTH_USE_COOKIE.
Lascio a voi la modifica della libreria per permettere la gestione dell?ID tramite metodi
alternativi. Questo array non verrà mai letto direttamente, ma utilizzeremo le funzioni
auth_get_option() e auth_set_option(). In questo modo potremo implementare una gestione
più completa delle opzioni, magari elaborando i dati presenti nell'array in caso di richieste
particolari;
auth_get_status() viene utilizzata per prelevare un array di due valori avente come primo
valore lo stato dell'utente che sta navigando la pagina e come secondo una lista di informazioni
relative all'utente, in caso questi sia connesso. Per prima cosa vengono eliminate le sessioni
scadute, poi viene recuperato l'ID univoco. Se questo non è presente, significa che l'utente non
ha ancora effettuato il login o che la sua sessione è scaduta. Se invece esiste, vengono
prelevate dal database le informazioni relative all'utente e restituite.
auth_login() effettua il login: accetta come parametri l'username e la password esegue una
query di selezione per controllare che i dati permettano il login di un utente. In caso
affermativo restituisce lo status AUTH_LOGEDD_IN ed i dati dell'utente, in caso negativo
restituisce AUTH_INVALID_PARAMS e nessun altra informazione.
Il file presentati all?interno della cartella principale del file compresso contengono un semplice
applicativo di esempio. La libreria viene utilizzata per effettuare il login nel seguente modo:
<?php
include_once("include/config.php");
include_once("include/auth.lib.php");
if($status == AUTH_NOT_LOGGED){
$uname = strtolower(trim($_POST['uname']));
$passw = strtolower(trim($_POST['passw']));
switch($status){
//... controllare nel file login.php per il codice completo
} ?>
Dopo aver controllato che lo status dell?utente non corrisponda ad AUTH_LOGGED, e dopo
aver controllato che entrambi i dati passati tramite POST siano corretti, richiamiamo le funzioni
auth_login() ed auth_register_session() per eseguire il login e registrare una nuova sezione. Il
grosso switch presente alla fine della pagina controlla il valore della variabile $status (che
rappresenta lo stato in cui lo script è terminato), e visualizza un messaggio all?utente. Con
questo metodo possiamo gestire varie possibilità molto semplicemente.
Oltretutto in ogni pagina privata è presente un semplice controllo sullo stato dell?utente che
sta navigando attualmente (prelevato sempre attraverso auth_get_status()). In caso lo stato
sia AUTH_LOGGED sappiamo che l?utente è loggato e possiamo permettergli di visualizzare i
dati della pagina, altrimenti no .
Continuiamo oggi la serie di articoli sulla registrazioni degli utenti avviati la settimana scorsa.
L'articolo odierno tratterà il processo di registrazione di un nuovo utente. Gli script utilizzati si
basano sui sorgenti dell'articolo precedente, e cercano di seguire una struttura simile in modo
da non confondere eccessivamente le idee ai lettori.
• Effettuare un controllo sui campi compilati, in modo da riportare all'utente eventuali errori
di compilazione
• Richiedere una conferma via email all'utente, al fine di valicare i dati inseriti (nello script
l'indirizzo email non verrà salvato nel database. Potrete comunque decidere di farlo
apportando poche ed intuitive modifiche allo script)
• Impedire l'accesso agli utenti registrati ma che non hanno ancora confermato i loro dati
L'articolo sarà strutturato in modo da descrivere le modifiche apportate ad ogni file e spiegare
la struttura dei nuovi script aggiunti.
Anche in questo caso è consigliabile scaricare subito i sorgenti con tutte le modifiche
apportate.
Prima di addentrarci nel codice PHP, apportiamo delle modifiche alla tabella utenti in modo da
renderla adatta a gestire il nostro processo di autenticazione:
ALTER TABLE utenti
ADD indirizzo VARCHAR( 100 ) NOT NULL,
ADD occupazione VARCHAR( 100 ) NOT NULL,
ADD temp SET( '0', '1' ) NOT NULL,
ADD regdate VARCHAR( 11 ) NOT NULL,
ADD uid VARCHAR( 32 ) NOT NULL;
i primi due campi aggiunti sono due dati simbolici che rappresentano le informazioni necessarie
affinché l'utente possa registrarsi. Potete aggiungerne altri, ma ricordate di apportare le
modifiche necessarie ai file descritti in seguito.
Il campo temp contiene un valore pari a 1 in caso l'utente non abbia ancora confermato la
registrazione, pari a 0 in caso contrario. Dato che un utente che non ha ancora confermato i
dati non può effettuare il login, modifichiamo la query SQL eseguita dalla funzione auth_login
all'interno del file auth.lib.php in questo modo:
$result = mysql_query("
SELECT *
FROM ".$_CONFIG['table_utenti']."
WHERE username='".$uname."' and password=MD5('".$passw."') and temp = '0'"
);
Il campo regdate conterrà l'istante in cui la registrazione è stata effettuata. Verrà utilizzato per
rimuovere le registrazioni non ancora confermate e scadute.
Infine il campo uid conterrà un indice univoco che utilizzeremo per la conferma della
registrazione.
Aggiungiamo alla tabella dei link all'interno del file home.php un riferimento al form di
registrazione:
<td><a href="registrati.php">Registrati</a></td>
La libreria di registrazione
La libreria per la registrazione che ci accingiamo a scrivere conterrà funzioni utili per il
controllo, il salvataggio e la validazione dei dati. Il codice sorgente può essere prelevato dal file
reg.lib.php all'interno della cartella include.
reg_clean_expired ripulisce la tabella utenti dalle registrazioni scadute, basandosi sui dati
presenti nel file di configurazione. reg_get_unique_id genera un indice univoco, utilizzato per la
conferma.
La funzione reg_check_data viene utilizzata per effettuare un controllo sui dati inseriti
dall'utente; per ogni dato presente all'interno dell'array passato come argomento, questa
funzione richiama una callback associata precedentemente all'interno del file di configurazione,
la quale si occuperà di validare o meno il dato; nel caso in cui siano stati riscontrati errori,
questa funzione li restituirà al blocco di codice chiamante, in modo che questi possa gestirli
correttamente.
L'ultima funzione presente all'interno del modulo, reg_confirm, è quella che effettua la
conferma dei dati, modificando il valore del campo temp nella tabella utenti in base al
parametro passatole.
Come possiamo notare anche questo modulo è molto semplice e compatto, e contiene tutte le
operazioni necessarie a soddisfare gli obiettivi che ci eravamo posti all'inizio dell'articolo.
Non ci resta che adattare gli altri script alla nuova libreria.
Le funzioni check_* sono quelle di callback. Per non allungare il codice inutilmente, ho
associato la funzione check_global a quasi tutti i campi.
Il modulo di registrazione (contenuto nel file registrati.php) è un semplice form HTML contente
un numero di campi pari ai valori necessari al fine di rendere la registrazione corretta.
In caso voleste aggiungere o rimuovere dei campi dal processo di registrazione, le operazioni
da seguire sono le seguenti:
<html>
<head>
<style type="text/css">
<!--
.style1 {
color: #FF0000;
font-weight: bold;
}
-->
</style>
</head>
<body>
<?php
include_once("include/config.php");
include_once("include/reg.lib.php");
switch($status){
case REG_ERRORS:
?>
<span class="style1">Sono stati rilevati i seguenti errori:</span><br>
<?php
foreach($ret as $error)
printf("<b>%s</b>: %s<br>", $error[0], $error[1]);
?>
<br>Premere "indietro" per modificare i dati
<?php
break;
case REG_FAILED:
echo "Registrazione Fallita a causa di un errore interno.";
break;
case REG_SUCCESS:
echo "Registrazione avvenuta con successo.<br>
Vi è stata inviata una email contente le istruzioni per confermare la
registrazione.";
break;
}
}
?>
</body>
</html>
A parte l'ovvio codice HTML, possiamo notare che, dopo aver effettuato un controllo sul fatto
che la pagina abbia ricevuto dei dati, lo script si occupa di controllare il valore dei dati ricevuti
e di effettuare successivamente la registrazione. Il controllo della variabile $status permette di
mostrare all'utente un output differente in base al risultato delle funzioni richiamate: ad
esempio, in caso di errori, lo script si occupa di mostrare all'utente una lista contenete il nome
del campo ed il valore dell'errore.
<?php
include_once("include/config.php");
include_once("include/reg.lib.php");
switch($status){
case REG_SUCCESS:
echo "La tua registrazione è stata confermata; ora puoi effettuare il
login.";
break;
case REG_FAILED:
echo "La registrazione non può essere confermata, probabilmente picchè è
scaduta.";
break;
}
}
?>
Dopo aver controllato che sia stato passato un ID valido alla pagina tramite querystring, lo
script rimuove le registrazioni scadute e richiede una conferma dei dati: in caso affermativo
sarà concesso all'utente di effettuare il login, altrimenti verrà visualizzato un messaggio di
errore
Per oggi è tutto. Vi do appuntamento a settimana prossima per la terza parte della serie in cui
tratteremo la gestione dei permessi degli utenti attraverso un sistema particolare ma molto
efficace.
Con l'articolo odierno concludiamo la guida sulla gestione degli utenti con PHP. Abbiamo iniziato
strutturando il database e creando degli script che ci permettessero di Gestire gli utenti con
PHP: login, logout e sessioni. Successivamente abbiamo esteso l'esempio aggiungendo, senza
troppe difficoltà data l'organizzazione procedurale dei file, un modulo che permettesse la
registrazione di nuovi utenti.
In questo articolo, infine, ci preoccuperemo di implementare degli script che rendano possibile
la gestione di permessi relativi ad ogni utente, così da avere la possibilità di impedire o
permettere l'esecuzione di alcune operazioni in base all'utente con il quale il server sta
dialogando.
Esistono molti sistemi per gestire l'assegnazione di permessi agli utenti; io ho deciso di
implementarne uno abbastanza semplice basato su operazioni binarie, che verrà descritto il più
dettagliatamente possibile in questo articolo.
Come sempre potete scaricare i file dell'articolo. Sono state corrette alcune imprecisioni al fine
di rendere gli script notice free.
Impostare il progetto
Come negli altri articoli, prima di spiegare le modifiche fatte agli script, ci accingiamo ad
eseguire semplici query SQL per rendere il database adatto a gestire le aggiunte. Eseguiamo le
seguenti query:
ALTER TABLE utenti ADD permessi INT DEFAULT '0' NOT NULL ;
La prima query modifica la tabella utenti aggiungendole un campo permessi nel quale
salveremo un intero che rappresenta i permessi associati al singolo utente. La seconda query si
occupa di creare la tabella per la gestione dei permessi:
• il campo id conterrà un multiplo di due che indica in modo univoco il nostro permesso:
utilizziamo un multiplo di due perché sfrutteremo le operazioni boolean AND ed OR sugli
interi per controllare che un utente abbia i permessi adatti ad eseguire certe operazioni;
• il campo nome conterrà il nome del permesso: verrà utilizzato all'interno della semplice
pagina di amministrazione che creeremo e come riferimento leggibile per il check;
Dopo aver apportato le modifiche al database e dopo aver modificato leggermente il testo della
pagina home.php (guardate il file omonimo per le semplicissime modifiche), ci apportiamo ad
impostare la pagina di amministrazione: questa pagina ci permetterà di assegnare o togliere i
permessi ad un dato utente e di crearne di nuovi; ho impostato la pagina in modo che abbia un
aspetto simile a seguente:
Figura 1
<?php
function get_users_list(){
$result = mysql_query("
SELECT *
FROM utenti
WHERE temp='0'
");
$data = array();
while($tmp = mysql_fetch_assoc($result)){
array_push($data, $tmp);
};
return $data;
}
function user_get_id($user){
return mysql_result(mysql_query("
SELECT id
FROM utenti
WHERE username='".$user['username']."' and password='".$user['password']."'
"), 0, 'id');
}
?>
La funzione get_users_list restituisce una lista di tutti gli utenti registrati presenti all'interno
del database. La funzione user_get_id accetta come parametro un array contente le
informazioni relative ad un utente, e ne restituisce l'id.
La libreria contenuta nel file license.lib.php è invece leggermente più complicata, e contiene
tutte le procedure necessarie a gestire i permessi:
• license_has controlla che un utente abbia un dato permesso; accetta come parametri
l'id dell'utente ed una stringa rappresentante il nome del permesso e controlla, dopo aver
prelevato i permessi dell'utente e l'id del permesso preso in esame, che l'operazione
boolean AND restituisca un valore vero
• license_get resituisce i permessi associati ad un dato utente, i cui dati sono passati
come primo argomento
Urge una breve spiegazione delle operazioni boolene su multipli di due: i multipli di due,
trasformati in numeri binari, assumono il seguente aspetto:
Figura 2
quando i numeri binari sono combinati attraverso le operazioni boolean AND ed OR, viene fatto
un controllo booleano cifra per cifra nel seguente modo:
Figura 3
• in caso di A|B il risultato avrà come cifra alla posizione N la combinazione booleana delle
rispettive cifre dei valori A e B alla posizione N. Siccome questi valori sono 1 o 0,
l'operazione è molto semplice
La sezione di amministrazione
La sezione di amministrazione, contenuta nel file admin.php, è molto semplice da sviluppare:
oltre al solito codice HTML per impaginare i dati, svolgiamo le seguenti operazioni:
• la tabella dei permessi è generata prelevando in modo incrociato tutti gli utenti e tutti i
permessi da database. In caso un utente abbia un dato permesso la checkbox viene
settata come checked, altrimenti no;
• I nomi assegnati alle checkbox sono degli array nella forma "u" + USER_ID + "[]", in
modo da poter gestire agilmente i dati tramite PHP;
• In caso un untente prema il pulsante aggiungi, ci occupiamo di aggiungere un nuovo
permesso PRIMA di generare la tabella del primo punto;
• In caso un untente prema modifica, eseguiamo un controllo su tutti li array che iniziano
per "u" e salviamo i dati relativi ad ogni utente.
Come potete notare la zona di amministrazione è molto semplice ma funzionale; non viene
effettuato alcun controllo al momento dell'accesso alla pagina, quindi sarebbe opportuno
aggiungere il sistema di autenticazione anche a questa pagina.
Controllare i permessi
Il procedimento per controllare i permessi è molto semplice: ho modficato leggermete la
pagina pagina4.php in modo che necessiti del permesso "test" (che ho precedentemente creato
all'interno del database tramite la pagina di amministrazione):
<?php
include_once("include/config.php");
include_once("include/auth.lib.php");
include_once("include/utils.lib.php");
include_once("include/license.lib.php");
if($status == AUTH_LOGGED){
$msg = "Hai i seguenti permessi:<br>";
foreach(license_get($user) as $perm){
$msg .= ">> ".$perm['nome']."<br>";
}
$msg .= (license_has($user, "test"))
? "HAI IL PERMESSO TEST, e quindi ti é permesso eseguire questa operazione"
: "<b>NON</b> HAI IL PERMESSO TEST, e quindi <b>NON</b> ti é permesso eseguire
questa operazione";
Dopo aver controllato che l'utente ha effettuato il login attraverso il metodo descritto nel primo
articolo, utilizziamo la funzione license_has per controllare che l'utente abbia il permesso
necessario (test): in caso affermativo visualizziamo un messaggio, in caso negativo un altro. In
questo modo, utilizzando semplici istruzioni condizionali, possiamo visualizzare e permettere
operazioni solamente ad utenti aventi un particolare permesso. Potremmo per esempio
visualizzare opzioni aggiuntive all'interno di un forum solamente agli utenti che hanno il
permesso "moderatore", oppure visualizzare la lista dei forum in base ai permessi di
visualizzazione che ha l'utente che sta visitando la pagina.
Come semplice controllo, visualizzo anche la lista di tutti i permessi associati all'utente
corrente.
Siamo arrivati alla fine dell'articolo e della guida. Spero l'argomento sia stato di vostro
gradimento, e vi invito ad approfondire i discorsi affrontati in modo da gestire in modo più
completo i sistemi di autenticazione.
Purtroppo non ho potuto affrontare la gestione della sicurezza avanzata, ma nulla toglie che in
futuro scriveremo un articolo proprio su questo argomento. Nel frattempo sarò lieto di
rispondere ad ogni vostra domanda. Alla prossima.