web/lib/Zend/Session/SaveHandler/DbTable.php
changeset 64 162c1de6545a
parent 19 1c2f13fd785c
child 68 ecaf28ffe26e
equal deleted inserted replaced
63:5b37998e522e 64:162c1de6545a
       
     1 <?php
       
     2 
       
     3 /**
       
     4  * Zend Framework
       
     5  *
       
     6  * LICENSE
       
     7  *
       
     8  * This source file is subject to the new BSD license that is bundled
       
     9  * with this package in the file LICENSE.txt.
       
    10  * It is also available through the world-wide-webat this URL:
       
    11  * http://framework.zend.com/license/new-bsd
       
    12  * If you did not receive a copy of the license and are unable to
       
    13  * obtain it through the world-wide-web, please send an email
       
    14  * to license@zend.com so we can send you a copy immediately.
       
    15  *
       
    16  * @category   Zend
       
    17  * @package    Zend_Session
       
    18  * @copyright  Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
       
    19  * @license    http://framework.zend.com/license/new-bsd     New BSD License
       
    20  * @version    $Id: DbTable.php 20096 2010-01-06 02:05:09Z bkarwin $
       
    21  */
       
    22 
       
    23 /**
       
    24  * @see Zend_Session
       
    25  */
       
    26 require_once 'Zend/Session.php';
       
    27 
       
    28 /**
       
    29  * @see Zend_Db_Table_Abstract
       
    30  */
       
    31 require_once 'Zend/Db/Table/Abstract.php';
       
    32 
       
    33 /**
       
    34  * @see Zend_Db_Table_Row_Abstract
       
    35  */
       
    36 require_once 'Zend/Db/Table/Row/Abstract.php';
       
    37 
       
    38 /**
       
    39  * @see Zend_Config
       
    40  */
       
    41 require_once 'Zend/Config.php';
       
    42 
       
    43 /**
       
    44  * Zend_Session_SaveHandler_DbTable
       
    45  *
       
    46  * @category   Zend
       
    47  * @package    Zend_Session
       
    48  * @subpackage SaveHandler
       
    49  * @copyright  Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
       
    50  * @license    http://framework.zend.com/license/new-bsd     New BSD License
       
    51  */
       
    52 class Zend_Session_SaveHandler_DbTable
       
    53     extends Zend_Db_Table_Abstract
       
    54     implements Zend_Session_SaveHandler_Interface
       
    55 {
       
    56     const PRIMARY_ASSIGNMENT                   = 'primaryAssignment';
       
    57     const PRIMARY_ASSIGNMENT_SESSION_SAVE_PATH = 'sessionSavePath';
       
    58     const PRIMARY_ASSIGNMENT_SESSION_NAME      = 'sessionName';
       
    59     const PRIMARY_ASSIGNMENT_SESSION_ID        = 'sessionId';
       
    60 
       
    61     const MODIFIED_COLUMN   = 'modifiedColumn';
       
    62     const LIFETIME_COLUMN   = 'lifetimeColumn';
       
    63     const DATA_COLUMN       = 'dataColumn';
       
    64 
       
    65     const LIFETIME          = 'lifetime';
       
    66     const OVERRIDE_LIFETIME = 'overrideLifetime';
       
    67 
       
    68     const PRIMARY_TYPE_NUM         = 'PRIMARY_TYPE_NUM';
       
    69     const PRIMARY_TYPE_PRIMARYNUM  = 'PRIMARY_TYPE_PRIMARYNUM';
       
    70     const PRIMARY_TYPE_ASSOC       = 'PRIMARY_TYPE_ASSOC';
       
    71     const PRIMARY_TYPE_WHERECLAUSE = 'PRIMARY_TYPE_WHERECLAUSE';
       
    72 
       
    73     /**
       
    74      * Session table primary key value assignment
       
    75      *
       
    76      * @var array
       
    77      */
       
    78     protected $_primaryAssignment = null;
       
    79 
       
    80     /**
       
    81      * Session table last modification time column
       
    82      *
       
    83      * @var string
       
    84      */
       
    85     protected $_modifiedColumn = null;
       
    86 
       
    87     /**
       
    88      * Session table lifetime column
       
    89      *
       
    90      * @var string
       
    91      */
       
    92     protected $_lifetimeColumn = null;
       
    93 
       
    94     /**
       
    95      * Session table data column
       
    96      *
       
    97      * @var string
       
    98      */
       
    99     protected $_dataColumn = null;
       
   100 
       
   101     /**
       
   102      * Session lifetime
       
   103      *
       
   104      * @var int
       
   105      */
       
   106     protected $_lifetime = false;
       
   107 
       
   108     /**
       
   109      * Whether or not the lifetime of an existing session should be overridden
       
   110      *
       
   111      * @var boolean
       
   112      */
       
   113     protected $_overrideLifetime = false;
       
   114 
       
   115     /**
       
   116      * Session save path
       
   117      *
       
   118      * @var string
       
   119      */
       
   120     protected $_sessionSavePath;
       
   121 
       
   122     /**
       
   123      * Session name
       
   124      *
       
   125      * @var string
       
   126      */
       
   127     protected $_sessionName;
       
   128 
       
   129     /**
       
   130      * Constructor
       
   131      *
       
   132      * $config is an instance of Zend_Config or an array of key/value pairs containing configuration options for
       
   133      * Zend_Session_SaveHandler_DbTable and Zend_Db_Table_Abstract. These are the configuration options for
       
   134      * Zend_Session_SaveHandler_DbTable:
       
   135      *
       
   136      * primaryAssignment => (string|array) Session table primary key value assignment
       
   137      *      (optional; default: 1 => sessionId) You have to assign a value to each primary key of your session table.
       
   138      *      The value of this configuration option is either a string if you have only one primary key or an array if
       
   139      *      you have multiple primary keys. The array consists of numeric keys starting at 1 and string values. There
       
   140      *      are some values which will be replaced by session information:
       
   141      *
       
   142      *      sessionId       => The id of the current session
       
   143      *      sessionName     => The name of the current session
       
   144      *      sessionSavePath => The save path of the current session
       
   145      *
       
   146      *      NOTE: One of your assignments MUST contain 'sessionId' as value!
       
   147      *
       
   148      * modifiedColumn    => (string) Session table last modification time column
       
   149      *
       
   150      * lifetimeColumn    => (string) Session table lifetime column
       
   151      *
       
   152      * dataColumn        => (string) Session table data column
       
   153      *
       
   154      * lifetime          => (integer) Session lifetime (optional; default: ini_get('session.gc_maxlifetime'))
       
   155      *
       
   156      * overrideLifetime  => (boolean) Whether or not the lifetime of an existing session should be overridden
       
   157      *      (optional; default: false)
       
   158      *
       
   159      * @param  Zend_Config|array $config      User-provided configuration
       
   160      * @return void
       
   161      * @throws Zend_Session_SaveHandler_Exception
       
   162      */
       
   163     public function __construct($config)
       
   164     {
       
   165         if ($config instanceof Zend_Config) {
       
   166             $config = $config->toArray();
       
   167         } else if (!is_array($config)) {
       
   168             /**
       
   169              * @see Zend_Session_SaveHandler_Exception
       
   170              */
       
   171             require_once 'Zend/Session/SaveHandler/Exception.php';
       
   172 
       
   173             throw new Zend_Session_SaveHandler_Exception(
       
   174                 '$config must be an instance of Zend_Config or array of key/value pairs containing '
       
   175               . 'configuration options for Zend_Session_SaveHandler_DbTable and Zend_Db_Table_Abstract.');
       
   176         }
       
   177 
       
   178         foreach ($config as $key => $value) {
       
   179             do {
       
   180                 switch ($key) {
       
   181                     case self::PRIMARY_ASSIGNMENT:
       
   182                         $this->_primaryAssignment = $value;
       
   183                         break;
       
   184                     case self::MODIFIED_COLUMN:
       
   185                         $this->_modifiedColumn = (string) $value;
       
   186                         break;
       
   187                     case self::LIFETIME_COLUMN:
       
   188                         $this->_lifetimeColumn = (string) $value;
       
   189                         break;
       
   190                     case self::DATA_COLUMN:
       
   191                         $this->_dataColumn = (string) $value;
       
   192                         break;
       
   193                     case self::LIFETIME:
       
   194                         $this->setLifetime($value);
       
   195                         break;
       
   196                     case self::OVERRIDE_LIFETIME:
       
   197                         $this->setOverrideLifetime($value);
       
   198                         break;
       
   199                     default:
       
   200                         // unrecognized options passed to parent::__construct()
       
   201                         break 2;
       
   202                 }
       
   203                 unset($config[$key]);
       
   204             } while (false);
       
   205         }
       
   206 
       
   207         parent::__construct($config);
       
   208     }
       
   209 
       
   210     /**
       
   211      * Destructor
       
   212      *
       
   213      * @return void
       
   214      */
       
   215     public function __destruct()
       
   216     {
       
   217         Zend_Session::writeClose();
       
   218     }
       
   219 
       
   220     /**
       
   221      * Set session lifetime and optional whether or not the lifetime of an existing session should be overridden
       
   222      *
       
   223      * $lifetime === false resets lifetime to session.gc_maxlifetime
       
   224      *
       
   225      * @param int $lifetime
       
   226      * @param boolean $overrideLifetime (optional)
       
   227      * @return Zend_Session_SaveHandler_DbTable
       
   228      */
       
   229     public function setLifetime($lifetime, $overrideLifetime = null)
       
   230     {
       
   231         if ($lifetime < 0) {
       
   232             /**
       
   233              * @see Zend_Session_SaveHandler_Exception
       
   234              */
       
   235             require_once 'Zend/Session/SaveHandler/Exception.php';
       
   236             throw new Zend_Session_SaveHandler_Exception();
       
   237         } else if (empty($lifetime)) {
       
   238             $this->_lifetime = (int) ini_get('session.gc_maxlifetime');
       
   239         } else {
       
   240             $this->_lifetime = (int) $lifetime;
       
   241         }
       
   242 
       
   243         if ($overrideLifetime != null) {
       
   244             $this->setOverrideLifetime($overrideLifetime);
       
   245         }
       
   246 
       
   247         return $this;
       
   248     }
       
   249 
       
   250     /**
       
   251      * Retrieve session lifetime
       
   252      *
       
   253      * @return int
       
   254      */
       
   255     public function getLifetime()
       
   256     {
       
   257         return $this->_lifetime;
       
   258     }
       
   259 
       
   260     /**
       
   261      * Set whether or not the lifetime of an existing session should be overridden
       
   262      *
       
   263      * @param boolean $overrideLifetime
       
   264      * @return Zend_Session_SaveHandler_DbTable
       
   265      */
       
   266     public function setOverrideLifetime($overrideLifetime)
       
   267     {
       
   268         $this->_overrideLifetime = (boolean) $overrideLifetime;
       
   269 
       
   270         return $this;
       
   271     }
       
   272 
       
   273     /**
       
   274      * Retrieve whether or not the lifetime of an existing session should be overridden
       
   275      *
       
   276      * @return boolean
       
   277      */
       
   278     public function getOverrideLifetime()
       
   279     {
       
   280         return $this->_overrideLifetime;
       
   281     }
       
   282 
       
   283     /**
       
   284      * Open Session
       
   285      *
       
   286      * @param string $save_path
       
   287      * @param string $name
       
   288      * @return boolean
       
   289      */
       
   290     public function open($save_path, $name)
       
   291     {
       
   292         $this->_sessionSavePath = $save_path;
       
   293         $this->_sessionName     = $name;
       
   294 
       
   295         return true;
       
   296     }
       
   297 
       
   298     /**
       
   299      * Close session
       
   300      *
       
   301      * @return boolean
       
   302      */
       
   303     public function close()
       
   304     {
       
   305         return true;
       
   306     }
       
   307 
       
   308     /**
       
   309      * Read session data
       
   310      *
       
   311      * @param string $id
       
   312      * @return string
       
   313      */
       
   314     public function read($id)
       
   315     {
       
   316         $return = '';
       
   317 
       
   318         $rows = call_user_func_array(array(&$this, 'find'), $this->_getPrimary($id));
       
   319 
       
   320         if (count($rows)) {
       
   321             if ($this->_getExpirationTime($row = $rows->current()) > time()) {
       
   322                 $return = $row->{$this->_dataColumn};
       
   323             } else {
       
   324                 $this->destroy($id);
       
   325             }
       
   326         }
       
   327 
       
   328         return $return;
       
   329     }
       
   330 
       
   331     /**
       
   332      * Write session data
       
   333      *
       
   334      * @param string $id
       
   335      * @param string $data
       
   336      * @return boolean
       
   337      */
       
   338     public function write($id, $data)
       
   339     {
       
   340         $return = false;
       
   341 
       
   342         $data = array($this->_modifiedColumn => time(),
       
   343                       $this->_dataColumn     => (string) $data);
       
   344 
       
   345         $rows = call_user_func_array(array(&$this, 'find'), $this->_getPrimary($id));
       
   346 
       
   347         if (count($rows)) {
       
   348             $data[$this->_lifetimeColumn] = $this->_getLifetime($rows->current());
       
   349 
       
   350             if ($this->update($data, $this->_getPrimary($id, self::PRIMARY_TYPE_WHERECLAUSE))) {
       
   351                 $return = true;
       
   352             }
       
   353         } else {
       
   354             $data[$this->_lifetimeColumn] = $this->_lifetime;
       
   355 
       
   356             if ($this->insert(array_merge($this->_getPrimary($id, self::PRIMARY_TYPE_ASSOC), $data))) {
       
   357                 $return = true;
       
   358             }
       
   359         }
       
   360 
       
   361         return $return;
       
   362     }
       
   363 
       
   364     /**
       
   365      * Destroy session
       
   366      *
       
   367      * @param string $id
       
   368      * @return boolean
       
   369      */
       
   370     public function destroy($id)
       
   371     {
       
   372         $return = false;
       
   373 
       
   374         if ($this->delete($this->_getPrimary($id, self::PRIMARY_TYPE_WHERECLAUSE))) {
       
   375             $return = true;
       
   376         }
       
   377 
       
   378         return $return;
       
   379     }
       
   380 
       
   381     /**
       
   382      * Garbage Collection
       
   383      *
       
   384      * @param int $maxlifetime
       
   385      * @return true
       
   386      */
       
   387     public function gc($maxlifetime)
       
   388     {
       
   389         $this->delete($this->getAdapter()->quoteIdentifier($this->_modifiedColumn) . ' + '
       
   390                     . $this->getAdapter()->quoteIdentifier($this->_lifetimeColumn) . ' < '
       
   391                     . $this->getAdapter()->quote(time()));
       
   392 
       
   393         return true;
       
   394     }
       
   395 
       
   396     /**
       
   397      * Calls other protected methods for individual setup tasks and requirement checks
       
   398      *
       
   399      * @return void
       
   400      */
       
   401     protected function _setup()
       
   402     {
       
   403         parent::_setup();
       
   404 
       
   405         $this->_setupPrimaryAssignment();
       
   406         $this->setLifetime($this->_lifetime);
       
   407 
       
   408         $this->_checkRequiredColumns();
       
   409     }
       
   410 
       
   411     /**
       
   412      * Initialize table and schema names
       
   413      *
       
   414      * @return void
       
   415      * @throws Zend_Session_SaveHandler_Exception
       
   416      */
       
   417     protected function _setupTableName()
       
   418     {
       
   419         if (empty($this->_name) && basename(($this->_name = session_save_path())) != $this->_name) {
       
   420             /**
       
   421              * @see Zend_Session_SaveHandler_Exception
       
   422              */
       
   423             require_once 'Zend/Session/SaveHandler/Exception.php';
       
   424 
       
   425             throw new Zend_Session_SaveHandler_Exception('session.save_path is a path and not a table name.');
       
   426         }
       
   427 
       
   428         if (strpos($this->_name, '.')) {
       
   429             list($this->_schema, $this->_name) = explode('.', $this->_name);
       
   430         }
       
   431     }
       
   432 
       
   433     /**
       
   434      * Initialize session table primary key value assignment
       
   435      *
       
   436      * @return void
       
   437      * @throws Zend_Session_SaveHandler_Exception
       
   438      */
       
   439     protected function _setupPrimaryAssignment()
       
   440     {
       
   441         if ($this->_primaryAssignment === null) {
       
   442             $this->_primaryAssignment = array(1 => self::PRIMARY_ASSIGNMENT_SESSION_ID);
       
   443         } else if (!is_array($this->_primaryAssignment)) {
       
   444             $this->_primaryAssignment = array(1 => (string) $this->_primaryAssignment);
       
   445         } else if (isset($this->_primaryAssignment[0])) {
       
   446             array_unshift($this->_primaryAssignment, null);
       
   447 
       
   448             unset($this->_primaryAssignment[0]);
       
   449         }
       
   450 
       
   451         if (count($this->_primaryAssignment) !== count($this->_primary)) {
       
   452             /**
       
   453              * @see Zend_Session_SaveHandler_Exception
       
   454              */
       
   455             require_once 'Zend/Session/SaveHandler/Exception.php';
       
   456 
       
   457             throw new Zend_Session_SaveHandler_Exception(
       
   458                 "Value for configuration option '" . self::PRIMARY_ASSIGNMENT . "' must have an assignment "
       
   459               . "for each session table primary key.");
       
   460         } else if (!in_array(self::PRIMARY_ASSIGNMENT_SESSION_ID, $this->_primaryAssignment)) {
       
   461             /**
       
   462              * @see Zend_Session_SaveHandler_Exception
       
   463              */
       
   464             require_once 'Zend/Session/SaveHandler/Exception.php';
       
   465 
       
   466             throw new Zend_Session_SaveHandler_Exception(
       
   467                 "Value for configuration option '" . self::PRIMARY_ASSIGNMENT . "' must have an assignment "
       
   468               . "for the session id ('" . self::PRIMARY_ASSIGNMENT_SESSION_ID . "').");
       
   469         }
       
   470     }
       
   471 
       
   472     /**
       
   473      * Check for required session table columns
       
   474      *
       
   475      * @return void
       
   476      * @throws Zend_Session_SaveHandler_Exception
       
   477      */
       
   478     protected function _checkRequiredColumns()
       
   479     {
       
   480         if ($this->_modifiedColumn === null) {
       
   481             /**
       
   482              * @see Zend_Session_SaveHandler_Exception
       
   483              */
       
   484             require_once 'Zend/Session/SaveHandler/Exception.php';
       
   485 
       
   486             throw new Zend_Session_SaveHandler_Exception(
       
   487                 "Configuration must define '" . self::MODIFIED_COLUMN . "' which names the "
       
   488               . "session table last modification time column.");
       
   489         } else if ($this->_lifetimeColumn === null) {
       
   490             /**
       
   491              * @see Zend_Session_SaveHandler_Exception
       
   492              */
       
   493             require_once 'Zend/Session/SaveHandler/Exception.php';
       
   494 
       
   495             throw new Zend_Session_SaveHandler_Exception(
       
   496                 "Configuration must define '" . self::LIFETIME_COLUMN . "' which names the "
       
   497               . "session table lifetime column.");
       
   498         } else if ($this->_dataColumn === null) {
       
   499             /**
       
   500              * @see Zend_Session_SaveHandler_Exception
       
   501              */
       
   502             require_once 'Zend/Session/SaveHandler/Exception.php';
       
   503 
       
   504             throw new Zend_Session_SaveHandler_Exception(
       
   505                 "Configuration must define '" . self::DATA_COLUMN . "' which names the "
       
   506               . "session table data column.");
       
   507         }
       
   508     }
       
   509 
       
   510     /**
       
   511      * Retrieve session table primary key values
       
   512      *
       
   513      * @param string $id
       
   514      * @param string $type (optional; default: self::PRIMARY_TYPE_NUM)
       
   515      * @return array
       
   516      */
       
   517     protected function _getPrimary($id, $type = null)
       
   518     {
       
   519         $this->_setupPrimaryKey();
       
   520 
       
   521         if ($type === null) {
       
   522             $type = self::PRIMARY_TYPE_NUM;
       
   523         }
       
   524 
       
   525         $primaryArray = array();
       
   526 
       
   527         foreach ($this->_primary as $index => $primary) {
       
   528             switch ($this->_primaryAssignment[$index]) {
       
   529                 case self::PRIMARY_ASSIGNMENT_SESSION_SAVE_PATH:
       
   530                     $value = $this->_sessionSavePath;
       
   531                     break;
       
   532                 case self::PRIMARY_ASSIGNMENT_SESSION_NAME:
       
   533                     $value = $this->_sessionName;
       
   534                     break;
       
   535                 case self::PRIMARY_ASSIGNMENT_SESSION_ID:
       
   536                     $value = (string) $id;
       
   537                     break;
       
   538                 default:
       
   539                     $value = (string) $this->_primaryAssignment[$index];
       
   540                     break;
       
   541             }
       
   542 
       
   543             switch ((string) $type) {
       
   544                 case self::PRIMARY_TYPE_PRIMARYNUM:
       
   545                     $primaryArray[$index] = $value;
       
   546                     break;
       
   547                 case self::PRIMARY_TYPE_ASSOC:
       
   548                     $primaryArray[$primary] = $value;
       
   549                     break;
       
   550                 case self::PRIMARY_TYPE_WHERECLAUSE:
       
   551                     $primaryArray[] = $this->getAdapter()->quoteIdentifier($primary) . ' = '
       
   552                                     . $this->getAdapter()->quote($value);
       
   553                     break;
       
   554                 case self::PRIMARY_TYPE_NUM:
       
   555                 default:
       
   556                     $primaryArray[] = $value;
       
   557                     break;
       
   558             }
       
   559         }
       
   560 
       
   561         return $primaryArray;
       
   562     }
       
   563 
       
   564     /**
       
   565      * Retrieve session lifetime considering Zend_Session_SaveHandler_DbTable::OVERRIDE_LIFETIME
       
   566      *
       
   567      * @param Zend_Db_Table_Row_Abstract $row
       
   568      * @return int
       
   569      */
       
   570     protected function _getLifetime(Zend_Db_Table_Row_Abstract $row)
       
   571     {
       
   572         $return = $this->_lifetime;
       
   573 
       
   574         if (!$this->_overrideLifetime) {
       
   575             $return = (int) $row->{$this->_lifetimeColumn};
       
   576         }
       
   577 
       
   578         return $return;
       
   579     }
       
   580 
       
   581     /**
       
   582      * Retrieve session expiration time
       
   583      *
       
   584      * @param Zend_Db_Table_Row_Abstract $row
       
   585      * @return int
       
   586      */
       
   587     protected function _getExpirationTime(Zend_Db_Table_Row_Abstract $row)
       
   588     {
       
   589         return (int) $row->{$this->_modifiedColumn} + $this->_getLifetime($row);
       
   590     }
       
   591 }