43. Le Sessioni

Il protocollo HTTP è stateless, ossia "privo di stato", il che significa che navigando un sito il navigatore effettua delle richieste al server che vengono di volta in volta terminate, rendendo tutte le connessioni "uguali" agli occhi del server senza poter stabilire quali provengono effettivamente dal medesimo utente.

Le sessioni sono molto simili ai cookie e ci consentono anche essi di tenere in memoria dei dati su un determinato utente.

Per questi motivi i cookie e le sessioni sono così largamente utilizzati dai Web Developer, rendendo ormai piuttosto raro trovare un navigatore che non accetta i cookie.

Tenere traccia dello stato di un utente è molto importante per costruire delle applicazioni web efficaci, come ad esempio un sito e-commerce dove è necessario "ricordarsi" il contenuto del carrello dell'utente mentre questo naviga il catalogo dei prodotti.

PHP ci fornisce delle funzioni molto utili per assegnare un ID di sessione univoco ad ogni utente, e ci consente di tenerne traccia sostanzialmente in due modi : passando l'ID della sessione negli URL (come accade nell'invio dei dati con GET) oppure memorizzandolo in un cookie dedicato.

Per motivi di sicurezza vi sconsiglio decisamente il primo metodo, usando le sessioni sempre tramite cookie.

Nelle impostazioni di default, PHP è settato per memorizzare le sessioni in un cookie, non dovreste quindi dover apportare alcuna modifica al vostro server.

A questo punto potremmo anche descrivere una sessione come un cookie che scade alla fine di una "sessione browser", considerando la fine di una sessione browser come la chiusura di quest ultimo da parte dell'utente.

Un'altra differenza molto importante fra cookie e sessioni è dove effettivamente vengono memorizzati i dati.

I cookie, come spiegato nei capitoli precedenti, memorizzano i dati nel browser dell'utente (lato client) mentre le sessioni le memorizzano direttamente sul server, tenendo nel lato client solamente l'ID della sessione, ID che sarà utilizzato poi per risalire ai dati memorizzati sul server.

Questo rende le sessioni molto più indicate quando è necessario gestire dei dati sensibili, dal momento che i cookie e il loro contenuto sono sempre accessibili dall'utente e quindi anche dai linguaggi di scripting client side, come ad esempio Javascript, consentendo ai malintenzionati di apportare modifiche al cookie e ai suoi dati mettendo a serio rischio la sicurezza della vostra applicazione.

Usando le sessioni inoltre non andrete incontro ai problemi di spazio che avreste con i cookie, che come ho scritto due capitoli addietro, qualora un browser rispetti gli standard, non è possibile creare un cookie più grande di 4KB per un massimo di 20 cookie per dominio e un totale di 200 cookie in un browser.


Esempio Sessioni PHP

Vedremo ora un esempio molto semplice dove illustrerò uno scambio di dati fra due pagine mediante l'uso delle sessioni.

index.php

<?php

	session_start();

	$_SESSION["utente"] = "Mario Rossi";

?>

<a href="test.php">Test</a>

test.php

<?php

	session_start();

	if (isset($_SESSION["utente"]))
		echo "Utente = " . $_SESSION["utente"];
	else
	{
		echo "Utente non trovato.<br>\n";
		echo "Andare prima <a href=\"index.php\">qui</a>.";
	}

?>

Come possiamo osservare nell'esempio soprastante, per utilizzare le sessioni è sufficiente chiamare la funzione session_start() in tutte le pagine dove si intende accedere ai dati sessione, e l'array globale $_SESSION[] viene reso automaticamente disponibile.

La prima volta che viene chiamata session_start() viene creato un cookie di nome PHPSESSID, il cui contenuto sarà l'ID di sessione univoco assegnatoci dal server, e che sarà poi utilizzato da quest ultimo per accedere ai dati di sessione.

Se state utilizzando Firefox, una volta eseguita una delle due pagine di esempio, dalla console "Mostra i cookie" avrete modo di leggere il cookie di sessione.

Se eseguirete per prima la pagina index.php, verrà inizializzata la sessione memorizzandovi il dato "utente" e verrà infine stampato il link per accedere alla seconda pagina ossia test.php.

Se invece eseguirete per prima test.php, la pagina stamperà una notifica (Utente non trovato) e a seguire un link per index.php dove sarà memorizzato il dato "utente".

Riavviando il browser la sessione verrà automaticamente terminata, oppure è possibile eliminarla volontariamente in questo modo :

