Skip to content

Instantly share code, notes, and snippets.

@mwillbanks
Last active August 29, 2015 14:02
Show Gist options
  • Save mwillbanks/72def29ddb0f1dc88a09 to your computer and use it in GitHub Desktop.
Save mwillbanks/72def29ddb0f1dc88a09 to your computer and use it in GitHub Desktop.
Some ideas around sessions

Sessions

Zend Framework 3 (ZF3) will provide a new session management layer that will decouple it from ext/session. In doing this we will allow you to run multiple sessions at the same time in an application, utilize sessions in long-running applications, compatibility/convertibility with other applications, languages, etc.

With decoupling ext/session we will also provide a compatibility layer that will allow you to continue to utilize ext/session and the super global $_SESSION thus allowing you to continue with like behavior as you would have come to expect with generic session management in PHP.

In Zend Framework 2 (ZF2), we encountered numerous issues throughout the session management layer. Certain compatibility issues with ext/session specifically relating to session uploads. Session uploads caused corruption to the internal handing of sessions generally due to it's attempt to rewrite the session data. We also encountered several issues with PHP itself specifically regarding the usage of ArrayObject (deep unsets, references, etc) which removing will provide better long-term support.

In addition the session management layer will attempt to decouple itself by utilizing events as a means of inner-process communication which will allow for the user to take a new route and short-circuit the session if necessary.

Highlights

  • Config
    • General configuration values for session implementation
  • Container
    • Remove array object; merge storage as a container; all session values are part of a container or a default container
    • Containers will utilize simple key => value pairs
  • Serializer
    • Provide strategies as to how data is serialized and unserialized.
  • Storage
    • This will be removed; this is what allowed us to have ArrayObject and different means of storage; ArrayObject caused many issues and in addition makes things far more difficult in the long run. It also caused several issues with corruption due to how sessions were manipulated (ext/session that is)
  • Persistence
    • To replace SaveHandler, persistance will no longer follow ext/session but a compatibility layer may utilize events to short circuit.
  • Validation
    • Referrer
    • IP / Hostname

Limitations of not using ext/session

  • Upload Process - Upload progress is built into the PHP core and would not work as expected unless utilizing the compatibility mode.
    • While the values may get set, it could be in the wrong session area such as a local file system by PHP defaults.
    • Overall other methods exist that can chunk data and provide the user with progress on that front and overall being far more flexible than attempting to do it on the server side.

Configuration

The configuration class will allow for setting specific configuration values.

** Configuration Values **

  • lazy_persistence - The ability to lazily write the session; aka do not write anything unless something had changed.
    • This in addition for expiration reasons may need to 'touch' the session from time to time.
    • Ex: 1 - (lifetime + sessionTime / currentTime) <= .1 update or something like it
  • lifetime - The value in seconds that a session can live for, ** see above for usage of this value **
  • id_strategy - The strategy in how we generate out the session id, likely utilize RandomLib as a default, or utilize php to generate it
  • gc_strategy - Handling probability, and lifetime for gc reasons. More than likely a class and we can read the php configuration values here which could supply the default ** note: gc_lifetime should minimally be the same as lifetime **
  • serializer - factory to set the serializer preference, generally php serialization
  • validation_chain - factory to set the validation chain which will likely utilize an array of values or array of Validation objects
  • compatibility - to force PHP compatability
    • This could cause changes to the above values for instance, serializer must be a php compatable serialize handler
    • lazy_persistence does not necessarily work in ext/session and instead would have to be enforced in the persistence area to know if values had changed

Container

The container would work much as it does today; although we'd move away from the ArrayObject or ArrayAccess method of doing things. Instead providing a getter and setter that can handle the values. This still has not been thought through 100% here but overall we want to avoid having issues with deep linking and unsetting or changing values. This means that we attempt to maintain simple key => value pairs and it is up to the user to handle the deeper nesting.

Containers would have the ability to have expiration in both immediate expiration and at a specific datetime. By removing the seconds and hops it clears up additional areas. However, hops will likely be expected by the user and to replicate it will be as easy as setting $container->expireAt(new \DateTime()) for a single hop. Hop's just do not make as much sense as it is easy to become expired by an XHR request and instead should likely be manually expired.

For instance, take a FlashMessenger. The flash messenger should create a container that would then expire once the value is read thus being the responsibility of the flash messenger to call ->expire() on the container.

The container itself could maintain the meta-data separately from the values and the container's data may be stored in a zf specific indici.

An example

$container = $session->getContainer('foo');
$container->set('foo', 'bar');
$container->set('bar', 'baz');

var_dump($session->toArray());

array(
    'foo' => array(
    	'foo' => 'bar',
    	'bar' => 'baz',
    ),
);

Serializer

The Serializer would simply be any class implementing Serializable. We would then call the serialize() and unserialize() methods manually.

An Example

Note: You would need to implement JsonSerailizable on all objects that you would want to have properly hydrated.

class Json implement Serializable
{
	protected $data;

	public function __construct($data = null)
	{
		$this->data = $data;
	}

    public function serialize() {
    	return json_encode($this->data);
    }
    
    public function unserialize($data) {
    	return json_decode($data);
    }
}

Persistence

Persistence will attempt to closely follow SessionHandlerInterface in PHP itself. However, we will have a separate interface as the storage will be passed certain objects that are not available in PHP itself. This is why during compatibility mode that we will supply a method of proxying this information.

However, we will not utilize the same interface directly. The reason for this is the need for additional data and information.

Validation

Session validation would be changed to no longer throw exceptions and gracefully handle session errors. In many cases on a failed session validation, a new session should be generated for the user and initialized that way.

In ZF2 many users had issues with the session validators because they would throw an exception causing the application to error. Instead this should be handled gracefully as to not attempt to destroy the overall session but to supply it with the ability to regenerate an id and utilize the new session in that way.

Example

$config = new Zend\Session\Config();
$config->setLazyPersistence(true); // 
$config->setLifetime(3600);
$config->setIdStrategy('php');
$config->setGcStategy('php');

$session = new Zend\Session\Session('name', $config); // $config could be an object
$session->setSerializer('php');
$session->setValidationChain(array($validator, $v2, $v3));
$session->setCompat(true); // works with ext/session
$session->start();

$container = $session->getContainer('foo');
$container->get('var', 'default');
$container->set('var', 'foo');
$container->expire(); // expire immediate
$container->expireAt(DateTime); // expire at a specific time

$session->save();
@jaapio
Copy link

jaapio commented Jun 10, 2014

Sounds good, especially the serializer part, which will solve the strange ext/session serialization of protected and private properties. If you want to persist an object using the current session container in a database session in a text field you will get some strange results.

Tnx for this one.

@weierophinney
Copy link

@mwillbanks How do you envision garbage collection working? Would it emulate how it is done by default in PHP? Or would we be recommending usage of a scheduler that would handle it? I'd like some more details on this aspect.

@mwillbanks
Copy link
Author

@weierophinney I would say that I would envision this that we would recommend a scheduler for instance, debian has it set on a cron when you install packages thus if you use a custom session handler you need to override the basic php configuration anyhow.

Since the default of this would still utilize ext/session we would leave php up to the garbage collection. Ultimately on a high performance site you do not want the gc process to happen on x number of requests or thing of that nature.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment