Handling PHP Sessions in Windows Azure

One of the challenges in building a distributed web application is in handling sessions. When you have multiple instances of an application running and session data is written to local files (as is the default behavior for the session handling functions in PHP) a user session can be lost when a session is started on one instance but subsequent requests are directed (via a load balancer) to other instances. To successfully manage sessions across multiple instances, you need a common data store. In this post I’ll show you how the Windows Azure SDK for PHP makes this easy by storing session data in Windows Azure Table storage.

In the 4.0 release of the Windows Azure SDK for PHP, session handling via Windows Azure Table and Blob storage was included in the newly added SessionHandler class.

Note: The SessionHandler class supports storing session data in Table storage or Blob storage. I will focus on using Table storage in this post largely because I haven’t been able to come up with a scenario in which using Blob storage would be better (or even necessary). If you have ideas about how/why Blob storage would be better, I’d love to hear them.

The SessionHandler class makes it possible to write code for handling sessions in the same way you always have, but the session data is stored on a Windows Azure Table instead of local files. To accomplish this, precede your usual session handling code with these lines:

 require_once 'Microsoft/WindowsAzure/Storage/Table.php';
 require_once 'Microsoft/WindowsAzure/SessionHandler.php';
 $storageClient = new Microsoft_WindowsAzure_Storage_Table('table.core.windows.net', 
                                                           'your storage account name', 
                                                           'your storage account key');
 $sessionHandler = new Microsoft_WindowsAzure_SessionHandler($storageClient , 'sessionstable');
 $sessionHandler->register();

Now you can call session_start() and other session functions as you normally would. Nicely, it just works.

Really, that’s all there is to using the SessionHandler, but I found it interesting to take a look at how it works. The first interesting thing to note is that the register method is simply calling the session_set_save_handler function to essentially map the session handling functionality to custom functions. Here’s what the method looks like from the source code:

 public function register()
 {
     return session_set_save_handler(array($this, 'open'),
                                     array($this, 'close'),
                                     array($this, 'read'),
                                     array($this, 'write'),
                                     array($this, 'destroy'),
                                     array($this, 'gc')
     );
 }

The reading, writing, and deleting of session data is only slightly more complicated. When writing session data, the key-value pairs that make up the data are first serialized and then base64 encoded. The serialization of the data allows for lots of flexibility in the data you want to store (i.e. you don’t have to worry about matching some schema in the data store). When storing data in a table, each entry must have a partition key and row key that uniquely identify it. The partition key is a string (“sessions” by default, but this is changeable in the class constructor) and the the row key is the session ID. (For more information about the structure of Tables, see this post.) Finally, the data is either updated (it it already exists in the Table) or a new entry is inserted. Here’s a portion of the write function:

  
 $serializedData = base64_encode(serialize($serializedData));
  
 $sessionRecord = new Microsoft_WindowsAzure_Storage_DynamicTableEntity($this->_sessionContainerPartition, $id);
 $sessionRecord->sessionExpires = time();
 $sessionRecord->serializedData = $serializedData;
  
 try
 {
     $this->_storage->updateEntity($this->_sessionContainer, $sessionRecord);
 }
 catch (Microsoft_WindowsAzure_Exception $unknownRecord)
 {
     $this->_storage->insertEntity($this->_sessionContainer, $sessionRecord);
 }

Not surprisingly, when session data is read from the table, it is retrieved by session ID, base64 decoded, and unserialized. Again, here’s a snippet that show’s what is happening:

 $sessionRecord = $this->_storage->retrieveEntityById(
     $this->_sessionContainer,
     $this->_sessionContainerPartition,
     $id
 );
 return unserialize(base64_decode($sessionRecord->serializedData));

As you can see, the SessionHandler class makes good use of the storage APIs in the SDK. To learn more about the SessionHandler class (and the storage APIs), check out the documentation on Codeplex. You can, of course, get the complete source code here: https://phpazure.codeplex.com/SourceControl/list/changesets.

As I investigated the session handling in the Windows Azure SDK for PHP, I noticed that the absence of support for SQL Azure as a session store was conspicuous. I’m curious about how many people would prefer to use SQL Azure over Azure Tables as a session store. If you have an opinion on this, please let me know in the comments.

Thanks.

-Brian

Share this on Twitter