Como expiro uma sessão PHP após 30 minutos?


1047

Eu preciso manter uma sessão viva por 30 minutos e depois destruí-la.


35
Observe que pelo menos duas configurações são cruciais para definir o tempo da sessão e talvez três. Os dois certamente cruciais são session.gc_maxlifetime e session.cookie_lifetime (onde 0 não é o mesmo que um número longo). Para ter 100% de certeza de permitir longos períodos, também pode ser necessário definir o session.save_path, devido à variação do tempo de limpeza controlado pelo SO no diretório / tmp em que os arquivos de sessão são armazenados por padrão.
Kzqai

1
Não entendo por que você deseja expirar a sessão. Se você se preocupa que o usuário saia do computador sem fazer logout e um usuário não autorizado o controle, a expiração da sessão no site não impedirá que o seqüestrador acesse os arquivos da vítima no disco.
precisa saber é o seguinte

Não está claro o que você está perguntando aqui. Você quer dizer que deseja implementar um tempo limite de inatividade difícil (atualmente o PHP permite que você use uma sessão que não foi tocada por mais que session.gc_maxlifetime) ou quer limitar a sessão a 30 minutos, independentemente de inatividade? Francamente, acho que a resposta aceita aqui é um péssimo conselho para qualquer um dos problemas - em ambos os casos, a lógica deve ser implementada com um manipulador de sessão personalizado.
19418 sycbean

Respostas:


1663

Você deve implementar seu próprio tempo limite da sessão. Ambas as opções mencionadas por outras pessoas ( session.gc_maxlifetime e session.cookie_lifetime ) não são confiáveis. Eu vou explicar as razões para isso.

Primeiro:

session.gc_maxlifetime
session.gc_maxlifetime especifica o número de segundos após os quais os dados serão vistos como 'lixo' e limpos. A coleta de lixo ocorre durante o início da sessão.

Mas o coletor de lixo é iniciado apenas com uma probabilidade de session.gc_probability dividida por session.gc_divisor . E usando os valores padrão para essas opções (1 e 100 respectivamente), a chance é de apenas 1%.

Bem, você pode simplesmente ajustar esses valores para que o coletor de lixo seja iniciado com mais frequência. Mas quando o coletor de lixo é iniciado, ele verifica a validade de cada sessão registrada. E isso custa muito.

Além disso, ao usar os arquivos session.save_handler padrão do PHP , os dados da sessão são armazenados nos arquivos em um caminho especificado em session.save_path . Com esse manipulador de sessão, a idade dos dados da sessão é calculada na data da última modificação do arquivo e não na data do último acesso:

Nota: Se você estiver usando o manipulador de sessões baseado em arquivo padrão, seu sistema de arquivos deve acompanhar os tempos de acesso (atime). O Windows FAT não funciona, portanto você terá que criar outra maneira de lidar com a coleta de lixo da sua sessão, se você estiver com um sistema de arquivos FAT ou qualquer outro sistema de arquivos em que o rastreamento de atime não esteja disponível. Desde o PHP 4.2.3, ele usa mtime (data de modificação) em vez de atime. Portanto, você não terá problemas com sistemas de arquivos nos quais o atime tracking não está disponível.

Portanto, adicionalmente, pode ocorrer que um arquivo de dados da sessão seja excluído enquanto a própria sessão ainda é considerada válida porque os dados da sessão não foram atualizados recentemente.

E em segundo lugar:

session.cookie_lifetime
session.cookie_lifetime especifica o tempo de vida do cookie em segundos, que é enviado ao navegador. [...]

Sim está certo. Isso afeta apenas a vida útil do cookie e a própria sessão ainda pode ser válida. Mas é tarefa do servidor invalidar uma sessão, não o cliente. Então isso não ajuda em nada. De fato, ter session.cookie_lifetime definido como 0tornaria o cookie da sessão um cookie de sessão real , válido apenas até o navegador ser fechado.

Conclusão / melhor solução:

A melhor solução é implementar seu próprio tempo limite de sessão. Use um registro de data e hora simples que indique a hora da última atividade (ou seja, solicitação) e atualize-a com cada solicitação:

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

A atualização dos dados da sessão com cada solicitação também altera a data de modificação do arquivo da sessão, para que a sessão não seja removida pelo coletor de lixo prematuramente.

Você também pode usar um carimbo de data / hora adicional para gerar novamente o ID da sessão periodicamente para evitar ataques a sessões como a fixação da sessão :

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 deve ser pelo menos igual ao tempo de vida desse manipulador de expiração personalizado (1800 neste exemplo);
  • se você quiser expirar a sessão após 30 minutos de atividade, em vez de após 30 minutos desde o início , também precisará usar setcookiecom um prazo de validade time()+60*30para manter o cookie da sessão ativo.

3
Como você pode alterar isso se quiser verificar o "tempo inativo"? Em outras palavras, o usuário efetua login e, enquanto continuar usando o site, ele não será desconectado. No entanto, se ficarem inativos por 30 minutos, eles serão desconectados?
Metropolis

14
@ Metropolis: use algo $_SESSION['LAST_ACTIVITY']parecido com o local $_SESSION['CREATED']onde você armazena o horário da última atividade do usuário, mas atualize esse valor a cada solicitação. Agora, se a diferença desse tempo para o tempo atual for maior que 1800 segundos, a sessão não será usada por mais de 30 minutos.
Gumbo

