Sessioni
HTTP è un protocollo stateless, tuttavia quasi ogni applicazione ha bisogno di mantenere lo stato tra le richieste, ad esempio il contenuto del carrello degli acquisti. A questo servono le sessioni. Vedremo:
- come usare le sessioni
- come prevenire conflitti di nomi
- come impostare la scadenza
Quando si usano le sessioni, ogni utente riceve un identificatore univoco chiamato ID di sessione, che viene passato in un cookie. Questo funge da chiave per i dati della sessione. A differenza dei cookie, che vengono memorizzati lato browser, i dati della sessione vengono memorizzati lato server.
Impostiamo la sessione nella configurazione, l'opzione del tempo di scadenza è particolarmente importante.
La gestione della sessione è affidata all'oggetto Nette\Http\Session, a cui potete accedere facendovelo passare
tramite dependency injection. Nei presenter,
basta chiamare $session = $this->getSession()
.
Avvio della Sessione
Per default, Nette avvia automaticamente la sessione nel momento in cui iniziamo a leggere o scrivere dati in essa.
Manualmente, la sessione si avvia con $session->start()
.
PHP invia header HTTP che influenzano la cache all'avvio della sessione, vedi session_cache_limiter, e potenzialmente anche un cookie con l'ID di sessione. Pertanto, è necessario avviare sempre la sessione prima di inviare qualsiasi output al browser, altrimenti verrà lanciata un'eccezione. Quindi, se sapete che la sessione verrà utilizzata durante il rendering della pagina, avviatela manualmente prima, ad esempio nel presenter.
In modalità sviluppatore, Tracy avvia la sessione perché la utilizza per visualizzare le barre con i reindirizzamenti e le richieste AJAX nella Tracy Bar.
Sezioni
In PHP puro, l'archivio dati della sessione è implementato come un array accessibile tramite la variabile globale
$_SESSION
. Il problema è che le applicazioni sono comunemente composte da molte parti indipendenti e se tutte hanno
accesso a un solo array, prima o poi si verificherà una collisione di nomi.
Nette Framework risolve il problema dividendo l'intero spazio in sezioni (oggetti Nette\Http\SessionSection). Ogni unità utilizza quindi la propria sezione con un nome univoco e non possono più verificarsi collisioni.
Otteniamo la sezione dalla sessione:
$section = $session->getSection('nome univoco');
Nel presenter, basta usare getSession()
con un parametro:
// $this è Presenter
$section = $this->getSession('nome univoco');
È possibile verificare l'esistenza di una sezione con il metodo $session->hasSection('nome univoco')
.
Lavorare con la sezione stessa è quindi molto facile usando i metodi set()
, get()
e
remove()
:
// scrittura della variabile
$section->set('userName', 'franta');
// lettura della variabile, restituisce null se non esiste
echo $section->get('userName');
// cancellazione della variabile
$section->remove('userName');
Per ottenere tutte le variabili da una sezione, è possibile utilizzare un ciclo foreach
:
foreach ($section as $key => $val) {
echo "$key = $val";
}
Impostazione della Scadenza
È possibile impostare una scadenza per singole sezioni o addirittura per singole variabili. Possiamo quindi far scadere il login dell'utente dopo 20 minuti, ma continuare a ricordare il contenuto del carrello.
// la sezione scadrà dopo 20 minuti
$section->setExpiration('20 minutes');
Per impostare la scadenza delle singole variabili, si usa il terzo parametro del metodo set()
:
// la variabile 'flash' scadrà dopo soli 30 secondi
$section->set('flash', $message, '30 seconds');
Non dimenticate che il tempo di scadenza dell'intera sessione (vedi configurazione della sessione) deve essere uguale o superiore al tempo impostato per le singole sezioni o variabili.
L'annullamento di una scadenza precedentemente impostata si ottiene con il metodo removeExpiration()
. La
cancellazione immediata dell'intera sezione è garantita dal metodo remove()
.
Eventi $onStart, $onBeforeWrite
L'oggetto Nette\Http\Session
ha eventi
$onStart
e $onBeforeWrite
, quindi potete aggiungere callback che vengono invocati dopo l'avvio della
sessione o prima della sua scrittura su disco e successiva chiusura.
$session->onBeforeWrite[] = function () {
// scriviamo i dati nella sessione
$this->section->set('basket', $this->basket);
};
Gestione della Sessione
Panoramica dei metodi della classe Nette\Http\Session
per la gestione della sessione:
start(): void
Avvia la sessione.
isStarted(): bool
La sessione è avviata?
close(): void
Termina la sessione. La sessione termina automaticamente alla fine dell'esecuzione dello script.
destroy(): void
Termina ed elimina la sessione.
exists(): bool
La richiesta HTTP contiene un cookie con l'ID di sessione?
regenerateId(): void
Genera un nuovo ID di sessione casuale. I dati rimangono conservati.
getId(): string
Restituisce l'ID di sessione.
Configurazione
Impostiamo la sessione nella configurazione. Se state scrivendo un'applicazione che non utilizza un container DI, questi metodi vengono utilizzati per la configurazione. Devono essere chiamati prima dell'avvio della sessione.
setName (string $name): static
Imposta il nome del cookie in cui viene trasmesso l'ID di sessione. Il nome standard è PHPSESSID
. È utile nel
caso in cui si eseguano diverse applicazioni distinte all'interno dello stesso sito web.
getName(): string
Restituisce il nome del cookie in cui viene trasmesso l'ID di sessione.
setOptions (array $options): static
Configura la sessione. È possibile impostare tutte le direttive di sessione PHP (in formato camelCase, ad esempio,
invece di session.save_path
scriviamo savePath
) e anche readAndClose.
setExpiration (?string $time): static
Imposta il periodo di inattività dopo il quale la sessione scade.
setCookieParameters (string $path, ?string $domain=null, ?bool $secure=null, ?string $samesite=null): static
Impostazione dei parametri per i cookie. I valori predefiniti dei parametri possono essere modificati nella configurazione.
setSavePath (string $path): static
Imposta la directory in cui vengono salvati i file di sessione.
setHandler (\SessionHandlerInterface $handler): static
Impostazione di un handler personalizzato, vedi documentazione PHP.
Sicurezza Prima di Tutto
Il server presume di comunicare sempre con lo stesso utente finché le richieste sono accompagnate dallo stesso ID di sessione. Il compito dei meccanismi di sicurezza è garantire che ciò avvenga effettivamente e che non sia possibile rubare o falsificare l'identificatore.
Nette Framework configura quindi correttamente le direttive PHP in modo che l'ID di sessione venga trasmesso solo nei cookie, lo renda inaccessibile a JavaScript e ignori eventuali identificatori nell'URL. Inoltre, nei momenti critici, come il login dell'utente, genera un nuovo ID di sessione.
Per la configurazione di PHP si utilizza la funzione ini_set, che purtroppo alcuni hosting vietano. Se questo è il caso del vostro hoster, cercate di concordare con lui l'abilitazione della funzione o almeno la configurazione del server.