Introduzione
Nell'articolo sulle Le nuove variabili superglobali abbiamo visto come rendere i "nuovi" script in php (sviluppati per funzionare con una versione superiore alla 4.0.6) compatibili con quei server su cui gira ancora una versione vecchia. Non è stata presa in esame la retrocompatibilità delle sessioni perchè questo è un argomento più complesso e articolato delle semplici "variabili esterne" di php.
Fino a quando i server giravano con la direttiva "register_globals = on" le variabili di sessione venivano registrate mediante la funzione session_register().
Il manuale indica la possibilità di salvare un valore come variabile di sessione semplicemente aggiungendo un indice all'array $HTTP_SESSION_VARS/$_SESSION; da questo sembrerebbe quindi che per garantire la retrocompatibilità delle sessioni sia sufficiente valorizzare per riferimento l'array $_SESSION, dove non presente, con il contenuto dell'array $HTTP_SESSION_VARS.
Alcuni sviluppatori hanno però avuto dei problemi nell'utilizzo di questa soluzione; problemi che non garantivano il corretto funzionamento del work-around. Dobbiamo quindi pensare a strade alternative per risolvere il problema.
Le soluzioni
Vorrei suggerire due possibili vie per ottenere comunque la retrocompatibilità delle sessioni:
- la scrittura di una classe apposita interfacciata alla libreria standard del php
- l'utilizzo di una versione di session_register "personalizzata".
Analizziamo la prima soluzione
La scrittura di una classe interfacciata alla libreria standard ha sicuramente dei vantaggi evidenti: è possibile apportare variamenti alla gestione delle sessioni modificando un solo file, è possibile aggiungere altri sistemi di salvataggio delle sessioni se queste vengono ulteriormente modificate; ma possiede anche un grosso svantaggio: la scrittura di script che si interfacciano alle sessioni chiamando funzioni non standard.
Prima di tutto analizziamo le funzionalità che dovrebbe presentare una classe per gestire le sessioni. Essa dovrebbe poter:
- determinare la versione del php
- scrivere una variabile di sessione nella maniera apposita
- leggere una variabile di sessione nella maniera apposita
Questa classe è una semplificazione di quella proposta da Andrea Colanicchia sulla mailing list PHP-IT
<?php
class Sessione{
var $Old;
function Sessione(){
if( !function_exists('version_compare') ){
$this->SetOldVersion(1);
}
else{
$this->SetOldVersion(0);
}
}
function Write($NomeVar, $Valore){
if( IsOldVersion() ){
global $HTTP_SESSION_VARS;
if( !isset($HTTP_SESSION_VARS[$NomeVar]) ){
session_register($NomeVar);
}
$HTTP_SESSION_VARS = $Valore;
$GLOBALS[$NomeVar] = $Valore;
}
else{
$_SESSION[$NomeVar] = $Valore;
}
}
function Read($NomeVar){
if( IsOldVersion() ){
global $HTTP_SESSION_VARS;
if( !isset($HTTP_SESSION_VARS[$NomeVar]) ){
session_register($NomeVar);
}
return $HTTP_SESSION_VARS[$NomeVar];
}
else{
return $_SESSION[$NomeVar];
}
}
function SetOldVersion($old){
$this->Old = (bool)$old;
return true;
}
function IsOldVersion(){
return (bool) $this->Old;
}
}
?>
Come si può vedere, nel costruttore viene individuata la versione di php usata dal server attraverso l'utilizzo di function_exists come abbiamo visto la scorsa volta. Attraverso le due funzioni pubbliche Read e Write la classe si occupa di registrare nella maniera corretta la variabile di sessione registrata.
Utilizzo della classe
Se si vuole rendere le proprie variabili di sessione retrocompatibili con questa soluzione dovremo per forza di cose riscrivere il nostro codice affinchè le sessioni vengano salvate tramite questa classe e non tramite i gestori standard.
Prima di tutto dobbiamo attivare le sessioni:
session_start();
Poi dobbiamo includere il file contenente la classe e inizializzarla:
include_once 'sessione.class.php';
$s = new Sessione();
A questo punto possiamo scrivere e leggere le variabili di sessione:
$s->Write('a', 'alpha');
$s->Write('b', 'beta');
echo $s->Read('b'); //beta
Ovviamente è possibile aggiungere molte funzionalità alla classe:
- scelta del nome di sessione
- unset delle variabili di sessione
- destroy dell'intero insieme di variabili di sessione
Questa è semplicemente una classe "base" che illustra il procedimento da utilizzare.
La seconda soluzione proposta
Come abbiamo visto nell'introduzione, prima dell'arrivo della versione 4.1.0 di php, molti sviluppatori utilizzavano session_register insieme alla caratteristica di register_globals = on
Quindi perchè non utilizzare una soluzione simile per rendere le sessioni compatibili con tutte le versioni di php4?
In realtà i motivi non mancano, per citarne uno possiamo dire che in questa maniera non viene utilizzata la nuova sintassi e quindi gli script saranno sempre più obsoleti. Comunque se vogliamo solo applicare una pezza questa soluzione non è per niente male.
In sostanza scriveremo una funzione che simuli il funzionamento di session_register con metodi diversi a seconda della versione con cui sta funzionando. Purtroppo il php non supporta la sovrascrittura delle funzioni, per cui dovremmo modificare anche i riferimenti a questa funzione. Creaiamo un file esterno che importeremo in ogni pagina in cui servano le sessioni:
<?php
if( !function_exists('version_compare') ){
// gestione < php 4.1.0
function my_session_register($NomeVar){
session_register($NomeVar);
}
}
else{
// gestione > php 4.1.0
function my_session_register($NomeVar){
$_SESSION[$NomeVar] = &$GLOBALS[$NomeVar];
}
}
?>
lo importiamo nella pagina in cui serve: include_once 'Sessioni.php';
attiviamo le sessioni: session_start()
e infine le utilizziamo:
$var = "Le sessioni sono utili";
my_session_register('var');
Conclusione
In definitiva ritengo che sia più produttivo utilizzare il primo sistema. Richiede un maggior tempo di sviluppo in quanto vanno modificati tutti i riferimenti all'utilizzo delle sessioni, ma al tempo stesso è più sicuro in quanto non si cerca di scavalcare il "register_globals = off". La seconda soluzione è da preferire solo quando ci sia bisogno di tempi brevi e si abbia uno script già pronto e funzionante con le versioni vecchie di php4.