¿Cómo expiro una sesión PHP después de 30 minutos?


1047

Necesito mantener viva una sesión durante 30 minutos y luego destruirla.


35
Tenga en cuenta que al menos dos configuraciones son cruciales para configurar el tiempo de sesión, y tal vez tres. Los dos ciertamente cruciales son session.gc_maxlifetime y session.cookie_lifetime (donde 0 no es lo mismo que un número largo). Para completar, 100% de certeza de permitir largos tiempos, también puede ser necesario configurar el session.save_path, debido al tiempo de limpieza variable controlado por el sistema operativo en el directorio / tmp donde los archivos de sesión se almacenan por defecto.
Kzqai

1
No entiendo por qué quieres caducar la sesión. Si le preocupa que el usuario abandone su computadora sin cerrar sesión, y un usuario no autorizado se haga cargo de su computadora, el vencimiento de la sesión en su sitio no impedirá que el secuestrador acceda a los archivos de la víctima en el disco.
Gqqnbig

No está claro lo que estás preguntando aquí. ¿Quiere decir que desea implementar un tiempo de espera de inactividad difícil (actualmente PHP felizmente le permitirá usar una sesión que no ha sido tocada por más de session.gc_maxlifetime) o quiere decir que desea limitar la sesión a 30 minutos independientemente de ¿inactividad? Francamente, creo que la respuesta aceptada aquí es un mal consejo para cualquier problema: en ambos casos, la lógica debe implementarse con un controlador de sesión personalizado.
symcbean

Respuestas:


1663

Debe implementar un tiempo de espera de sesión propio. Ambas opciones mencionadas por otros ( session.gc_maxlifetime y session.cookie_lifetime ) no son confiables. Explicaré las razones de eso.

Primero:

session.gc_maxlifetime
session.gc_maxlifetime especifica el número de segundos después de los cuales los datos serán vistos como 'basura' y limpiados. La recolección de basura ocurre durante el inicio de la sesión.

Pero el recolector de basura solo se inicia con una probabilidad de session.gc_probability dividida por session.gc_divisor . Y utilizando los valores predeterminados para esas opciones (1 y 100 respectivamente), la probabilidad es solo del 1%.

Bueno, simplemente puede ajustar estos valores para que el recolector de basura se inicie con más frecuencia. Pero cuando se inicia el recolector de basura, verificará la validez de cada sesión registrada. Y eso es costoso.

Además, cuando se usan los archivos session.save_handler predeterminados de PHP , los datos de la sesión se almacenan en archivos en una ruta especificada en session.save_path . Con ese controlador de sesión, la antigüedad de los datos de la sesión se calcula en la última fecha de modificación del archivo y no en la última fecha de acceso:

Nota: Si está utilizando el controlador de sesión predeterminado basado en archivos, su sistema de archivos debe realizar un seguimiento de los tiempos de acceso (atime). Windows FAT no lo hace, por lo que tendrá que encontrar otra forma de manejar la recolección de basura de su sesión si está atascado con un sistema de archivos FAT o cualquier otro sistema de archivos donde el seguimiento de tiempo no esté disponible. Desde PHP 4.2.3 ha usado mtime (fecha de modificación) en lugar de atime. Por lo tanto, no tendrá problemas con los sistemas de archivos donde el seguimiento de atime no está disponible.

Por lo tanto, también puede ocurrir que un archivo de datos de sesión se elimine mientras la sesión en sí misma todavía se considera válida porque los datos de la sesión no se actualizaron recientemente.

Y segundo:

session.cookie_lifetime
session.cookie_lifetime especifica la duración de la cookie en segundos que se envía al navegador. [...]

Si, eso es correcto. Esto solo afecta la vida útil de la cookie y la sesión misma puede ser válida. Pero es tarea del servidor invalidar una sesión, no el cliente. Entonces esto no ayuda en nada. De hecho, tener session.cookie_lifetime configurado en 0haría que la cookie de la sesión sea una cookie de sesión real que solo es válida hasta que se cierre el navegador.

Conclusión / mejor solución:

