|
1 <?php |
|
2 /** |
|
3 * Zend Framework |
|
4 * |
|
5 * LICENSE |
|
6 * |
|
7 * This source file is subject to the new BSD license that is bundled |
|
8 * with this package in the file LICENSE.txt. |
|
9 * It is also available through the world-wide-web at this URL: |
|
10 * http://framework.zend.com/license/new-bsd |
|
11 * If you did not receive a copy of the license and are unable to |
|
12 * obtain it through the world-wide-web, please send an email |
|
13 * to license@zend.com so we can send you a copy immediately. |
|
14 * |
|
15 * @category Zend |
|
16 * @package Zend_Session |
|
17 * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) |
|
18 * @license http://framework.zend.com/license/new-bsd New BSD License |
|
19 * @version $Id: Namespace.php 20096 2010-01-06 02:05:09Z bkarwin $ |
|
20 * @since Preview Release 0.2 |
|
21 */ |
|
22 |
|
23 |
|
24 /** |
|
25 * @see Zend_Session |
|
26 */ |
|
27 require_once 'Zend/Session.php'; |
|
28 |
|
29 |
|
30 /** |
|
31 * @see Zend_Session_Abstract |
|
32 */ |
|
33 require_once 'Zend/Session/Abstract.php'; |
|
34 |
|
35 |
|
36 /** |
|
37 * Zend_Session_Namespace |
|
38 * |
|
39 * @category Zend |
|
40 * @package Zend_Session |
|
41 * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) |
|
42 * @license http://framework.zend.com/license/new-bsd New BSD License |
|
43 */ |
|
44 class Zend_Session_Namespace extends Zend_Session_Abstract implements IteratorAggregate |
|
45 { |
|
46 |
|
47 /** |
|
48 * used as option to constructor to prevent additional instances to the same namespace |
|
49 */ |
|
50 const SINGLE_INSTANCE = true; |
|
51 |
|
52 /** |
|
53 * Namespace - which namespace this instance of zend-session is saving-to/getting-from |
|
54 * |
|
55 * @var string |
|
56 */ |
|
57 protected $_namespace = "Default"; |
|
58 |
|
59 /** |
|
60 * Namespace locking mechanism |
|
61 * |
|
62 * @var array |
|
63 */ |
|
64 protected static $_namespaceLocks = array(); |
|
65 |
|
66 /** |
|
67 * Single instance namespace array to ensure data security. |
|
68 * |
|
69 * @var array |
|
70 */ |
|
71 protected static $_singleInstances = array(); |
|
72 |
|
73 /** |
|
74 * resetSingleInstance() |
|
75 * |
|
76 * @param string $namespaceName |
|
77 * @return null |
|
78 */ |
|
79 public static function resetSingleInstance($namespaceName = null) |
|
80 { |
|
81 if ($namespaceName != null) { |
|
82 if (array_key_exists($namespaceName, self::$_singleInstances)) { |
|
83 unset(self::$_singleInstances[$namespaceName]); |
|
84 } |
|
85 return; |
|
86 } |
|
87 |
|
88 self::$_singleInstances = array(); |
|
89 return; |
|
90 } |
|
91 |
|
92 /** |
|
93 * __construct() - Returns an instance object bound to a particular, isolated section |
|
94 * of the session, identified by $namespace name (defaulting to 'Default'). |
|
95 * The optional argument $singleInstance will prevent construction of additional |
|
96 * instance objects acting as accessors to this $namespace. |
|
97 * |
|
98 * @param string $namespace - programmatic name of the requested namespace |
|
99 * @param bool $singleInstance - prevent creation of additional accessor instance objects for this namespace |
|
100 * @return void |
|
101 */ |
|
102 public function __construct($namespace = 'Default', $singleInstance = false) |
|
103 { |
|
104 if ($namespace === '') { |
|
105 /** |
|
106 * @see Zend_Session_Exception |
|
107 */ |
|
108 require_once 'Zend/Session/Exception.php'; |
|
109 throw new Zend_Session_Exception('Session namespace must be a non-empty string.'); |
|
110 } |
|
111 |
|
112 if ($namespace[0] == "_") { |
|
113 /** |
|
114 * @see Zend_Session_Exception |
|
115 */ |
|
116 require_once 'Zend/Session/Exception.php'; |
|
117 throw new Zend_Session_Exception('Session namespace must not start with an underscore.'); |
|
118 } |
|
119 |
|
120 if (preg_match('#(^[0-9])#i', $namespace[0])) { |
|
121 /** |
|
122 * @see Zend_Session_Exception |
|
123 */ |
|
124 require_once 'Zend/Session/Exception.php'; |
|
125 throw new Zend_Session_Exception('Session namespace must not start with a number.'); |
|
126 } |
|
127 |
|
128 if (isset(self::$_singleInstances[$namespace])) { |
|
129 /** |
|
130 * @see Zend_Session_Exception |
|
131 */ |
|
132 require_once 'Zend/Session/Exception.php'; |
|
133 throw new Zend_Session_Exception("A session namespace object already exists for this namespace ('$namespace'), and no additional accessors (session namespace objects) for this namespace are permitted."); |
|
134 } |
|
135 |
|
136 if ($singleInstance === true) { |
|
137 self::$_singleInstances[$namespace] = true; |
|
138 } |
|
139 |
|
140 $this->_namespace = $namespace; |
|
141 |
|
142 // Process metadata specific only to this namespace. |
|
143 Zend_Session::start(true); // attempt auto-start (throws exception if strict option set) |
|
144 |
|
145 if (self::$_readable === false) { |
|
146 /** |
|
147 * @see Zend_Session_Exception |
|
148 */ |
|
149 require_once 'Zend/Session/Exception.php'; |
|
150 throw new Zend_Session_Exception(self::_THROW_NOT_READABLE_MSG); |
|
151 } |
|
152 |
|
153 if (!isset($_SESSION['__ZF'])) { |
|
154 return; // no further processing needed |
|
155 } |
|
156 |
|
157 // do not allow write access to namespaces, after stop() or writeClose() |
|
158 if (parent::$_writable === true) { |
|
159 if (isset($_SESSION['__ZF'][$namespace])) { |
|
160 |
|
161 // Expire Namespace by Namespace Hop (ENNH) |
|
162 if (isset($_SESSION['__ZF'][$namespace]['ENNH'])) { |
|
163 $_SESSION['__ZF'][$namespace]['ENNH']--; |
|
164 |
|
165 if ($_SESSION['__ZF'][$namespace]['ENNH'] === 0) { |
|
166 if (isset($_SESSION[$namespace])) { |
|
167 self::$_expiringData[$namespace] = $_SESSION[$namespace]; |
|
168 unset($_SESSION[$namespace]); |
|
169 } |
|
170 unset($_SESSION['__ZF'][$namespace]); |
|
171 } |
|
172 } |
|
173 |
|
174 // Expire Namespace Variables by Namespace Hop (ENVNH) |
|
175 if (isset($_SESSION['__ZF'][$namespace]['ENVNH'])) { |
|
176 foreach ($_SESSION['__ZF'][$namespace]['ENVNH'] as $variable => $hops) { |
|
177 $_SESSION['__ZF'][$namespace]['ENVNH'][$variable]--; |
|
178 |
|
179 if ($_SESSION['__ZF'][$namespace]['ENVNH'][$variable] === 0) { |
|
180 if (isset($_SESSION[$namespace][$variable])) { |
|
181 self::$_expiringData[$namespace][$variable] = $_SESSION[$namespace][$variable]; |
|
182 unset($_SESSION[$namespace][$variable]); |
|
183 } |
|
184 unset($_SESSION['__ZF'][$namespace]['ENVNH'][$variable]); |
|
185 } |
|
186 } |
|
187 if(empty($_SESSION['__ZF'][$namespace]['ENVNH'])) { |
|
188 unset($_SESSION['__ZF'][$namespace]['ENVNH']); |
|
189 } |
|
190 } |
|
191 } |
|
192 |
|
193 if (empty($_SESSION['__ZF'][$namespace])) { |
|
194 unset($_SESSION['__ZF'][$namespace]); |
|
195 } |
|
196 |
|
197 if (empty($_SESSION['__ZF'])) { |
|
198 unset($_SESSION['__ZF']); |
|
199 } |
|
200 } |
|
201 } |
|
202 |
|
203 |
|
204 /** |
|
205 * getIterator() - return an iteratable object for use in foreach and the like, |
|
206 * this completes the IteratorAggregate interface |
|
207 * |
|
208 * @return ArrayObject - iteratable container of the namespace contents |
|
209 */ |
|
210 public function getIterator() |
|
211 { |
|
212 return new ArrayObject(parent::_namespaceGetAll($this->_namespace)); |
|
213 } |
|
214 |
|
215 |
|
216 /** |
|
217 * lock() - mark a session/namespace as readonly |
|
218 * |
|
219 * @return void |
|
220 */ |
|
221 public function lock() |
|
222 { |
|
223 self::$_namespaceLocks[$this->_namespace] = true; |
|
224 } |
|
225 |
|
226 |
|
227 /** |
|
228 * unlock() - unmark a session/namespace to enable read & write |
|
229 * |
|
230 * @return void |
|
231 */ |
|
232 public function unlock() |
|
233 { |
|
234 unset(self::$_namespaceLocks[$this->_namespace]); |
|
235 } |
|
236 |
|
237 |
|
238 /** |
|
239 * unlockAll() - unmark all session/namespaces to enable read & write |
|
240 * |
|
241 * @return void |
|
242 */ |
|
243 public static function unlockAll() |
|
244 { |
|
245 self::$_namespaceLocks = array(); |
|
246 } |
|
247 |
|
248 |
|
249 /** |
|
250 * isLocked() - return lock status, true if, and only if, read-only |
|
251 * |
|
252 * @return bool |
|
253 */ |
|
254 public function isLocked() |
|
255 { |
|
256 return isset(self::$_namespaceLocks[$this->_namespace]); |
|
257 } |
|
258 |
|
259 |
|
260 /** |
|
261 * unsetAll() - unset all variables in this namespace |
|
262 * |
|
263 * @return true |
|
264 */ |
|
265 public function unsetAll() |
|
266 { |
|
267 return parent::_namespaceUnset($this->_namespace); |
|
268 } |
|
269 |
|
270 |
|
271 /** |
|
272 * __get() - method to get a variable in this object's current namespace |
|
273 * |
|
274 * @param string $name - programmatic name of a key, in a <key,value> pair in the current namespace |
|
275 * @return mixed |
|
276 */ |
|
277 public function & __get($name) |
|
278 { |
|
279 if ($name === '') { |
|
280 /** |
|
281 * @see Zend_Session_Exception |
|
282 */ |
|
283 require_once 'Zend/Session/Exception.php'; |
|
284 throw new Zend_Session_Exception("The '$name' key must be a non-empty string"); |
|
285 } |
|
286 |
|
287 return parent::_namespaceGet($this->_namespace, $name); |
|
288 } |
|
289 |
|
290 |
|
291 /** |
|
292 * __set() - method to set a variable/value in this object's namespace |
|
293 * |
|
294 * @param string $name - programmatic name of a key, in a <key,value> pair in the current namespace |
|
295 * @param mixed $value - value in the <key,value> pair to assign to the $name key |
|
296 * @throws Zend_Session_Exception |
|
297 * @return true |
|
298 */ |
|
299 public function __set($name, $value) |
|
300 { |
|
301 if (isset(self::$_namespaceLocks[$this->_namespace])) { |
|
302 /** |
|
303 * @see Zend_Session_Exception |
|
304 */ |
|
305 require_once 'Zend/Session/Exception.php'; |
|
306 throw new Zend_Session_Exception('This session/namespace has been marked as read-only.'); |
|
307 } |
|
308 |
|
309 if ($name === '') { |
|
310 /** |
|
311 * @see Zend_Session_Exception |
|
312 */ |
|
313 require_once 'Zend/Session/Exception.php'; |
|
314 throw new Zend_Session_Exception("The '$name' key must be a non-empty string"); |
|
315 } |
|
316 |
|
317 if (parent::$_writable === false) { |
|
318 /** |
|
319 * @see Zend_Session_Exception |
|
320 */ |
|
321 require_once 'Zend/Session/Exception.php'; |
|
322 throw new Zend_Session_Exception(parent::_THROW_NOT_WRITABLE_MSG); |
|
323 } |
|
324 |
|
325 $name = (string) $name; |
|
326 |
|
327 $_SESSION[$this->_namespace][$name] = $value; |
|
328 } |
|
329 |
|
330 |
|
331 /** |
|
332 * apply() - enables applying user-selected function, such as array_merge() to the namespace |
|
333 * Parameters following the $callback argument are passed to the callback function. |
|
334 * Caveat: ignores members expiring now. |
|
335 * |
|
336 * Example: |
|
337 * $namespace->apply('array_merge', array('tree' => 'apple', 'fruit' => 'peach'), array('flower' => 'rose')); |
|
338 * $namespace->apply('count'); |
|
339 * |
|
340 * @param string|array $callback - callback function |
|
341 */ |
|
342 public function apply($callback) |
|
343 { |
|
344 $arg_list = func_get_args(); |
|
345 $arg_list[0] = $_SESSION[$this->_namespace]; |
|
346 return call_user_func_array($callback, $arg_list); |
|
347 } |
|
348 |
|
349 |
|
350 /** |
|
351 * applySet() - enables applying user-selected function, and sets entire namespace to the result |
|
352 * Result of $callback must be an array. |
|
353 * Parameters following the $callback argument are passed to the callback function. |
|
354 * Caveat: ignores members expiring now. |
|
355 * |
|
356 * Example: |
|
357 * $namespace->applySet('array_merge', array('tree' => 'apple', 'fruit' => 'peach'), array('flower' => 'rose')); |
|
358 * |
|
359 * @param string|array $callback - callback function |
|
360 */ |
|
361 public function applySet($callback) |
|
362 { |
|
363 $arg_list = func_get_args(); |
|
364 $arg_list[0] = $_SESSION[$this->_namespace]; |
|
365 $result = call_user_func_array($callback, $arg_list); |
|
366 if (!is_array($result)) { |
|
367 /** |
|
368 * @see Zend_Session_Exception |
|
369 */ |
|
370 require_once 'Zend/Session/Exception.php'; |
|
371 throw new Zend_Session_Exception('Result must be an array. Got: ' . gettype($result)); |
|
372 } |
|
373 $_SESSION[$this->_namespace] = $result; |
|
374 return $result; |
|
375 } |
|
376 |
|
377 |
|
378 /** |
|
379 * __isset() - determine if a variable in this object's namespace is set |
|
380 * |
|
381 * @param string $name - programmatic name of a key, in a <key,value> pair in the current namespace |
|
382 * @return bool |
|
383 */ |
|
384 public function __isset($name) |
|
385 { |
|
386 if ($name === '') { |
|
387 /** |
|
388 * @see Zend_Session_Exception |
|
389 */ |
|
390 require_once 'Zend/Session/Exception.php'; |
|
391 throw new Zend_Session_Exception("The '$name' key must be a non-empty string"); |
|
392 } |
|
393 |
|
394 return parent::_namespaceIsset($this->_namespace, $name); |
|
395 } |
|
396 |
|
397 |
|
398 /** |
|
399 * __unset() - unset a variable in this object's namespace. |
|
400 * |
|
401 * @param string $name - programmatic name of a key, in a <key,value> pair in the current namespace |
|
402 * @return true |
|
403 */ |
|
404 public function __unset($name) |
|
405 { |
|
406 if ($name === '') { |
|
407 /** |
|
408 * @see Zend_Session_Exception |
|
409 */ |
|
410 require_once 'Zend/Session/Exception.php'; |
|
411 throw new Zend_Session_Exception("The '$name' key must be a non-empty string"); |
|
412 } |
|
413 |
|
414 return parent::_namespaceUnset($this->_namespace, $name); |
|
415 } |
|
416 |
|
417 |
|
418 /** |
|
419 * setExpirationSeconds() - expire the namespace, or specific variables after a specified |
|
420 * number of seconds |
|
421 * |
|
422 * @param int $seconds - expires in this many seconds |
|
423 * @param mixed $variables - OPTIONAL list of variables to expire (defaults to all) |
|
424 * @throws Zend_Session_Exception |
|
425 * @return void |
|
426 */ |
|
427 public function setExpirationSeconds($seconds, $variables = null) |
|
428 { |
|
429 if (parent::$_writable === false) { |
|
430 /** |
|
431 * @see Zend_Session_Exception |
|
432 */ |
|
433 require_once 'Zend/Session/Exception.php'; |
|
434 throw new Zend_Session_Exception(parent::_THROW_NOT_WRITABLE_MSG); |
|
435 } |
|
436 |
|
437 if ($seconds <= 0) { |
|
438 /** |
|
439 * @see Zend_Session_Exception |
|
440 */ |
|
441 require_once 'Zend/Session/Exception.php'; |
|
442 throw new Zend_Session_Exception('Seconds must be positive.'); |
|
443 } |
|
444 |
|
445 if ($variables === null) { |
|
446 |
|
447 // apply expiration to entire namespace |
|
448 $_SESSION['__ZF'][$this->_namespace]['ENT'] = time() + $seconds; |
|
449 |
|
450 } else { |
|
451 |
|
452 if (is_string($variables)) { |
|
453 $variables = array($variables); |
|
454 } |
|
455 |
|
456 foreach ($variables as $variable) { |
|
457 if (!empty($variable)) { |
|
458 $_SESSION['__ZF'][$this->_namespace]['ENVT'][$variable] = time() + $seconds; |
|
459 } |
|
460 } |
|
461 } |
|
462 } |
|
463 |
|
464 |
|
465 /** |
|
466 * setExpirationHops() - expire the namespace, or specific variables after a specified |
|
467 * number of page hops |
|
468 * |
|
469 * @param int $hops - how many "hops" (number of subsequent requests) before expiring |
|
470 * @param mixed $variables - OPTIONAL list of variables to expire (defaults to all) |
|
471 * @param boolean $hopCountOnUsageOnly - OPTIONAL if set, only count a hop/request if this namespace is used |
|
472 * @throws Zend_Session_Exception |
|
473 * @return void |
|
474 */ |
|
475 public function setExpirationHops($hops, $variables = null, $hopCountOnUsageOnly = false) |
|
476 { |
|
477 if (parent::$_writable === false) { |
|
478 /** |
|
479 * @see Zend_Session_Exception |
|
480 */ |
|
481 require_once 'Zend/Session/Exception.php'; |
|
482 throw new Zend_Session_Exception(parent::_THROW_NOT_WRITABLE_MSG); |
|
483 } |
|
484 |
|
485 if ($hops <= 0) { |
|
486 /** |
|
487 * @see Zend_Session_Exception |
|
488 */ |
|
489 require_once 'Zend/Session/Exception.php'; |
|
490 throw new Zend_Session_Exception('Hops must be positive number.'); |
|
491 } |
|
492 |
|
493 if ($variables === null) { |
|
494 |
|
495 // apply expiration to entire namespace |
|
496 if ($hopCountOnUsageOnly === false) { |
|
497 $_SESSION['__ZF'][$this->_namespace]['ENGH'] = $hops; |
|
498 } else { |
|
499 $_SESSION['__ZF'][$this->_namespace]['ENNH'] = $hops; |
|
500 } |
|
501 |
|
502 } else { |
|
503 |
|
504 if (is_string($variables)) { |
|
505 $variables = array($variables); |
|
506 } |
|
507 |
|
508 foreach ($variables as $variable) { |
|
509 if (!empty($variable)) { |
|
510 if ($hopCountOnUsageOnly === false) { |
|
511 $_SESSION['__ZF'][$this->_namespace]['ENVGH'][$variable] = $hops; |
|
512 } else { |
|
513 $_SESSION['__ZF'][$this->_namespace]['ENVNH'][$variable] = $hops; |
|
514 } |
|
515 } |
|
516 } |
|
517 } |
|
518 } |
|
519 |
|
520 /** |
|
521 * Returns the namespace name |
|
522 * |
|
523 * @return string |
|
524 */ |
|
525 public function getNamespace() |
|
526 { |
|
527 return $this->_namespace; |
|
528 } |
|
529 } |