¿Cómo cambiar el tiempo de espera de la sesión en PHP?

Respuestas:

324

El tiempo de espera de la sesión es una noción que debe implementarse en el código si desea garantías estrictas; esa es la única forma en que puede estar absolutamente seguro de que ninguna sesión sobrevivirá después de X minutos de inactividad.

Si se acepta un poco este requisito y está bien si coloca un límite inferior en lugar de un límite estricto a la duración, puede hacerlo fácilmente y sin escribir una lógica personalizada.

Conveniencia en ambientes relajados: cómo y por qué

Si sus sesiones se implementan con cookies (que probablemente lo sean), y si los clientes no son maliciosos, puede establecer un límite superior en la duración de la sesión modificando ciertos parámetros. Si está utilizando el manejo de sesión predeterminado de PHP con cookies, la configuración session.gc_maxlifetimejunto con session_set_cookie_paramsdebería funcionar para usted así:

// 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!

Esto funciona configurando el servidor para mantener los datos de la sesión durante al menos una hora de inactividad e instruyendo a sus clientes que deben "olvidar" su identificación de sesión después del mismo lapso de tiempo. Ambos pasos son necesarios para lograr el resultado esperado.

  • Si no le dice a los clientes que olviden su ID de sesión después de una hora (o si los clientes son maliciosos y eligen ignorar sus instrucciones), seguirán usando la misma ID de sesión y su duración efectiva no será determinista. Esto se debe a que las sesiones cuya vida útil ha expirado en el lado del servidor no se recolectan de forma inmediata, sino solo cuando se inicia la sesión GC .

    El GC es un proceso potencialmente costoso, por lo que, por lo general, la probabilidad es bastante pequeña o incluso cero (un sitio web que recibe un gran número de visitas probablemente renunciará por completo al GC probabilístico y programará que ocurra en segundo plano cada X minutos). En ambos casos (suponiendo clientes que no cooperan), el límite inferior para la duración efectiva de la sesión será session.gc_maxlifetime, pero el límite superior será impredecible.

  • Si no establece session.gc_maxlifetimeel mismo intervalo de tiempo, el servidor puede descartar los datos de la sesión inactiva antes de eso; en este caso, un cliente que todavía recuerda su ID de sesión lo presentará pero el servidor no encontrará datos asociados con esa sesión, comportándose efectivamente como si la sesión acabara de comenzar.

Certeza en ambientes críticos.

Puede hacer que las cosas sean completamente controlables utilizando una lógica personalizada para colocar también un límite superior en la inactividad de la sesión; junto con el límite inferior desde arriba, esto da como resultado una configuración estricta.

Haga esto guardando el límite superior junto con el resto de los datos de la sesión:

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;

Persistencia de id de sesión

Hasta ahora no nos hemos preocupado en absoluto por los valores exactos de cada ID de sesión, solo por el requisito de que los datos deben existir siempre que los necesitemos. Tenga en cuenta que, en el caso (poco probable) de que los ID de sesión le importen, se debe tener cuidado para regenerarlos session_regenerate_idcuando sea necesario.

Jon
fuente
Pregunta: si llamamos a esto, digamos cada minuto, ¿aumentará su límite? ejemplo a las 10:00 Lo llamé para que su límite sea 11:00, después de 1 miute, 10:01, ¿será el límite 11:01?
oneofakind
@oneofakind: ¿Si llamas a qué exactamente?
Jon
1
Estos: ini_set ('session.gc_maxlifetime', 3600); session_set_cookie_params (3600);
oneofakind
@oneofakind: Sí, pero solo si llama session_start()también (de lo contrario no tiene ningún efecto) y solo si siempre llama a esos dos antes session_start(de lo contrario gc_maxlifetimetiene el potencial de afectar todas las sesiones actualmente abiertas, mientras session_set_cookie_paramsque solo puede afectar una nueva sesión que comienza con La solicitud actual).
Jon
@ Jon si llamo a session_start () nuevamente, ¿restablecerá todo en mi $ _SESSION? si quiere decir con "tiene el potencial de afectar a todas las sesiones", ¿cómo es eso? Gracias por la respuesta.
oneofakind
33

