web/lib/Zend/Service/WindowsAzure/SessionHandler.php
changeset 807 877f952ae2bd
parent 207 621fa6caec0c
child 1230 68c69c656a2c
equal deleted inserted replaced
805:5e7a0fedabdf 807:877f952ae2bd
    13  * to license@zend.com so we can send you a copy immediately.
    13  * to license@zend.com so we can send you a copy immediately.
    14  *
    14  *
    15  * @category   Zend
    15  * @category   Zend
    16  * @package    Zend_Service_WindowsAzure
    16  * @package    Zend_Service_WindowsAzure
    17  * @subpackage Session
    17  * @subpackage Session
    18  * @copyright  Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
    18  * @copyright  Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
    19  * @license    http://framework.zend.com/license/new-bsd     New BSD License
    19  * @license    http://framework.zend.com/license/new-bsd     New BSD License
    20  * @version    $Id: SessionHandler.php 20785 2010-01-31 09:43:03Z mikaelkael $
    20  * @version    $Id: SessionHandler.php 24593 2012-01-05 20:35:02Z matthew $
    21  */
    21  */
    22 
       
    23 /** Zend_Service_WindowsAzure_Storage_Table */
       
    24 require_once 'Zend/Service/WindowsAzure/Storage/Table.php';
       
    25 
       
    26 /**
       
    27  * @see Zend_Service_WindowsAzure_Exception
       
    28  */
       
    29 require_once 'Zend/Service/WindowsAzure/Exception.php';
       
    30 
    22 
    31 /**
    23 /**
    32  * @category   Zend
    24  * @category   Zend
    33  * @package    Zend_Service_WindowsAzure
    25  * @package    Zend_Service_WindowsAzure
    34  * @subpackage Session
    26  * @subpackage Session
    35  * @copyright  Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
    27  * @copyright  Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
    36  * @license    http://framework.zend.com/license/new-bsd     New BSD License
    28  * @license    http://framework.zend.com/license/new-bsd     New BSD License
    37  */
    29  */
    38 class Zend_Service_WindowsAzure_SessionHandler
    30 class Zend_Service_WindowsAzure_SessionHandler
    39 {
    31 {
    40     /**
    32 	/**
    41      * Table storage
    33 	 * Maximal property size in table storage.
    42      * 
    34 	 * 
    43      * @var Zend_Service_WindowsAzure_Storage_Table
    35 	 * @var int
    44      */
    36 	 * @see http://msdn.microsoft.com/en-us/library/dd179338.aspx
    45     protected $_tableStorage;
    37 	 */
    46     
    38 	const MAX_TS_PROPERTY_SIZE = 65536;
    47     /**
    39 	
    48      * Session table name
    40 	/** Storage backend type */
       
    41 	const STORAGE_TYPE_TABLE = 'table';
       
    42 	const STORAGE_TYPE_BLOB = 'blob';
       
    43 	
       
    44     /**
       
    45      * Storage back-end
       
    46      * 
       
    47      * @var Zend_Service_WindowsAzure_Storage_Table|Zend_Service_WindowsAzure_Storage_Blob
       
    48      */
       
    49     protected $_storage;
       
    50     
       
    51     /**
       
    52      * Storage backend type
    49      * 
    53      * 
    50      * @var string
    54      * @var string
    51      */
    55      */
    52     protected $_sessionTable;
    56     protected $_storageType;
    53     
    57     
    54     /**
    58     /**
    55      * Session table partition
    59      * Session container name
    56      * 
    60      * 
    57      * @var string
    61      * @var string
    58      */
    62      */
    59     protected $_sessionTablePartition;
    63     protected $_sessionContainer;
       
    64     
       
    65     /**
       
    66      * Session container partition
       
    67      * 
       
    68      * @var string
       
    69      */
       
    70     protected $_sessionContainerPartition;
    60 	
    71 	
    61     /**
    72     /**
    62      * Creates a new Zend_Service_WindowsAzure_SessionHandler instance
    73      * Creates a new Zend_Service_WindowsAzure_SessionHandler instance
    63      * 
    74      * 
    64      * @param Zend_Service_WindowsAzure_Storage_Table $tableStorage Table storage
    75      * @param Zend_Service_WindowsAzure_Storage_Table|Zend_Service_WindowsAzure_Storage_Blob $storage Storage back-end, can be table storage and blob storage
    65      * @param string $sessionTable Session table name
    76      * @param string $sessionContainer Session container name
    66      * @param string $sessionTablePartition Session table partition
    77      * @param string $sessionContainerPartition Session container partition
    67      */
    78      */
    68     public function __construct(Zend_Service_WindowsAzure_Storage_Table $tableStorage, $sessionTable = 'phpsessions', $sessionTablePartition = 'sessions')
    79     public function __construct(Zend_Service_WindowsAzure_Storage $storage, $sessionContainer = 'phpsessions', $sessionContainerPartition = 'sessions')
    69 	{
    80 	{
       
    81 		// Validate $storage
       
    82 		if (!($storage instanceof Zend_Service_WindowsAzure_Storage_Table || $storage instanceof Zend_Service_WindowsAzure_Storage_Blob)) {
       
    83 			require_once 'Zend/Service/WindowsAzure/Exception.php';
       
    84 			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.');
       
    85 		}
       
    86 		
       
    87 		// Validate other parameters
       
    88 		if ($sessionContainer == '' || $sessionContainerPartition == '') {
       
    89 			require_once 'Zend/Service/WindowsAzure/Exception.php';
       
    90 			throw new Zend_Service_WindowsAzure_Exception('Session container and session partition should be specified.');
       
    91 		}
       
    92 		
       
    93 		// Determine storage type
       
    94 		$storageType = self::STORAGE_TYPE_TABLE;
       
    95 		if ($storage instanceof Zend_Service_WindowsAzure_Storage_Blob) {
       
    96 			$storageType = self::STORAGE_TYPE_BLOB;
       
    97 		}
       
    98 		
    70 	    // Set properties
    99 	    // Set properties
    71 		$this->_tableStorage = $tableStorage;
   100 		$this->_storage = $storage;
    72 		$this->_sessionTable = $sessionTable;
   101 		$this->_storageType = $storageType;
    73 		$this->_sessionTablePartition = $sessionTablePartition;
   102 		$this->_sessionContainer = $sessionContainer;
       
   103 		$this->_sessionContainerPartition = $sessionContainerPartition;
    74 	}
   104 	}
    75 	
   105 	
    76 	/**
   106 	/**
    77 	 * Registers the current session handler as PHP's session handler
   107 	 * Registers the current session handler as PHP's session handler
    78 	 * 
   108 	 * 
    94      * 
   124      * 
    95      * @return bool
   125      * @return bool
    96      */
   126      */
    97     public function open()
   127     public function open()
    98     {
   128     {
    99     	// Make sure table exists
   129     	// Make sure storage container exists
   100     	$tableExists = $this->_tableStorage->tableExists($this->_sessionTable);
   130     	if ($this->_storageType == self::STORAGE_TYPE_TABLE) {
   101     	if (!$tableExists) {
   131     		$this->_storage->createTableIfNotExists($this->_sessionContainer);
   102 		    $this->_tableStorage->createTable($this->_sessionTable);
   132     	} else if ($this->_storageType == self::STORAGE_TYPE_BLOB) {
   103 		}
   133     		$this->_storage->createContainerIfNotExists($this->_sessionContainer);
   104 		
   134     	}
       
   135     	
   105 		// Ok!
   136 		// Ok!
   106 		return true;
   137 		return true;
   107     }
   138     }
   108 
   139 
   109     /**
   140     /**
   122      * @param int $id Session Id
   153      * @param int $id Session Id
   123      * @return string
   154      * @return string
   124      */
   155      */
   125     public function read($id)
   156     public function read($id)
   126     {
   157     {
   127         try
   158     	// Read data
   128         {
   159        	if ($this->_storageType == self::STORAGE_TYPE_TABLE) {
   129             $sessionRecord = $this->_tableStorage->retrieveEntityById(
   160     		// In table storage
   130                 $this->_sessionTable,
   161 	        try
   131                 $this->_sessionTablePartition,
   162 	        {
   132                 $id
   163 	            $sessionRecord = $this->_storage->retrieveEntityById(
   133             );
   164 	                $this->_sessionContainer,
   134             return base64_decode($sessionRecord->serializedData);
   165 	                $this->_sessionContainerPartition,
   135         }
   166 	                $id
   136         catch (Zend_Service_WindowsAzure_Exception $ex)
   167 	            );
   137         {
   168 	            return unserialize(base64_decode($sessionRecord->serializedData));
   138             return '';
   169 	        }
   139         }
   170 	        catch (Zend_Service_WindowsAzure_Exception $ex)
       
   171 	        {
       
   172 	            return '';
       
   173 	        }
       
   174        	} else if ($this->_storageType == self::STORAGE_TYPE_BLOB) {
       
   175     		// In blob storage
       
   176     	    try
       
   177 	        {
       
   178     			$data = $this->_storage->getBlobData(
       
   179     				$this->_sessionContainer,
       
   180     				$this->_sessionContainerPartition . '/' . $id
       
   181     			);
       
   182 	            return unserialize(base64_decode($data));
       
   183 	        }
       
   184 	        catch (Zend_Service_WindowsAzure_Exception $ex)
       
   185 	        {
       
   186 	            return false;
       
   187 	        }
       
   188     	}
   140     }
   189     }
   141     
   190     
   142     /**
   191     /**
   143      * Write a specific session
   192      * Write a specific session
   144      * 
   193      * 
   145      * @param int $id Session Id
   194      * @param int $id Session Id
   146      * @param string $serializedData Serialized PHP object
   195      * @param string $serializedData Serialized PHP object
       
   196      * @throws Exception
   147      */
   197      */
   148     public function write($id, $serializedData)
   198     public function write($id, $serializedData)
   149     {
   199     {
   150         $sessionRecord = new Zend_Service_WindowsAzure_Storage_DynamicTableEntity($this->_sessionTablePartition, $id);
   200     	// Encode data
   151         $sessionRecord->sessionExpires = time();
   201     	$serializedData = base64_encode(serialize($serializedData));
   152         $sessionRecord->serializedData = base64_encode($serializedData);
   202     	if (strlen($serializedData) >= self::MAX_TS_PROPERTY_SIZE && $this->_storageType == self::STORAGE_TYPE_TABLE) {
   153         
   203     		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.');
   154         $sessionRecord->setAzurePropertyType('sessionExpires', 'Edm.Int32');
   204     	}
   155 
   205     	
   156         try
   206     	// Store data
   157         {
   207        	if ($this->_storageType == self::STORAGE_TYPE_TABLE) {
   158             $this->_tableStorage->updateEntity($this->_sessionTable, $sessionRecord);
   208     		// In table storage
   159         }
   209        	    $sessionRecord = new Zend_Service_WindowsAzure_Storage_DynamicTableEntity($this->_sessionContainerPartition, $id);
   160         catch (Zend_Service_WindowsAzure_Exception $unknownRecord)
   210 	        $sessionRecord->sessionExpires = time();
   161         {
   211 	        $sessionRecord->serializedData = $serializedData;
   162             $this->_tableStorage->insertEntity($this->_sessionTable, $sessionRecord);
   212 	        
   163         }
   213 	        $sessionRecord->setAzurePropertyType('sessionExpires', 'Edm.Int32');
       
   214 	
       
   215 	        try
       
   216 	        {
       
   217 	            $this->_storage->updateEntity($this->_sessionContainer, $sessionRecord);
       
   218 	        }
       
   219 	        catch (Zend_Service_WindowsAzure_Exception $unknownRecord)
       
   220 	        {
       
   221 	            $this->_storage->insertEntity($this->_sessionContainer, $sessionRecord);
       
   222 	        }
       
   223     	} else if ($this->_storageType == self::STORAGE_TYPE_BLOB) {
       
   224     		// In blob storage
       
   225     		$this->_storage->putBlobData(
       
   226     			$this->_sessionContainer,
       
   227     			$this->_sessionContainerPartition . '/' . $id,
       
   228     			$serializedData,
       
   229     			array('sessionexpires' => time())
       
   230     		);
       
   231     	}
   164     }
   232     }
   165     
   233     
   166     /**
   234     /**
   167      * Destroy a specific session
   235      * Destroy a specific session
   168      * 
   236      * 
   169      * @param int $id Session Id
   237      * @param int $id Session Id
   170      * @return boolean
   238      * @return boolean
   171      */
   239      */
   172     public function destroy($id)
   240     public function destroy($id)
   173     {
   241     {
   174         try
   242 		// Destroy data
   175         {
   243        	if ($this->_storageType == self::STORAGE_TYPE_TABLE) {
   176             $sessionRecord = $this->_tableStorage->retrieveEntityById(
   244     		// In table storage
   177                 $this->_sessionTable,
   245        	    try
   178                 $this->_sessionTablePartition,
   246 	        {
   179                 $id
   247 	            $sessionRecord = $this->_storage->retrieveEntityById(
   180             );
   248 	                $this->_sessionContainer,
   181             $this->_tableStorage->deleteEntity($this->_sessionTable, $sessionRecord);
   249 	                $this->_sessionContainerPartition,
   182             
   250 	                $id
   183             return true;
   251 	            );
   184         }
   252 	            $this->_storage->deleteEntity($this->_sessionContainer, $sessionRecord);
   185         catch (Zend_Service_WindowsAzure_Exception $ex)
   253 	            
   186         {
   254 	            return true;
   187             return false;
   255 	        }
   188         }
   256 	        catch (Zend_Service_WindowsAzure_Exception $ex)
       
   257 	        {
       
   258 	            return false;
       
   259 	        }
       
   260     	} else if ($this->_storageType == self::STORAGE_TYPE_BLOB) {
       
   261     		// In blob storage
       
   262     	    try
       
   263 	        {
       
   264     			$this->_storage->deleteBlob(
       
   265     				$this->_sessionContainer,
       
   266     				$this->_sessionContainerPartition . '/' . $id
       
   267     			);
       
   268 	            
       
   269 	            return true;
       
   270 	        }
       
   271 	        catch (Zend_Service_WindowsAzure_Exception $ex)
       
   272 	        {
       
   273 	            return false;
       
   274 	        }
       
   275     	}
   189     }
   276     }
   190     
   277     
   191     /**
   278     /**
   192      * Garbage collector
   279      * Garbage collector
   193      * 
   280      * 
   198      * @usage Execution rate 1/100 (session.gc_probability/session.gc_divisor)
   285      * @usage Execution rate 1/100 (session.gc_probability/session.gc_divisor)
   199      * @return boolean
   286      * @return boolean
   200      */
   287      */
   201     public function gc($lifeTime)
   288     public function gc($lifeTime)
   202     {
   289     {
   203         try
   290        	if ($this->_storageType == self::STORAGE_TYPE_TABLE) {
   204         {
   291     		// In table storage
   205             $result = $this->_tableStorage->retrieveEntities($this->_sessionTable, 'PartitionKey eq \'' . $this->_sessionTablePartition . '\' and sessionExpires lt ' . (time() - $lifeTime));
   292        	    try
   206             foreach ($result as $sessionRecord)
   293 	        {
   207             {
   294 	            $result = $this->_storage->retrieveEntities($this->_sessionContainer, 'PartitionKey eq \'' . $this->_sessionContainerPartition . '\' and sessionExpires lt ' . (time() - $lifeTime));
   208                 $this->_tableStorage->deleteEntity($this->_sessionTable, $sessionRecord);
   295 	            foreach ($result as $sessionRecord)
   209             }
   296 	            {
   210             return true;
   297 	                $this->_storage->deleteEntity($this->_sessionContainer, $sessionRecord);
   211         }
   298 	            }
   212         catch (Zend_Service_WindowsAzure_exception $ex)
   299 	            return true;
   213         {
   300 	        }
   214             return false;
   301 	        catch (Zend_Service_WindowsAzure_exception $ex)
   215         }
   302 	        {
       
   303 	            return false;
       
   304 	        }
       
   305     	} else if ($this->_storageType == self::STORAGE_TYPE_BLOB) {
       
   306     		// In blob storage
       
   307     	    try
       
   308 	        {
       
   309 	            $result = $this->_storage->listBlobs($this->_sessionContainer, $this->_sessionContainerPartition, '', null, null, 'metadata');
       
   310 	            foreach ($result as $sessionRecord)
       
   311 	            {
       
   312 	            	if ($sessionRecord->Metadata['sessionexpires'] < (time() - $lifeTime)) {
       
   313 	                	$this->_storage->deleteBlob($this->_sessionContainer, $sessionRecord->Name);
       
   314 	            	}
       
   315 	            }
       
   316 	            return true;
       
   317 	        }
       
   318 	        catch (Zend_Service_WindowsAzure_exception $ex)
       
   319 	        {
       
   320 	            return false;
       
   321 	        }
       
   322     	}
   216     }
   323     }
   217 }
   324 }