La mejor solución es implementar un tiempo de espera de sesión propio. Use una marca de tiempo simple que indique la hora de la última actividad (es decir, la solicitud) y actualícela con cada solicitud:

if (isset($_SESSION['LAST_ACTIVITY']) && (time() - $_SESSION['LAST_ACTIVITY'] > 1800)) {
    // last request was more than 30 minutes ago
    session_unset();     // unset $_SESSION variable for the run-time 
    session_destroy();   // destroy session data in storage
}
$_SESSION['LAST_ACTIVITY'] = time(); // update last activity time stamp

La actualización de los datos de sesión con cada solicitud también cambia la fecha de modificación del archivo de sesión para que el recolector de basura no elimine la sesión prematuramente.

También puede usar una marca de tiempo adicional para regenerar la ID de la sesión periódicamente para evitar ataques en sesiones como la fijación de la sesión :

if (!isset($_SESSION['CREATED'])) {
    $_SESSION['CREATED'] = time();
} else if (time() - $_SESSION['CREATED'] > 1800) {
    // session started more than 30 minutes ago
    session_regenerate_id(true);    // change session ID for the current session and invalidate old session ID
    $_SESSION['CREATED'] = time();  // update creation time
}

Notas:

  • session.gc_maxlifetime debe ser al menos igual a la vida útil de este controlador de caducidad personalizado (1800 en este ejemplo);
  • si desea expirar la sesión después de 30 minutos de actividad en lugar de transcurridos 30 minutos desde el inicio , también deberá usar setcookieuna expiración de time()+60*30para mantener activa la cookie de sesión.

3
¿Cómo podría alterar esto si quisiera verificar el "tiempo inactivo"? En otras palabras, el usuario inicia sesión y, mientras continúe usando el sitio, no cerrará sesión. Sin embargo, si están inactivos durante 30 minutos, ¿los cerrará sesión?
Metropolis

14
@Metropolis: use algo $_SESSION['LAST_ACTIVITY']similar a $_SESSION['CREATED']donde almacena el tiempo de la última actividad del usuario, pero actualice ese valor con cada solicitud. Ahora, si la diferencia de ese tiempo con el tiempo actual es mayor que 1800 segundos, la sesión no se ha utilizado durante más de 30 minutos.
Gumbo

3
@Metropolis: session_unsethace lo mismo que $_SESSION = array().
Gumbo

14
@Gumbo - Estoy un poco confundido, ¿no deberías usar tu código en combinación con ini_set('session.gc-maxlifetime', 1800)? De lo contrario, la información de su sesión podría destruirse mientras se supone que su sesión todavía es válida, al menos si la configuración inicial es el estándar de 24 minutos. ¿O me estoy perdiendo algo?
jeroen 27/10/10

10
@jeron: Sí, deberías. Pero tenga en cuenta que session.gc_maxlifetime depende de la última fecha de modificación del archivo si filesse utiliza el controlador de guardado de sesión . Por lo tanto, session.gc_maxlifetime debería ser al menos igual al tiempo de vida de este controlador de caducidad personalizado.
Gumbo

135

Forma simple de expiración de sesión PHP en 30 minutos.

Nota: si desea cambiar la hora, simplemente cambie el 30 con el tiempo deseado y no cambie * 60: esto le dará los minutos.


En minutos: (30 * 60)
En días: (n * 24 * 60 * 60) n = no de días


Login.php

<?php
    session_start();
?>

<html>
    <form name="form1" method="post">
        <table>
            <tr>
                <td>Username</td>
                <td><input type="text" name="text"></td>
            </tr>
            <tr>
                <td>Password</td>
                <td><input type="password" name="pwd"></td>
            </tr>
            <tr>
                <td><input type="submit" value="SignIn" name="submit"></td>
            </tr>
        </table>
    </form>
</html>

