Como alterar o tempo limite da sessão em PHP?

Respostas:

324

O tempo limite da sessão é uma noção que deve ser implementada no código se você deseja garantias estritas; essa é a única maneira de ter certeza absoluta de que nenhuma sessão sobreviverá após X minutos de inatividade.

Se relaxar um pouco esse requisito é aceitável e você não pode colocar um limite inferior em vez de um limite estrito para a duração, é possível fazê-lo facilmente e sem escrever uma lógica personalizada.

Conveniência em ambientes descontraídos: como e por quê

Se suas sessões forem implementadas com cookies (o que provavelmente são) e se os clientes não forem maliciosos, você poderá definir um limite superior na duração da sessão, ajustando determinados parâmetros. Se você estiver usando o manuseio de sessão padrão do PHP com cookies, a configuração session.gc_maxlifetimejunto com ele session_set_cookie_paramsdeve funcionar assim:

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

Isso funciona configurando o servidor para manter os dados da sessão por pelo menos uma hora de inatividade e instruindo seus clientes que eles devem "esquecer" sua identificação de sessão após o mesmo período. Ambas as etapas são necessárias para alcançar o resultado esperado.

  • Se você não disser aos clientes que esqueçam o ID de sua sessão após uma hora (ou se os clientes forem maliciosos e optarem por ignorar suas instruções), eles continuarão usando o mesmo ID de sessão e sua duração efetiva será não determinística. Isso ocorre porque as sessões cuja vida útil expirou no lado do servidor não são coletadas de lixo imediatamente, mas apenas sempre que a sessão GC entra em ação .

    O GC é um processo potencialmente caro, portanto, normalmente a probabilidade é pequena ou até zero (um site que obtém um grande número de hits provavelmente renuncia inteiramente ao GC probabilístico e o programa para que ocorra em segundo plano a cada X minutos). Nos dois casos (assumindo clientes que não colaboram), o limite inferior para o tempo de vida útil da sessão será session.gc_maxlifetime, mas o limite superior será imprevisível.

  • Se você não definir session.gc_maxlifetimeo mesmo período, o servidor poderá descartar os dados da sessão ociosa mais cedo; nesse caso, um cliente que ainda se lembra da identificação da sessão a apresentará, mas o servidor não encontrará dados associados a essa sessão, comportando-se efetivamente como se a sessão tivesse acabado de iniciar.

Certeza em ambientes críticos

Você pode tornar as coisas completamente controláveis ​​usando a lógica personalizada para também colocar um limite superior na inatividade da sessão; junto com o limite inferior acima, isso resulta em uma configuração estrita.

Faça isso salvando o limite superior junto com o restante dos dados da sessão:

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;

Persistência do ID da Sessão

Até o momento, não nos preocupamos com os valores exatos de cada ID de sessão, apenas com o requisito de que os dados existam pelo tempo que for necessário. Esteja ciente de que, no caso (improvável) de que os IDs de sessão sejam importantes para você, deve-se tomar cuidado para regenerá-los session_regenerate_idquando necessário.

Jon
fonte
Pergunta: se chamar, digamos que a cada minuto, aumentará seu limite? exemplo, às 10:00 Eu liguei para que o limite fosse 11:00, depois de 1 minuto, 10:01, o limite será 11:01?
precisa
@oneofakind: Se você ligar para o que exatamente?
31414 Jon
1
Estes: ini_set ('session.gc_maxlifetime', 3600); session_set_cookie_params (3600);
01
@oneofakind: Sim, mas apenas se você ligar session_start()também (caso contrário, nenhum efeito) e apenas se você sempre ligar para os dois antes session_start(caso contrário gc_maxlifetime, poderá afetar todas as sessões abertas no momento, enquanto session_set_cookie_paramssó poderá afetar uma nova sessão que comece com a solicitação atual).
31414 Jon
@ Jon, se eu chamar session_start () novamente, ele redefinirá tudo na minha $ _SESSION? se você quer dizer com "tem o potencial de afetar todas as sessões", como? Obrigado pela resposta.
precisa
33

