Vai al contenuto principale
Per fornire da un pacchetto una destinazione di salvataggio delle sessioni personalizzata, separa la registrazione del salvataggio dalla selezione da parte dell’applicazione. La semplice installazione non deve cambiare dove viene salvato lo stato di login: progetta il pacchetto in modo che l’utente possa attivarlo dopo aver valutato l’impatto sulle sessioni esistenti. Questa pagina esamina i sorgenti ufficiali di Laravel Framework v13.39.0. Per le operazioni di base consulta Sessioni, per il caricamento automatico dei provider consulta Package auto-discovery.

extend riceve un handler, non uno Store

Il callback di Session::extend() restituisce un handler di salvataggio che implementa la SessionHandlerInterface di PHP. Non è un’API che restituisce direttamente uno Store che implementa Illuminate\Contracts\Session\Session o un Repository di cache. SessionManager::callCustomCreator() passa il valore restituito dal callback a buildSession(), che lo avvolge in uno Store o in un EncryptedStore a seconda di session.encrypt. In quel momento applica anche il nome del cookie e session.serialization. Nella normale elaborazione HTTP, il middleware StartSession gestisce l’avvio e il salvataggio della sessione. Per fornire un handler, il pacchetto non deve chiamare session_start() né session_set_save_handler().

Distinguere le parti del contratto di salvataggio

Per implementare un backend personalizzato, soddisfa i seguenti ruoli. Poiché lo Store si occupa di serializzazione e ripristino, l’handler non deve applicare di nuovo serialize() o json_encode() all’array di sessione. Anche con la cifratura attiva, salva così com’è la stringa elaborata da EncryptedStore.
Distingui i dati non salvati da un guasto del backend. Lo Store::readFromHandler() esaminato tratta un risultato di lettura vuoto o false come una sessione vuota. Inoltre, Store::save() non controlla il valore restituito dal write() dell’handler.Nei pacchetti che devono sempre trattare i guasti come eccezioni, rendi esplicita la politica e testala: non sopprimere le eccezioni dello storage e, per i backend che restituiscono false, rilevalo nell’handler e convertilo in eccezione. Non è detto che Laravel ritenti automaticamente o segnali il mancato salvataggio.

Registrare solo la creazione in boot

L’esempio minimo seguente riutilizza il CacheBasedSessionHandler integrato. Non implementa un nuovo protocollo di storage, ma mostra come registrare un driver personalizzato che usa uno store di cache con nome. Acme\SessionBridge\ corrisponde a src/ tramite il PSR-4 di Composer. Prepara il provider in src/SessionBridgeServiceProvider.php.
Session::extend() ottiene il SessionManager e registra la creazione, ma a questo punto lo store di cache all’interno del callback non viene risolto. Lo storage viene creato solo quando il driver viene selezionato per la prima volta. Non eseguire verifiche di connessione né salvataggi di dati nel boot() del provider. Se usi una tua implementazione di SessionHandlerInterface, sostituisci l’handler restituito dal callback. Arrivare fino a new Store(...) non corrisponde più al valore di ritorno atteso dal SessionManager.
  • Carica il provider come un normale provider non differito.
  • Completa la registrazione prima del primo utilizzo della sessione. Se un altro provider risolve il tuo driver prima, verifica anche l’ordine di caricamento.
  • Usa un nome di driver specifico del pacchetto. Un extend() con lo stesso nome sovrascrive la creazione, e registrando il nome di un driver integrato si ottiene la precedenza sull’implementazione integrata.

L’applicazione che usa il pacchetto sceglie in modo esplicito

L’utente modifica le chiavi corrispondenti del proprio config/session.php esistente. Le altre impostazioni restano invariate.
Per lo storage, aggiungi uno store con nome all’array stores esistente di config/cache.php. L’esempio seguente usa la connessione Redis default. La configurazione della connessione Redis e il client necessario vanno preparati dall’applicazione.
La connessione e il prefisso di questo esempio sono determinati dalla configurazione dello store di cache. Poiché non si passa per il createRedisDriver() del driver di sessione Redis integrato, aggiungere session.connection o session.prefix non viene recepito automaticamente da questo callback. Questo callback non modifica né il Repository né la configurazione dello storage: usa lo store con nome così com’è. Anche lo store array di test condivide lo stesso spazio di salvataggio all’interno della stessa applicazione. Il pacchetto non deve riscrivere incondizionatamente session.driver, il nome del cookie o il prefisso di cache globale dell’applicazione. Verifica con l’utente anche che lo spazio di salvataggio non sia condiviso con altri usi e che più server possano usare lo stesso storage.
Se l’obiettivo è solo un normale salvataggio su Redis o database, parti dai driver di sessione integrati. Un driver personalizzato è un punto di estensione per i casi in cui servono un nuovo storage o regole di salvataggio aggiuntive.

