Warning: Undefined array key "tbm_guide_level" in /data/websites/htmlit/web/app/themes/htmlit/src/ViewModel/Post/Templates/SingleGuide.php on line 113

Warning: Trying to access array offset on value of type null in /data/websites/htmlit/web/app/themes/htmlit/src/ViewModel/Post/Templates/SingleGuide.php on line 113

Warning: Undefined array key "tbm_guide_level" in /data/websites/htmlit/web/app/themes/htmlit/src/ViewModel/Post/Templates/SingleGuide.php on line 113

Warning: Trying to access array offset on value of type null in /data/websites/htmlit/web/app/themes/htmlit/src/ViewModel/Post/Templates/SingleGuide.php on line 113

Warning: Undefined array key "tbm_guide_level" in /data/websites/htmlit/web/app/themes/htmlit/src/ViewModel/Post/Templates/SingleGuide.php on line 113

Warning: Trying to access array offset on value of type null in /data/websites/htmlit/web/app/themes/htmlit/src/ViewModel/Post/Templates/SingleGuide.php on line 113
Gestire le sessioni su APC, cache e database | HTML.it
Nessun risultato. Prova con un altro termine.
Guide
Notizie
Software
Tutorial

Gestire le sessioni su APC, cache e database

Una classe standard che ci permette di gestire le sessioni in diversi scenari di configurazione: APC, memcache, wincache, SQLite, MySQL.
Una classe standard che ci permette di gestire le sessioni in diversi scenari di configurazione: APC, memcache, wincache, SQLite, MySQL.
Link copiato negli appunti

Le sessioni vengono normalmente salvate da PHP su file ma, come abbiamo visto anche nel nostro articolo Sessioni PHP: cosa sono come si usano, sono disponibili anche dei meccanismi di memorizzazione alternativi detti 'handler' che sono generalmente associati a particolari estensioni.

In questo articolo vedremo come configurarli ma soprattutto come creare handler personalizzati per poter salvare i dati delle nostre sessioni sui supporti più disparati e secondo le nostre esigenze in modo del tutto trasparente rispetto agli applicativi che li andranno ad utilizzare.

In questo articolo vedremo, oltre a creare handler di sessione personalizzati, anche le istruzioni per gestire le sessioni con sistemi alternativi. In particolare, vedremo come:

I session handler ed il PHP 5.4

Prima di iniziare è bene ricordare che con la versione 5.4 di PHP è stata introdotta un'interfaccia SessionHandlerInterface SessionHandler

La registrazione degli handler siffatti può essere eseguita sempre attraverso la funzione session_set_save_handler() session_write_close() register_shutdown_function()

C’è da dire che vengono proposte solo delle strutture. Tutte le implementazioni sono a carico dell’utilizzatore; in più, essendo basate su metodi dinamici, soffrono delle problematiche che hanno  portato alla scelta usare metodi statici in questo articolo, come vedremo di seguito.

Come creare degli handler di sessione personalizzati

La definizione di un handler personalizzato è consentita attraverso la funzione: session_set_save_handler(), nell'uso classico occorre passare a questa funzione sei parametri che corrispondono ai nomi

  1. Open: Apertura sella sessione,
  2. Read: Lettura dei dati di sessione da un sistema di archiviazione, $_SESSION
  3. Write: Scrittura dei dati nel sistema di archiviazione session_write_close $_SESSION
  4. Close: Chiusura della sessione
  5. Destroy: Distruzione dei dati della sessione session_destroy()
  6. GC: Pulizia delle sessioni scadute php.ini session.gc_probability session.gc_divisor. session.gc_maxlifetime

Prima di cominciare a scrivere le funzioni per implementare un handler di sessioni personalizzato, vediamo come si può standardizzare questo procedimento tramite una classe astratta da estendere di volta in volta a seconda delle tecnologie le strategie scelte.

<?
abstract class mySessionHandler {

    /**
     * Registrazione dei metodi open,gc,close, read,write,destroy
     * della classe che li implementa */
    public static function set_handler() {
        //ricava il nome della classe che invoca il metodo
        $classe = get_called_class();
        //utilizziamo come parametri della funzione session_set_save_handler()
        //le chiamate ai metodi statici astratti definiti in questa classe
        session_set_save_handler("$classe::open", "$classe::close", "$classe::read", "$classe::write", "$classe::destroy", "$classe::gc");
    }
    /* Metodi di gestione da implementare */

