File indexing completed on 2024-12-22 05:37:05

0001 <?php
0002 /**
0003  * Zend Framework
0004  *
0005  * LICENSE
0006  *
0007  * This source file is subject to the new BSD license that is bundled
0008  * with this package in the file LICENSE.txt.
0009  * It is also available through the world-wide-web at this URL:
0010  * http://framework.zend.com/license/new-bsd
0011  * If you did not receive a copy of the license and are unable to
0012  * obtain it through the world-wide-web, please send an email
0013  * to license@zend.com so we can send you a copy immediately.
0014  *
0015  * @category   Zend
0016  * @package    Zend_Service_WindowsAzure
0017  * @subpackage Session
0018  * @copyright  Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
0019  * @license    http://framework.zend.com/license/new-bsd     New BSD License
0020  * @version    $Id$
0021  */
0022 
0023 /**
0024  * @category   Zend
0025  * @package    Zend_Service_WindowsAzure
0026  * @subpackage Session
0027  * @copyright  Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
0028  * @license    http://framework.zend.com/license/new-bsd     New BSD License
0029  */
0030 class Zend_Service_WindowsAzure_SessionHandler
0031 {
0032   /**
0033    * Maximal property size in table storage.
0034    * 
0035    * @var int
0036    * @see http://msdn.microsoft.com/en-us/library/dd179338.aspx
0037    */
0038   const MAX_TS_PROPERTY_SIZE = 65536;
0039   
0040   /** Storage backend type */
0041   const STORAGE_TYPE_TABLE = 'table';
0042   const STORAGE_TYPE_BLOB = 'blob';
0043   
0044     /**
0045      * Storage back-end
0046      * 
0047      * @var Zend_Service_WindowsAzure_Storage_Table|Zend_Service_WindowsAzure_Storage_Blob
0048      */
0049     protected $_storage;
0050     
0051     /**
0052      * Storage backend type
0053      * 
0054      * @var string
0055      */
0056     protected $_storageType;
0057     
0058     /**
0059      * Session container name
0060      * 
0061      * @var string
0062      */
0063     protected $_sessionContainer;
0064     
0065     /**
0066      * Session container partition
0067      * 
0068      * @var string
0069      */
0070     protected $_sessionContainerPartition;
0071   
0072     /**
0073      * Creates a new Zend_Service_WindowsAzure_SessionHandler instance
0074      * 
0075      * @param Zend_Service_WindowsAzure_Storage_Table|Zend_Service_WindowsAzure_Storage_Blob $storage Storage back-end, can be table storage and blob storage
0076      * @param string $sessionContainer Session container name
0077      * @param string $sessionContainerPartition Session container partition
0078      */
0079     public function __construct(Zend_Service_WindowsAzure_Storage $storage, $sessionContainer = 'phpsessions', $sessionContainerPartition = 'sessions')
0080   {
0081     // Validate $storage
0082     if (!($storage instanceof Zend_Service_WindowsAzure_Storage_Table || $storage instanceof Zend_Service_WindowsAzure_Storage_Blob)) {
0083       // require_once 'Zend/Service/WindowsAzure/Exception.php';
0084       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.');
0085     }
0086     
0087     // Validate other parameters
0088     if ($sessionContainer == '' || $sessionContainerPartition == '') {
0089       // require_once 'Zend/Service/WindowsAzure/Exception.php';
0090       throw new Zend_Service_WindowsAzure_Exception('Session container and session partition should be specified.');
0091     }
0092     
0093     // Determine storage type
0094     $storageType = self::STORAGE_TYPE_TABLE;
0095     if ($storage instanceof Zend_Service_WindowsAzure_Storage_Blob) {
0096       $storageType = self::STORAGE_TYPE_BLOB;
0097     }
0098     
0099       // Set properties
0100     $this->_storage = $storage;
0101     $this->_storageType = $storageType;
0102     $this->_sessionContainer = $sessionContainer;
0103     $this->_sessionContainerPartition = $sessionContainerPartition;
0104   }
0105   
0106   /**
0107    * Registers the current session handler as PHP's session handler
0108    * 
0109    * @return boolean
0110    */
0111   public function register()
0112   {
0113         return session_set_save_handler(array($this, 'open'),
0114                                         array($this, 'close'),
0115                                         array($this, 'read'),
0116                                         array($this, 'write'),
0117                                         array($this, 'destroy'),
0118                                         array($this, 'gc')
0119         );
0120   }
0121   
0122     /**
0123      * Open the session store
0124      * 
0125      * @return bool
0126      */
0127     public function open()
0128     {
0129       // Make sure storage container exists
0130       if ($this->_storageType == self::STORAGE_TYPE_TABLE) {
0131         $this->_storage->createTableIfNotExists($this->_sessionContainer);
0132       } else if ($this->_storageType == self::STORAGE_TYPE_BLOB) {
0133         $this->_storage->createContainerIfNotExists($this->_sessionContainer);
0134       }
0135       
0136     // Ok!
0137     return true;
0138     }
0139 
0140     /**
0141      * Close the session store
0142      * 
0143      * @return bool
0144      */
0145     public function close()
0146     {
0147         return true;
0148     }
0149     
0150     /**
0151      * Read a specific session
0152      * 
0153      * @param int $id Session Id
0154      * @return string
0155      */
0156     public function read($id)
0157     {
0158       // Read data
0159         if ($this->_storageType == self::STORAGE_TYPE_TABLE) {
0160         // In table storage
0161           try
0162           {
0163               $sessionRecord = $this->_storage->retrieveEntityById(
0164                   $this->_sessionContainer,
0165                   $this->_sessionContainerPartition,
0166                   $id
0167               );
0168               return unserialize(base64_decode($sessionRecord->serializedData));
0169           }
0170           catch (Zend_Service_WindowsAzure_Exception $ex)
0171           {
0172               return '';
0173           }
0174         } else if ($this->_storageType == self::STORAGE_TYPE_BLOB) {
0175         // In blob storage
0176           try
0177           {
0178           $data = $this->_storage->getBlobData(
0179             $this->_sessionContainer,
0180             $this->_sessionContainerPartition . '/' . $id
0181           );
0182               return unserialize(base64_decode($data));
0183           }
0184           catch (Zend_Service_WindowsAzure_Exception $ex)
0185           {
0186               return false;
0187           }
0188       }
0189     }
0190     
0191     /**
0192      * Write a specific session
0193      * 
0194      * @param int $id Session Id
0195      * @param string $serializedData Serialized PHP object
0196      * @throws Exception
0197      */
0198     public function write($id, $serializedData)
0199     {
0200       // Encode data
0201       $serializedData = base64_encode(serialize($serializedData));
0202       if (strlen($serializedData) >= self::MAX_TS_PROPERTY_SIZE && $this->_storageType == self::STORAGE_TYPE_TABLE) {
0203         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.');
0204       }
0205       
0206       // Store data
0207         if ($this->_storageType == self::STORAGE_TYPE_TABLE) {
0208         // In table storage
0209             $sessionRecord = new Zend_Service_WindowsAzure_Storage_DynamicTableEntity($this->_sessionContainerPartition, $id);
0210           $sessionRecord->sessionExpires = time();
0211           $sessionRecord->serializedData = $serializedData;
0212           
0213           $sessionRecord->setAzurePropertyType('sessionExpires', 'Edm.Int32');
0214   
0215           try
0216           {
0217               $this->_storage->updateEntity($this->_sessionContainer, $sessionRecord);
0218           }
0219           catch (Zend_Service_WindowsAzure_Exception $unknownRecord)
0220           {
0221               $this->_storage->insertEntity($this->_sessionContainer, $sessionRecord);
0222           }
0223       } else if ($this->_storageType == self::STORAGE_TYPE_BLOB) {
0224         // In blob storage
0225         $this->_storage->putBlobData(
0226           $this->_sessionContainer,
0227           $this->_sessionContainerPartition . '/' . $id,
0228           $serializedData,
0229           array('sessionexpires' => time())
0230         );
0231       }
0232     }
0233     
0234     /**
0235      * Destroy a specific session
0236      * 
0237      * @param int $id Session Id
0238      * @return boolean
0239      */
0240     public function destroy($id)
0241     {
0242     // Destroy data
0243         if ($this->_storageType == self::STORAGE_TYPE_TABLE) {
0244         // In table storage
0245             try
0246           {
0247               $sessionRecord = $this->_storage->retrieveEntityById(
0248                   $this->_sessionContainer,
0249                   $this->_sessionContainerPartition,
0250                   $id
0251               );
0252               $this->_storage->deleteEntity($this->_sessionContainer, $sessionRecord);
0253               
0254               return true;
0255           }
0256           catch (Zend_Service_WindowsAzure_Exception $ex)
0257           {
0258               return false;
0259           }
0260       } else if ($this->_storageType == self::STORAGE_TYPE_BLOB) {
0261         // In blob storage
0262           try
0263           {
0264           $this->_storage->deleteBlob(
0265             $this->_sessionContainer,
0266             $this->_sessionContainerPartition . '/' . $id
0267           );
0268               
0269               return true;
0270           }
0271           catch (Zend_Service_WindowsAzure_Exception $ex)
0272           {
0273               return false;
0274           }
0275       }
0276     }
0277     
0278     /**
0279      * Garbage collector
0280      * 
0281      * @param int $lifeTime Session maximal lifetime
0282      * @see session.gc_divisor  100
0283      * @see session.gc_maxlifetime 1440
0284      * @see session.gc_probability 1
0285      * @usage Execution rate 1/100 (session.gc_probability/session.gc_divisor)
0286      * @return boolean
0287      */
0288     public function gc($lifeTime)
0289     {
0290         if ($this->_storageType == self::STORAGE_TYPE_TABLE) {
0291         // In table storage
0292             try
0293           {
0294               $result = $this->_storage->retrieveEntities($this->_sessionContainer, 'PartitionKey eq \'' . $this->_sessionContainerPartition . '\' and sessionExpires lt ' . (time() - $lifeTime));
0295               foreach ($result as $sessionRecord)
0296               {
0297                   $this->_storage->deleteEntity($this->_sessionContainer, $sessionRecord);
0298               }
0299               return true;
0300           }
0301           catch (Zend_Service_WindowsAzure_exception $ex)
0302           {
0303               return false;
0304           }
0305       } else if ($this->_storageType == self::STORAGE_TYPE_BLOB) {
0306         // In blob storage
0307           try
0308           {
0309               $result = $this->_storage->listBlobs($this->_sessionContainer, $this->_sessionContainerPartition, '', null, null, 'metadata');
0310               foreach ($result as $sessionRecord)
0311               {
0312                 if ($sessionRecord->Metadata['sessionexpires'] < (time() - $lifeTime)) {
0313                     $this->_storage->deleteBlob($this->_sessionContainer, $sessionRecord->Name);
0314                 }
0315               }
0316               return true;
0317           }
0318           catch (Zend_Service_WindowsAzure_exception $ex)
0319           {
0320               return false;
0321           }
0322       }
0323     }
0324 }