Description
We seem to have encountered a case where PdoSessionStorage, or a similar class may not save to DB / storage at the end of the request.
We've worked around it, however I'm posting this issue at the request of someone on the newsgroup.
We have a derivative of NativeSessionStorage who's start() method is identical (+/- whitespace) to PdoSessionStorage.php
/**
* Starts the session.
*/
public function start()
{
if (self::$sessionStarted) {
return;
}
// use this object as the session handler
session_set_save_handler(
array($this, 'sessionOpen'),
array($this, 'sessionClose'),
array($this, 'sessionRead'),
array($this, 'sessionWrite'),
array($this, 'sessionDestroy'),
array($this, 'sessionGC')
);
parent::start();
}
We then more or less implement sessionWrite, sessionRead, etc.
The problem is that sessionWrite in certain circumstances doesn't seem to be called at the end of the request, resulting in variables not written to our session storage.
What we see is :
- PdoSessionStorage(or Equivalent)->sessionWrite() (called by PHP save_handler routine)
- Session->__destruct
- Calls Session->save()
- Calls PdoSessionStorage(NativeSessionStorage)->write()
- $_SESSION updated
- end of request. (updated $_SESSION never saved)
What actually needs to happen:
- Session->__destruct
- Calls Session->save()
- Calls PdoSessionStorage(NativeSessionStorage)->write()
- $_SESSION updated
- PdoSessionStorage(or Equivalent)->sessionWrite()
- end of request.
We've hacked around it, but I think the problem is that PHP is calling the save handler before __destruct, and doesn't call it afterwards as perhaps it's cleared or something (don't know internally the order of things).
Our hack extends Session and implementing a __destruct such as below, and using this as the session handler instead by overriding it in a custom session.xml file similar to this:
namespace Us\OurBundle\Session;
class HackedSession
extends \Symfony\Component\HttpFoundation\Session
{
public function __destruct()
{
parent::__destruct();
if (true === $this->started && !$this->closed) {
if(method_exists($this->storage, 'sessionWrite'));
$this->storage->sessionWrite($this->getId(), session_encode());
}
}
}
session.xml:
<parameters>
<!-- ... -->
<parameter key="session.class">Us\OurBundle\Session\HackedSession</parameter>
</parameters>
Then load this session.xml under our DependencyInjection class using $loader->load...
Anyway, I'm not sure this is the best way to fix the problem but would appreciate input.