back to top

PHP/OOP: Creare un sistema di registrazione e autenticazione per gli utenti

Dalle mail che ricevo e dalle discussioni sui forum che seguo, noto ancora una certa difficoltà di alcuni sviluppatori PHP nel passaggio dal paradigma procedurale a quello della programmazione orientata agli oggetti; in realtà credo che alla base di tutto ci sia soltanto una questione di abitudini consolidate, la OOP non è difficile quanto sembra e la maggior parte di coloro che vorrebbero utilizzarla possiedono già, spesso senza saperlo, gli strumenti tecnici per trasformarla in un mezzo per realizzare le proprie applicazioni.

Per dimostrare quanto appena sostenuto, presenterò in questa guida la procedura necessaria per la creazione di un sistema di registrazione e autenticazione basato sulla programmazione ad oggetti, sarà un’occasione per mostrare in modo molto semplice come classi, metodi, proprietà e, appunto, oggetti non siano necessariamente destinati all’utilizzo in applicazioni complesse. Il nostro script utilizzerà il DBMS MySQL per la memorizzazione delle informazioni, quindi come prima operazione dovremo crearci un database e dargli un nome, ad esempio "registrazione", all’interno di esso sarà presente una tabella della quale, per comodità del lettore, riporto il dump SQL pronto per l’importazione:

