File indexing completed on 2025-03-02 05:29:51
0001 <?php 0002 0003 /** 0004 * Zend Framework 0005 * 0006 * LICENSE 0007 * 0008 * This source file is subject to the new BSD license that is bundled 0009 * with this package in the file LICENSE.txt. 0010 * It is also available through the world-wide-webat this URL: 0011 * http://framework.zend.com/license/new-bsd 0012 * If you did not receive a copy of the license and are unable to 0013 * obtain it through the world-wide-web, please send an email 0014 * to license@zend.com so we can send you a copy immediately. 0015 * 0016 * @category Zend 0017 * @package Zend_Session 0018 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) 0019 * @license http://framework.zend.com/license/new-bsd New BSD License 0020 * @version $Id$ 0021 */ 0022 0023 /** 0024 * @see Zend_Session 0025 */ 0026 // require_once 'Zend/Session.php'; 0027 0028 /** 0029 * @see Zend_Db_Table_Abstract 0030 */ 0031 // require_once 'Zend/Db/Table/Abstract.php'; 0032 0033 /** 0034 * @see Zend_Db_Table_Row_Abstract 0035 */ 0036 // require_once 'Zend/Db/Table/Row/Abstract.php'; 0037 0038 /** 0039 * @see Zend_Config 0040 */ 0041 // require_once 'Zend/Config.php'; 0042 0043 /** 0044 * Zend_Session_SaveHandler_DbTable 0045 * 0046 * @category Zend 0047 * @package Zend_Session 0048 * @subpackage SaveHandler 0049 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) 0050 * @license http://framework.zend.com/license/new-bsd New BSD License 0051 */ 0052 class Zend_Session_SaveHandler_DbTable 0053 extends Zend_Db_Table_Abstract 0054 implements Zend_Session_SaveHandler_Interface 0055 { 0056 const PRIMARY_ASSIGNMENT = 'primaryAssignment'; 0057 const PRIMARY_ASSIGNMENT_SESSION_SAVE_PATH = 'sessionSavePath'; 0058 const PRIMARY_ASSIGNMENT_SESSION_NAME = 'sessionName'; 0059 const PRIMARY_ASSIGNMENT_SESSION_ID = 'sessionId'; 0060 0061 const MODIFIED_COLUMN = 'modifiedColumn'; 0062 const LIFETIME_COLUMN = 'lifetimeColumn'; 0063 const DATA_COLUMN = 'dataColumn'; 0064 0065 const LIFETIME = 'lifetime'; 0066 const OVERRIDE_LIFETIME = 'overrideLifetime'; 0067 0068 const PRIMARY_TYPE_NUM = 'PRIMARY_TYPE_NUM'; 0069 const PRIMARY_TYPE_PRIMARYNUM = 'PRIMARY_TYPE_PRIMARYNUM'; 0070 const PRIMARY_TYPE_ASSOC = 'PRIMARY_TYPE_ASSOC'; 0071 const PRIMARY_TYPE_WHERECLAUSE = 'PRIMARY_TYPE_WHERECLAUSE'; 0072 0073 /** 0074 * Session table primary key value assignment 0075 * 0076 * @var array 0077 */ 0078 protected $_primaryAssignment = null; 0079 0080 /** 0081 * Session table last modification time column 0082 * 0083 * @var string 0084 */ 0085 protected $_modifiedColumn = null; 0086 0087 /** 0088 * Session table lifetime column 0089 * 0090 * @var string 0091 */ 0092 protected $_lifetimeColumn = null; 0093 0094 /** 0095 * Session table data column 0096 * 0097 * @var string 0098 */ 0099 protected $_dataColumn = null; 0100 0101 /** 0102 * Session lifetime 0103 * 0104 * @var int 0105 */ 0106 protected $_lifetime = false; 0107 0108 /** 0109 * Whether or not the lifetime of an existing session should be overridden 0110 * 0111 * @var boolean 0112 */ 0113 protected $_overrideLifetime = false; 0114 0115 /** 0116 * Session save path 0117 * 0118 * @var string 0119 */ 0120 protected $_sessionSavePath; 0121 0122 /** 0123 * Session name 0124 * 0125 * @var string 0126 */ 0127 protected $_sessionName; 0128 0129 /** 0130 * Constructor 0131 * 0132 * $config is an instance of Zend_Config or an array of key/value pairs containing configuration options for 0133 * Zend_Session_SaveHandler_DbTable and Zend_Db_Table_Abstract. These are the configuration options for 0134 * Zend_Session_SaveHandler_DbTable: 0135 * 0136 * primaryAssignment => (string|array) Session table primary key value assignment 0137 * (optional; default: 1 => sessionId) You have to assign a value to each primary key of your session table. 0138 * The value of this configuration option is either a string if you have only one primary key or an array if 0139 * you have multiple primary keys. The array consists of numeric keys starting at 1 and string values. There 0140 * are some values which will be replaced by session information: 0141 * 0142 * sessionId => The id of the current session 0143 * sessionName => The name of the current session 0144 * sessionSavePath => The save path of the current session 0145 * 0146 * NOTE: One of your assignments MUST contain 'sessionId' as value! 0147 * 0148 * modifiedColumn => (string) Session table last modification time column 0149 * 0150 * lifetimeColumn => (string) Session table lifetime column 0151 * 0152 * dataColumn => (string) Session table data column 0153 * 0154 * lifetime => (integer) Session lifetime (optional; default: ini_get('session.gc_maxlifetime')) 0155 * 0156 * overrideLifetime => (boolean) Whether or not the lifetime of an existing session should be overridden 0157 * (optional; default: false) 0158 * 0159 * @param Zend_Config|array $config User-provided configuration 0160 * @return void 0161 * @throws Zend_Session_SaveHandler_Exception 0162 */ 0163 public function __construct($config) 0164 { 0165 if ($config instanceof Zend_Config) { 0166 $config = $config->toArray(); 0167 } else if (!is_array($config)) { 0168 /** 0169 * @see Zend_Session_SaveHandler_Exception 0170 */ 0171 // require_once 'Zend/Session/SaveHandler/Exception.php'; 0172 0173 throw new Zend_Session_SaveHandler_Exception( 0174 '$config must be an instance of Zend_Config or array of key/value pairs containing ' 0175 . 'configuration options for Zend_Session_SaveHandler_DbTable and Zend_Db_Table_Abstract.'); 0176 } 0177 0178 foreach ($config as $key => $value) { 0179 do { 0180 switch ($key) { 0181 case self::PRIMARY_ASSIGNMENT: 0182 $this->_primaryAssignment = $value; 0183 break; 0184 case self::MODIFIED_COLUMN: 0185 $this->_modifiedColumn = (string) $value; 0186 break; 0187 case self::LIFETIME_COLUMN: 0188 $this->_lifetimeColumn = (string) $value; 0189 break; 0190 case self::DATA_COLUMN: 0191 $this->_dataColumn = (string) $value; 0192 break; 0193 case self::LIFETIME: 0194 $this->setLifetime($value); 0195 break; 0196 case self::OVERRIDE_LIFETIME: 0197 $this->setOverrideLifetime($value); 0198 break; 0199 default: 0200 // unrecognized options passed to parent::__construct() 0201 break 2; 0202 } 0203 unset($config[$key]); 0204 } while (false); 0205 } 0206 0207 parent::__construct($config); 0208 } 0209 0210 /** 0211 * Destructor 0212 * 0213 * @return void 0214 */ 0215 public function __destruct() 0216 { 0217 Zend_Session::writeClose(); 0218 } 0219 0220 /** 0221 * Set session lifetime and optional whether or not the lifetime of an existing session should be overridden 0222 * 0223 * $lifetime === false resets lifetime to session.gc_maxlifetime 0224 * 0225 * @param int $lifetime 0226 * @param boolean $overrideLifetime (optional) 0227 * @return Zend_Session_SaveHandler_DbTable 0228 */ 0229 public function setLifetime($lifetime, $overrideLifetime = null) 0230 { 0231 if ($lifetime < 0) { 0232 /** 0233 * @see Zend_Session_SaveHandler_Exception 0234 */ 0235 // require_once 'Zend/Session/SaveHandler/Exception.php'; 0236 throw new Zend_Session_SaveHandler_Exception(); 0237 } else if (empty($lifetime)) { 0238 $this->_lifetime = (int) ini_get('session.gc_maxlifetime'); 0239 } else { 0240 $this->_lifetime = (int) $lifetime; 0241 } 0242 0243 if ($overrideLifetime != null) { 0244 $this->setOverrideLifetime($overrideLifetime); 0245 } 0246 0247 return $this; 0248 } 0249 0250 /** 0251 * Retrieve session lifetime 0252 * 0253 * @return int 0254 */ 0255 public function getLifetime() 0256 { 0257 return $this->_lifetime; 0258 } 0259 0260 /** 0261 * Set whether or not the lifetime of an existing session should be overridden 0262 * 0263 * @param boolean $overrideLifetime 0264 * @return Zend_Session_SaveHandler_DbTable 0265 */ 0266 public function setOverrideLifetime($overrideLifetime) 0267 { 0268 $this->_overrideLifetime = (boolean) $overrideLifetime; 0269 0270 return $this; 0271 } 0272 0273 /** 0274 * Retrieve whether or not the lifetime of an existing session should be overridden 0275 * 0276 * @return boolean 0277 */ 0278 public function getOverrideLifetime() 0279 { 0280 return $this->_overrideLifetime; 0281 } 0282 0283 /** 0284 * Open Session 0285 * 0286 * @param string $save_path 0287 * @param string $name 0288 * @return boolean 0289 */ 0290 public function open($save_path, $name) 0291 { 0292 $this->_sessionSavePath = $save_path; 0293 $this->_sessionName = $name; 0294 0295 return true; 0296 } 0297 0298 /** 0299 * Close session 0300 * 0301 * @return boolean 0302 */ 0303 public function close() 0304 { 0305 return true; 0306 } 0307 0308 /** 0309 * Read session data 0310 * 0311 * @param string $id 0312 * @return string 0313 */ 0314 public function read($id) 0315 { 0316 $return = ''; 0317 0318 $rows = call_user_func_array(array(&$this, 'find'), $this->_getPrimary($id)); 0319 0320 if (count($rows)) { 0321 if ($this->_getExpirationTime($row = $rows->current()) > time()) { 0322 $return = $row->{$this->_dataColumn}; 0323 } else { 0324 $this->destroy($id); 0325 } 0326 } 0327 0328 return $return; 0329 } 0330 0331 /** 0332 * Write session data 0333 * 0334 * @param string $id 0335 * @param string $data 0336 * @return boolean 0337 */ 0338 public function write($id, $data) 0339 { 0340 $return = false; 0341 0342 $data = array($this->_modifiedColumn => time(), 0343 $this->_dataColumn => (string) $data); 0344 0345 $rows = call_user_func_array(array(&$this, 'find'), $this->_getPrimary($id)); 0346 0347 if (count($rows)) { 0348 $data[$this->_lifetimeColumn] = $this->_getLifetime($rows->current()); 0349 0350 if ($this->update($data, $this->_getPrimary($id, self::PRIMARY_TYPE_WHERECLAUSE))) { 0351 $return = true; 0352 } 0353 } else { 0354 $data[$this->_lifetimeColumn] = $this->_lifetime; 0355 0356 if ($this->insert(array_merge($this->_getPrimary($id, self::PRIMARY_TYPE_ASSOC), $data))) { 0357 $return = true; 0358 } 0359 } 0360 0361 return $return; 0362 } 0363 0364 /** 0365 * Destroy session 0366 * 0367 * @param string $id 0368 * @return boolean 0369 */ 0370 public function destroy($id) 0371 { 0372 $return = false; 0373 0374 if ($this->delete($this->_getPrimary($id, self::PRIMARY_TYPE_WHERECLAUSE))) { 0375 $return = true; 0376 } 0377 0378 return $return; 0379 } 0380 0381 /** 0382 * Garbage Collection 0383 * 0384 * @param int $maxlifetime 0385 * @return true 0386 */ 0387 public function gc($maxlifetime) 0388 { 0389 $this->delete($this->getAdapter()->quoteIdentifier($this->_modifiedColumn, true) . ' + ' 0390 . $this->getAdapter()->quoteIdentifier($this->_lifetimeColumn, true) . ' < ' 0391 . $this->getAdapter()->quote(time())); 0392 0393 return true; 0394 } 0395 0396 /** 0397 * Calls other protected methods for individual setup tasks and requirement checks 0398 * 0399 * @return void 0400 */ 0401 protected function _setup() 0402 { 0403 parent::_setup(); 0404 0405 $this->_setupPrimaryAssignment(); 0406 $this->setLifetime($this->_lifetime); 0407 0408 $this->_checkRequiredColumns(); 0409 } 0410 0411 /** 0412 * Initialize table and schema names 0413 * 0414 * @return void 0415 * @throws Zend_Session_SaveHandler_Exception 0416 */ 0417 protected function _setupTableName() 0418 { 0419 if (empty($this->_name) && basename(($this->_name = session_save_path())) != $this->_name) { 0420 /** 0421 * @see Zend_Session_SaveHandler_Exception 0422 */ 0423 // require_once 'Zend/Session/SaveHandler/Exception.php'; 0424 0425 throw new Zend_Session_SaveHandler_Exception('session.save_path is a path and not a table name.'); 0426 } 0427 0428 if (strpos($this->_name, '.')) { 0429 list($this->_schema, $this->_name) = explode('.', $this->_name); 0430 } 0431 } 0432 0433 /** 0434 * Initialize session table primary key value assignment 0435 * 0436 * @return void 0437 * @throws Zend_Session_SaveHandler_Exception 0438 */ 0439 protected function _setupPrimaryAssignment() 0440 { 0441 if ($this->_primaryAssignment === null) { 0442 $this->_primaryAssignment = array(1 => self::PRIMARY_ASSIGNMENT_SESSION_ID); 0443 } else if (!is_array($this->_primaryAssignment)) { 0444 $this->_primaryAssignment = array(1 => (string) $this->_primaryAssignment); 0445 } else if (isset($this->_primaryAssignment[0])) { 0446 array_unshift($this->_primaryAssignment, null); 0447 0448 unset($this->_primaryAssignment[0]); 0449 } 0450 0451 if (count($this->_primaryAssignment) !== count($this->_primary)) { 0452 /** 0453 * @see Zend_Session_SaveHandler_Exception 0454 */ 0455 // require_once 'Zend/Session/SaveHandler/Exception.php'; 0456 0457 throw new Zend_Session_SaveHandler_Exception( 0458 "Value for configuration option '" . self::PRIMARY_ASSIGNMENT . "' must have an assignment " 0459 . "for each session table primary key."); 0460 } else if (!in_array(self::PRIMARY_ASSIGNMENT_SESSION_ID, $this->_primaryAssignment)) { 0461 /** 0462 * @see Zend_Session_SaveHandler_Exception 0463 */ 0464 // require_once 'Zend/Session/SaveHandler/Exception.php'; 0465 0466 throw new Zend_Session_SaveHandler_Exception( 0467 "Value for configuration option '" . self::PRIMARY_ASSIGNMENT . "' must have an assignment " 0468 . "for the session id ('" . self::PRIMARY_ASSIGNMENT_SESSION_ID . "')."); 0469 } 0470 } 0471 0472 /** 0473 * Check for required session table columns 0474 * 0475 * @return void 0476 * @throws Zend_Session_SaveHandler_Exception 0477 */ 0478 protected function _checkRequiredColumns() 0479 { 0480 if ($this->_modifiedColumn === null) { 0481 /** 0482 * @see Zend_Session_SaveHandler_Exception 0483 */ 0484 // require_once 'Zend/Session/SaveHandler/Exception.php'; 0485 0486 throw new Zend_Session_SaveHandler_Exception( 0487 "Configuration must define '" . self::MODIFIED_COLUMN . "' which names the " 0488 . "session table last modification time column."); 0489 } else if ($this->_lifetimeColumn === null) { 0490 /** 0491 * @see Zend_Session_SaveHandler_Exception 0492 */ 0493 // require_once 'Zend/Session/SaveHandler/Exception.php'; 0494 0495 throw new Zend_Session_SaveHandler_Exception( 0496 "Configuration must define '" . self::LIFETIME_COLUMN . "' which names the " 0497 . "session table lifetime column."); 0498 } else if ($this->_dataColumn === null) { 0499 /** 0500 * @see Zend_Session_SaveHandler_Exception 0501 */ 0502 // require_once 'Zend/Session/SaveHandler/Exception.php'; 0503 0504 throw new Zend_Session_SaveHandler_Exception( 0505 "Configuration must define '" . self::DATA_COLUMN . "' which names the " 0506 . "session table data column."); 0507 } 0508 } 0509 0510 /** 0511 * Retrieve session table primary key values 0512 * 0513 * @param string $id 0514 * @param string $type (optional; default: self::PRIMARY_TYPE_NUM) 0515 * @return array 0516 */ 0517 protected function _getPrimary($id, $type = null) 0518 { 0519 $this->_setupPrimaryKey(); 0520 0521 if ($type === null) { 0522 $type = self::PRIMARY_TYPE_NUM; 0523 } 0524 0525 $primaryArray = array(); 0526 0527 foreach ($this->_primary as $index => $primary) { 0528 switch ($this->_primaryAssignment[$index]) { 0529 case self::PRIMARY_ASSIGNMENT_SESSION_SAVE_PATH: 0530 $value = $this->_sessionSavePath; 0531 break; 0532 case self::PRIMARY_ASSIGNMENT_SESSION_NAME: 0533 $value = $this->_sessionName; 0534 break; 0535 case self::PRIMARY_ASSIGNMENT_SESSION_ID: 0536 $value = (string) $id; 0537 break; 0538 default: 0539 $value = (string) $this->_primaryAssignment[$index]; 0540 break; 0541 } 0542 0543 switch ((string) $type) { 0544 case self::PRIMARY_TYPE_PRIMARYNUM: 0545 $primaryArray[$index] = $value; 0546 break; 0547 case self::PRIMARY_TYPE_ASSOC: 0548 $primaryArray[$primary] = $value; 0549 break; 0550 case self::PRIMARY_TYPE_WHERECLAUSE: 0551 $primaryArray[] = $this->getAdapter()->quoteIdentifier($primary, true) . ' = ' 0552 . $this->getAdapter()->quote($value); 0553 break; 0554 case self::PRIMARY_TYPE_NUM: 0555 default: 0556 $primaryArray[] = $value; 0557 break; 0558 } 0559 } 0560 0561 return $primaryArray; 0562 } 0563 0564 /** 0565 * Retrieve session lifetime considering Zend_Session_SaveHandler_DbTable::OVERRIDE_LIFETIME 0566 * 0567 * @param Zend_Db_Table_Row_Abstract $row 0568 * @return int 0569 */ 0570 protected function _getLifetime(Zend_Db_Table_Row_Abstract $row) 0571 { 0572 $return = $this->_lifetime; 0573 0574 if (!$this->_overrideLifetime) { 0575 $return = (int) $row->{$this->_lifetimeColumn}; 0576 } 0577 0578 return $return; 0579 } 0580 0581 /** 0582 * Retrieve session expiration time 0583 * 0584 * @param Zend_Db_Table_Row_Abstract $row 0585 * @return int 0586 */ 0587 protected function _getExpirationTime(Zend_Db_Table_Row_Abstract $row) 0588 { 0589 return (int) $row->{$this->_modifiedColumn} + $this->_getLifetime($row); 0590 } 0591 }