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 * |
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 } |