<?php
    if (isset($_POST['submit'])) {
        $v1 = "FirstUser";
        $v2 = "MyPassword";
        $v3 = $_POST['text'];
        $v4 = $_POST['pwd'];
        if ($v1 == $v3 && $v2 == $v4) {
            $_SESSION['luser'] = $v1;
            $_SESSION['start'] = time(); // Taking now logged in time.
            // Ending a session in 30 minutes from the starting time.
            $_SESSION['expire'] = $_SESSION['start'] + (30 * 60);
            header('Location: http://localhost/somefolder/homepage.php');
        } else {
            echo "Please enter the username or password again!";
        }
    }
?>

HomePage.php

<?php
    session_start();

    if (!isset($_SESSION['luser'])) {
        echo "Please Login again";
        echo "<a href='http://localhost/somefolder/login.php'>Click Here to Login</a>";
    }
    else {
        $now = time(); // Checking the time now when home page starts.

        if ($now > $_SESSION['expire']) {
            session_destroy();
            echo "Your session has expired! <a href='http://localhost/somefolder/login.php'>Login here</a>";
        }
        else { //Starting this else one [else1]
?>
            <!-- From here all HTML coding can be done -->
            <html>
                Welcome
                <?php
                    echo $_SESSION['luser'];
                    echo "<a href='http://localhost/somefolder/logout.php'>Log out</a>";
                ?>
            </html>
<?php
        }
    }
?>

LogOut.php

<?php
    session_start();
    session_destroy();
    header('Location: http://localhost/somefolder/login.php');
?>

42
La combinación de lógica y presentación no es aconsejable en estos días cuando MVC es la norma.
bcosca

Tal vez me estoy perdiendo algo elemental sobre las sesiones, pero ¿de qué sirve esto si las sesiones son destruidas cada 30 minutos por el sistema operativo?

25
@stillstanding Habla por ti mismo [sonrisa] Veo MVC como una abominación.

2
¿MVC es una buena idea incluso cuando el proyecto es pequeño, con un solo programador? Siento que debería hacer mis propios proyectos en el modelo MVC (o resolver el problema ENTONCES hacerlo MVC) pero con la falta de experiencia con MVC se convierte en un bloqueo mental "¿Cómo hago este MVC?" y una distracción del objetivo / problema inicial que requiere una solución.
MrVimes

@todavía otra mención es que en los Login.phpencabezados se envían DESPUÉS del contenido, lo cual es malo.
machineaddict

43

¿Esto es para desconectar al usuario después de un tiempo establecido? Establecer el tiempo de creación de la sesión (o un tiempo de caducidad) cuando está registrado, y luego verificar eso en cada carga de página podría manejar eso.

P.ej:

$_SESSION['example'] = array('foo' => 'bar', 'registered' => time());

// later

if ((time() - $_SESSION['example']['registered']) > (60 * 30)) {
    unset($_SESSION['example']);
}

Editar: Tengo la sensación de que quieres decir algo más.

Puede eliminar sesiones después de una determinada vida útil utilizando la session.gc_maxlifetimeconfiguración ini:

Editar: ini_set ('session.gc_maxlifetime', 60 * 30);


1
session.gc-maxlifetime es probablemente la mejor manera de hacerlo.
Powerlord

2
Hay algunos problemas con la duración de la cookie de sesión, sobre todo, depende del cliente para hacerla cumplir. La vida útil de las cookies está ahí para permitir al cliente limpiar las cookies inútiles / caducadas, no debe confundirse con nada relacionado con la seguridad.
Jacco

Es gc_maxlifetimeo gc-maxlifetime. ¿Es compatible con guiones bajos y guiones?
Mike Causer

24

Esta publicación muestra un par de formas de controlar el tiempo de espera de la sesión: http://bytes.com/topic/php/insights/889606-setting-timeout-php-sessions

En mi humilde opinión, la segunda opción es una buena solución:

<?php
/***
 * Starts a session with a specific timeout and a specific GC probability.
 * @param int $timeout The number of seconds until it should time out.
 * @param int $probability The probablity, in int percentage, that the garbage 
 *        collection routine will be triggered right now.
 * @param strint $cookie_domain The domain path for the cookie.
 */
