Come modificare il timeout della sessione in PHP?


Risposte:


324

Il timeout della sessione è una nozione che deve essere implementata nel codice se si desidera una rigorosa garanzia; è l'unico modo per essere assolutamente certi che nessuna sessione sopravviverà mai dopo X minuti di inattività.

Se un po 'di attenuazione di questo requisito è accettabile e stai bene ponendo un limite inferiore anziché un limite rigoroso alla durata, puoi farlo facilmente e senza scrivere una logica personalizzata.

Convenienza in ambienti rilassati: come e perché

Se le tue sessioni sono implementate con i cookie (che probabilmente sono) e se i client non sono dannosi, puoi impostare un limite superiore per la durata della sessione modificando alcuni parametri. Se stai utilizzando la gestione della sessione predefinita di PHP con i cookie, l'impostazione session.gc_maxlifetimeinsieme a session_set_cookie_paramsdovrebbe funzionare per te in questo modo:

// server should keep session data for AT LEAST 1 hour
ini_set('session.gc_maxlifetime', 3600);

// each client should remember their session id for EXACTLY 1 hour
session_set_cookie_params(3600);

session_start(); // ready to go!

Funziona configurando il server per mantenere i dati della sessione per almeno un'ora di inattività e istruendo i client che devono "dimenticare" il loro ID di sessione dopo lo stesso periodo di tempo. Entrambi questi passaggi sono necessari per ottenere il risultato atteso.

  • Se non si dice ai client di dimenticare il proprio ID di sessione dopo un'ora (o se i client sono dannosi e si sceglie di ignorare le istruzioni) continueranno a utilizzare lo stesso ID di sessione e la sua durata effettiva non sarà deterministica. Questo perché le sessioni la cui durata è scaduta sul lato server non vengono immediatamente messe in spazzatura ma solo ogni volta che inizia la sessione GC .

    Il GC è un processo potenzialmente costoso, quindi in genere la probabilità è piuttosto piccola o addirittura zero (un sito Web che ottiene un numero enorme di hit probabilmente rinuncerà completamente al GC probabilistico e programmerà che accada in background ogni X minuti). In entrambi i casi (presupponendo che i clienti non cooperino) il limite inferiore per una durata effettiva della sessione sarà session.gc_maxlifetime, ma il limite superiore sarà imprevedibile.

  • Se non si imposta session.gc_maxlifetimelo stesso intervallo di tempo, il server potrebbe scartare i dati della sessione inattiva prima di quello; in questo caso, un client che ricorda ancora il proprio ID di sessione lo presenterà ma il server non troverà alcun dato associato a quella sessione, comportandosi effettivamente come se la sessione fosse appena iniziata.

Certezza in ambienti critici

Puoi rendere le cose completamente controllabili usando la logica personalizzata per porre anche un limite superiore all'inattività della sessione; insieme al limite inferiore dall'alto, ciò si traduce in un ambiente rigoroso.

Fallo salvando il limite superiore insieme al resto dei dati della sessione:

session_start(); // ready to go!

$now = time();
if (isset($_SESSION['discard_after']) && $now > $_SESSION['discard_after']) {
    // this session has worn out its welcome; kill it and start a brand new one
    session_unset();
    session_destroy();
    session_start();
}

// either new or old, it should live at most for another hour
$_SESSION['discard_after'] = $now + 3600;

Persistenza dell'ID sessione

Finora non ci siamo preoccupati affatto dei valori esatti di ciascun ID di sessione, ma solo del requisito che i dati debbano esistere finché ne abbiamo bisogno. Tieni presente che nel caso (improbabile) che gli ID di sessione contino per te, devi fare attenzione a rigenerarli session_regenerate_idquando richiesto.


Domanda: se chiami questo, diciamo che ogni minuto aumenterà il suo limite? esempio alle 10:00 l'ho chiamato in modo che il suo limite sarebbe 11:00, dopo 1 minuto, 10:01, sarà il limite 11:01?
oneofakind

@oneofakind: se chiami esattamente cosa?
Jon

