Nessun risultato. Prova con un altro termine.
Guide
Notizie
Software
Tutorial

Sessioni alternative in Php

Utilizzare le sessioni immagazzinando i dati in un database
Utilizzare le sessioni immagazzinando i dati in un database
Link copiato negli appunti

Introduzione

Come sanno tutti gli appassionati di PHP, una delle principali novità introdotte a partire da PHP4 è costituita dall'integrazione del sistema di gestione delle sessioni.

Quando si parla di sessioni, si fa riferimento al tentativo di far sì che una sessione di navigazione di un client, ad esempio tutto il periodo di tempo che si sta su un sito, sia tale a tutti gli effetti, ossia che il Server sia in grado di "accorgersi" che determinate richieste inviate provengano dalla stessa macchina per comportarsi di conseguenza. Con questo tentativo di definizione siamo riusciti ad isolare le due caratteristiche principali che un sistema di gestione delle sessioni dovrebbe avere, ossia scoprire quando più chiamate provengano da uno stesso client e registrare conseguentemente i vari dati di quella sessione.

Ma abbiamo altresì messo in luce il limite principale del protocollo http, quello di essere privo di stato, per cui il web server non riesce ad associare in automatico i dati ad una determinata richiesta, di qui i vari tentativi di superare questo limite (sessioni, cookies, passaggio di dati tramite query string o campi di moduli).

Sessioni alternative

In breve, e senza entrare troppo nell'argomento, le sessioni consentono di identificare un determinato client per un determinato periodo di tempo e di associargli dei dati, che vengono serializzati e salvati in un file di testo avente il nome sess_idsessione (dove idsessione è una stringa alfanumerica di 32 caratteri - sufficienti quindi ad evitare il rischio di due sessioni con identico nome) passata in un cookie al client o "appesa" ad ogni URL.

Fin qui la definizione e lo scopo delle sessioni, ma una domanda si pone obbligatoriamente: quanto sono sicure ed affidabili, così come sono congegnate ? La risposta, ovvia, è che sono "abbastanza" sicure (ammesso che la parola sicurezza, sul web e non solo, abbia un reale significato), non foss'altro per la fiducia che dobbiamo ai creatori del nostro amato linguaggio.

Questo mio convincimento, è radicalmente mutato dopo la lettura del libro Programmare in PHP e, segnatamente, del
passo in cui si parlava di vari problemi legati alla sicurezza; la certezza di cui sopra, già incrinatasi,
ha subito poi lo scossone definitivo quando ho letto tra gli autori del manuale il nome di Rasmus Lerdorf, colui che è unanimemente riconosciuto come l'inventore di PHP e che fa attivamente
parte del gruppo ufficiale di sviluppo.