Se você usa o tratamento padrão da sessão do PHP, a única maneira de alterar com segurança a duração da sessão em todas as plataformas é alterar o php.ini . Isso ocorre porque, em algumas plataformas, a coleta de lixo é implementada por meio de um script que é executado a cada momento (um script cron ) que lê diretamente do php.ini e, portanto, qualquer tentativa de alterá-lo no tempo de execução, por exemplo ini_set(), via , não é confiável e provavelmente não vai funcionar.

Por exemplo, nos sistemas Debian Linux, a coleta de lixo interna do PHP é desabilitada por session.gc_probability=0padrão na configuração, e é feita via /etc/cron.d/php, que roda em XX: 09 e XX: 39 (ou seja, A cada meia hora). Este trabalho cron procura por sessões anteriores ao session.gc_maxlifetime especificado na configuração e, se houver alguma, são excluídas. Como conseqüência, nesses sistemas ini_set('session.gc_maxlifetime', ...)é ignorado. Isso também explica por que nesta pergunta: as sessões do PHP atingem o tempo limite muito rapidamente , o OP teve problemas em um host, mas os problemas cessaram ao mudar para um host diferente.

Portanto, como você não tem acesso ao php.ini , se quiser fazê-lo de maneira portável, usar o tratamento de sessão padrão não é uma opção. Aparentemente, estender a vida útil do cookie foi suficiente para o seu host, mas se você deseja uma solução que funcione de maneira confiável, mesmo que você troque de host, é necessário usar uma alternativa diferente.

Os métodos alternativos disponíveis incluem:

  1. Defina um manipulador de sessão (salvar) diferente no PHP para salvar suas sessões em um diretório diferente ou em um banco de dados, conforme especificado em PHP: Manipuladores de sessão personalizados (manual PHP) , para que o trabalho cron não o atinja, e apenas o PHP a coleta de lixo interna ocorre. Essa opção provavelmente pode ser usada ini_set()para definir session.gc_maxlifetime, mas eu prefiro simplesmente ignorar o parâmetro maxlifetime no meu gc()retorno de chamada e determinar a vida útil máxima por conta própria.

  2. Esqueça completamente o manuseio de sessões internas do PHP e implemente seu próprio gerenciamento de sessões. Esse método tem duas desvantagens principais: você precisará de suas próprias variáveis ​​globais de sessão, para perder a vantagem da $_SESSIONsuperglobal, e ela precisa de mais código, portanto, há mais oportunidades para bugs e falhas de segurança. Mais importante, o identificador da sessão deve ser gerado a partir de números aleatórios ou pseudo-aleatórios criptograficamente seguros para evitar a previsibilidade do ID da sessão (levando a um possível seqüestro de sessão), e isso não é tão fácil de se fazer com o PHP de maneira portável. A principal vantagem é que ele funcionará de forma consistente em todas as plataformas e você terá controle total sobre o código. Essa é a abordagem adotada, por exemplo, pelo software do fórum phpBB (pelo menos na versão 1; não tenho certeza das versões mais recentes).

Há um exemplo de (1) na documentação parasession_set_save_handler() . O exemplo é longo, mas vou reproduzi-lo aqui, com as modificações relevantes necessárias para estender a duração da sessão. Observe a inclusão de session_set_cookie_params()para aumentar também a vida útil do 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

A abordagem (2) é mais complicada; basicamente, você deve reimplementar todas as funções da sessão por conta própria. Não vou entrar em detalhes aqui.

Pedro Gimeno
fonte
Alguém poderia confirmar isso?
11283 Oli
@ Oli: Parece correto após uma leitura superficial. Você também pode consultar stackoverflow.com/questions/520237/… , mas se você não tiver acesso às php.inisuas opções práticas, será severamente restringido.
Jon
Além disso, no Ubuntu 14 parece que /usr/lib/php5/maxlifetimenão calculará um valor abaixo de 24 minutos. Portanto, você não pode definir o tempo limite da sua sessão para menos do que isso.
22717 Henry
"Esqueça completamente o manuseio de sessões internas do PHP e implemente seu próprio gerenciamento de sessões." bom deus, esse é um conselho perigoso. Um pesadelo de segurança resultaria inevitavelmente.
Kzqai
@Kzqai Também observo que "ele precisa de mais código, portanto há mais oportunidades para bugs e falhas de segurança". Não é um conselho, estou enumerando as alternativas, mas se você tiver uma sugestão para melhorá-lo, faça-o.
Pedro Gimeno
3

