File indexing completed on 2024-12-22 05:37:06
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_Session 0017 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) 0018 * @license http://framework.zend.com/license/new-bsd New BSD License 0019 * @version $Id$ 0020 * @since Preview Release 0.2 0021 */ 0022 0023 0024 /** 0025 * @see Zend_Session 0026 */ 0027 // require_once 'Zend/Session.php'; 0028 0029 0030 /** 0031 * @see Zend_Session_Abstract 0032 */ 0033 // require_once 'Zend/Session/Abstract.php'; 0034 0035 0036 /** 0037 * Zend_Session_Namespace 0038 * 0039 * @category Zend 0040 * @package Zend_Session 0041 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) 0042 * @license http://framework.zend.com/license/new-bsd New BSD License 0043 */ 0044 class Zend_Session_Namespace extends Zend_Session_Abstract implements IteratorAggregate 0045 { 0046 0047 /** 0048 * used as option to constructor to prevent additional instances to the same namespace 0049 */ 0050 const SINGLE_INSTANCE = true; 0051 0052 /** 0053 * Namespace - which namespace this instance of zend-session is saving-to/getting-from 0054 * 0055 * @var string 0056 */ 0057 protected $_namespace = "Default"; 0058 0059 /** 0060 * Namespace locking mechanism 0061 * 0062 * @var array 0063 */ 0064 protected static $_namespaceLocks = array(); 0065 0066 /** 0067 * Single instance namespace array to ensure data security. 0068 * 0069 * @var array 0070 */ 0071 protected static $_singleInstances = array(); 0072 0073 /** 0074 * resetSingleInstance() 0075 * 0076 * @param string $namespaceName 0077 * @return null 0078 */ 0079 public static function resetSingleInstance($namespaceName = null) 0080 { 0081 if ($namespaceName != null) { 0082 if (array_key_exists($namespaceName, self::$_singleInstances)) { 0083 unset(self::$_singleInstances[$namespaceName]); 0084 } 0085 return; 0086 } 0087 0088 self::$_singleInstances = array(); 0089 return; 0090 } 0091 0092 /** 0093 * __construct() - Returns an instance object bound to a particular, isolated section 0094 * of the session, identified by $namespace name (defaulting to 'Default'). 0095 * The optional argument $singleInstance will prevent construction of additional 0096 * instance objects acting as accessors to this $namespace. 0097 * 0098 * @param string $namespace - programmatic name of the requested namespace 0099 * @param bool $singleInstance - prevent creation of additional accessor instance objects for this namespace 0100 * @return void 0101 */ 0102 public function __construct($namespace = 'Default', $singleInstance = false) 0103 { 0104 if ($namespace === '') { 0105 /** 0106 * @see Zend_Session_Exception 0107 */ 0108 // require_once 'Zend/Session/Exception.php'; 0109 throw new Zend_Session_Exception('Session namespace must be a non-empty string.'); 0110 } 0111 0112 if ($namespace[0] == "_") { 0113 /** 0114 * @see Zend_Session_Exception 0115 */ 0116 // require_once 'Zend/Session/Exception.php'; 0117 throw new Zend_Session_Exception('Session namespace must not start with an underscore.'); 0118 } 0119 0120 if (preg_match('#(^[0-9])#i', $namespace[0])) { 0121 /** 0122 * @see Zend_Session_Exception 0123 */ 0124 // require_once 'Zend/Session/Exception.php'; 0125 throw new Zend_Session_Exception('Session namespace must not start with a number.'); 0126 } 0127 0128 if (isset(self::$_singleInstances[$namespace])) { 0129 /** 0130 * @see Zend_Session_Exception 0131 */ 0132 // require_once 'Zend/Session/Exception.php'; 0133 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."); 0134 } 0135 0136 if ($singleInstance === true) { 0137 self::$_singleInstances[$namespace] = true; 0138 } 0139 0140 $this->_namespace = $namespace; 0141 0142 // Process metadata specific only to this namespace. 0143 Zend_Session::start(true); // attempt auto-start (throws exception if strict option set) 0144 0145 if (self::$_readable === false) { 0146 /** 0147 * @see Zend_Session_Exception 0148 */ 0149 // require_once 'Zend/Session/Exception.php'; 0150 throw new Zend_Session_Exception(self::_THROW_NOT_READABLE_MSG); 0151 } 0152 0153 if (!isset($_SESSION['__ZF'])) { 0154 return; // no further processing needed 0155 } 0156 0157 // do not allow write access to namespaces, after stop() or writeClose() 0158 if (parent::$_writable === true) { 0159 if (isset($_SESSION['__ZF'][$namespace])) { 0160 0161 // Expire Namespace by Namespace Hop (ENNH) 0162 if (isset($_SESSION['__ZF'][$namespace]['ENNH'])) { 0163 $_SESSION['__ZF'][$namespace]['ENNH']--; 0164 0165 if ($_SESSION['__ZF'][$namespace]['ENNH'] === 0) { 0166 if (isset($_SESSION[$namespace])) { 0167 self::$_expiringData[$namespace] = $_SESSION[$namespace]; 0168 unset($_SESSION[$namespace]); 0169 } 0170 unset($_SESSION['__ZF'][$namespace]); 0171 } 0172 } 0173 0174 // Expire Namespace Variables by Namespace Hop (ENVNH) 0175 if (isset($_SESSION['__ZF'][$namespace]['ENVNH'])) { 0176 foreach ($_SESSION['__ZF'][$namespace]['ENVNH'] as $variable => $hops) { 0177 $_SESSION['__ZF'][$namespace]['ENVNH'][$variable]--; 0178 0179 if ($_SESSION['__ZF'][$namespace]['ENVNH'][$variable] === 0) { 0180 if (isset($_SESSION[$namespace][$variable])) { 0181 self::$_expiringData[$namespace][$variable] = $_SESSION[$namespace][$variable]; 0182 unset($_SESSION[$namespace][$variable]); 0183 } 0184 unset($_SESSION['__ZF'][$namespace]['ENVNH'][$variable]); 0185 } 0186 } 0187 if(empty($_SESSION['__ZF'][$namespace]['ENVNH'])) { 0188 unset($_SESSION['__ZF'][$namespace]['ENVNH']); 0189 } 0190 } 0191 } 0192 0193 if (empty($_SESSION['__ZF'][$namespace])) { 0194 unset($_SESSION['__ZF'][$namespace]); 0195 } 0196 0197 if (empty($_SESSION['__ZF'])) { 0198 unset($_SESSION['__ZF']); 0199 } 0200 } 0201 } 0202 0203 0204 /** 0205 * getIterator() - return an iteratable object for use in foreach and the like, 0206 * this completes the IteratorAggregate interface 0207 * 0208 * @return ArrayObject - iteratable container of the namespace contents 0209 */ 0210 public function getIterator() 0211 { 0212 return new ArrayObject(parent::_namespaceGetAll($this->_namespace)); 0213 } 0214 0215 0216 /** 0217 * lock() - mark a session/namespace as readonly 0218 * 0219 * @return void 0220 */ 0221 public function lock() 0222 { 0223 self::$_namespaceLocks[$this->_namespace] = true; 0224 } 0225 0226 0227 /** 0228 * unlock() - unmark a session/namespace to enable read & write 0229 * 0230 * @return void 0231 */ 0232 public function unlock() 0233 { 0234 unset(self::$_namespaceLocks[$this->_namespace]); 0235 } 0236 0237 0238 /** 0239 * unlockAll() - unmark all session/namespaces to enable read & write 0240 * 0241 * @return void 0242 */ 0243 public static function unlockAll() 0244 { 0245 self::$_namespaceLocks = array(); 0246 } 0247 0248 0249 /** 0250 * isLocked() - return lock status, true if, and only if, read-only 0251 * 0252 * @return bool 0253 */ 0254 public function isLocked() 0255 { 0256 return isset(self::$_namespaceLocks[$this->_namespace]); 0257 } 0258 0259 0260 /** 0261 * unsetAll() - unset all variables in this namespace 0262 * 0263 * @return true 0264 */ 0265 public function unsetAll() 0266 { 0267 return parent::_namespaceUnset($this->_namespace); 0268 } 0269 0270 0271 /** 0272 * __get() - method to get a variable in this object's current namespace 0273 * 0274 * @param string $name - programmatic name of a key, in a <key,value> pair in the current namespace 0275 * @return mixed 0276 */ 0277 public function & __get($name) 0278 { 0279 if ($name === '') { 0280 /** 0281 * @see Zend_Session_Exception 0282 */ 0283 // require_once 'Zend/Session/Exception.php'; 0284 throw new Zend_Session_Exception("The '$name' key must be a non-empty string"); 0285 } 0286 0287 return parent::_namespaceGet($this->_namespace, $name); 0288 } 0289 0290 0291 /** 0292 * __set() - method to set a variable/value in this object's namespace 0293 * 0294 * @param string $name - programmatic name of a key, in a <key,value> pair in the current namespace 0295 * @param mixed $value - value in the <key,value> pair to assign to the $name key 0296 * @throws Zend_Session_Exception 0297 * @return true 0298 */ 0299 public function __set($name, $value) 0300 { 0301 if (isset(self::$_namespaceLocks[$this->_namespace])) { 0302 /** 0303 * @see Zend_Session_Exception 0304 */ 0305 // require_once 'Zend/Session/Exception.php'; 0306 throw new Zend_Session_Exception('This session/namespace has been marked as read-only.'); 0307 } 0308 0309 if ($name === '') { 0310 /** 0311 * @see Zend_Session_Exception 0312 */ 0313 // require_once 'Zend/Session/Exception.php'; 0314 throw new Zend_Session_Exception("The '$name' key must be a non-empty string"); 0315 } 0316 0317 if (parent::$_writable === false) { 0318 /** 0319 * @see Zend_Session_Exception 0320 */ 0321 // require_once 'Zend/Session/Exception.php'; 0322 throw new Zend_Session_Exception(parent::_THROW_NOT_WRITABLE_MSG); 0323 } 0324 0325 $name = (string) $name; 0326 0327 $_SESSION[$this->_namespace][$name] = $value; 0328 } 0329 0330 0331 /** 0332 * apply() - enables applying user-selected function, such as array_merge() to the namespace 0333 * Parameters following the $callback argument are passed to the callback function. 0334 * Caveat: ignores members expiring now. 0335 * 0336 * Example: 0337 * $namespace->apply('array_merge', array('tree' => 'apple', 'fruit' => 'peach'), array('flower' => 'rose')); 0338 * $namespace->apply('count'); 0339 * 0340 * @param string|array $callback - callback function 0341 */ 0342 public function apply($callback) 0343 { 0344 $arg_list = func_get_args(); 0345 $arg_list[0] = $_SESSION[$this->_namespace]; 0346 return call_user_func_array($callback, $arg_list); 0347 } 0348 0349 0350 /** 0351 * applySet() - enables applying user-selected function, and sets entire namespace to the result 0352 * Result of $callback must be an array. 0353 * Parameters following the $callback argument are passed to the callback function. 0354 * Caveat: ignores members expiring now. 0355 * 0356 * Example: 0357 * $namespace->applySet('array_merge', array('tree' => 'apple', 'fruit' => 'peach'), array('flower' => 'rose')); 0358 * 0359 * @param string|array $callback - callback function 0360 */ 0361 public function applySet($callback) 0362 { 0363 $arg_list = func_get_args(); 0364 $arg_list[0] = $_SESSION[$this->_namespace]; 0365 $result = call_user_func_array($callback, $arg_list); 0366 if (!is_array($result)) { 0367 /** 0368 * @see Zend_Session_Exception 0369 */ 0370 // require_once 'Zend/Session/Exception.php'; 0371 throw new Zend_Session_Exception('Result must be an array. Got: ' . gettype($result)); 0372 } 0373 $_SESSION[$this->_namespace] = $result; 0374 return $result; 0375 } 0376 0377 0378 /** 0379 * __isset() - determine if a variable in this object's namespace is set 0380 * 0381 * @param string $name - programmatic name of a key, in a <key,value> pair in the current namespace 0382 * @return bool 0383 */ 0384 public function __isset($name) 0385 { 0386 if ($name === '') { 0387 /** 0388 * @see Zend_Session_Exception 0389 */ 0390 // require_once 'Zend/Session/Exception.php'; 0391 throw new Zend_Session_Exception("The '$name' key must be a non-empty string"); 0392 } 0393 0394 return parent::_namespaceIsset($this->_namespace, $name); 0395 } 0396 0397 0398 /** 0399 * __unset() - unset a variable in this object's namespace. 0400 * 0401 * @param string $name - programmatic name of a key, in a <key,value> pair in the current namespace 0402 * @return true 0403 */ 0404 public function __unset($name) 0405 { 0406 if ($name === '') { 0407 /** 0408 * @see Zend_Session_Exception 0409 */ 0410 // require_once 'Zend/Session/Exception.php'; 0411 throw new Zend_Session_Exception("The '$name' key must be a non-empty string"); 0412 } 0413 0414 return parent::_namespaceUnset($this->_namespace, $name); 0415 } 0416 0417 0418 /** 0419 * setExpirationSeconds() - expire the namespace, or specific variables after a specified 0420 * number of seconds 0421 * 0422 * @param int $seconds - expires in this many seconds 0423 * @param mixed $variables - OPTIONAL list of variables to expire (defaults to all) 0424 * @throws Zend_Session_Exception 0425 * @return void 0426 */ 0427 public function setExpirationSeconds($seconds, $variables = null) 0428 { 0429 if (parent::$_writable === false) { 0430 /** 0431 * @see Zend_Session_Exception 0432 */ 0433 // require_once 'Zend/Session/Exception.php'; 0434 throw new Zend_Session_Exception(parent::_THROW_NOT_WRITABLE_MSG); 0435 } 0436 0437 if ($seconds <= 0) { 0438 /** 0439 * @see Zend_Session_Exception 0440 */ 0441 // require_once 'Zend/Session/Exception.php'; 0442 throw new Zend_Session_Exception('Seconds must be positive.'); 0443 } 0444 0445 if ($variables === null) { 0446 0447 // apply expiration to entire namespace 0448 $_SESSION['__ZF'][$this->_namespace]['ENT'] = time() + $seconds; 0449 0450 } else { 0451 0452 if (is_string($variables)) { 0453 $variables = array($variables); 0454 } 0455 0456 foreach ($variables as $variable) { 0457 if (!empty($variable)) { 0458 $_SESSION['__ZF'][$this->_namespace]['ENVT'][$variable] = time() + $seconds; 0459 } 0460 } 0461 } 0462 } 0463 0464 0465 /** 0466 * setExpirationHops() - expire the namespace, or specific variables after a specified 0467 * number of page hops 0468 * 0469 * @param int $hops - how many "hops" (number of subsequent requests) before expiring 0470 * @param mixed $variables - OPTIONAL list of variables to expire (defaults to all) 0471 * @param boolean $hopCountOnUsageOnly - OPTIONAL if set, only count a hop/request if this namespace is used 0472 * @throws Zend_Session_Exception 0473 * @return void 0474 */ 0475 public function setExpirationHops($hops, $variables = null, $hopCountOnUsageOnly = false) 0476 { 0477 if (parent::$_writable === false) { 0478 /** 0479 * @see Zend_Session_Exception 0480 */ 0481 // require_once 'Zend/Session/Exception.php'; 0482 throw new Zend_Session_Exception(parent::_THROW_NOT_WRITABLE_MSG); 0483 } 0484 0485 if ($hops <= 0) { 0486 /** 0487 * @see Zend_Session_Exception 0488 */ 0489 // require_once 'Zend/Session/Exception.php'; 0490 throw new Zend_Session_Exception('Hops must be positive number.'); 0491 } 0492 0493 if ($variables === null) { 0494 0495 // apply expiration to entire namespace 0496 if ($hopCountOnUsageOnly === false) { 0497 $_SESSION['__ZF'][$this->_namespace]['ENGH'] = $hops; 0498 } else { 0499 $_SESSION['__ZF'][$this->_namespace]['ENNH'] = $hops; 0500 } 0501 0502 } else { 0503 0504 if (is_string($variables)) { 0505 $variables = array($variables); 0506 } 0507 0508 foreach ($variables as $variable) { 0509 if (!empty($variable)) { 0510 if ($hopCountOnUsageOnly === false) { 0511 $_SESSION['__ZF'][$this->_namespace]['ENVGH'][$variable] = $hops; 0512 } else { 0513 $_SESSION['__ZF'][$this->_namespace]['ENVNH'][$variable] = $hops; 0514 } 0515 } 0516 } 0517 } 0518 } 0519 0520 /** 0521 * Returns the namespace name 0522 * 0523 * @return string 0524 */ 0525 public function getNamespace() 0526 { 0527 return $this->_namespace; 0528 } 0529 }