Sessões

HTTP é um protocolo sem estado, mas quase todas as aplicações precisam manter o estado entre as solicitações, por exemplo, o conteúdo de um carrinho de compras. É para isso que uma sessão é usada. Vamos ver

  • como usar as sessões
  • como evitar conflitos de nomes
  • como definir a expiração

Ao utilizar as sessões, cada usuário recebe um identificador único chamado ID da sessão, que é passado em um cookie. Isto serve como a chave para os dados da sessão. Ao contrário dos cookies, que são armazenados no lado do navegador, os dados da sessão são armazenados no lado do servidor.

Nós configuramos a sessão em configuração, a escolha do tempo de expiração é importante.

A sessão é gerenciada pelo objeto Nette\Http\Session, que você obtém passando por injeção de dependência. Nos apresentadores, basta ligar para $session = $this->getSession().

Instalação e requisitos

Sessão inicial

Por padrão, a Nette iniciará uma sessão automaticamente no momento em que começarmos a ler a partir dela ou a escrever dados para ela. Para iniciar manualmente uma sessão, use $session->start().

PHP envia cabeçalhos HTTP que afetam o cache ao iniciar a sessão, veja session_cache_limiter, e possivelmente um cookie com o ID da sessão. Portanto, é sempre necessário iniciar a sessão antes de enviar qualquer saída para o navegador, caso contrário, será lançada uma exceção. Portanto, se você souber que uma sessão será usada durante a renderização da página, inicie-a manualmente antes, por exemplo, no apresentador.

No modo desenvolvedor, Tracy inicia a sessão porque a utiliza para exibir o redirecionamento e AJAX solicita barras na barra Tracy.

Seção

Em PHP puro, o armazenamento de dados da sessão é implementado como uma matriz acessível através de uma variável global $_SESSION. O problema é que as aplicações normalmente consistem em várias partes independentes, e se todas tiverem apenas uma mesma matriz disponível, mais cedo ou mais tarde ocorrerá uma colisão de nome.

Nette Framework resolve o problema dividindo o espaço inteiro em seções (objetos Nette\Http\SessionSection). Cada unidade então usa sua própria seção com um nome único e não podem ocorrer colisões.

Recebemos a seção do gerente da sessão:

$section = $session->getSection('unique name');

No apresentador, basta ligar para getSession() com o parâmetro:

// $this é Apresentador
$section = $this->getSession('unique name');

A existência da seção pode ser verificada pelo método $session->hasSection('unique name').

A seção em si é muito fácil de trabalhar com o uso dos métodos set(), get() e remove():

// escrita variável
$section->set('userName', 'franta');

// lendo uma variável, retorna nula se ela não existir
echo $section->get('userName');

// remoção variável
$section->remove('userName');

É possível utilizar o ciclo foreach para obter todas as variáveis da seção:

foreach ($section as $key => $val) {
	echo "$key = $val";
}

Como definir a expiração

A expiração pode ser definida para seções individuais ou mesmo variáveis individuais. Podemos deixar o login do usuário expirar em 20 minutos, mas ainda assim lembrar o conteúdo de um carrinho de compras.

// seção expirará após 20 minutos
$section->setExpiration('20 minutes');

O terceiro parâmetro do método set() é usado para definir a expiração de variáveis individuais:

// o 'flash' variável expira após 30 segundos
$section->set('flash', $message, '30 seconds');

Lembre-se que o tempo de expiração de toda a sessão (ver configuração da sessão) deve ser igual ou superior ao tempo definido para seções ou variáveis individuais.

O cancelamento da expiração previamente estabelecida pode ser conseguido pelo método removeExpiration(). O cancelamento imediato de toda a seção será assegurado pelo método remove().

Eventos $onStart, $onBeforeWrite

O objeto Nette\Http\Session tem eventos $onStart a $onBeforeWrite, assim você pode adicionar callbacks que são chamados após o início da sessão ou antes de ser gravado em disco e depois terminado.

$session->onBeforeWrite[] = function () {
	// escrever dados para a sessão
	$this->section->set('basket', $this->basket);
};

Gerenciamento da sessão

Visão geral dos métodos da classe Nette\Http\Session para gerenciamento de sessões:

start(): void

Inicia uma sessão.

isStarted(): bool

A sessão foi iniciada?

close(): void

Encerra a sessão. A sessão termina automaticamente no final do roteiro.

destroy(): void

Encerra e apaga a sessão.

exists(): bool

A solicitação HTTP contém um cookie com um ID de sessão?

regenerateId(): void

Gera uma nova identificação de sessão aleatória. Os dados permanecem inalterados.

getId(): string

Devolve a identificação da sessão.

Configuração

Configuramos a sessão em configuração. Se você estiver escrevendo uma aplicação que não utilize um recipiente DI, use estes métodos para configurá-la. Eles devem ser chamados antes de iniciar a sessão.

setName(string $name): static

Define o nome do cookie que é usado para transmitir o ID da sessão. O nome padrão é PHPSESSID. Isto é útil se você executar várias aplicações diferentes no mesmo site.

getName(): string

Retorna o nome do cookie da sessão.

setOptions(array $options)static

Configura a sessão. É possível configurar todas as diretrizes da sessão PHP (em formato camelCase, por exemplo, escrever savePath ao invés de session.save_path) e também lerAndClose.

setExpiration(?string $time)static

Define o tempo de inatividade após o qual a sessão expira.

setCookieParameters(string $path, string $domain=null, bool $secure=null, string $samesite=null)static

Estabelece parâmetros para cookies. Você pode alterar os valores padrão dos parâmetros na configuração#Bookie de sessão.

setSavePath(string $path)static

Define o diretório onde os arquivos das sessões são armazenados.

setHandler(\SessionHandlerInterface $handler)static

Define manipulador personalizado, veja a documentação PHP.

Segurança em primeiro lugar

O servidor assume que ele se comunica com o mesmo usuário desde que as solicitações contenham o mesmo ID de sessão. A tarefa dos mecanismos de segurança é garantir que este comportamento realmente funcione e que não haja possibilidade de substituir ou roubar um identificador.

É por isso que a Nette Framework configura corretamente as diretrizes PHP para transferir o ID da sessão somente em cookies, para evitar o acesso a partir do JavaScript e para ignorar os identificadores na URL. Além disso, em momentos críticos, como o login do usuário, ele gera um novo ID de sessão.

A função ini_set é usada para configurar PHP, mas infelizmente, seu uso é proibido em alguns serviços de hospedagem web. Se for seu caso, tente pedir ao seu provedor de hospedagem que permita esta função para você, ou pelo menos que configure seu servidor adequadamente.

versão: 4.0