    public static function open($path, $name) {
    }

    public static function read($sid) {
    }

    public static function write($sid, $dati_sessione) {
    }

    public static function destroy($sid) {
    }

    public static function gc($maxlifetime) {
    }

    public static function close() {
    }

}
?>

Concentriamoci ora sul metodo setHandler() $classe=get_called_class() session_set_save_handler get_called_class() __CLASS__ __CLASS__ mySessionHandler

La scelta di usare solo metodi statici è dovuta alle seguenti motivazioni:

  1. Il gestore delle sessione in ogni script è generalmente uno, laddove per qualche ragione se ne dovessero creare più istanze sarebbe comunque opportuno riciclare sempre la stessa, di fatto quindi un singleton che non vale la pena implementare in questo caso;
  2. per accedere ai metodi dinamici di una classe occorre istanziarla e mantenere "viva" tale istanza conservando sempre una variabile associata ad essa, pur non avendo mai la necessità di usarla direttamente poiché i metodi sono richiamati da PHP su determinati eventi;
  3. in fase di shutdown il PHP elimina le istanze in ordine inverso a quello di istanziazione e quindi l'istanza che gestisce le sessioni potrebbe essere distrutta prima di un'altra istanza che prevedeva modifica di $_SESSION nel distruttore vanificando così gli effetti di queste modifiche, e questo vale anche se si usa un Singleton;
  4. l'accesso ai metodi statici è generalmente più performante rispetto a quelli dinamici seppure in questo caso sarebbe un vantaggio del tutto trascurabile.
  5. Gestire le sessioni PHP con APC

    APC (Alternative PHP Cache) si sta sempre più affermando come estensione per il caching degli script. Un'ulteriore caratteristica di questa estensione è quella di fornire dei comandi primitivi per la gestione di RAM condivisa tra gli script.

    Ecco un esempio di handler di sessioni realizzando estendendo mySessionHandler ed usando l'APC per memorizzare i dati:

    <?
    Class APC_mySessionHandler extends mySessionHandler{
                    public static function read($sid){
                                            return  apc_fetch(get_called_class().'_'.$sid);
                                            }
                    public static function write($sid, $dati_sessione){
                                             apc_store(get_called_class().'_'.$sid,$dati_sessione, ini_get('session.gc_maxlifetime'));
                                            }
    
                    public static function destroy($sid){
                                          apc_delete(get_called_class().'_'.$sid);
                                            }
    }     
    ?>

    Come si può notare i metodi open(), gc() e close() sono del tutto inutili nel contesto APC che non prevede connessioni e/o disconnessioni ed ha un garbage collector interno e quindi non ne è stato fatto l'overriding.

    Meritano di essere evidenziati:

    • La scelta di usare come chiave per la memorizzazione delle sessioni la stringa composta dal SID seguito dall'underscore seguito dal nome della classe invocata per evitare eventuali conflitti con chiavi eventualmente usate in altri contesti.
    • Il secondo parametro passato al comando apc_store write() php.ini session.gc_maxlifetime

    Per attivare il nuovo handler basterà fare precedere il session_start() da APC_mySessionHandler::setHandler() ad esempio, supponendo di aver conservato tutte le classi in un unico file mySessionHandlers.php possiamo scrivere:

    <?
    include("./mySessionHandlers.php");
    APC_mySessionHandler::setHandler();
    session_start();
    
    //resto del codice
    ?>

    Per chi usa Zend Server e vuol sfruttare l'analoga estensione Zend data cache può non essere necessario implementare una versione ad hoc dell'handler in quanto di default la Zend data cache è in grado di simulare la presenza di APC e quindi si può usare direttamente questa stessa classe; anche se sarebbe consigliabile i comandi in quanto le primitive della Zend data cache sono in grado di gestire dei namspaces delle chiavi memorizzate ed il tutto risulterebbe più pulito.

    Carichiamo i nostri handler in modo trasparente

    Ma come si può caricare un handler personalizzato in modo trasparente, facendo in modo che i nostri script lo usino senza neanche accorgersene e soprattutto senza dover minimamente mettere mano al codice preesistente?

    Per queste evenienze ci viene in aiuto la direttiva auto_prepend_file php.ini

    /www/protected/sessionhandler.php
    <?
    include(__DIR__."/mySessionHandlers.php"); //assumiamo che anche il file con il codice della classe risieda in /www/protected/
    APC_mySessionHandler::setHandler();
    //non si inserisce qui il session_start() ma sarà eventualmente lo script in esecuzione a doverlo fare
    ?>

    Semplicemente inserendo nel php.ini auto_prepend_file='/www/protected/sessionhandler.php'

    Gestire le sessioni PHP con Windows Wincache for PHP

    Negli ultimi anni il PHP ha sempre più trovato trovando spazio su IIS, questo grazie anche all'inatteso interessamento di Microsoft che ha sviluppato in collaborazione con Zend Technologies un modulo fastcgi in grado di far girare PHP su piattaforma Windows a prestazioni più che soddisfacenti. Ma il colosso di Redmond non si è fermato qui, ha dedicato un'intera sezione del sito di IIS al mondo PHP nella quale, oltre a forum e tutorial, mette a disposizione la "Web Platform for PHP".

    Questo tool permette di scaricare ed installare su IIS, oltre a famosi CMS come WordPress, Drupal o Joomla, anche una versione di PHP potendo disporre di una comoda interfaccia grafica di configurazione del php.ini (il PHPManager) e delle estensioni PHP sviluppate interamente da Microsoft quali la nuova libreria di connessione a SQL Server ed una di caching degli script del tutto analoga ad APC: la Wincache for PHP. Quest'ultima viene presentata coma una valida e più performante alternativa ad APC per le installazioni su Windows e mette anche a disposizione un handler nativo delle sessioni, è sufficiente modificare i php.ini come segue:

    session.save_handler = wincache
    session.save_path = C:inetpubtempsession

    Da notare la presenza di una cartella nella quale l'handler salva i file temporaneamente per evitare perdite di dati durante il riciclo degli "application pool", ma se il nostro IIS è impostato in modo da non riciclare mai gli "applicaction pools" come si può fare ad evitare questo inutile spreco di tempo e spazio sul disco?

    Ecco come si può facilmente scrivere un handler di sessioni basato su Wincache salvata esclusivamente in RAM..

    <?
    Class WinCache_mySessionHandler extends mySessionHandler{
                    public static function read($sid){
                                            return  wincache_ucache_get(get_called_class().'_'.$sid);
                                            }
    
                    public static function write($sid, $dati_sessione){
                                             wincache_ucache_set(get_called_class().'_'.$sid,$dati_sessione, ini_get('session.gc_maxlifetime'));
                                            }
                    public static function destroy($sid){
                                          wincache_ucache_delete(get_called_class().'_'.$sid);
                                            }
    
    }
    ?>

    Gestire le sessioni PHP con Memcached

    Finora sono state prese in considerazione le metodologie di memorizzazione dei dati di sessione più performanti, basate cioè su ram condivisa tra gli script, ma adatte esclusivamente ad un uso singolo server. p>

    In condizioni di load balancing tra più server le richieste di uno stesso client possono essere indirizzate a più server alternativamente (a meno che non si configuri in modo diverso il bilanciatore) ed i dati di sessione contenuti in un server non sarebbero disponibili quando il client viene indirizzato sull'altro e viceversa.

    Con l'handler di sessioni basato su file system tale inconveniente viene generalmente risolto facendo puntare 'session.save_path' ad una share di rete ma è prestazionalmente proibitivo ed in assenza di apparati sufficientemente performanti potrebbe persino annullare il vantaggio del load balancing. Per questa ragione si può installare su una delle macchine, o su un server terzo, un servizio memcached a cui tutti i server faranno riferimento come deposito di sessioni.

    PHP possiede già un handler di sessioni specifico per memcached. Anzi, ne possiede due: uno per l'estensione memcache ed uno per l'estensione memcached ed è possibile attivarli direttamente da php.ini

    ;indicare qui memcache o memcached a seconda dell'estensione che si vuole usare
    session.save_handler = memcache

    ;indicare qui IP:PORTA del/dei server memcached ed eventuali parametri
    session.save_path= "tcp://192.22.22.22:11211"

    Il collegamento può avvenire via tcp, udp o socket unix ed è anche possibile usare più server memcache in parallelo definendo politiche di connessione attraverso opportuni parametri.

    Avere un'handler memcached fatto in casa può permettere di inserire dei prefissi alle chiavi per evitare eventuali collisioni nel caso il servizio non sia dedicato a memorizzare solo le sessioni oppure può permettere di gestire l'evento di mancata connessione alla memcached inviando una mail ad un sistemista e/o lanciando un'eccezione come nell'esempio seguente:

    <?
    class memcache_mySessionHandler extends mySessionHandler{
    protected static $memcache;     
                    public static function open($path,$name) {
                                    self::$memcache=new memcache();
                                    $host=explode(':',$path,2); //assumendo che $path contenga un indirizzo nella forma 192.22.22.22:11211 lo scompone
                                    $connesso=@self::$memcache->pconnect($host[0],($host[1]?$host[1]:11211)); //se il secondo parametro non è valorizzato lo setta a 11211
                                    if(!$connesso) {
                                                    mail('administrato@myhost.it','Memcached non attiva','Attenzione memcached non risponde alle ore '.date('H:i:s'));
                                                    throw new Exception('Errore memcache');
                                               }
                    } 
    
                    public static function read($sid){
                                return  self::$memcache->get(get_called_class().'_'.$sid);
                    }
                    public static function write($sid, $dati_sessione){
                                self::$memcache->set(get_called_class().'_'.$sid,$dati_sessione, 0, ini_get('session.gc_maxlifetime'));
                                                                                         //il terzo parametro a 0 indica la non compressione del dato
                    }
    
                    public static function destroy($sid){
                                self::$memcache->delete(get_called_class().'_'.$sid);
                    }
    public static function gc($maxlifetime){} //provvederà memcached a eliminare variabili scadute 
    
                    public static function close(){//la chiusura effettiva non avviene, ma si rilascia per l'assegnazione ad eventuali altri script
                                self::$memcache->close();
                    } 
    }
    ?>

    Il parametro $path può essere della forma IP (es. 127.0.0.1) o IP:porta (127.0.0.1:11211) e viene usato per indicare al nostro handler a quale servizio memcached connettersi; in questo modo tale informazione potrà essere impostata direttamente nel php.ini modificando il parametro session.save_path oppure da programma tramite il comando ini_set(); in alternativa si può sempre fare un'ulteriore estensione, come nel seguente esempio che sfrutta un servizio memcached locale ed ignora del tutto i parametri passati.

    <?
    class local_memcache_mySessionHandler extends memcache_mySessionHandler {
                    public static function open($non_usato1,$non_usato2) {
                                            self::$memcache=new memcache();
                                            $connesso= self::$memcache->pconnect('127.0.0.1',11211);
          if(!$connesso) {
                                                    mail('administrato@myhost.it','Memcached non attiva','Attenzione memcached non risponde alle ore '.date('H:i:s'));
                                                    throw new Exception('Errore memcache');
                                                    }
                                            }
    }
    ?&?>

    Occorre tenere presente che normalmente memcached non permette la memorizzazione di variabili più grandi di 1 MB, nessuno si sognerebbe mai di generare variabili di sessione tanto grandi, me se non si è certi di cosa fanno gli script sul proprio server, ove disponibile, sarebbe consigliabile nel comando set(), invocato all'interno del metodo write(), passare come secondo parametro MEMCACHE_COMPRESSED anziché 0, in questo modo i dati verranno compressi prima della memorizzazione in modo del tutto trasparente avendo molto più spazio disponibile (anche 10 volte) al costo di qualche microsecondo durante compressione e decompressione.

    Gestire le sessioni PHP con SQLite e MySQL

    Uno dei metodi più robusti e diffusi per gestire le sessioni (seppure non altrettanto efficiente della memcached) è quello di memorizzarle in un DB. Abilitando l'estensione SQLite è possibile usufruire di un handler predefinito per la gestione delle sessioni basato su DB, basterà infatti modificare queste due righe nel file php.ini:

    session.save_handler = sqlite
    session.save_path = "/cartellanascosta/sessioni.db"

    per far sì che tutte le sessioni vengano registrate nel DB SQLite presente al percorso /cartellanascosta/sessioni.db.

    Pur essendo estremamente efficiente e performante, SQLite potrebbe non dare le sufficienti garanzie di sicurezza e, soprattutto, scalabilità dei nostri sistemi su più server.

    In caso di sistemi scalati su più server l'uso di un DB locale per memorizzare le sessioni ripresenterebbe il problema tipici degli handler basati su file o ram locale, vedremo quindi come usare un server MySQL che coniuga affidabilità, efficienza, sicurezza e scalabilità.

    Prima di tutto creiamo la tabella destinata a memorizzare le nostre sessioni, che per carenza di fantasia chiameremo 'sessioni', e posizioniamola in un apposito schema che chiameremo 'sistema' al quale tutti gli script avranno diritto di accedere in lettura e scrittura.

    CREATE DATABASE IF NOT EXISTS `sistema`;
    USE `sistema`;
    CREATE TABLE IF NOT EXISTS `sessioni` (
    `sid` varchar(36) NOT NULL COMMENT 'Deve contenere il valore del SID, quindi accertarsi che sia sufficientemente lungo da contenerlo tutto',
    `dati` blob NOT NULL COMMENT 'Dati della sessione',
    `time` int(10) unsigned NOT NULL COMMENT 'Ultima modifica della sessione in formato UNIX_TIMESTAMP(), usato per definire la scadenza delle sessioni',
    PRIMARY KEY (`sid`)
    );

    Come si può notare si tratta di una semplice tabella con tre colonne, il SID (che è anche chiave primaria), i dati della sessione, ed un valore intero positivo che tiene dell'ultimo accesso alla sessione espresso in secondi

    Vediamo ora una classe che può usare questa tabella basandoci per generalità sui comandi primitivi del MySQL.

    <?
    Class mysql_mySessionHandler extends mySessionHandler{
    protected static $mysqlconn;    
                    public static function open($path,$name) {
                                    $pars=explode('/',$path,3); //assumendo che $path sia della forma host/user/pass la scompone in $pars
                                    self::$mysqlconn=mysql_pconnect($pars[0],$pars[1],$pars[2]); //non aggiungo mysql_select_db perché espliciterò sempre lo schema nelle query                                     if(!self::$mysqlconn) {
                                                    mail('administrato@myhost.it',Mysql non connesso','Attenzione mysql non risponde alle ore '.date('H:i:s'));
                                                    throw new Exception('Errore mysql);
                                               }
                    } 
    
                    public static function read($sid){
                                    $sid=mysql_real_escape_string($sid); //quoto per ulteriore sicurezza,potrebbe esserci un attacco di sql-injection sul cookie di sessione
                                    $rs=mysql_query("select dati from sistema.`sessioni` where sid='$sid' limit 1",self::$mysqlconn);
                                    $sessione=mysql_fetch_row($rs);
                                    return $sessione[0];
                    }
                    public static function write($sid, $dati_sessione){
                                    $sid=mysql_real_escape_string($sid);
                                    $dati_sessione=mysql_real_escape_string($dati_sessione);
                                    mysql_query("insert into sistema.`sessioni` values( '$sid' , '$dati_sessione' , unix_timestamp() )
            on duplicate key dati='$dati_sessione', time=unix_timestamp()  ",self::$mysqlconn);
    }
    
                    public static function destroy($sid){
                                    $sid=mysql_real_escape_string($sid);
                                    mysql_query("delete from sistema.`sessioni` where sid='$sid' limit 1",self::$mysqlconn);
                    }
                  public static function gc($maxlifetime){
                                    mysql_query("delete from sistema.`sessioni` where time<unix_timestamp() - $maxlifetime ",self::$mysqlconn);
                    } 
    
                    public static function close(){
                                    mysql_close(self::$mysqlconn);
                    }
            }
    ?>

    Cominciamo con il sottolineare che in questa classe non si antepongono prefissi ai SID, perché avendo una tabella e addirittura uno schema dedicati, non ci sono rischi di collisioni tra i nomi delle chiavi memorizzate; inoltre tutti i parametri, ed in special modo i SID, vengono sempre quotati prima di essere inseriti nelle query, questo perché non bisogna mai dimenticare che il SID (il Session ID) viaggia sui cookie (e nel peggiore dei casi sulle url) e quindi un hacker potrebbe tentare di modificarne il valore per effettuare una SQL-Injection

    Nel metodo open(), in analogia alla classe memcache_mySessionHandler si effettua la connessione al servizio, in questo caso però i parametri necessari sono tre: host, utente e password, che memorizzeremo nel session.save_path seguiti da '/', quindi nel caso di un db posizionato sulla porta non standard 6603 del server 192.128.5.3 a cui accediamo con login:root e password:pwd, il php.ini dovrà presentare session.save_path='192.128.5.3:6603/root/pwd'.

    Naturalmente è sempre possibile eseguire la valorizzazione di tale parametro da programma attraverso il comando set_ini('session.save_path','192.128.5.3:6603/root/pwd') o implementando una specifica estensione di classe che integri i parametri nell'overriding del metodo open() analogamente a quando realizzato nella local_memcache_mySessionHandler.

    Ogni volta che la sessione viene salvata nella relativa tabella, la colonna time viene valorizzata con la funzione MySQL: unix_timestamp che restituisce il numero di secondi dalla mezzanotte del 1/1/1970 al momento in cui è stata eseguita. Questo torna utile nella fase di implementazione del metodo gc() nel quale vengono eliminate tutte le tuple in cui la colonna time si presenta antecedente allo unix_timestamp() decrementato del numero di secondi di durata massima della sessione.

    Attenzione, nel metodo write(), per salvare la sessione è stato usata un insert con clausola on duplicate c che ci permette di operare un'update di dati e time in caso di dati già presenti nel DB in modo performante ed "atomico".

    La sicurezza nell'handler MySQL

    Dal punto di vista della sicurezza, l'architettura della classe precedente è sufficientemente flessibile da permettere di dedicare alla connessione usata per le sessioni un'utenza DB con diritti di modifica/lettura esclusivamente sullo schema 'sistema' sul quale assumiamo non possano operare gli altri account DB, ed il tutto controllato da php.ini p>

    Resta però un problema: se il server propone servizi di hosting o ci sono fragilità di code-injection session hijacking

    A questo si rimedierebbe formalmente assemblando alcune soluzioni già citate in questo articolo ossia realizzare delle estensioni di mysql_mySessionHandler open() auto_prepend_file FINAL

    Prendiamo ad esempio questa classe:

    <?
    FINAL class embedded_mysql_mySessionHandler extends mysql_mySessionHandler{
                    public static function open($ignora1,$ignora2) {
                                    self::$mysqlconn=mysql_pconnect('192.128.5.3:6603', 'root', 'pwd');
                                    if(!self::$mysqlconn) {
                                                    mail('administrato@myhost.it', 'Mysql non connesso','Attenzione mysql non risponde alle ore '.date('H:i:s'));
                                                    throw new Exception('Errore mysql');
                                               }
                    }
    }
    ?>

    Il codice sottostente per effetto della clausola final andrà sempre in errore ma sarebbe stata sufficiente non averla inserita perché venisse eseguito.

    <?
    //Estende la classe caricata implicitamente
    class hack_embedded_mysql_mySessionHandler extends embedded_mysql_mySessionHandler {
                    public static function hacked() {
                                     $rs=mysql_query("select * from sistema.sessioni",self::$mysqlconn);
     while ($sessione=mysql_fetch_row($rs)) print_r($sessione);
                                    }
            }
            session_start();//lascia che la classe embedded_mysql_mySessionHandler effettui il collegamento al DB
            hack_embedded_mysql_mySessionHandler::hacked();//recupera e mostra tutte le sessioni
    ?>

    A questo punto si potrà obbiettare che in effetti per scrivere quella classe occorrerebbe conoscere troppe cose:

    1. Il nome della classe da estendere; ma si può ricavare con il comando get_declared_classes().
    2. Il nome dell' attributo protetto con il link alla connessione; ma si ottiene con queste due righe:
    3. <?
      //Estende la classe caricata implicitamente
      class hack_embedded_mysql_mySessionHandler extends embedded_mysql_mySessionHandler {
                      public static function hacked() {
                                       $rs=mysql_query("select * from sistema.sessioni",self::$mysqlconn);
       while ($sessione=mysql_fetch_row($rs)) print_r($sessione);
                                      }
              }
              session_start();//lascia che la classe embedded_mysql_mySessionHandler effettui il collegamento al DB
              hack_embedded_mysql_mySessionHandler::hacked();//recupera e mostra tutte le sessioni
      ?>

      1. Il nome della tabelle e lo schema per scrivere la query; che sono ricavabili semplicemente interrogando l'information schema.

      Il vero punto da obbiettare, che è poi il motivo per cui ho definito la classe embedded_mysql_mySessionHandler mysql_query()

      <?
      session_start();
      $rs=mysql_query("select * from sistema.sessioni");
      while ($sessione=mysql_fetch_row($rs)) print_r($sessione);
      ?>

      Una soluzione potrebbe essere quella di sostituire la classe embedded_mysql_mySessionHandler con questa:

      <?
      FINAL class embedded_mysql_mySessionHandler extends mysql_mySessionHandler{   
                      //nuovo metodo static che esegue la connessione a DB
      private static function connect() {
                                      self::$mysqlconn=mysql_pconnect('192.128.5.3:6603', 'root', 'pwd');
                                      if(!self::$mysqlconn) {
                                                      mail('administrato@myhost.it','Mysql non connesso','Attenzione mysql non risponde alle ore '.date('H:i:s'));
                                                      throw new Exception('Errore mysql');
                                                 }
                      } 
                      public static function open($path,$name) {} //non svolge più alcun ruolo
                      public static function close() {} // non svolge più alcun ruolo
                      public static function gc($maxlifetime){
                                      self::connect(); //connette DB
                                              parent::gc($maxlifetime); //esegue funzioni classe madre
                                      parent::close(); //esegue chiusura DB da classe madre
                      } 
                      public static function read($sid){
                                      self::connect();
                                              $read=parent::read($sid);
                                      parent::close();
                                      return $read;
                      }
                      public static function write($sid, $dati_sessione){
                                      self::connect();
                                              parent::write($sid, $dati_sessione);
                                      parent::close();                }
                      public static function destroy($sid){
                                      self::connect();
                                              parent::destroy($sid);
                                      parent::close();
                      }
        }
      ?>

      In pratica la connessione al DB viene aperta ed immediatamente richiusa ad ogni operazione dell'handler, il che non è decisamente performante, seppure si stiano usando connessioni persistenti.

      L'ultima soluzione proposta prevede la cifratura e decifratura dei dati di sessione durante l'operazione di open() write()

      <?
      FINAL class embedded_mysql_mySessionHandler extends mysql_mySessionHandler{   
             public static function open($ignora1,$ignora2) {
                                      self::$mysqlconn=mysql_pconnect('192.128.5.3:6603', 'root', 'pwd');
                                      if(!self::$mysqlconn) {
                                                      mail('administrato@myhost.it', 'Mysql non connesso','Attenzione mysql non risponde alle ore '.date('H:i:s'));
                                                      throw new Exception('Errore mysql');
                                                 }
                      }
                      //nuovo metodo che effettua cifratura basata su algoritmo RIJNDAEL 256, uno dei miglio dal punto di vista prestazionale e della sicurezza
                      private static function encript($data){
                              $iv = mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB), MCRYPT_RAND);
                              return  mcrypt_encrypt(MCRYPT_RIJNDAEL_256, "PasswordDiCifraturaSegreta", $data, MCRYPT_MODE_ECB, $iv);
                      }
                      // nuovo metodo che effettua decifratura basata su algoritmo RIJNDAEL 256, uno dei miglio dal punto di vista prestazionale e della sicurezza
                      private static function decript($data){
                              return mcrypt_decrypt(MCRYPT_RIJNDAEL_256, "PasswordDiCifraturaSegreta", $data, MCRYPT_MODE_ECB);
                      }
                      public static function read($sid){
                                      return self::decript(parent::read(self::encript($sid)));
                      }
                      public static function write($sid, $dati_sessione){
                                  parent::write(self::encript($sid), self::encript($dati_sessione));
                      }
              public static function destroy($sid){
                                  parent::destroy(self::encript($sid));
                      }
              }
      ?>

      Ovviamente la connessione resta in balia di hacker, ma sia gli ID sia i dati delle sessioni sono cifrati con una password integrata php_mcript

      Per chiudere definitivamente la questione si potrebbe riscrivere il tutto tramite la libreria mysqli_*

      Nota sui lock

      Tutte le implementazioni presentate non prevedono lock sulle sessioni, questi possono essere introdotti con relativa semplicità nell'handler MySQL attraverso le funzioni get_lock() release_lock() select for update

Ti consigliamo anche