Una sessione che sparisce sembra un problema di accesso e non lo è quasi mai. L'accesso ha funzionato; a perdersi è stata la prova di quell'accesso, fra una richiesta e la successiva.

1. Qualcosa sta ripulendo i file di sessione

Su Debian e Ubuntu un timer spazza i file di sessione di PHP secondo un calendario tutto suo, usando l'idea della DISTRIBUZIONE sulla durata - non quella che la sua pagina imposta con ini_set. Una pagina che alza gc_maxlifetime a runtime non cambia nulla di quella spazzata.

systemctl list-timers | grep phpsessionclean
php -i | grep -E "session.save_path|session.gc_maxlifetime"

Il rimedio è una directory di sessioni tutta sua che lo spazzino non tocca, con la durata impostata nella configurazione del pool e non a runtime.

php_admin_value[session.save_path] = /var/lib/php/sessions-mysite
php_admin_value[session.gc_maxlifetime] = 86400

2. Il cookie non torna indietro

session.cookie_secure = 1
session.cookie_httponly = 1
session.cookie_samesite = Lax
cookie_secure su un sito raggiungibile anche via http nudo vuol dire che il cookie non viene mai rimandato indietro, e l'utente si ritrova disconnesso all'istante senza un errore da nessuna parte. È corretto su un sito solo https ed è fatale su uno misto.

3. Due server, una sessione

Dietro un bilanciatore, la prima richiesta atterra sul server A e vi scrive un file di sessione; la seconda atterra su B, che quel file non ce l'ha. L'utente viene disconnesso a caso, ed è la versione più difficile da riprodurre.

  • Sessioni in Redis o nel database, condivise da entrambi.
  • Oppure sessioni appiccicose sul bilanciatore: funziona, e non sopravvive alla sostituzione di un server.

Lo guardi accadere

ls -la /var/lib/php/sessions/ | head
# log in, then look again: your file should be there and should stay
Se il file c'è e l'utente è comunque disconnesso, è il cookie. Se il file sparisce, è lo spazzino. Quella sola osservazione taglia il problema a metà.