Mantenere l’unità del TTL e il formato di salvataggio

Il costruttore di CacheBasedSessionHandler riceve la durata di conservazione in minuti. Poiché write() passa ogni volta $minutes * 60 al put() del Repository di cache, nell’esempio precedente il TTL si rinnova a ogni scrittura. gc() restituisce 0 e delega la scadenza alla cache. La durata che StartSession passa al gc($lifetime) dell’handler è invece in secondi. Non implementare un salvataggio che usa direttamente il valore di session.lifetime come secondi. Inoltre, le modifiche seguenti non si risolvono con un semplice cambio di nome nella configurazione. Se un aggiornamento del pacchetto modifica questi elementi, valuta istruzioni per una nuova autenticazione, l’eventuale necessità di una migrazione e i deploy in cui convivono la versione vecchia e quella nuova. Come in Gestire la compatibilità tra versioni dei pacchetti, includi formato di salvataggio e chiavi di configurazione nella specifica pubblica da mantenere.

Uno Store già creato non viene sostituito solo cambiando la configurazione

Manager, la classe padre del SessionManager, conserva i driver creati per nome. Inoltre, SessionServiceProvider registra session.store come singleton. forgetDrivers() non è nemmeno un’API per eliminare i dati di sessione. Ricreare lo Store durante una richiesta in corso causa incongruenze con i dati già letti o con altri riferimenti. Anche il CacheManager di questo esempio conserva gli store con nome. Se ne modifichi la configurazione di connessione, non basta risolvere di nuovo soltanto il SessionManager. Nei deploy che usano la cache della configurazione, ricostruisci la cache e riavvia anche i worker di lunga durata perché carichino il nuovo codice e la nuova configurazione. Il riavvio dell’applicazione e la migrazione dei dati salvati sono attività distinte.

Il salvataggio della sessione e il lock delle richieste sono separati

Implementare un handler personalizzato non basta a serializzare le richieste parallele sulla stessa sessione. Il blocco di StartSession usa i lock dello store di cache scelto con session.block_store, che non coincide necessariamente con lo storage della sessione stessa. Se lo controlli con Route::post(...)->block() o simili, verifica separatamente uno store di cache che supporti i lock, la condivisione tra più server e i tempi di attesa e di mantenimento. Il pacchetto non deve attivare di sua iniziativa il blocco per l’intera applicazione.

Testare fino al salvataggio e alla rilettura

Nei pacchetti che usano Orchestra Testbench, carica il provider e prepara test che selezionino davvero il tuo driver. Ecco un esempio di tests/SessionDriverTest.php. La cache array di test non usa connessioni esterne.
Questo test è un test isolato che ricrea lo Store all’interno della stessa applicazione. Non verifica il middleware HTTP, l’andata e ritorno dei cookie, la persistenza verso un altro processo né la scadenza o i lock di un Redis reale. Non usare array come storage condiviso in produzione. Prima di pubblicare un handler personalizzato, aggiungi anche i seguenti controlli.
  • Un ID non salvato o scaduto restituisce una stringa vuota
  • La stringa salvata viene ripristinata senza modifiche e non è più recuperabile dopo l’eliminazione
  • L’unità e il rinnovo del TTL, e la scadenza sul backend reale
  • I fallimenti di lettura, scrittura ed eliminazione producono i valori di ritorno o le eccezioni stabiliti
  • L’andata e ritorno con session.encrypt attivo e i formati di serializzazione supportati
  • Il solo caricamento del provider non accede allo storage e non sottrae la selezione ai driver integrati
  • Se necessario, test HTTP che passano per il vero middleware web e i cookie, e il lock delle richieste parallele

Pagine correlate

Sessioni

Lettura e scrittura della sessione, dati flash e rigenerazione dell’ID.

Implementazione interna di Manager

Creazione e conservazione dei driver personalizzati e delega al driver predefinito.

Store di cache personalizzati nei pacchetti

Suddivisione dei ruoli tra lo Store di cache usato come storage e il Repository, e contratto del TTL.

Ciclo di vita dei servizi di un pacchetto

Dipendenze conservate dai worker di lunga durata e isolamento dello stato.

Fonti primarie

Ultima modifica il 2 novembre 2026