3
@ Metropolis: session_unsetfaz o mesmo que $_SESSION = array().
Gumbo

14
@ Gumbo - Estou um pouco confuso, você não deveria usar seu código em combinação com ini_set('session.gc-maxlifetime', 1800)? Caso contrário, as informações da sua sessão poderão ser destruídas enquanto a sua sessão ainda é válida, pelo menos se a configuração ini for o padrão de 24 minutos. Ou eu estou esquecendo de alguma coisa?
jeroen

10
@ jeron: Sim, você deveria. Mas observe que session.gc_maxlifetime depende da data da última modificação do arquivo se o manipulador de salvamento da sessão filesfor usado. Portanto, session.gc_maxlifetime deve ser pelo menos igual ao tempo de vida desse manipulador de expiração personalizado.
Gumbo

135

Maneira simples de expirar a sessão do PHP em 30 minutos.

Nota: se você quiser alterar a hora, basta alterar a 30 com a hora desejada e não altere * 60: isso fornecerá os minutos.


Em minutos: (30 * 60)
Em dias: (n * 24 * 60 * 60) n = não de dias


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
Combinar lógica e apresentação não é aconselhável atualmente, quando o MVC é a norma.
bcosca

Talvez eu esteja perdendo algo elementar sobre as sessões, mas que benefício isso faz se as sessões são destruídas a cada 30 minutos pelo sistema operacional?

25
@stillstanding Fale por si [sorriso] Eu vejo o MVC como uma abominação.

2
O MVC é uma boa ideia, mesmo quando o projeto é pequeno, com um único programador? Eu sinto que deveria estar fazendo meus próprios projetos no modelo MVC (ou resolver o problema ENTÃO torná-lo MVC), mas com a falta de experiência com o MVC, isso se torna um bloqueio mental "Como faço para criar este MVC?" e uma distração do objetivo / problema inicial que requer uma solução.
MrVimes 27/07/18

@ ainda outra menção é que nos Login.phpcabeçalhos são enviados APÓS o conteúdo, o que é ruim.
precisa

43

Isso é para desconectar o usuário após um tempo definido? Definir o tempo de criação da sessão (ou um tempo de expiração) quando ele é registrado e, em seguida, verificar se o carregamento de cada página pode lidar com isso.

Por exemplo:

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

// later

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

Edit: Eu tenho a sensação de que você quer dizer outra coisa.

Você pode descartar sessões após uma certa vida útil, usando a session.gc_maxlifetimeconfiguração ini:

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


1
session.gc-maxlifetime é provavelmente o melhor caminho a percorrer.
Powerlord

2
Há alguns problemas com a vida útil do cookie de sessão, principalmente, ele depende do cliente para aplicá-lo. A vida útil do cookie existe para permitir que o cliente limpe cookies inúteis / expirados, não deve ser confundida com nada relacionado à segurança.
Jacco 15/05

É gc_maxlifetimeou gc-maxlifetime. Ele suporta sublinhados e hífens?
Mike Causador

24

Esta postagem mostra algumas maneiras de controlar o tempo limite da sessão: http://bytes.com/topic/php/insights/889606-setting-timeout-php-sessions

IMHO a segunda opção é uma boa solução:

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

Bem, eu entendo que as respostas acima estão corretas, mas estão no nível do aplicativo. Por que simplesmente não usamos o .htaccessarquivo para definir o tempo de expiração?

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

1
A resposta do @ Lode dá uma explicação perfeita por que essa resposta não é confiável não deve ser usada.
emix

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


11

Na verdade, é fácil com uma função como a seguinte. Ele usa o nome da tabela de banco de dados 'sessões' com os campos 'id' e 'time'.

Sempre que o usuário visitar seu site ou serviço novamente, você deverá chamar esta função para verificar se o valor de retorno é VERDADEIRO. Se for FALSE, o usuário expirou e a sessão será destruída.

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

Armazenar um carimbo de data / hora na sessão


<?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");
}
?>

Agora, verifique se o registro de data e hora está dentro da janela de tempo permitido (1800 segundos é 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

Use o seguinte bloco de código no seu arquivo de inclusão, carregado em todas as páginas.

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

1

Use esta classe por 30 min

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 carimbo de data e hora ...

<?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>";
    }
}
?>

Eu usei 20 segundos para expirar a sessão usando o carimbo de data / hora .

Se precisar de 30 min, adicione 1800 (30 min em segundos) ...


0

Você pode usar diretamente um banco de dados para fazer isso como uma alternativa. Eu uso uma função DB para fazer isso que chamo de chk_lgn.

Verifique as verificações de login para ver se elas estão conectadas ou não e, ao fazer isso, define o registro de data e hora da verificação como a última atividade na linha / coluna db do usuário.

Eu também faço a verificação do tempo lá. Isso funciona para mim no momento, pois uso essa função para todas as páginas.

PS: Ninguém que eu tinha visto sugerira uma solução pura de banco de dados.



-1

Apenas armazene o horário atual e, se exceder 30 minutos, comparando, destrua a sessão atual.


A única vez que você avaliaria isso ao usar a sessão, certo?
Eric Kramer
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.