2015-02-18
2015-02-15
Session expire under Zend Framework 2
Few days ago I met a problem with session expire under Zend Framework 2. I set gc_maxlifetime in SessionManager but my session didn’t expire. Ok, you’ll say that I can set session.gc_maxlifetime in php.ini. Yes, I can and it’s one of the solutions. But in my solution, I want to manage session lifetime in application configuration. I looked deeper in ZF2 session implementation to find the problem and solutions. This is what I found.
My configuration looks like this:
<?php
//…
'session' => [
'config' => [
'class' => 'Zend\Session\Config\SessionConfig',
'options' => [
'name' => 'session_name',
'use_cookies' => true,
'gc_maxlifetime' => 1800
]
],
'storage' => 'Zend\Session\Storage\SessionArrayStorage'
],
//…
And my SessionManager factory:
<?php
//…
class SessionManagerFactory implements FactoryInterface
{
public function createService(ServiceLocatorInterface $serviceLocator)
{
$config = $serviceLocator->get('config');
if (isset($config['session'])) {
$session = $config['session'];
$sessionConfig = null;
if (isset($session['config'])) {
$class = isset($session['config']['class']) ? $session['config']['class'] : 'Zend\Session\Config\SessionConfig';
$options = isset($session['config']['options']) ? $session['config']['options'] : array();
$sessionConfig = new $class();
$sessionConfig->setOptions($options);
}
$sessionStorage = null;
if (isset($session['storage'])) {
$class = $session['storage'];
$sessionStorage = new $class();
}
$sessionSaveHandler = null;
if (isset($session['save_handler'])) {
will require constructor arguments
$sessionSaveHandler = $serviceLocator->get($session['save_handler']);
}
$sessionManager = new SessionManager($sessionConfig, $sessionStorage, $sessionSaveHandler);
} else {
$sessionManager = new SessionManager();
}
return $sessionManager;
}
}
Ok, next step, I created session Container:
$sessionManager = $serviceLocator->get('my_project\SessionManager'); $container = new Container(’container_name’, sessionManager);
And what happened after 30 minutes? Nothing. My session still existed.
Let’s go deeper.
After first request Container will be created. If we print $_SESSION we will see something like this:
…
__ZF =>
[’container_name’] =>
['EXPIRE'] => 1423757542
…
After 30 minutes $_SESSION looks like this:
__ZF =>
[’container_name’] => null
And finally, my implementation to check if session has expired looks like this:
//...
abstract class ContainerFactoryAbstract implements FactoryInterface
{
private $containerName;
private $config;
private $sessionManager;
public function createService(ServiceLocatorInterface $serviceLocator)
{
if (is_null($this->containerName)) {
throw new RuntimeException('Is not set name of container!');
}
$this->config = $serviceLocator->get('Config');
$this->sessionManager = $serviceLocator->get('SysSession\SessionManager');
$container = $this->getContainer();
if ($this->isSessionExpired($this->containerName)) {
$this->sessionManager->destroy();
}
if ($this->getSessionMaxLifeTime()) {
$container->setExpirationSeconds($this->getSessionMaxLifeTime());
}
return $container;
}
public function setContainerName($name)
{
$this->containerName = $name;
}
private function getContainer()
{
return new Container($this->containerName, $this->sessionManager);
}
private function isSetInitialSecureData(Container $container)
{
return isset($container->init);
}
private function isSessionExpired($containerName)
{
if (! $this->isSetSessionMaxLifeTime($this->config)) {
return false;
}
return (isset($_SESSION['__ZF'][$containerName]) && (! $this->isSetExpireTimestamp($containerName)));
}
private function isSetSessionMaxLifeTime()
{
return isset($this->config['session']['config']['options']['gc_maxlifetime']);
}
private function getSessionMaxLifeTime()
{
if (! $this->isSetSessionMaxLifeTime()) {
throw new RuntimeException('Is not set value for gc_maxlifetime session!');
}
return $this->config['session']['config']['options']['gc_maxlifetime'];
}
private function isSetExpireTimestamp($containerName)
{
return isset($_SESSION['__ZF'][$containerName]['EXPIRE']);
}
}
My configuration looks like this:
<?php
//…
'session' => [
'config' => [
'class' => 'Zend\Session\Config\SessionConfig',
'options' => [
'name' => 'session_name',
'use_cookies' => true,
'gc_maxlifetime' => 1800
]
],
'storage' => 'Zend\Session\Storage\SessionArrayStorage'
],
//…
And my SessionManager factory:
<?php
//…
class SessionManagerFactory implements FactoryInterface
{
public function createService(ServiceLocatorInterface $serviceLocator)
{
$config = $serviceLocator->get('config');
if (isset($config['session'])) {
$session = $config['session'];
$sessionConfig = null;
if (isset($session['config'])) {
$class = isset($session['config']['class']) ? $session['config']['class'] : 'Zend\Session\Config\SessionConfig';
$options = isset($session['config']['options']) ? $session['config']['options'] : array();
$sessionConfig = new $class();
$sessionConfig->setOptions($options);
}
$sessionStorage = null;
if (isset($session['storage'])) {
$class = $session['storage'];
$sessionStorage = new $class();
}
$sessionSaveHandler = null;
if (isset($session['save_handler'])) {
will require constructor arguments
$sessionSaveHandler = $serviceLocator->get($session['save_handler']);
}
$sessionManager = new SessionManager($sessionConfig, $sessionStorage, $sessionSaveHandler);
} else {
$sessionManager = new SessionManager();
}
return $sessionManager;
}
}
Ok, next step, I created session Container:
$sessionManager = $serviceLocator->get('my_project\SessionManager'); $container = new Container(’container_name’, sessionManager);
And what happened after 30 minutes? Nothing. My session still existed.
Let’s go deeper.
After first request Container will be created. If we print $_SESSION we will see something like this:
…
__ZF =>
[’container_name’] =>
['EXPIRE'] => 1423757542
…
After 30 minutes $_SESSION looks like this:
__ZF =>
[’container_name’] => null
And finally, my implementation to check if session has expired looks like this:
//...
abstract class ContainerFactoryAbstract implements FactoryInterface
{
private $containerName;
private $config;
private $sessionManager;
public function createService(ServiceLocatorInterface $serviceLocator)
{
if (is_null($this->containerName)) {
throw new RuntimeException('Is not set name of container!');
}
$this->config = $serviceLocator->get('Config');
$this->sessionManager = $serviceLocator->get('SysSession\SessionManager');
$container = $this->getContainer();
if ($this->isSessionExpired($this->containerName)) {
$this->sessionManager->destroy();
}
if ($this->getSessionMaxLifeTime()) {
$container->setExpirationSeconds($this->getSessionMaxLifeTime());
}
return $container;
}
public function setContainerName($name)
{
$this->containerName = $name;
}
private function getContainer()
{
return new Container($this->containerName, $this->sessionManager);
}
private function isSetInitialSecureData(Container $container)
{
return isset($container->init);
}
private function isSessionExpired($containerName)
{
if (! $this->isSetSessionMaxLifeTime($this->config)) {
return false;
}
return (isset($_SESSION['__ZF'][$containerName]) && (! $this->isSetExpireTimestamp($containerName)));
}
private function isSetSessionMaxLifeTime()
{
return isset($this->config['session']['config']['options']['gc_maxlifetime']);
}
private function getSessionMaxLifeTime()
{
if (! $this->isSetSessionMaxLifeTime()) {
throw new RuntimeException('Is not set value for gc_maxlifetime session!');
}
return $this->config['session']['config']['options']['gc_maxlifetime'];
}
private function isSetExpireTimestamp($containerName)
{
return isset($_SESSION['__ZF'][$containerName]['EXPIRE']);
}
}
Subskrybuj:
Posty (Atom)