function session_start_timeout($timeout=5, $probability=100, $cookie_domain='/') {
    // Set the max lifetime
    ini_set("session.gc_maxlifetime", $timeout);

    // Set the session cookie to timout
    ini_set("session.cookie_lifetime", $timeout);

    // Change the save path. Sessions stored in teh same path
    // all share the same lifetime; the lowest lifetime will be
    // used for all. Therefore, for this to work, the session
    // must be stored in a directory where only sessions sharing
    // it's lifetime are. Best to just dynamically create on.
    $seperator = strstr(strtoupper(substr(PHP_OS, 0, 3)), "WIN") ? "\\" : "/";
    $path = ini_get("session.save_path") . $seperator . "session_" . $timeout . "sec";
    if(!file_exists($path)) {
        if(!mkdir($path, 600)) {
            trigger_error("Failed to create session save path directory '$path'. Check permissions.", E_USER_ERROR);
        }
    }
    ini_set("session.save_path", $path);

    // Set the chance to trigger the garbage collection.
    ini_set("session.gc_probability", $probability);
    ini_set("session.gc_divisor", 100); // Should always be 100

    // Start the session!
    session_start();

    // Renew the time left until this session times out.
    // If you skip this, the session will time out based
    // on the time when it was created, rather than when
    // it was last used.
    if(isset($_COOKIE[session_name()])) {
        setcookie(session_name(), $_COOKIE[session_name()], time() + $timeout, $cookie_domain);
    }
}

19

Bueno, entiendo que las respuestas anteriores son correctas, pero están en el nivel de aplicación, ¿por qué no usamos simplemente el .htaccessarchivo para establecer el tiempo de caducidad?

<IfModule mod_php5.c>
    #Session timeout
    php_value session.cookie_lifetime 1800
    php_value session.gc_maxlifetime 1800
</IfModule>

1
La respuesta de @ Lode da una explicación perfecta de por qué esta respuesta no es confiable no debe usarse.
emix

15
if (isSet($_SESSION['started'])){
    if((mktime() - $_SESSION['started'] - 60*30) > 0){
        //Logout, destroy session, etc.
    }
}
else {
    $_SESSION['started'] = mktime();
}


11

En realidad es fácil con una función como la siguiente. Utiliza el nombre de la tabla de la base de datos 'sesiones' con los campos 'id' y 'hora'.

Cada vez que el usuario visite su sitio o servicio nuevamente, debe invocar esta función para verificar si su valor de retorno es VERDADERO. Si es FALSO, el usuario ha expirado y la sesión se destruirá (Nota: esta función utiliza una clase de base de datos para conectarse y consultar la base de datos, por supuesto, también puede hacerlo dentro de su función o algo así):

function session_timeout_ok() {
    global $db;
    $timeout = SESSION_TIMEOUT; //const, e.g. 6 * 60 for 6 minutes
    $ok = false;
    $session_id = session_id();
    $sql = "SELECT time FROM sessions WHERE session_id = '".$session_id."'";
    $rows = $db->query($sql);
    if ($rows === false) {
        //Timestamp could not be read
        $ok = FALSE;
    }
    else {
        //Timestamp was read succesfully
        if (count($rows) > 0) {
            $zeile = $rows[0];
            $time_past = $zeile['time'];
            if ( $timeout + $time_past < time() ) {
                //Time has expired
                session_destroy();
                $sql = "DELETE FROM sessions WHERE session_id = '" . $session_id . "'";
                $affected = $db -> query($sql);
                $ok = FALSE;
            }
            else {
                //Time is okay
                $ok = TRUE;
                $sql = "UPDATE sessions SET time='" . time() . "' WHERE session_id = '" . $session_id . "'";
                $erg = $db -> query($sql);
                if ($erg == false) {
                    //DB error
                }
            }
        }
        else {
            //Session is new, write it to database table sessions
            $sql = "INSERT INTO sessions(session_id,time) VALUES ('".$session_id."','".time()."')";
            $res = $db->query($sql);
            if ($res === FALSE) {
                //Database error
                $ok = false;
            }
            $ok = true;
        }
        return $ok;
    }
    return $ok;
}

9

Almacenar una marca de tiempo en la sesión