CREATE TABLE IF NOT EXISTS `iscritti` (
  `id_utente` int(4) NOT NULL AUTO_INCREMENT,
  `nome_utente` varchar(20) DEFAULT NULL,
  `password` varchar(40) DEFAULT NULL,
  `nome_reale` varchar(50) DEFAULT NULL,
  `email` varchar(80) DEFAULT NULL,
  PRIMARY KEY (`id_utente`),
  UNIQUE KEY `username` (`nome_utente`),
  UNIQUE KEY `email` (`email`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;

La tabella "iscritti" sarà quindi composta da 5 campi:

  • id_utente: destinato ad ospitare l’identificativo univoco di ogni record;
  • nome_utente: registrerà la username di ogni utente;
  • password: permetterà ad ogni utente iscritto di loggarsi alla pagina riservata;
  • nome_reale: il vero nome dell’utente, potrà anche essere diverso dalla username;
  • email: l’indirizzo di posta elettronica dell’iscritto.

Ma come sarà strutturata la nostra applicazione? Avremo innanzitutto un file di configurazione, lo chiameremo per esempio "config.php", che ci permetterà di interagire con il DBMS connettendoci ad esso e selezionando il database precedentemente creato; vediamo come:

<?php
# definizione delle costanti per l'autenticazione al DBMS
define('DATA_HOST', 'localhost');
define('DATA_UTENTE', 'root');
define('DATA_PASS', '');
define('DATA_DB', 'registrazione');
# classe per l'interazione con il database
class DATA_Class {
  # definizione del costruttore
  function __construct() {
    # connessione al DBMS
    $connessione = @mysql_connect(DATA_HOST, DATA_UTENTE, DATA_PASS) or die('Errore nella connessione: ' . mysql_error());
    # selezione del database
    @mysql_select_db(DATA_DB, $connessione) or die('Errore dal database: ' . mysql_error());
  }
}
?>

Niente di particolarmente complesso, il file "config.php" si occuperà in pratica di:

  • definire le costanti che conterranno le informazioni necessarie alla connessione;
  • definire una classe che gestirà l’interazione con MySQL;
  • connettersi al DBMS e selezionare la base di dati di riferimento.

Come è possibile notare, la classe verrà introdotta per semplice dichiarazione, per definirla basterà infatti attribuirle un nome:

class DATA_Class {..

All’interno della classe, delimitato da parentesi graffe, vi dovrà essere un metodo particolare, detto "costruttore", definito in questo modo:

function __construct() {..

Il costruttore è in pratica un metodo associato ad una classe che ha il compito di porre in essere l’istanza della classe stessa e di inizializzarla per la creazione di un oggetto; una chiamata al costruttore viene effettuata in modo automatico nel momento in cui viene generato un nuovo oggetto di una classe. Un concetto troppo complicato? Solo apparentemente, nel codice proposto infatti il costruttore delimita il codice necessario per connettersi a MySQL e selezionare il database, ciò vuol dire che ad ogni istanza della classe corrisponderà una chiamata automatica del costruttore che si occuperà di svolgere questi compiti. Ora che il quadro si va semplificando è possibile passare alla fase successiva, cioè alla creazione del file contenente gli altri metodi che verranno utilizzati nella nostra applicazione.

Il file di funzione

Nel precedente capitolo abbiamo affrontato il discorso relativo alla creazione di una classe in grado di gestire le operazioni di interazione con il Database manager, si tratta di una base che ci permetterà di definire i metodi per le varie procedure che dovranno essere svolte dalla nostra applicazione per la registrazione e l’autenticazione. A questo scopo creeremo un file di funzione, lo definiremo "functions.php", in cui sarà presente una classe, denominata "Iscrizioni", che conterrà l’istanza della classe per il database e i metodi per:

  • l’iscrizione;
  • il login;
  • la visualizzazione di dati relativi agli utenti;
  • la verifica della sessione corrente;
  • il logout.

Ecco il codice del nostro file di funzione:

<?php
# inclusione del file di configurazione
@include_once 'config.php';
# definizione della classe che conterrà i metodi per la gestione degli iscritti
class Iscrizioni {
  
  # definizione del costruttore
  public function __construct() 
  {
    # istanza della classe per la connessione al database
    $data = new DATA_Class();
  }

  # metodo per la registrazione 
  public function registra($nome_reale, $nome_utente, $password, $email) 
  {
    # tolgo eventuali spazi vuoti
    $nome_reale = trim($nome_reale);
    $nome_utente = trim($nome_utente);
    $password = trim($password);
    # verifico che il modulo sia stato compilato
    if (strlen($nome_reale) == 0 || strlen($nome_utente) == 0 || strlen($password) == 0) return false;
    else {
      # cifratura della password
      $password = @sha1($password);
      # confronto degli input con i dati contenuti in tabella
      $query = @mysql_query("SELECT id_utente FROM iscritti WHERE nome_utente = '$nome_utente' OR email = '$email'") or die('Errore: ' . mysql_error());
      # controllo sulla presenza di corrispondenze prodotte dal confronto
      $conta = @mysql_num_rows($query);
      # se il confronto non genera corrispondenze..
      if ($conta == 0) 
      {
        # ..si procede con la registrazione..
        $risultato = @mysql_query("INSERT INTO iscritti(nome_utente, password, nome_reale, email) VALUES ('$nome_utente', '$password','$nome_reale','$email')") or die('Errore: ' .mysql_error());
        return $risultato;
      }else{
        # ..altrimenti l'esito della registrazione sarà negativo
        return false;
      }
    }
  }

  # metodo per l'autenticazione
  public function verifica_login($email_o_nome_utente, $password) 
  {
    # cifratura della password
    $password = @sha1($password);
    # confronto degli input con i dati contenuti in tabella
    $query = @mysql_query("SELECT id_utente FROM iscritti WHERE (email = '$email_o_nome_utente' OR nome_utente='$email_o_nome_utente') AND password = '$password'") or die('Errore: ' . mysql_error());
    # controllo sulla presenza di una corrispondenza prodotta dal confronto
    $conta = @mysql_num_rows($query);
    # se il confronto genera una corrispondenza..
    if ($conta == 1) 
    {
      # ..viene generata la sessione di login..
      $risultato = @mysql_fetch_object($query);
      $_SESSION['login'] = true;
      $_SESSION['id_utente'] = $risultato->id_utente;
      return true;
    }else{
      # ..altrimenti l'esito dell'autenticazione sarà negativo
      return false;
    }
  }

  # metodo per la visualizzazione del nome dell'utente loggato
  public function mostra_utente($id_utente) 
  {
    # estrazione del nome reale sulla base dell'identificatore memorizzato in sessione
    $query = @mysql_query("SELECT nome_reale FROM iscritti WHERE id_utente = $id_utente") or die('Errore: ' . mysql_error());
    $risultato = @mysql_fetch_object($query);
    # stampa a video del nome reale dell'utente
    echo $risultato->nome_reale;
  }

  # metodo per il controllo sulla sessione
  public function verifica_sessione() 
  {
    # il metodo restituisce l'informazione relativa alla sessione a patto che questa sia stata inizializzata
    if(isset($_SESSION['login']))
    {
      return $_SESSION['login'];
    }else{
      return false;
    }
  }
  
  # metodo per il logout
  # la sessione viene distrutta a seguito di uno specifico input dell'utente
  public function esci() {
    $_SESSION['login'] = FALSE;
    @session_destroy();
    }
  }
?>

I commenti inseriti permetteranno di comprendere meglio il funzionamento dell’applicazione, in ogni caso, nel prossimo capitolo smonteremo il nostro file di funzione descrivendone nel dettaglio le diverse componenti.

Descrizione dei metodi

Il file "functions.php" presenterà innanzitutto un’inclusione del file "config.php", in questo modo sarà immediatamente disponibile la classe relativa all’interazione con il database; il passaggio successivo sarà invece quello relativo alla definizione di una classe destinata a contenere i diversi metodi, per primo verrà però richiamato un costruttore che consenta l’instanza di DATA_Class:

public function __construct() 
{ 
  $data = new DATA_Class(); 
}

In questo modo avremo a disposizione la connessione al DBMS che potrà essere sfruttata per l’esecuzione delle funzionalità successive. Costruttore a parte, il primo metodo definito all’interno del file sarà quello relativo alla registrazione, esso accetterà come argomenti i dati inviati come input dal form per l’iscrizione e, copo aver verificato che i campi non siano vuoti, controllerà che il nome utente e l’email non siano stati già memorizzati nel database e, se il controllo dovesse restituire esito negativo (nessuna corrispondenza nei record), procederà con l’archiviazione:

 
public function registra($nome_reale, $nome_utente, $password, $email) 
{
  $nome_reale = trim($nome_reale);
  $nome_utente = trim($nome_utente);
  $password = trim($password);
  if (strlen($nome_reale) == 0 || strlen($nome_utente) == 0 || strlen($password) == 0) return false;
  else {
    $password = @sha1($password);
    $query = @mysql_query("SELECT id_utente FROM iscritti WHERE nome_utente = '$nome_utente' OR email = '$email'") or die('Errore: ' . mysql_error());
    $conta = @mysql_num_rows($query);
    if ($conta == 0) 
    {
      $risultato = @mysql_query("INSERT INTO iscritti(nome_utente, password, nome_reale, email) VALUES ('$nome_utente', '$password','$nome_reale','$email')") or die('Errore: ' .mysql_error());
      return $risultato;
    }else{
      return false;
    }
  }
}

Da notare come anche per "registra()", esattamente come accade per gli altri metodi definiti, la regola di visibilità utilizzata sia "public", ciò vuol dire che il metodo sarà accessibile, modificabile e richiamabile dall’interno e dall’esterno della classe e dall’interno delle classi che da essa erediteranno metodi e proprietà.

Il secondo metodo proposto sarà quello relativo alla procedura di login:

public function verifica_login($email_o_nome_utente, $password) 
{
  $password = @sha1($password);
  $query = @mysql_query("SELECT id_utente FROM iscritti WHERE (email = '$email_o_nome_utente' OR nome_utente='$email_o_nome_utente') AND password = '$password'") or die('Errore: ' . mysql_error());
  $conta = @mysql_num_rows($query);
  if ($conta == 1) 
  {
    $risultato = @mysql_fetch_object($query);
    $_SESSION['login'] = true;
    $_SESSION['id_utente'] = $risultato->id_utente;
    return true;
  }else{
    return false;
  }
}

Esso in pratica effettuerà un confronto tra i dati inviati tramite il modulo per l’autenticazione e il contenuto della tabella relativa agli iscritti, se esso dovesse produrre un esito positivo allora verranno creati due valori di sessione, uno contenente l’identificativo univoco corrispondente all’utente loggato, l’altro lo stato corrente del login (TRUE e quindi attivo).

Passiamo quindi al metodo successivo, esso consisterà essenzialmente in una query che ci permetterà di estrarre il nome reale dell’utente autenticato:

public function mostra_utente($id_utente) 
{
  $query = @mysql_query("SELECT nome_reale FROM iscritti WHERE id_utente = $id_utente") or die('Errore: ' . mysql_error());
  $risultato = @mysql_fetch_object($query);
  echo $risultato->nome_reale;
}

Il metodo definito in precedenza, "verica_login()", consentirà infatti di creare una sessione che avrà come valore l’"id_utente" dell’utente loggato, esso potrà essere utilizzato dal metodo "mostra_utente()" per interrogare la tabella "iscritti" ed estrarre il dato richiesto che potrà essere così stampato a video.

Il penultimo metodo proposto sarà necessario per la verifica delle sessioni di login:

public function verifica_sessione() 
{
  if(isset($_SESSION['login']))
  {
    return $_SESSION['login'];
  }else{
    return false;
  }
}

In questo caso non verranno utilizzate delle query, il metodo infatti consisterà essenzialmente in un confronto basato sulla condizione che il valore di sessione sia stato definito, in mancanza di esso il metodo restituirà semplicemente FALSE indicando che non sussiste alcuna sessione in corso.

Veniamo ora all’ultimo metodo, il più semplice tra quelli presenti all’interno del file di funzione:

public function esci()
{
  $_SESSION['login'] = FALSE;
  @session_destroy();
  }
}

"esci()" svolgerà essenzialmente la parte del distruttore della sessione corrente nel caso in cui essa sia stata inizializzata.

Nei prossimi capitoli vedremo come questi metodi verranno utilizzati all’interno della logica della nostra applicazione.

Registrazione e autenticazione

Dopo aver analizzato nel dettaglio i metodi che vengono messi a disposizione dalla classe "Iscrizioni", vediamo come sia possibile utilizzarli per svolgere tutte le procedure previste dal nostro sistema di registrazione e autenticazione; il primo file che andremo a creare sarà appunto "iscrizione.php" e presenterà tutte le funzionalità necessarie per l’inserimenti dei dati dell’utente nel database; passiamo subito al codice commentato:

<?php
# inclusione del file di funzione
@include_once 'functions.php';
# istanza della classe
$obj = new Iscrizioni();
# chiamata al metodo per la verifica della sessione
if ($obj->verifica_sessione())
{
  #redirect in caso di esito negativo
  @header("location:area_riservata.php");
}
# chiamata al metodo per la registrazione
if ($_SERVER["REQUEST_METHOD"] == "POST") 
{
  $registrato = $obj->registra(htmlentities($_POST['nome_reale'], ENT_QUOTES), htmlentities($_POST['nome_utente'], ENT_QUOTES), htmlentities($_POST['password'], ENT_QUOTES), htmlentities($_POST['email'], ENT_QUOTES));
  # controllo sull'esito del metodo
  if ($registrato) {
    # notifica in caso di esito positivo
    echo 'Registrazione conclusa <a href="autenticazione.php">ora puoi loggarti</a>.';
  }else{
    # notifica in caso di esito negativo
    echo 'Il form non è stato compilato correttamente oppure stai cercando di registrarti con dei dati gi&aacute; presenti nel database.';
  }
}
# form per l'iscrizione
?>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Pagina per la registrazione</title>
</head>
<body>
<div id="container">
  <div id="main-body">
  <form method="POST" action="<?php echo $_SERVER['PHP_SELF']; ?>" id="form_registrazione" name="registrazione">
    <div class="head"><h1>Registrazione iscritti</h1></div>
    <label>Nome</label><br/>
    <input type="text" name="nome_reale" /><br/>
    <label>Nome utente</label><br/>
    <input type="text" name="nome_utente" /><br/>
    <label>Password</label><br/>
    <input type="password" name="password" /><br/>
    <label>Il tuo indirizzo di posta elettronica</label><br/>
    <input type="text" name="email" id="email" /><br/><br/>
    <input type="submit" name="registra" value="Registrami"/><br/><br/>
    <label><a href="autenticazione.php" title="Login">Se sei già registrato puoi loggarti da qui</a></label> 
  </form>
  </div>
</div>
</body>
</html>

Il file sarà composto per la parte HTML da un semplice form che si occuperà dell’invio dei dati all’applicazione; quest’ultima effettuerà un controllo sulla sessione, tramite il metodo "verifica_sessione()", se essa è già stata inizializzata verrà eseguito un redirect automatico alla pagina dell’area riservata, se la sessione non dovesse sussistere allora il metodo "registra()" raccoglierà gli eventuali input provenienti dal form e li confronterà con quelli già presenti in tabella; nel caso in cui non vi siano corrispondenze avrà luogo la registrazione, diversamente verrà stampata a video un’apposita notifica.

Una volta registrato, l’utente avrà la possibilità di autenticarsi attraverso l’apposito form presente all’interno del file denominato "autenticazione.php" di cui viene mostrato di seguito il codice:

<?php
# inizializzazione della sessione
@session_start();
# inclusione del file di funzione
@include_once 'functions.php';
# istanza della classe
$obj = new Iscrizioni();
# chiamata al metodo per la verifica della sessione
if ($obj->verifica_sessione())
{
  # redirect in caso di esito positivo
  @header("location:area_riservata.php");
}
# chiamata al metodo per l'autenticazione
if ($_SERVER["REQUEST_METHOD"] == "POST") { 
  $login = $obj->verifica_login(htmlentities($_POST['email_o_nome_utente'], ENT_QUOTES), htmlentities($_POST['password'], ENT_QUOTES));
  # controllo sull'esito del metodo
  if ($login) {
    # redirect in caso di esito positivo
    @header("location:area_riservata.php");
  }else{
    # notifica in caso di esito negativo
    echo 'I dati indicati non sono corretti.';
  }
}
# form per l'autenticazione
?>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Pagina per l'autenticazione</title>
</head>
<body>
<div id="container">
  <div id="main-body">
  <form method="POST" action="<?php echo $_SERVER['PHP_SELF']; ?>" id="form_autenticazione" name="autenticazione">
  <div class="head"><h1>Per poter accedere devi autenticarti</h1></div>
  <label>Inserisci l'email o il nome utente</label><br/>
  <input type="text" name="email_o_nome_utente" /><br/>
  <label>Inserisci la password</label><br/>
  <input type="password" name="password" id="password" /><br/>
  <input type="submit" name="invio_dati" value="Invia"/><br/><br/>
  <label><a href="iscrizione.php" title="Registrazione">Se non sei registrato puoi farlo adesso</a></label>
  </form>
  </div>
</div>
</body>
</html>

Anche in questo caso, dopo l’istanza della classe verrà lanciata la procedura di verifica della sessione, se questa dovesse già sussiste non sarà infatti necessario loggarsi nuovamente e il browser subirà un redirect verso l’area riservata; in caso contrario entrerà in gioco il metodo "verfica_login()" che accetterà come parametri gli input inviati dal form e li confronterà con i dati presenti in tabella, se il confronto dovesse restuituire esito positivo allora si potrà avere accesso alla pagina "area_riservata.php", e sarà proprio di questa che parleremo nel prossimo capitolo.

Area riservata e logout

Una volta registratosi e loggatosi, l’utente avrà la possibilità di visitare la pagina protetta dell’applicazione, quella a cui possono avere accesso soltanto gli iscritti autenticati, dalla stessa area egli avrà anche la possibilità di utilizzare o meglio, chiamare, il metodo per il logout in modo da eliminare la sessione corrente; diamo quindi un sguardo al listato della pagina "area_riservata.php":

<?php
# inizializzazione della sessione
@session_start();
# inclusione del file di funzione
@include_once 'functions.php';
# istanza della classe
$obj = new Iscrizioni();
# identificativo univoco dell'utente
$id_utente = $_SESSION['id_utente'];
# chiamata al metodo per la verifica della sessione
if (!$obj->verifica_sessione())
{
  #redirect in caso di sessione non verificata
  @header("location:autenticazione.php");
}
# controllo sul valore di input per il logout
if (isset($_GET['val']) && ($_GET['val'] == 'fine_sessione')) 
{
  # chiamata al metodo per il logout
  $obj->esci();
  # redirezione alla pagina di login
  @header("location:autenticazione.php");
}
# Area riservata
?>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Area riservata</title>
</head>
<body>
<div id="container">
  <div id="header"><a href="<?php echo $_SERVER['PHP_SELF']; ?>?val=fine_sessione" title="Logout">Esci</a></div>
  <div id="main-body">
  <h1>Benvenuto nell'area riservata <?php $obj->mostra_utente($id_utente);# visualizzazione del nome reale dell'utente ?></h1>
  </div>
  <div id="footer">© MrWebmaster.it</div>
</div>
</body>
</html>

Nel caso specifico del nostro esempio, l’area risevata consisterà essenzialmente in una pagina HTML in cui, grazie al metodo denominato "mostra_utente()" che accetterà come argomento l’identificativo univoco memorizzato in sessione, verrà visualizzato il dato relativo al nome reale dell’utente autenticato. La seconda funzionalità disponibile verrà fornita attraverso un link, se clickato questo invierà all’applicazione un parametro ("$_GET[‘val’]") che, se valorizzato, permetterà all’applicazione di richiamare il metodo "esci()" con il quale la sessione corrente verrà distrutta.

Inserimento di un nuovo metodo

In questa trattazione abbiamo affrontato l’argomento relativo all’utilizzo di classi, metodi e oggetti per la creazione di un’applicazione di registrazione e autenticazione in PHP il cui codice rispettasse il più possibile il paradigma OOP; come è stato possibile osservare, il file "functions.php" contiene la maggior parte dei metodi necessari per il funzionamento dello script, a quelli già elencati se ne potranno però aggiungere in ogni momento di nuovi, rispettando la logica dell’applicazione; vediamo per esempio come sia possibile definire un metodo per la visualizzazione del nome utente:

# metodo per la visualizzazione del nome utente
public function mostra_username($id_utente) 
{ 
  # estrazione del dato sulla base dell'identificativo univoco memorizzato in sessione 
  $query = @mysql_query("SELECT nome_utente FROM iscritti WHERE id_utente = $id_utente") or die(mysql_error()); 
  $risultato = mysql_fetch_object($query);
  # stampa a video del risultato 
  echo $risultato->nome_utente; 
}

Il metodo definito dovrà essere inserito all’interno della classe "Iscrizioni" esattamente come quelli mostrati in precedenza:

<?php $obj->mostra_utente($id_utente); ?>

La logica applicativa rimane comunque sempre la stessa rispetto a quella esposta all’inizio di questa trattazione, infatti, si definisce una classe:

class Iscrizioni {..

si crea un oggetto della classe tramite istanza:

$obj = new Iscrizioni();

e si richiama un metodo appartenente all’oggetto: quando si vuole compiere l’azione per il quale il metodo è stato concepito:

$obj->mostra_utente($id_utente);

Naturalmente, nulla vieta di implementare lo script aggiungendo ulteriori funzionalità, come per esempio un metodo appositamente dedicato ad una più accurata validazione degli input e l’introduzione di Ajax per rendere l’applicazione ancora più dinamica.

Pubblicitร 
Claudio Garau
Claudio Garau
Web developer, programmatore, Database Administrator, Linux Admin, docente e copywriter specializzato in contenuti sulle tecnologie orientate a Web, mobile, Cybersecurity e Digital Marketing per sviluppatori, PA e imprese.

Leggi anche...

Correggere l’errore the uploaded file exceeds the upload_max_filesize directive in php.ini

L'errore the uploaded file exceeds the upload_max_filesize directive in...

Cannot modify header information – headers already sent: come risolvere l’errore PHP

L'errore di PHP cannot modify header information - headers...

Ricavare l’estensione di un file con PHP

Quando si lavora con i file in un'applicazione web,...

GD Library: creazione, manipolazione e ridimensionamento immagini con PHP

Le librerie GD (o GD Library), sono componenti fondamentali...

PHP: impostare il fuso orario italiano

Le tue pagine PHP non mostrano l’orario corretto? Probabilmente...
Pubblicitร