Saltar al contenido

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

Solución:

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 puede estar absolutamente seguro de que ninguna sesión sobrevivirá después de X minutos de inactividad.

Si relajar un poco este requisito es aceptable y está de acuerdo con colocar 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.

Comodidad en entornos 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 ajustando ciertos parámetros. Si está utilizando el manejo de sesión predeterminado de PHP con cookies, establezca session.gc_maxlifetime junto con session_set_cookie_params debería funcionar para ti 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 indicando a sus clientes que deben “olvidar” su identificación de sesión después del mismo período de tiempo. Ambos pasos son necesarios para lograr el resultado esperado.

  • Si no les dice a los clientes que olviden su identificación de sesión después de una hora (o si los clientes son maliciosos y eligen ignorar sus instrucciones), seguirán usando la misma identificación 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 como basura de inmediato, sino solo cuando se inicia la sesión GC.

    La GC es un proceso potencialmente costoso, por lo que normalmente la probabilidad es bastante pequeña o incluso nula (un sitio web que obtenga una gran cantidad de visitas probablemente renunciará a la GC probabilística por completo y lo programará para que suceda en segundo plano cada X minutos). En ambos casos (asumiendo 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 configuras session.gc_maxlifetime en el mismo lapso de tiempo, el servidor podría descartar los datos de la sesión inactiva antes de eso; en este caso, un cliente que aún 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 entornos críticos

Puede hacer que las cosas sean completamente controlables mediante el uso de lógica personalizada para colocar también un límite superior sobre la inactividad de la sesión; junto con el límite inferior desde arriba, esto da como resultado un ajuste estricto.

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 con el requisito de que los datos existan mientras los necesitemos. Tenga en cuenta que en el caso (poco probable) de que los identificadores de sesión sean importantes para usted, debe tener cuidado de regenerarlos con session_regenerate_id cuando sea necesario.

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 cron script) que se lee directamente de php.ini, y por lo tanto cualquier intento de cambiarlo en tiempo de ejecución, por ejemplo, a través de ini_set(), no son confiables y lo más probable es que no funcionen.

Por ejemplo, en los sistemas Debian Linux, la recolección de basura interna de PHP se deshabilita configurando session.gc_probability=0 de forma predeterminada en la configuración, y en su lugar se realiza a través de /etc/cron.d/php, que se ejecuta a las XX: 09 y XX: 39 (es decir, cada media hora). Este trabajo cron busca sesiones anteriores a la session.gc_maxlifetime especificados en la configuración y, si se encuentran, 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 se agotan demasiado rápido, el OP tuvo problemas en un host, pero los problemas cesaron al cambiar a un host diferente.

Entonces, dado que no tiene acceso a php.ini, si desea hacerlo de manera portátil, usar el manejo de sesión predeterminado no es una opción. 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. Configure 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 de PHP), para que el cron el trabajo no lo alcanza, y solo se lleva a cabo la recolección de basura interna de PHP. Esta opción probablemente pueda hacer uso de ini_set() para establecer session.gc_maxlifetime pero prefiero simplemente ignorar el maxlifetime parámetro en mi gc() devolución de llamada y determinar la vida útil máxima por mi cuenta.

  2. Olvídese por completo del manejo interno de sesiones de PHP e implemente su propia administración de sesiones. Este método tiene dos desventajas principales: necesitará sus propias variables de sesión globales, por lo que perderá la ventaja de $_SESSION superglobal, 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 la 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 un control total sobre el código. Ese es el enfoque adoptado, por ejemplo, por phpBB software del foro (al menos la versión 1; no estoy seguro de versiones más recientes).

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

<?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 la sesión por su cuenta. No entraré en detalles aquí.

Poner $_SESSION['login_time'] = time(); en la página de autenticación anterior. Y lo recortado a continuación en todas las demás páginas 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 olvides agregar die() después de una redirección, porque algunos scripts / robots pueden ignorarlo. Además, destruir directamente la sesión con session_destroy() en lugar de depender de una redirección, esa podría ser una mejor opción, nuevamente, en caso de un cliente malintencionado o un robot.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *