web/lib/Zend/Session/Namespace.php
changeset 64 162c1de6545a
parent 19 1c2f13fd785c
child 68 ecaf28ffe26e
equal deleted inserted replaced
63:5b37998e522e 64:162c1de6545a
       
     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 }