diff -r 5e7a0fedabdf -r 877f952ae2bd web/lib/Zend/Service/WindowsAzure/SessionHandler.php --- a/web/lib/Zend/Service/WindowsAzure/SessionHandler.php Thu Mar 21 17:31:31 2013 +0100 +++ b/web/lib/Zend/Service/WindowsAzure/SessionHandler.php Thu Mar 21 19:50:53 2013 +0100 @@ -15,62 +15,92 @@ * @category Zend * @package Zend_Service_WindowsAzure * @subpackage Session - * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: SessionHandler.php 20785 2010-01-31 09:43:03Z mikaelkael $ + * @version $Id: SessionHandler.php 24593 2012-01-05 20:35:02Z matthew $ */ -/** Zend_Service_WindowsAzure_Storage_Table */ -require_once 'Zend/Service/WindowsAzure/Storage/Table.php'; - -/** - * @see Zend_Service_WindowsAzure_Exception - */ -require_once 'Zend/Service/WindowsAzure/Exception.php'; - /** * @category Zend * @package Zend_Service_WindowsAzure * @subpackage Session - * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License */ class Zend_Service_WindowsAzure_SessionHandler { + /** + * Maximal property size in table storage. + * + * @var int + * @see http://msdn.microsoft.com/en-us/library/dd179338.aspx + */ + const MAX_TS_PROPERTY_SIZE = 65536; + + /** Storage backend type */ + const STORAGE_TYPE_TABLE = 'table'; + const STORAGE_TYPE_BLOB = 'blob'; + /** - * Table storage + * Storage back-end * - * @var Zend_Service_WindowsAzure_Storage_Table + * @var Zend_Service_WindowsAzure_Storage_Table|Zend_Service_WindowsAzure_Storage_Blob */ - protected $_tableStorage; + protected $_storage; /** - * Session table name + * Storage backend type * * @var string */ - protected $_sessionTable; + protected $_storageType; /** - * Session table partition + * Session container name * * @var string */ - protected $_sessionTablePartition; + protected $_sessionContainer; + + /** + * Session container partition + * + * @var string + */ + protected $_sessionContainerPartition; /** * Creates a new Zend_Service_WindowsAzure_SessionHandler instance * - * @param Zend_Service_WindowsAzure_Storage_Table $tableStorage Table storage - * @param string $sessionTable Session table name - * @param string $sessionTablePartition Session table partition + * @param Zend_Service_WindowsAzure_Storage_Table|Zend_Service_WindowsAzure_Storage_Blob $storage Storage back-end, can be table storage and blob storage + * @param string $sessionContainer Session container name + * @param string $sessionContainerPartition Session container partition */ - public function __construct(Zend_Service_WindowsAzure_Storage_Table $tableStorage, $sessionTable = 'phpsessions', $sessionTablePartition = 'sessions') + public function __construct(Zend_Service_WindowsAzure_Storage $storage, $sessionContainer = 'phpsessions', $sessionContainerPartition = 'sessions') { + // Validate $storage + if (!($storage instanceof Zend_Service_WindowsAzure_Storage_Table || $storage instanceof Zend_Service_WindowsAzure_Storage_Blob)) { + require_once 'Zend/Service/WindowsAzure/Exception.php'; + throw new Zend_Service_WindowsAzure_Exception('Invalid storage back-end given. Storage back-end should be of type Zend_Service_WindowsAzure_Storage_Table or Zend_Service_WindowsAzure_Storage_Blob.'); + } + + // Validate other parameters + if ($sessionContainer == '' || $sessionContainerPartition == '') { + require_once 'Zend/Service/WindowsAzure/Exception.php'; + throw new Zend_Service_WindowsAzure_Exception('Session container and session partition should be specified.'); + } + + // Determine storage type + $storageType = self::STORAGE_TYPE_TABLE; + if ($storage instanceof Zend_Service_WindowsAzure_Storage_Blob) { + $storageType = self::STORAGE_TYPE_BLOB; + } + // Set properties - $this->_tableStorage = $tableStorage; - $this->_sessionTable = $sessionTable; - $this->_sessionTablePartition = $sessionTablePartition; + $this->_storage = $storage; + $this->_storageType = $storageType; + $this->_sessionContainer = $sessionContainer; + $this->_sessionContainerPartition = $sessionContainerPartition; } /** @@ -96,12 +126,13 @@ */ public function open() { - // Make sure table exists - $tableExists = $this->_tableStorage->tableExists($this->_sessionTable); - if (!$tableExists) { - $this->_tableStorage->createTable($this->_sessionTable); - } - + // Make sure storage container exists + if ($this->_storageType == self::STORAGE_TYPE_TABLE) { + $this->_storage->createTableIfNotExists($this->_sessionContainer); + } else if ($this->_storageType == self::STORAGE_TYPE_BLOB) { + $this->_storage->createContainerIfNotExists($this->_sessionContainer); + } + // Ok! return true; } @@ -124,19 +155,37 @@ */ public function read($id) { - try - { - $sessionRecord = $this->_tableStorage->retrieveEntityById( - $this->_sessionTable, - $this->_sessionTablePartition, - $id - ); - return base64_decode($sessionRecord->serializedData); - } - catch (Zend_Service_WindowsAzure_Exception $ex) - { - return ''; - } + // Read data + if ($this->_storageType == self::STORAGE_TYPE_TABLE) { + // In table storage + try + { + $sessionRecord = $this->_storage->retrieveEntityById( + $this->_sessionContainer, + $this->_sessionContainerPartition, + $id + ); + return unserialize(base64_decode($sessionRecord->serializedData)); + } + catch (Zend_Service_WindowsAzure_Exception $ex) + { + return ''; + } + } else if ($this->_storageType == self::STORAGE_TYPE_BLOB) { + // In blob storage + try + { + $data = $this->_storage->getBlobData( + $this->_sessionContainer, + $this->_sessionContainerPartition . '/' . $id + ); + return unserialize(base64_decode($data)); + } + catch (Zend_Service_WindowsAzure_Exception $ex) + { + return false; + } + } } /** @@ -144,23 +193,42 @@ * * @param int $id Session Id * @param string $serializedData Serialized PHP object + * @throws Exception */ public function write($id, $serializedData) { - $sessionRecord = new Zend_Service_WindowsAzure_Storage_DynamicTableEntity($this->_sessionTablePartition, $id); - $sessionRecord->sessionExpires = time(); - $sessionRecord->serializedData = base64_encode($serializedData); - - $sessionRecord->setAzurePropertyType('sessionExpires', 'Edm.Int32'); - - try - { - $this->_tableStorage->updateEntity($this->_sessionTable, $sessionRecord); - } - catch (Zend_Service_WindowsAzure_Exception $unknownRecord) - { - $this->_tableStorage->insertEntity($this->_sessionTable, $sessionRecord); - } + // Encode data + $serializedData = base64_encode(serialize($serializedData)); + if (strlen($serializedData) >= self::MAX_TS_PROPERTY_SIZE && $this->_storageType == self::STORAGE_TYPE_TABLE) { + throw new Zend_Service_WindowsAzure_Exception('Session data exceeds the maximum allowed size of ' . self::MAX_TS_PROPERTY_SIZE . ' bytes that can be stored using table storage. Consider switching to a blob storage back-end or try reducing session data size.'); + } + + // Store data + if ($this->_storageType == self::STORAGE_TYPE_TABLE) { + // In table storage + $sessionRecord = new Zend_Service_WindowsAzure_Storage_DynamicTableEntity($this->_sessionContainerPartition, $id); + $sessionRecord->sessionExpires = time(); + $sessionRecord->serializedData = $serializedData; + + $sessionRecord->setAzurePropertyType('sessionExpires', 'Edm.Int32'); + + try + { + $this->_storage->updateEntity($this->_sessionContainer, $sessionRecord); + } + catch (Zend_Service_WindowsAzure_Exception $unknownRecord) + { + $this->_storage->insertEntity($this->_sessionContainer, $sessionRecord); + } + } else if ($this->_storageType == self::STORAGE_TYPE_BLOB) { + // In blob storage + $this->_storage->putBlobData( + $this->_sessionContainer, + $this->_sessionContainerPartition . '/' . $id, + $serializedData, + array('sessionexpires' => time()) + ); + } } /** @@ -171,21 +239,40 @@ */ public function destroy($id) { - try - { - $sessionRecord = $this->_tableStorage->retrieveEntityById( - $this->_sessionTable, - $this->_sessionTablePartition, - $id - ); - $this->_tableStorage->deleteEntity($this->_sessionTable, $sessionRecord); - - return true; - } - catch (Zend_Service_WindowsAzure_Exception $ex) - { - return false; - } + // Destroy data + if ($this->_storageType == self::STORAGE_TYPE_TABLE) { + // In table storage + try + { + $sessionRecord = $this->_storage->retrieveEntityById( + $this->_sessionContainer, + $this->_sessionContainerPartition, + $id + ); + $this->_storage->deleteEntity($this->_sessionContainer, $sessionRecord); + + return true; + } + catch (Zend_Service_WindowsAzure_Exception $ex) + { + return false; + } + } else if ($this->_storageType == self::STORAGE_TYPE_BLOB) { + // In blob storage + try + { + $this->_storage->deleteBlob( + $this->_sessionContainer, + $this->_sessionContainerPartition . '/' . $id + ); + + return true; + } + catch (Zend_Service_WindowsAzure_Exception $ex) + { + return false; + } + } } /** @@ -200,18 +287,38 @@ */ public function gc($lifeTime) { - try - { - $result = $this->_tableStorage->retrieveEntities($this->_sessionTable, 'PartitionKey eq \'' . $this->_sessionTablePartition . '\' and sessionExpires lt ' . (time() - $lifeTime)); - foreach ($result as $sessionRecord) - { - $this->_tableStorage->deleteEntity($this->_sessionTable, $sessionRecord); - } - return true; - } - catch (Zend_Service_WindowsAzure_exception $ex) - { - return false; - } + if ($this->_storageType == self::STORAGE_TYPE_TABLE) { + // In table storage + try + { + $result = $this->_storage->retrieveEntities($this->_sessionContainer, 'PartitionKey eq \'' . $this->_sessionContainerPartition . '\' and sessionExpires lt ' . (time() - $lifeTime)); + foreach ($result as $sessionRecord) + { + $this->_storage->deleteEntity($this->_sessionContainer, $sessionRecord); + } + return true; + } + catch (Zend_Service_WindowsAzure_exception $ex) + { + return false; + } + } else if ($this->_storageType == self::STORAGE_TYPE_BLOB) { + // In blob storage + try + { + $result = $this->_storage->listBlobs($this->_sessionContainer, $this->_sessionContainerPartition, '', null, null, 'metadata'); + foreach ($result as $sessionRecord) + { + if ($sessionRecord->Metadata['sessionexpires'] < (time() - $lifeTime)) { + $this->_storage->deleteBlob($this->_sessionContainer, $sessionRecord->Name); + } + } + return true; + } + catch (Zend_Service_WindowsAzure_exception $ex) + { + return false; + } + } } }