Si usa el manejo de sesión predeterminado de PHP, la única forma de cambiar de manera confiable la duración de la sesión en todas las plataformas es cambiar php.ini . Esto se debe a que en algunas plataformas, la recolección de basura se implementa a través de un script que se ejecuta cada cierto tiempo (un script cron ) que se lee directamente desde php.ini y, por lo tanto, cualquier intento de cambiarlo en tiempo de ejecución, por ejemplo ini_set(), a través de , no es confiable y probablemente no funciona

Por ejemplo, en los sistemas Debian Linux, la recolección de basura interna de PHP se deshabilita configurando session.gc_probability=0de manera predeterminada en la configuración, y en su lugar se realiza a través de /etc/cron.d/php, que se ejecuta en XX: 09 y XX: 39 (es decir, Cada media hora). Este trabajo cron busca sesiones anteriores a la session.gc_maxlifetime especificada en la configuración y, si se encuentra alguna, se eliminan. Como consecuencia, en estos sistemas ini_set('session.gc_maxlifetime', ...)se ignora. Eso también explica por qué en esta pregunta: las sesiones de PHP caducaron demasiado rápido , el OP tuvo problemas en un host pero los problemas cesaron al cambiar a un host diferente.

Por lo tanto, dado que no tiene acceso a php.ini , si desea hacerlo de forma portátil, no es una opción usar el manejo de sesión predeterminado. Aparentemente, extender la vida útil de las cookies fue suficiente para su host, pero si desea una solución que funcione de manera confiable incluso si cambia de host, debe usar una alternativa diferente.

Los métodos alternativos disponibles incluyen:

  1. Establezca un controlador de sesión (guardar) diferente en PHP para guardar sus sesiones en un directorio diferente o en una base de datos, como se especifica en PHP: Controladores de sesión personalizados (manual PHP) , para que el trabajo cron no lo alcance, y solo PHP Se lleva a cabo la recolección interna de basura. Esta opción probablemente puede usarse ini_set()para establecer session.gc_maxlifetime, pero prefiero ignorar el parámetro maxlifetime en mi gc()devolución de llamada y determinar la vida útil máxima por mi cuenta.

  2. Olvídate por completo del manejo de sesión interna de PHP e implementa tu propia administración de sesión. Este método tiene dos desventajas principales: necesitará sus propias variables de sesión global, por lo que perderá la ventaja del $_SESSIONsuperglobal, y necesita más código, por lo que hay más oportunidades para errores y fallas de seguridad. Lo más importante es que el identificador de sesión debe generarse a partir de números aleatorios o pseudoaleatorios criptográficamente seguros para evitar la previsibilidad de la ID de sesión (lo que lleva a un posible secuestro de sesión), y eso no es tan fácil de hacer con PHP de forma portátil. La principal ventaja es que funcionará de manera consistente en todas las plataformas y usted tiene control total sobre el código. Ese es el enfoque adoptado, por ejemplo, por el software del foro phpBB (al menos la versión 1; no estoy seguro de las versiones más recientes).

Hay un ejemplo de (1) en la documentación desession_set_save_handler() . El ejemplo es largo, pero lo reproduciré aquí, con las modificaciones relevantes necesarias para extender la duración de la sesión. Tenga en cuenta la inclusión de session_set_cookie_params()para aumentar la vida útil de las cookies también.

<?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

El enfoque (2) es más complicado; básicamente, debe volver a implementar todas las funciones de sesión por su cuenta. No entraré en detalles aquí.

Pedro Gimeno
fuente
¿Alguien podría confirmar eso?
Oli
@Oli: Parece correcto después de una lectura superficial. También es posible que desee consultar stackoverflow.com/questions/520237/… , pero si no tiene acceso a php.inisus opciones prácticas, están severamente restringidas.
Jon
Además, en Ubuntu 14 parece /usr/lib/php5/maxlifetimeque no calculará un valor por debajo de 24 minutos. Por lo tanto, no puede establecer que los tiempos de espera de la sesión sean más bajos que eso.
Henry
"Olvídate por completo del manejo de sesiones internas de PHP e implementa tu propia administración de sesiones" Dios mío, ese es un consejo peligroso. Una pesadilla de seguridad inevitablemente resultaría.
Kzqai
@Kzqai También noto que "necesita más código, por lo tanto, hay más oportunidades para errores y fallas de seguridad". No es un consejo, enumero las alternativas, pero si tiene alguna sugerencia para mejorarlo, hágalo.
Pedro Gimeno
3

