cakephpamazon-web-servicesamazon-dynamodbphp

CakePHP: Use AWS's DynamoDB Session Handler


I have a CakePHP application hosted on AWS Elastic Beanstalk. Because of the multiple EC2 instances I will use in the future I want to store my PHP sessions in a database. AWS provides a very nice library for storing PHP sessions in their DynamoDB database. See http://docs.aws.amazon.com/aws-sdk-php/guide/latest/feature-dynamodb-session-handler.html

Now I putted the AWS SDK in my vendors folder and created an access wrapper for it (a plugin):

<?php

Configure::load('aws');

require_once VENDORS . 'autoload.php';
use Aws\Common\Aws;

class AwsComponent extends Component
{
    private $_aws;

    public function __construct()
    {
        $this->_aws = Aws::factory(array(
            'key'    => Configure::read('Aws.key'),
            'secret' => Configure::read('Aws.secret'),
            'region' => Configure::read('Aws.region')
        ));
    }

    public function getClient($service)
    {
        return $this->_aws->get($service);
    }
}

The wrapper is working well, I already implemented some S3 stuff. Now for the session handler i added the following code to my AppController.php:

public $components = array('Aws.Aws');

public function beforeFilter()
{
    $this->_setSessionStorage();
}

private function _setSessionStorage()
{
    $client = $this->Aws->getClient('dynamodb');
        
    $client->registerSessionHandler(array(
        'table_name' => 'sessions'
    ));
}

The AWS's internal registerSessionHandler() is executed (tested it) but the session is not beeing stored into the DynamoDB table. Of course I created the table before and if I add the call to the AWS library directly to my webroot/index.php before dispatcher is loaded everything works fine.

I think the problem is that my code is executed after CakePHP calls session_start(). So what is the best way to implement that? https://book.cakephp.org/2/en/development/sessions.html#creating-a-custom-session-handler doesn't help me, I don't want to rewrite the AWS library for beeing compatible with the CakePHP interface.


Solution

  • So what is the best way to implement that? https://book.cakephp.org/2/en/development/sessions.html#creating-a-custom-session-handler doesn't help me, I don't want to rewrite the AWS library for beeing compatible with the CakePHP interface.

    This is in fact the best way. And this does not mean to reinvent the wheel, abstraction in OOP means that you make things available in a generic interface that can be replaced with something else. You wrap a foreign API or code in an API compatible to your system, in this case a CakePHP application.

    Wrap the vendor lib in a AwsSession adapter that implements the CakeSessionHandlerInterface. This way it's API compatible with other session adapters in the case you change it and it might be even solve your core problem, because CakeSession will take care of the initialization.

    Your component is initialized after the session in CakePHP, when the controller is already instantiated and then is initializing all its components. So this happens at a pretty late time. Your alternative is to stop CakePHP from initializing the session, I never had a need to do so, so no idea without looking it up myself. Dig in CakeSession. Even if you manage to do so, other components like the default Auth adapter depends on being able to work with Sessions, so you have to take care of the issue that your component has to be loaded before Auth as well. Pretty fragile system with lots of possbile points of failure. Seriously, go for the Session adapter, guess its a lot less painful to get it working this way.

    By a quick look at the DynamoDB Session documentation this seems to be pretty easy. Extend the regular session handler and overload only the init and garbage collection of it to add the Aws API calls there, no guarantee this is right but seems to be easy.