1
Questi: ini_set ('session.gc_maxlifetime', 3600); session_set_cookie_params (3600);
oneofakind

@oneofakind: Sì, ma solo se chiami session_start()anche (altrimenti nessun effetto) e solo se chiami sempre quei due prima session_start(altrimenti gc_maxlifetimeha il potenziale per influenzare tutte le sessioni attualmente aperte, mentre session_set_cookie_paramspuò influenzare solo una nuova sessione che inizia con la richiesta corrente).
Jon

@Jon se chiamo di nuovo session_start () ripristinerà tutto nella mia $ _SESSION? se intendi per "ha il potenziale di influenzare tutta la sessione" come? Grazie per la risposta.
oneofakind

33

Se si utilizza la gestione della sessione predefinita di PHP, l'unico modo per modificare in modo affidabile la durata della sessione in tutte le piattaforme è cambiare php.ini . Questo perché in alcune piattaforme, la garbage collection viene implementata attraverso uno script che viene eseguito ogni volta (uno script cron ) che legge direttamente da php.ini , e quindi qualsiasi tentativo di cambiarlo in fase di esecuzione, ad esempio tramite ini_set(), è inaffidabile e molto probabilmente non funzionerà.

Ad esempio, nei sistemi Debian Linux, la garbage collection interna di PHP è disabilitata impostando session.gc_probability=0di default nella configurazione, ed è invece fatta tramite /etc/cron.d/php, che funziona a XX: 09 e XX: 39 (ovvero ogni mezz'ora). Questo cron job cerca sessioni precedenti a session.gc_maxlifetime specificate nella configurazione e, se ne trovano, vengono eliminate. Di conseguenza, in questi sistemi ini_set('session.gc_maxlifetime', ...)viene ignorato. Ciò spiega anche perché in questa domanda: le sessioni PHP scadono troppo rapidamente , l'OP ha avuto problemi in un host ma i problemi sono cessati quando si è passati a un altro host.

Quindi, dato che non hai accesso a php.ini , se vuoi farlo in modo portabile, usare la gestione della sessione predefinita non è un'opzione. Apparentemente, l'estensione della durata dei cookie è stata sufficiente per il tuo host, ma se desideri una soluzione che funzioni in modo affidabile anche se cambi host, devi utilizzare un'alternativa diversa.

I metodi alternativi disponibili includono:

  1. Imposta un gestore di sessione (salvataggio) diverso in PHP per salvare le tue sessioni in una directory diversa o in un database, come specificato in PHP: Custom Session Handlers (manuale PHP) , in modo che il cron job non lo raggiunga, e solo PHP la raccolta dei rifiuti interna ha luogo. Questa opzione probabilmente può utilizzare ini_set()per impostare session.gc_maxlifetime ma preferisco semplicemente ignorare il parametro maxlifetime nel mio gc()callback e determinare la durata massima da solo.

  2. Dimentica completamente la gestione delle sessioni interne di PHP e implementa la tua gestione delle sessioni. Questo metodo ha due principali svantaggi: avrai bisogno delle tue variabili di sessione globali, quindi perdi il vantaggio del $_SESSIONsuperglobal e ha bisogno di più codice, quindi ci sono più opportunità per bug e difetti di sicurezza. Ancora più importante, l'identificatore di sessione dovrebbe essere generato da numeri casuali o pseudocasuali crittograficamente sicuri per evitare la prevedibilità dell'ID di sessione (portando a possibili dirottamenti di sessione), e non è così facile da fare con PHP in modo portabile. Il vantaggio principale è che funzionerà in modo coerente su tutte le piattaforme e avrai il pieno controllo del codice. Questo è l'approccio adottato ad esempio dal software del forum phpBB (almeno la versione 1; non sono sicuro delle versioni più recenti).

C'è un esempio di (1) nella documentazione disession_set_save_handler() . L'esempio è lungo ma lo riprodurrò qui, con le modifiche pertinenti necessarie per prolungare la durata della sessione. Nota anche l'inclusione di session_set_cookie_params()aumentare la durata dei cookie.

<?php
class FileSessionHandler
{

    private $savePath;
    private $lifetime;

    function open($savePath, $sessionName)
    {
        $this->savePath = 'my_savepath'; // Ignore savepath and use our own to keep it safe from automatic GC
        $this->lifetime = 3600; // 1 hour minimum session duration
        if (!is_dir($this->savePath)) {
            mkdir($this->savePath, 0777);
        }

        return true;
    }

    function close()
    {
        return true;
    }

    function read($id)
    {
        return (string)@file_get_contents("$this->savePath/sess_$id");
    }

    function write($id, $data)
    {
        return file_put_contents("$this->savePath/sess_$id", $data) === false ? false : true;
    }

    function destroy($id)
    {
        $file = "$this->savePath/sess_$id";
        if (file_exists($file)) {
            unlink($file);
        }

        return true;
    }

    function gc($maxlifetime)
    {
        foreach (glob("$this->savePath/sess_*") as $file) {
            if (filemtime($file) + $this->lifetime < time() && file_exists($file)) { // Use our own lifetime
                unlink($file);
            }
        }

        return true;
    }
}

$handler = new FileSessionHandler();
session_set_save_handler(
    array($handler, 'open'),
    array($handler, 'close'),
    array($handler, 'read'),
    array($handler, 'write'),
    array($handler, 'destroy'),
    array($handler, 'gc')
    );

// the following prevents unexpected effects when using objects as save handlers
register_shutdown_function('session_write_close');

session_set_cookie_params(3600); // Set session cookie duration to 1 hour
session_start();
// proceed to set and retrieve values by key from $_SESSION

L'approccio (2) è più complicato; in pratica, devi implementare di nuovo tutte le funzioni della sessione da solo. Non entrerò nei dettagli qui.


Qualcuno potrebbe confermarlo?
Oli,

@Oli: sembra corretto dopo una lettura superficiale. Potresti anche voler consultare stackoverflow.com/questions/520237/… , ma se non hai accesso alle php.initue opzioni pratiche sono severamente limitate.
Jon,

Inoltre, su Ubuntu 14 sembra /usr/lib/php5/maxlifetimeche non calcolerà un valore inferiore a 24 minuti. Quindi non puoi impostare i timeout della sessione su un valore inferiore.
Henry,

"Dimentica completamente la gestione delle sessioni interne di PHP e implementa la tua gestione delle sessioni." buon dio, questo è un consiglio pericoloso. Ne conseguirebbe inevitabilmente un incubo di sicurezza.
Kzqai,

@Kzqai Noto anche che "ha bisogno di più codice, quindi ci sono più opportunità per bug e difetti di sicurezza". Non è un consiglio, sto elencando le alternative, ma se hai un suggerimento per migliorarlo, per favore fallo.
Pedro Gimeno,

3

L'aggiunta di commenti per chiunque utilizzi Plesk abbia problemi con quanto sopra visto che mi stava facendo impazzire, impostare session.gc_maxlifetime dal tuo script PHP non funzionerà poiché Plesk ha il suo script di garbage collection eseguito da cron.

Ho usato la soluzione pubblicata sul link di seguito per spostare il cron job da orario a quotidiano per evitare questo problema, quindi la risposta in alto sopra dovrebbe funzionare:

mv /etc/cron.hourly/plesk-php-cleanuper /etc/cron.daily/

https://websavers.ca/plesk-php-sessions-timing-earlier-expected


3

Inserisci $_SESSION['login_time'] = time();nella pagina di autenticazione precedente. E il frammento di seguito in ogni altra pagina in cui si desidera controllare il timeout della sessione.

if(time() - $_SESSION['login_time'] >= 1800){
    session_destroy(); // destroy session.
    header("Location: logout.php");
    die(); // See https://thedailywtf.com/articles/WellIntentioned-Destruction
    //redirect if the page is inactive for 30 minutes
}
else {        
   $_SESSION['login_time'] = time();
   // update 'login_time' to the last time a page containing this code was accessed.
}

Modifica: funziona solo se hai già usato le modifiche in altri post o se hai disabilitato la Garbage Collection e vuoi controllare manualmente la durata della sessione. Non dimenticare di aggiungere die()dopo un reindirizzamento, perché alcuni script / robot potrebbero ignorarlo. Inoltre, distruggere direttamente la sessione con session_destroy()invece di fare affidamento su un reindirizzamento per quella potrebbe essere un'opzione migliore, ancora una volta, nel caso di un client dannoso o un robot.


2

Solo un avviso per un server di hosting condiviso o aggiunto su domini =

Affinché le impostazioni funzionino, è necessario disporre di una directory di sessione di salvataggio diversa per il dominio aggiunto utilizzando php_value session.save_path "cartellaA / sessioniA".

Quindi crea una cartella sul tuo server di root, non in public_html e per non farti accedere alla pubblicità dall'esterno. Per il mio pannello / server ha funzionato bene i permessi della cartella 0700. Prova ...

  • codice php =

     #Session timeout, 2628000 sec = 1 month, 604800 = 1 week, 57600 = 16 hours, 86400 = 1 day
     ini_set('session.save_path', '/home/server/.folderA_sessionsA');
     ini_set('session.gc_maxlifetime', 57600); 
     ini_set('session.cookie_lifetime', 57600);
     ini_set('session.cache_expire', 57600);
     ini_set('session.name', 'MyDomainA');

prima di session_start ();

o

  • .htaccess =

     php_value session.save_path /home/server/.folderA_sessionsA
     php_value session.gc_maxlifetime 57600
     php_value session.cookie_lifetime 57600
     php_value session.cache_expire 57600
     php_value session.name MyDomainA

Dopo molte ricerche e prove questo ha funzionato bene per il server cpanel / php7 condiviso. Mille grazie a: NoiS


1

No. Se non hai accesso a php.ini, non puoi garantire che le modifiche abbiano alcun effetto.

Dubito che sia necessario prolungare il tempo delle sessioni.
Al momento ha un timeout abbastanza ragionevole e non ci sono ragioni per estenderlo.


Ciao Col, ho cercato dappertutto questo posto per trovare un modo per contattarti. Ho visto che mi hai dato alcuni suggerimenti sul mio ultimo post che è stato chiuso (domenica). Mi sono impegnato in un altro progetto e ora non c'è più. Mi piacerebbe davvero provare i tuoi suggerimenti. Questo lì comunque per trovare quello che hai scritto?
Il vecchio cane il

Per quanto posso vedere, non è stato solo chiuso, ma anche eliminato. Queste persone non hanno onore. Sì, il tuo problema ha una soluzione comune di cui stavo parlando. Ti scriverò via email. In breve, si trattava di eseguire 2 query aggiuntive per ottenere questi valori precedenti / successivi. SELECT id FROM gallery WHERE SortOrder > $currentsortorder LIMIT 1
Il tuo senso comune

0

Puoi sovrascrivere i valori in php.ini dal tuo codice PHP usando ini_set().


4
-1: session.gc_maxlifetimenon è l'impostazione che controlla la durata della sessione. Può essere bastonati a un'opera del genere se si imposta session.gc_divisora 1, ma questo è semplicemente orribile.
Jon,

1
@Jon Ho visto così tante risposte su SO che suggeriscono il contrario, perché? stackoverflow.com/questions/514155/... stackoverflow.com/questions/9904105/...
Giannis christofakis

2
@yannishristofakis: gc_maxlifetimeimposta l'intervallo dopo il quale i dati della sessione sono idonei per la garbage collection - se GC si verifica dopo che è trascorso tanto tempo, i dati della sessione verranno distrutti (con le impostazioni predefinite è lo stesso della scadenza della sessione). Ma GC viene attivato probabilisticamente ad ogni avvio della sessione, quindi non esiste alcuna garanzia che la sessione scada effettivamente: puoi tracciare una curva di prob vs tempo, ma non sembrerà un brickwall. Questa è solo la punta dell'iceberg; vedi stackoverflow.com/questions/520237/…
Jon
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.