<?php

	session_start();

	unset($_SESSION["utente"]); // Da usare per eliminare un solo dato di sessione, in questo caso "utente"

	// Da usare per distruggere completamente la sessione
	$_SESSION = array(); // oppure chiamate session_unset();
	session_destroy();

?>

In questo capitolo osserveremo più da vicino le sessioni, studiando alcuni settaggi e funzioni che ritengo di maggiore rilievo e che ci consentiranno un maggiore controllo sulla nostra applicazione.

Iniziamo dal file di configurazione php.ini, attraverso cui potremo personalizzare il comportamento del server.

  • session.save_path - La cartella del server dove andranno memorizzati i file di sessione.
  • session.use_cookies - Di default è impostato a 1, il che significa che il server tenterà sempre di memorizzare l'ID di sessione in un cookie nel browser dell'utente.
  • session.use_only_cookies - Di default è impostato a 0, ma vi consiglio di assegnarlo a 1 in modo da impedire attacchi dove vengono passati gli ID di sessione tramite URL. In questo caso però abbiate cura di eseguire sempre dei controlli sull'abilitazione dei cookie, e in caso di esito negativo notificate l'utente sulla necessità di avere i cookie abilitati per poter usufruire appieno del servizio da voi offerto.
  • session.name - Il nome di default della sessione, solitamente PHPSESSID.
  • session.cookie_lifetime - E' impostato a 0 di default eliminando il cookie di sessione alla chiusura del browser. Se avete necessità di rendere disponibile la sessione anche dopo la chiusura del browser allora impostate il parametro con i secondi di durata desiderati.
  • session.cache_expire - La durata in minuti della cache sul server, solitamente impostata a 3 ore.

Se non avete la possibilità di modificare il php.ini del vostro server, oppure avete più applicazioni sullo stesso server con esigenze diverse, allora potete impostare un comportamento diverso per ogni applicazione richiamando direttamente nello script le funzioni native che seguono :

  • string session_save_path ([string path]) - Se non viene specificato alcun parametro la funzione restituisce la path dove vengono salvati i file di sessione. Se invece specificate un parametro viene cambiato il percorso dove vengono salvati i file con quello nuovo.
  • string session_name ([string name]) - Restituisce il nome della sessione corrente. Se specificato un parametro invece imposta il nome di sessione con il nuovo.
  • void session_set_cookie_params (int lifetime [, string path [, string domain]]) - Il primo parametro è obbligatorio e definisce la durata in secondi del cookie di sessione. Gli altri due parametri facoltativi cambiano momentaneamente i rispettivi settaggi nel php.ini.
  • int session_cache_expire ([int cache_expire]) - Restituisce la durata in minuti della cache di sessione, oppure se impostate un parametro il valore corrente della scadenza cache verrà sostituito col nuovo.
  • string session_id ([string id]) - Ritorna l'ID di sessione corrente oppure se impostate un parametro sostituisce l'id corrente col nuovo.
  • void session_write_close (void) - Termina la sessione corrente e ne archivia i dati.

Per una descrizione dettagliata delle funzioni sopracitate e per l'elenco completo vi rimando alla Documentazione ufficiale di PHP.

Attraverso queste funzioni non è però possibile modificare due dei parametri più importanti :
"session.use_cookies" e "session.use_only_cookies".

Per modificare queste due impostanzioni ricorreremo alla funzione ini_set() come mostrato di seguito :

<?php

	ini_set('session.use_cookies', 1);
	ini_set('session.use_only_cookies', 1);

?>

Prima di chiudere il capitolo vediamo come può tornarci utile la funzione session_write_close(), aumentando le prestazioni del server con applicazioni che scrivono grandi quantità di dati per sessione.

E' necessario sapere che i dati di sessione vengono bloccati per evitare che più script scrivano contemporaneamente in essi, fino a che viene terminato uno script e viene concesso il permesso al successivo.

Di default PHP archivia i dati di sessione al termine dello script, ma è utile anticiparne l'archiviazione qualora utilizzaste ad esempio i frameset, che verranno caricati uno alla volta proprio a causa di questo blocco.

Non appena avete assegnato tutti i valori ai dati di sessione quindi, sarà bene terminare quest'ultima anticipando l'archiviazione dei dati mediante una chiamata a session_write_close(), per consentire l'accesso al prossimo script.

Nel prossimo capitolo vedremo come definire delle funzioni personalizzate per gestire in modo avanzato le sessioni.