Adicionar comentários para qualquer pessoa que esteja usando o Plesk tendo problemas com qualquer um dos itens acima, pois isso estava me deixando louco, configurar o session.gc_maxlifetime do seu script PHP não funcionará, pois o Plesk tem seu próprio script de coleta de lixo executado no cron.

Usei a solução postada no link abaixo para mover o trabalho cron de hora em hora para diariamente para evitar esse problema; a resposta principal acima deve funcionar:

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

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

Neil Walden
fonte
3

Coloque $_SESSION['login_time'] = time();na página de autenticação anterior. E o cortado abaixo em todas as outras páginas em que você deseja verificar o tempo limite da sessão.

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: Isso só funciona se você já usou os ajustes em outras postagens ou desabilitou a Coleta de Lixo e deseja verificar manualmente a duração da sessão. Não se esqueça de adicionar die()após um redirecionamento, porque alguns scripts / robôs podem ignorá-lo. Além disso, destruir diretamente a sessão com, em session_destroy()vez de depender de um redirecionamento, pode ser uma opção melhor, novamente, no caso de um cliente ou robô mal-intencionado.

mohamadRezaSamadi
fonte
2

Apenas um aviso para um servidor de hospedagem compartilhado ou adicionado em domínios =

Para que suas configurações funcionem, você deve ter um diretório de sessão de salvamento diferente para um domínio adicionado usando php_value session.save_path "folderA / sessionsA".

Portanto, crie uma pasta no servidor raiz, não no public_html e não seja acessado por publicidade de fora. Para o meu cpanel / servidor funcionou bem as permissões de pasta 0700. Experimente ...

  • 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 do session_start ();

ou

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

Após muitas pesquisas e testes, isso funcionou bem no servidor cpanel / php7 compartilhado. Muito obrigado a: NoiS

ChriStef
fonte
1

Não. Se você não tem acesso ao php.ini, não pode garantir que as alterações tenham algum efeito.

Duvido que você precise estender o tempo das sessões.
Tem um tempo limite bastante sensato no momento e não há motivos para estendê-lo.

Seu senso comum
fonte
Olá Col, tenho procurado por todo este lugar para encontrar uma maneira de entrar em contato com você. Vi que você me deu algumas sugestões no meu último post que foi fechado (domingo). Fiquei ocupado em outro projeto e agora ele se foi. Eu realmente gostaria de tentar suas sugestões. Isso aí de qualquer maneira para encontrar o que você escreveu?
O cachorro velho
Tanto quanto posso ver, não foi apenas fechado, mas também excluído. Essas pessoas não têm honra. Sim, seu problema tem uma solução comum sobre a qual eu estava falando. Escreverei por email. Em suma, tratava-se de executar duas consultas adicionais para obter esses valores anteriores / próximos. SELECT id FROM gallery WHERE SortOrder > $currentsortorder LIMIT 1
Seu senso comum
0

Você pode substituir valores no php.ini do seu código PHP usando ini_set().

Nathan Q
fonte
4
-1: session.gc_maxlifetimenão é a configuração que controla a vida útil da sessão. Ele pode ser espancado até a obra como que se você definir session.gc_divisora 1, mas isso é apenas horrível.
Jon
1
@ Jon Tenho visto tantas respostas sobre o SO sugerindo o oposto, por que isso? stackoverflow.com/questions/514155/… stackoverflow.com/questions/9904105/…
giannis christofakis
2
@yannishristofakis: gc_maxlifetimedefine o intervalo após o qual os dados da sessão são elegíveis para a coleta de lixo - se o GC ocorrer depois de muito tempo, os dados da sessão serão destruídos (com as configurações padrão é o mesmo que expirar a sessão). Mas o GC é acionado probabilisticamente a cada início da sessão, portanto não há garantia de que a sessão realmente expirará - você pode traçar uma curva de prob vs tempo, mas não parecerá uma parede de tijolos. Essa é apenas a ponta do iceberg; veja stackoverflow.com/questions/520237/…
Jon