<?php    
$user = $_POST['user_name'];
$pass = $_POST['user_pass'];

require ('db_connection.php');

// Hey, always escape input if necessary!
$result = mysql_query(sprintf("SELECT * FROM accounts WHERE user_Name='%s' AND user_Pass='%s'", mysql_real_escape_string($user), mysql_real_escape_string($pass));

if( mysql_num_rows( $result ) > 0)
{
    $array = mysql_fetch_assoc($result);    

    session_start();
    $_SESSION['user_id'] = $user;
    $_SESSION['login_time'] = time();
    header("Location:loggedin.php");            
}
else
{
    header("Location:login.php");
}
?>

Ahora, compruebe si la marca de tiempo está dentro del intervalo de tiempo permitido (1800 segundos son 30 minutos)

<?php
session_start();
if( !isset( $_SESSION['user_id'] ) || time() - $_SESSION['login_time'] > 1800)
{
    header("Location:login.php");
}
else
{
    // uncomment the next line to refresh the session, so it will expire after thirteen minutes of inactivity, and not thirteen minutes after login
    //$_SESSION['login_time'] = time();
    echo ( "this session is ". $_SESSION['user_id'] );
    //show rest of the page and all other content
}
?>

8

Utilice el siguiente bloque de código en su archivo de inclusión que se cargó en cada página.

$expiry = 1800 ;//session expiry required after 30 mins
    if (isset($_SESSION['LAST']) && (time() - $_SESSION['LAST'] > $expiry)) {
        session_unset();
        session_destroy();
    }
    $_SESSION['LAST'] = time();

1

Usa esta clase por 30 minutos

class Session{
    public static function init(){
        ini_set('session.gc_maxlifetime', 1800) ;
        session_start();
    }
    public static function set($key, $val){
        $_SESSION[$key] =$val;
    }
    public static function get($key){
        if(isset($_SESSION[$key])){
            return $_SESSION[$key];
        } else{
            return false;
        }
    }
    public static function checkSession(){
        self::init();
        if(self::get("adminlogin")==false){
            self::destroy();
            header("Location:login.php");
        }
    }
    public static function checkLogin(){
        self::init();
        if(self::get("adminlogin")==true){
            header("Location:index.php");
        }
    }
    public static function destroy(){
        session_destroy();
        header("Location:login.php");
    }
}

0

Usando marca de tiempo ...

<?php
if (!isset($_SESSION)) {
    $session = session_start();
} 
if ($session && !isset($_SESSION['login_time'])) {
    if ($session == 1) {
        $_SESSION['login_time']=time();
        echo "Login :".$_SESSION['login_time'];
        echo "<br>";
        $_SESSION['idle_time']=$_SESSION['login_time']+20;
        echo "Session Idle :".$_SESSION['idle_time'];
        echo "<br>";
    } else{
        $_SESSION['login_time']="";
    }
} else {
    if (time()>$_SESSION['idle_time']){
        echo "Session Idle :".$_SESSION['idle_time'];
        echo "<br>";
        echo "Current :".time();
        echo "<br>";
        echo "Session Time Out";
        session_destroy();
        session_unset();
    } else {
        echo "Logged In<br>";
    }
}
?>

He usado 20 segundos para expirar la sesión usando la marca de tiempo .

Si necesita 30 minutos, agregue 1800 (30 minutos en segundos) ...


0

Puede usar directamente una base de datos para hacerlo como alternativa. Utilizo una función DB para hacerlo que llamo chk_lgn.

Verifique las verificaciones de inicio de sesión para ver si han iniciado sesión o no y, al hacerlo, establece la marca de fecha y hora de la verificación como la última activa en la fila / columna db del usuario.

También hago la verificación de tiempo allí. Esto funciona para mí por el momento, ya que uso esta función para cada página.

PD: Nadie que haya visto había sugerido una solución de DB pura.



-1

Simplemente almacene la hora actual y si supera los 30 minutos comparando, destruya la sesión actual.


La única vez que evaluaría eso es cuando usa la sesión, ¿verdad?
Eric Kramer
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.