Fa notare, in breve, il buon Rasmus, che i file delle sessioni appartengono tutti allo stesso utente (l'utente di Apache, nobody di default) e vengono tutti salvati nella stessa directory, accessibile a tutti, in lettura e scrittura.
Ciò comporta che tutti i files di sessione possono essere letti da tutti gli script php presenti su quel server, con possibili conseguenze poco piacevoli.

Naturalmente questa è la situazione che si viene a creare, di norma, su un server condiviso, se si è proprietari del server il problema non si pone minimamente, ma tanto basta ad allarmare e a consigliare estrema prudenza nell'uso delle sessioni di php4. Conclude Rasmus con la sibillina frase "il posto più sicuro in cui memorizzare dati è un database".

Scopo della prima e della seconda parte di questo articolo è, appunto, cercare di costruire un sistema di sessioni alternativo a quello tradizionale, e facente uso di Database; nella terza ed ultima parte poi cercherò di illustrare (a scopo puramente dimostrativo) come si possa emulare il sistema di sessioni di PHP, facendo uso di files di testo.

Sessioni e database

Premetto che il sistema di sessioni da me presentato si avvarrà di un cookie, che chiameremo my_session_id,
per tenere traccia della sessione; in alternativa si può passare l'id di sessione via GET, ma bisogna ricordare di
"appendere" ad ogni link lo stesso id, pena il mancato funzionamento del sistema (le modifiche da fare al codice sono
veramente banali).

Occorre, in primo luogo, determinare alcuni parametri generali di cui il sistema si avvarrà e precisamente il tempo
di durata della sessione (che setteremo a zero di default), il tempo massimo oltre il quale tutte le sessioni
dovranno essere cancellate (che servirà alla procedura di garbage collection e che setteremo a trenta minuti) e,
naturalmente, i parametri necessari per accedere a MySql.

Creiamo un nuovo file, chiamandolo config.inc.php e scriviamo le variabili:

<?php

// valori espressi in secondi
$session_time = 0; // durata del cookie
$session_gc_time = 1800; // tempo per l'esecuzione della garbage collection

// variabili MySql
$db_host = 'localhost';
$db_user = 'username';
$db_password = 'password';
$db_name = 'dbname';

?>

Ovviamente dovete settare correttamente le variabili di MySql, mentre invece consiglio di non cambiare gli altri
valori, specialmente $session_time, infatti impostato a zero farà sì che il cookie scadrà automaticamente alla
chiusura della sessione di navigazione (ossia alla chiusura del browser).

Ovviamente avremo bisogno di costruire una tabella destinata a contenere i dati delle sessioni, la struttura potrebbe essere questa:

CREATE TABLE my_session (
sessid varchar(32) NOT NULL default '',
session_vars text NOT NULL,
session_date int(10) unsigned NOT NULL default '0',
UNIQUE KEY sessid (sessid)
) TYPE=MyISAM;

la tabella può essere creata da linea di comando, tramite script o per mezzo di un tool (o di un front-end) apposito come phpMyAdmin o MySqlFront.

La classe che gestisce la sessione

Occupiamoci adesso di creare il file che conterrà la classe che ci consentirà di gestire il nostro sistema di sessioni alternative.

Creiamo quindi un file chiamato db_session_class.php (all'interno della stessa directory dove c'è il file di configurazione) e copiamo al suo interno il seguente codice.

<?php

require('config.inc.php');

class my_session {

   var $my_session_id; // l'id di sessione
   var $session_time; // la durata della sessione
   var $session_gc_time; // il tempo per la garbage collection

   //il costruttore della classe, inizializza le variabili
   function my_session($session_time, $session_gc_time) {
      $this->my_session_id = (!isset($_COOKIE['my_session_id']))
          ? md5(uniqid(microtime()))
              : $_COOKIE['my_session_id'];
      $this->session_time = $session_time;
      $this->session_gc_time = $session_gc_time;
   }

   // avvia o aggiorna la sessione
   function my_session_start() {
      $cookie_expire = ($this->session_time > 0) ? (time() + $this->session_time) : 0;
      if(!isset($_COOKIE['my_session_id'])) {
         setcookie('my_session_id', $this->my_session_id, $cookie_expire);
         mysql_query("INSERT INTO my_session VALUES('" . $this->my_session_id . "', '', " . time() . ")");
      } else {
         if($this->session_time > 0)
            setcookie('my_session_id', $this->my_session_id, $cookie_expire);
      }
   }

   /*   registra la variabili di sessione
      specificata nel database */
   function my_session_register($name, $value) {
      $_MY_SESSION = array();
      $session_query = mysql_query("SELECT session_vars FROM my_session
      WHERE sessid = '{$this->my_session_id}'");
      if(mysql_num_rows($session_query) > 0) {
         $result = mysql_fetch_array($session_query);
         $_MY_SESSION = unserialize($result['session_vars']);
         $_MY_SESSION[$name] = $value;
         mysql_query("UPDATE my_session SET session_vars = '" . serialize($_MY_SESSION) . "'
         WHERE sessid = '{$this->my_session_id}'");
      } else {
         $_MY_SESSION[$name] = $value;
         mysql_query("UPDATE my_session SET session_vars = '" . serialize($_MY_SESSION) . "'
         WHERE sessid = '{$this->my_session_id}'");
      }
   }

   /*   legge e restituisce le variabili di sessione
      (o la singola variabile specificata */
   function my_session_read($key = '') {
      $session_query = mysql_query("SELECT session_vars FROM my_session
      WHERE sessid = '{$this->my_session_id}'");
      if(mysql_num_rows($session_query) > 0) {
         $result = mysql_fetch_array($session_query);
         $session_vars = unserialize($result['session_vars']);
         return (isset($key) && $key) ? $session_vars[$key] : $session_vars;
      }
   }

   /*   distrugge la sessione, rimuovendo i relativi
      dati (non cancella il cookie) */
   function my_session_destroy() {
      mysql_query("UPDATE my_session SET session_vars = ''
      WHERE sessid = '{$this->my_session_id}'");
   }

   // procedura di garbage collection
   function my_session_gc() {
      mysql_query("DELETE FROM my_session
      WHERE session_date < " . (time() - $this->session_gc_time));
   }

} // end class

?>

Questo è tutto per la prima parte di questo tutorial, la prossima settimana analizzeremo la classe appena presentata e illustreremo i vari script per utilizzarla.

La classe che gestisce la sessione

La classe, come evidente, è molto semplice. Cercherò di spiegare brevemente i suoi metodi uno per uno.

In primo luogo my_session() (il costruttore). Si occupa solamente di inizializzare le variabili necessarie al funzionamento del nostro sistema.

Il primo metodo è my_session_start() si occupa di avviare la sessione se ancora non esiste (verificando
l'eventuale presenza del cookie nel client) o di aggiornarla (aggiornando il tempo di scadenza del cookie), ma solo
nel caso in cui si sia settata la variabile $session_time ad un valore maggiore di zero.

Il metodo my_session_register() si occupa di registrare la variabile (previa serializzazione) di sessione
passatale come argomento (insieme al suo valore) nel database.

Il metodo my_session_read() si occupa di leggere tutti i dati della sessione (o, in alternativa la singola variabile
richiesta), deserializzarli e restituirli all'utente. Da notare che, se richiamata nella stessa pagina dove è stata avviata la sessione, la funzione fa riferimento alla
proprietà $this->my_session_id per recuperare i dati, essendo il cookie ancora non disponibile.

Infine, il metodo my_session_destroy(), che cancella i dati di sessione dal Database (senza cancellare il record ed il cookie), e il metodo my_session_gc() che provvede a ripulire la tabella delle sessioni dai record più vecchi di $session_gc_time (garbage collection).

Avviare la sessione

Adesso che abbiamo la nostra classe, preoccupiamoci di farla funzionare. In primo luogo il codice che ci servirà per avviare la sessione e per registrare alcune variabili. Creiamo un file chiamato start_session.php e copiamo al suo interno il seguente codice (i commenti all'interno dovrebbero essere sufficienti a spiegarne il funzionamento):

<?php

// inclusione del file che contiene la classe
require('db_session_class.php');

// connessione a MySql
mysql_connect($db_host, $db_user, $db_password);

// selezione del Database
mysql_select_db($db_name);

// Istanziamo l'oggetto
$my_session = new my_session($session_time, $session_gc_time);

// Avviamo la sessione inviando il cookie al client
$my_session->my_session_start();

// Richiamiamo la procedura di garbage collection
$my_session->my_session_gc();

// Registriamo tre variabili di prova
$my_session->my_session_register('nome 1', 'valore 1');
$my_session->my_session_register('nome 2', 'valore 2');
$my_session->my_session_register('nome 3', 'valore 3');

// Chiusura connessione
mysql_close();

?>

Leggere i dati della sessione

Adesso che la sessione è avviata e che alcuni dati sono stati registrati (se tutto è andato bene...), occupiamoci di
leggere e rendere disponibili questi dati.
Creiamo un file chiamato test_session.php e copiamo al suo interno il seguente codice (anche qui i commenti
all'interno dovrebbero essere sufficienti a spiegarne il funzionamento):

<?php

// inclusione del file che contiene la classe
require('db_session_class.php');

// connessione a MySql
mysql_connect($db_host, $db_user, $db_password);

// selezione del Database
mysql_select_db($db_name);

// Istanziamo l'oggetto
$my_session = new my_session($session_time, $session_gc_time);

// Aggiorniamo, se necessario, la sessione "allungando la vita" del cookie
$my_session->my_session_start();

// Inizializziamo l'array che conterrà i dati della sessione
$_MY_SESSION_VARS = array();

/* Richiamiamo il metodo che ci restituirà le variabili di sessione, e memorizziamo
le stesse nell'array $_MY_SESSION_VARS; in alternativa avremmo potuto ottenere il
valore di una sola variabile, specificandone il nome come argomento del metodo */
$_MY_SESSION_VARS = $my_session->my_session_read();

/* In questo semplice esempio ci limitiamo a stampare a video,
formattandole, tutte le variabili di sessione registrate,
ovviamente possiamo farne l'utilizzo desiderato */
echo "<pre>n";
print_r($_MY_SESSION_VARS);
echo "</pre>n";

// Chiusura connessione
mysql_close();

?>

Distruggere la sessione

Ecco infine lo script semplicissimo per distruggere la sessione, creiamo un file chiamato destroy_session.php e
copiamo al suo interno il seguente codice:

<?php

// inclusione del file che contiene la classe
require('db_session_class.php');

// connessione a MySql
mysql_connect($db_host, $db_user, $db_password);

// selezione del Database
mysql_select_db($db_name);

// Istanziamo l'oggetto
$my_session = new my_session($session_time, $session_gc_time);

// Richiamiamo il metodo che distrugge la sessione
$my_session->my_session_destroy();

// Chiusura connessione
mysql_close();

?>

Questo è tutto per ciò che riguarda il nostro sistema alternativo di sessioni facente uso di MySql. Va da sè che sono stato volutamente generico nell'illustrazione dei vari esempi, ma questo tipo di gestione delle sessioni può essere utilizzato per gestire anche aree riservate, o pannelli di amministrazione, apportando delle leggere modifiche agli script presentati.

Nella terza ed ultima parte di questo articolo, presenterò un altro sistema di gestione delle sessioni, facente uso di files e che, in buona sostanza, sarà un tentativo di emulare le sessioni tradizionali di PHP4 (a scopo puramente dimostrativo).

Emulare le sessioni di php4

In questa ultima parte di questo tutorial, illustrerò un ulteriore sistema alternativo di sessioni, ma, a differenza del precedente, questo farà uso di files di testo (esattamente come quello "ufficiale" che proverò quindi ad emulare).

Anche qui abbiamo bisogno, in primo luogo, di settare delle variabili generali, creiamo quindi un nuovo file, chiamandolo config.inc.php e scriviamo il seguente codice:

<?php

// valori espressi in secondi
$session_time = 0; // durata del cookie
$session_gc_time = 1800; // tempo per l'esecuzione della garbage collection

/* la directory dove memorizzare i dati della sessione,
sui sistemi Unix like, deve avere tuti i permessi (777) */
$session_dir = './test'; // senza slash finale

?>

Analogamente all'altro sistema che faceva uso del database, anche questo si avvarrà di un cookie per "trasportare" l'id di sessione e anche in questo caso consiglio di non cambiare il valore di $session_time. Se impostato a zero farà sì che il cookie scada automaticamente alla chiusura della sessione di navigazione (ossia alla chiusura del browser). Fate anche attenzione a non mettere lo slash finale nella variabile $session_dir (potete anche usare un percorso assoluto).

La classe che gestisce la sessione

Occupiamoci adesso di creare il file che conterrà la classe che ci consentirà di gestire il nostro sistema di sessioni alternative. Creiamo quindi un file chiamato file_session_class.php (all'interno della stessa directory dove c'è il file di configurazione) e copiamo al suo interno il seguente codice.

<?php

require('config.inc.php');

class my_session {

   var $session_dir; // la dir. dove fare lo storage dei dati di sessione
   var $my_session_id; // l'id di sessione
   var $session_time; // la durata della sessione
   var $session_gc_time; // il tempo per la garbage collection

   //il costruttore della classe, inizializza le variabili
   function my_session($session_dir, $session_time, $session_gc_time) {
      $this->my_session_id = (!isset($_COOKIE['my_session_id']))
         ? md5(uniqid(microtime()))
            : $_COOKIE['my_session_id'];
      $this->file_name = 'sess_' . $this->my_session_id;
      $this->session_dir = $session_dir;
      $this->session_time = $session_time;
      $this->session_gc_time = $session_gc_time;
   }

   // avvia o aggiorna la sessione
   function my_session_start() {
      $cookie_expire = ($this->session_time > 0) ? (time() + $this->session_time) : 0;
      if(!isset($_COOKIE['my_session_id'])) {
         setcookie('my_session_id', $this->my_session_id, $cookie_expire);
      } else {
         if($this->session_time > 0)
            setcookie('my_session_id', $this->my_session_id, $cookie_expire);
      }
   }

   // registra le variabili di sessione nel database
   function my_session_register($name, $value) {
      $session_name = (!isset($_COOKIE['my_session_id']))
         ? 'sess_' . $this->my_session_id
            : $this->file_name;
      $_MY_SESSION = array();
      if(file_exists($this->session_dir . '/' . $session_name)) {
         $_MY_SESSION = unserialize(implode('', file($this->session_dir . '/' . $session_name)));
         $_MY_SESSION[$name] = $value;
      } else {
         $_MY_SESSION[$name] = $value;
      }
      $fp = fopen($this->session_dir . '/' . $session_name, 'wb');
      fputs($fp, serialize($_MY_SESSION));
      fclose($fp);
   }

   /* legge e restituisce le variabili di sessione
      (o la singola variabile specificata */
   function my_session_read($key = '') {
      if(file_exists($this->session_dir . '/' . $this->file_name)) {
         $session_vars = unserialize(implode('', file($this->session_dir . '/' . $this->file_name)));
         return (isset($key) && $key) ? $session_vars[$key] : $session_vars;
      }
   }

   // distrugge la sessione, senza cancellare il cookie
   function my_session_destroy() {
      @unlink($this->session_dir . '/' . $this->file_name);
   }

   // procedura di garbage collection
   function my_session_gc() {
      $d = dir($this->session_dir);
      while ($entry = $d->read()) {
         if($entry != '.' && $entry != '..') {
            if(is_dir($entry)) continue;
            if(strpos($entry, 'sess_') !== FALSE) {
               if((filemtime($this->session_dir . '/' .$entry) + $this->session_gc_time) < time()) {
                  @unlink($this->session_dir . '/' .$entry);
               }
            }
         }
      }
      $d->close();
   }

}

?>

La classe che gestisce la sessione

Cerchiamo adesso di illustrare ad uno ad uno i vari metodi di cui si compone la classe appena presentata (noterete che sono del tutto analoghi a quelli dell'altra classe che faceva uso di MySql).
In primo luogo my_session() (il costruttore), che si occupa solamente di inizializzare le variabili necessarie al funzionamento del nostro sistema.

Il primo metodo è my_session_start(), che si occupa di avviare la sessione se ancora non esiste (verificando l'eventuale presenza del cookie nel client), o di aggiornarla (aggiornando il tempo di scadenza del cookie), ma solo nel caso in cui si sia settata la variabile $session_time ad un valore maggiore di zero.

Il metodo my_session_register(), si occupa di registrare la variabile (previa serializzazione) di sessione passatale come argomento (insieme al suo valore) nel database.

Il metodo my_session_read() si occupa di leggere tutti i dati della sessione(o, in alternativa la singola variabile richiesta), deserializzarli e restituirli all'utente.

Infine, il metodo my_session_destroy(), che cancella la sessione (cancellando fisicamente il file relativo, ma senza rimuovere il cookie), e la funzione my_session_gc() che provvede a cancellare le sessioni più vecchie di $session_gc_time (garbage collection), eliminando i relativi files dalla directory $session_dir.

Avviare la sessione

Ecco il codice che ci servirà per avviare la sessione e per registrare alcune variabili.
Creiamo un file chiamato start_session.php e copiamo al suo interno il seguente codice (i commenti all'interno dovrebbero essere sufficienti a spiegarne il funzionamento):

<?php

// inclusione del file che contiene la classe
require('file_session_class.php');

// Istanziamo l'oggetto
$my_session = new my_session($session_dir, $session_time, $session_gc_time);

// Avviamo la sessione inviando il cookie al client
$my_session->my_session_start();

// Richiamiamo la procedura di garbage collection
$my_session->my_session_gc();

// Registriamo tre variabili di prova
$my_session->my_session_register('nome 1', 'value1');
$my_session->my_session_register('nome 2', 'value2');
$my_session->my_session_register('nome 3', 'value3');

?>

Leggere i dati della sessione

Adesso che la sessione è avviata e che alcuni dati sono stati registrati (se tutto è andato bene...), occupiamoci di leggere e rendere disponibili questi dati. Creiamo un file chiamato test_session.php e copiamo al suo interno il seguente codice (anche qui i commenti all'interno dovrebbero essere sufficienti a spiegarne il funzionamento):

<?php

// inclusione del file che contiene la classe
require('file_session_class.php');

// Istanziamo l'oggetto
$my_session = new my_session($session_dir, $session_time, $session_gc_time);

// Aggiorniamo, se necessario, la sessione "allungando la vita" del cookie
$my_session->my_session_start();

// Inizializziamo l'array che conterrà i dati della sessione
$_MY_SESSION_VARS = array();

/* Richiamiamo il metodo che ci restituirà le variabili di sessione, e memorizziamo
le stesse nell'array $_MY_SESSION_VARS; in alternativa avremmo potuto ottenere il
valore di una sola variabile, specificandone il nome come argomento del metodo */
$_SESSION_VARS = $my_session->my_session_read();

/* In questo semplice esempio ci limitiamo a stampare a video,
formattandole, tutte le variabili di sessione registrate,
ovviamente possiamo farne l'utilizzo desiderato */
echo '<pre>';
print_r($_SESSION_VARS);
echo '</pre>';

?>

Distruggere la sessione

Ecco infine lo script semplicissimo per distruggere la sessione, creiamo un file chiamato destroy_session.php e copiamo al suo interno il seguente codice:

<?php

// inclusione del file che contiene la classe
require('file_session_class.php');

// Istanziamo l'oggetto
$my_session = new my_session($session_dir, $session_time, $session_gc_time);

// Richiamiamo il metodo che distrugge la sessione
$my_session->my_session_destroy();

?>

E con questo completiamo il discorso sulle "sessioni alternative" in PHP, tutti i metodi presentati sono, a mio avviso, abbastanza semplici da implementare ed abbastanza duttili da poter essere utilizzati in contesti diversi rispetto a quelli, volutamente, semplici e generici qui esposti.

Ti consigliamo anche