Agregar comentarios para cualquier persona que use Plesk que tenga problemas con cualquiera de los anteriores, ya que me estaba volviendo loco, establecer session.gc_maxlifetime desde su script PHP no funcionará ya que Plesk tiene su propio script de recolección de basura ejecutado desde cron.

Utilicé la solución publicada en el siguiente enlace para mover el trabajo cron de cada hora a diario para evitar este problema, entonces la respuesta superior anterior debería funcionar:

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

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

Neil Walden
fuente
3

Poner $_SESSION['login_time'] = time();en la página de autenticación anterior. Y el recortado a continuación en cada otra página donde desea verificar el tiempo de espera de la sesión.

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.
}

Editar: Esto solo funciona si ya usó los ajustes en otras publicaciones, o deshabilitó la Recolección de basura, y desea verificar manualmente la duración de la sesión. No olvide agregar die()después de una redirección, porque algunos scripts / robots podrían ignorarla. Además, destruir directamente la sesión en session_destroy()lugar de depender de una redirección para esa podría ser una mejor opción, nuevamente, en caso de un cliente malicioso o un robot.

mohamadRezaSamadi
fuente
2

Solo un aviso para un servidor de alojamiento compartido o agregado en dominios =

Para que su configuración funcione, debe tener un directorio de sesión de guardado diferente para el dominio agregado utilizando php_value session.save_path "folderA / sessionsA".

Por lo tanto, cree una carpeta en su servidor raíz, no en public_html y para que no se acceda a publicidad desde el exterior. Para mi cpanel / servidor funcionó bien los permisos de carpeta 0700. Pruébalo ...

  • código 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');
    

antes de 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
    

Después de muchas investigaciones y pruebas, esto funcionó bien para el servidor cpanel / php7 compartido. Muchas gracias a: NoiS

ChriStef
fuente
1

No. Si no tiene acceso a php.ini, no puede garantizar que los cambios tengan algún efecto.

Sin embargo, dudo que necesites extender el tiempo de tus sesiones.
Tiene un tiempo de espera bastante razonable en este momento y no hay razones para extenderlo.

Su sentido común
fuente
Hola Col, he estado buscando por todo este lugar para encontrar una manera de contactarte. Vi que me diste algunas sugerencias sobre mi última publicación que cerró (domingo). Me puse a trabajar en otro proyecto y ahora se ha ido. Realmente me gustaría probar sus sugerencias. ¿Esto de todos modos para encontrar lo que escribiste?
El perro viejo
Hasta donde puedo ver, no solo se cerró, sino que también se eliminó. Estas personas no tienen honor. Sí, su problema tiene una solución común de la que estaba hablando. Te escribiré por correo electrónico. En resumen, se trataba de ejecutar 2 consultas adicionales para obtener estos valores prev / next. SELECT id FROM gallery WHERE SortOrder > $currentsortorder LIMIT 1
Su sentido común
0

Puede anular valores en php.ini desde su código PHP usando ini_set().

Nathan Q
fuente
44
-1: session.gc_maxlifetimeno es la configuración que controla la duración de la sesión. Puede ser golpeado hasta la obra como que si establece session.gc_divisora 1, pero eso es simplemente horrible.
Jon
1
@ Jon He visto tantas respuestas en SO que sugieren lo contrario, ¿por qué? stackoverflow.com/questions/514155/… stackoverflow.com/questions/9904105/…
giannis christofakis
2
@yannishristofakis: gc_maxlifetimeestablece el intervalo después del cual los datos de la sesión son elegibles para la recolección de basura: si el GC ocurre después de que haya transcurrido tanto tiempo, los datos de la sesión se destruirán (con la configuración predeterminada, esto es lo mismo que expirar la sesión). Pero GC se activa probabilísticamente en cada inicio de sesión, por lo que no hay garantía de que la sesión realmente caduque: puede trazar una curva de problema vs tiempo, pero no se verá como un muro de ladrillos. Eso es solo la punta del iceberg; ver stackoverflow.com/questions/520237/…
Jon