| [ Index ] |
PHP Cross Reference of Joomla 1.5.26 DE |
[Summary view] [Print] [Text view]
1 <?php 2 /** 3 * @version $Id: session.php 19338 2010-11-03 14:51:55Z ian $ 4 * @package Joomla.Framework 5 * @subpackage Session 6 * @copyright Copyright (C) 2005 - 2010 Open Source Matters. All rights reserved. 7 * @license GNU/GPL, see LICENSE.php 8 * Joomla! is free software. This version may have been modified pursuant 9 * to the GNU General Public License, and as distributed it includes or 10 * is derivative of works licensed under the GNU General Public License or 11 * other free or open source software licenses. 12 * See COPYRIGHT.php for copyright notices and details. 13 */ 14 15 // Check to ensure this file is within the rest of the framework 16 defined('JPATH_BASE') or die(); 17 18 //Register the session storage class with the loader 19 JLoader::register('JSessionStorage', dirname(__FILE__).DS.'storage.php'); 20 21 /** 22 * Class for managing HTTP sessions 23 * 24 * Provides access to session-state values as well as session-level 25 * settings and lifetime management methods. 26 * Based on the standart PHP session handling mechanism it provides 27 * for you more advanced features such as expire timeouts. 28 * 29 * @package Joomla.Framework 30 * @subpackage Session 31 * @since 1.5 32 */ 33 class JSession extends JObject 34 { 35 /** 36 * internal state 37 * 38 * @access protected 39 * @var string $_state one of 'active'|'expired'|'destroyed|'error' 40 * @see getState() 41 */ 42 var $_state = 'active'; 43 44 /** 45 * Maximum age of unused session 46 * 47 * @access protected 48 * @var string $_expire minutes 49 */ 50 var $_expire = 15; 51 52 /** 53 * The session store object 54 * 55 * @access protected 56 * @var object A JSessionStorage object 57 */ 58 var $_store = null; 59 60 /** 61 * security policy 62 * 63 * Default values: 64 * - fix_browser 65 * - fix_adress 66 * 67 * @access protected 68 * @var array $_security list of checks that will be done. 69 */ 70 var $_security = array( 'fix_browser' ); 71 72 /** 73 * Force cookies to be SSL only 74 * 75 * @access protected 76 * @default false 77 * @var bool $force_ssl 78 */ 79 var $_force_ssl = false; 80 81 /** 82 * Constructor 83 * 84 * @access protected 85 * @param string $storage 86 * @param array $options optional parameters 87 */ 88 function __construct( $store = 'none', $options = array() ) 89 { 90 // Register faked "destructor" in PHP4, this needs to happen before creating the session store 91 if (version_compare(PHP_VERSION, '5') == -1) { 92 register_shutdown_function((array(&$this, '__destruct'))); 93 } 94 95 //Need to destroy any existing sessions started with session.auto_start 96 if (session_id()) { 97 session_unset(); 98 session_destroy(); 99 } 100 101 //set default sessios save handler 102 ini_set('session.save_handler', 'files'); 103 104 //disable transparent sid support 105 ini_set('session.use_trans_sid', '0'); 106 107 //create handler 108 $this->_store =& JSessionStorage::getInstance($store, $options); 109 110 //set options 111 $this->_setOptions( $options ); 112 113 $this->_setCookieParams(); 114 115 //load the session 116 $this->_start(); 117 118 //initialise the session 119 $this->_setCounter(); 120 $this->_setTimers(); 121 122 $this->_state = 'active'; 123 124 // perform security checks 125 $this->_validate(); 126 } 127 128 /** 129 * Session object destructor 130 * 131 * @access private 132 * @since 1.5 133 */ 134 function __destruct() { 135 $this->close(); 136 } 137 138 /** 139 * Returns a reference to the global Session object, only creating it 140 * if it doesn't already exist. 141 * 142 * This method must be invoked as: 143 * <pre> $session = &JSession::getInstance();</pre> 144 * 145 * @access public 146 * @return JSession The Session object. 147 * @since 1.5 148 */ 149 function & getInstance($handler, $options) 150 { 151 static $instance; 152 153 if (!is_object($instance)) { 154 $instance = new JSession($handler, $options); 155 } 156 157 return $instance; 158 } 159 160 /** 161 * Get current state of session 162 * 163 * @access public 164 * @return string The session state 165 */ 166 function getState() { 167 return $this->_state; 168 } 169 170 /** 171 * Get expiration time in minutes 172 * 173 * @access public 174 * @return integer The session expiration time in minutes 175 */ 176 function getExpire() { 177 return $this->_expire; 178 } 179 180 /** 181 * Get a session token, if a token isn't set yet one will be generated. 182 * 183 * Tokens are used to secure forms from spamming attacks. Once a token 184 * has been generated the system will check the post request to see if 185 * it is present, if not it will invalidate the session. 186 * 187 * @param boolean $forceNew If true, force a new token to be created 188 * @access public 189 * @return string The session token 190 */ 191 function getToken($forceNew = false) 192 { 193 $token = $this->get( 'session.token' ); 194 195 //create a token 196 if( $token === null || $forceNew ) { 197 $token = $this->_createToken( 12 ); 198 $this->set( 'session.token', $token ); 199 } 200 201 return $token; 202 } 203 204 /** 205 * Method to determine if a token exists in the session. If not the 206 * session will be set to expired 207 * 208 * @param string Hashed token to be verified 209 * @param boolean If true, expires the session 210 * @since 1.5 211 * @static 212 */ 213 function hasToken($tCheck, $forceExpire = true) 214 { 215 // check if a token exists in the session 216 $tStored = $this->get( 'session.token' ); 217 218 //check token 219 if(($tStored !== $tCheck)) 220 { 221 if($forceExpire) { 222 $this->_state = 'expired'; 223 } 224 return false; 225 } 226 227 return true; 228 } 229 230 231 /** 232 * Get session name 233 * 234 * @access public 235 * @return string The session name 236 */ 237 function getName() 238 { 239 if( $this->_state === 'destroyed' ) { 240 // @TODO : raise error 241 return null; 242 } 243 return session_name(); 244 } 245 246 /** 247 * Get session id 248 * 249 * @access public 250 * @return string The session name 251 */ 252 function getId() 253 { 254 if( $this->_state === 'destroyed' ) { 255 // @TODO : raise error 256 return null; 257 } 258 return session_id(); 259 } 260 261 /** 262 * Get the session handlers 263 * 264 * @access public 265 * @return array An array of available session handlers 266 */ 267 function getStores() 268 { 269 jimport('joomla.filesystem.folder'); 270 $handlers = JFolder::files(dirname(__FILE__).DS.'storage', '.php$'); 271 272 $names = array(); 273 foreach($handlers as $handler) 274 { 275 $name = substr($handler, 0, strrpos($handler, '.')); 276 $class = 'JSessionStorage'.ucfirst($name); 277 278 //Load the class only if needed 279 if(!class_exists($class)) { 280 require_once(dirname(__FILE__).DS.'storage'.DS.$name.'.php'); 281 } 282 283 if(call_user_func_array( array( trim($class), 'test' ), array())) { 284 $names[] = $name; 285 } 286 } 287 288 return $names; 289 } 290 291 /** 292 * Check whether this session is currently created 293 * 294 * @access public 295 * @return boolean $result true on success 296 */ 297 function isNew() 298 { 299 $counter = $this->get( 'session.counter' ); 300 if( $counter === 1 ) { 301 return true; 302 } 303 return false; 304 } 305 306 /** 307 * Get data from the session store 308 * 309 * @static 310 * @access public 311 * @param string $name Name of a variable 312 * @param mixed $default Default value of a variable if not set 313 * @param string $namespace Namespace to use, default to 'default' 314 * @return mixed Value of a variable 315 */ 316 function &get($name, $default = null, $namespace = 'default') 317 { 318 $namespace = '__'.$namespace; //add prefix to namespace to avoid collisions 319 320 if($this->_state !== 'active' && $this->_state !== 'expired') { 321 // @TODO :: generated error here 322 $error = null; 323 return $error; 324 } 325 326 if (isset($_SESSION[$namespace][$name])) { 327 return $_SESSION[$namespace][$name]; 328 } 329 return $default; 330 } 331 332 /** 333 * Set data into the session store 334 * 335 * @access public 336 * @param string $name Name of a variable 337 * @param mixed $value Value of a variable 338 * @param string $namespace Namespace to use, default to 'default' 339 * @return mixed Old value of a variable 340 */ 341 function set($name, $value, $namespace = 'default') 342 { 343 $namespace = '__'.$namespace; //add prefix to namespace to avoid collisions 344 345 if($this->_state !== 'active') { 346 // @TODO :: generated error here 347 return null; 348 } 349 350 $old = isset($_SESSION[$namespace][$name]) ? $_SESSION[$namespace][$name] : null; 351 352 if (null === $value) { 353 unset($_SESSION[$namespace][$name]); 354 } else { 355 $_SESSION[$namespace][$name] = $value; 356 } 357 358 return $old; 359 } 360 361 /** 362 * Check wheter data exists in the session store 363 * 364 * @access public 365 * @param string $name Name of variable 366 * @param string $namespace Namespace to use, default to 'default' 367 * @return boolean $result true if the variable exists 368 */ 369 function has( $name, $namespace = 'default' ) 370 { 371 $namespace = '__'.$namespace; //add prefix to namespace to avoid collisions 372 373 if( $this->_state !== 'active' ) { 374 // @TODO :: generated error here 375 return null; 376 } 377 378 return isset( $_SESSION[$namespace][$name] ); 379 } 380 381 /** 382 * Unset data from the session store 383 * 384 * @access public 385 * @param string $name Name of variable 386 * @param string $namespace Namespace to use, default to 'default' 387 * @return mixed $value the value from session or NULL if not set 388 */ 389 function clear( $name, $namespace = 'default' ) 390 { 391 $namespace = '__'.$namespace; //add prefix to namespace to avoid collisions 392 393 if( $this->_state !== 'active' ) { 394 // @TODO :: generated error here 395 return null; 396 } 397 398 $value = null; 399 if( isset( $_SESSION[$namespace][$name] ) ) { 400 $value = $_SESSION[$namespace][$name]; 401 unset( $_SESSION[$namespace][$name] ); 402 } 403 404 return $value; 405 } 406 407 /** 408 * Start a session 409 * 410 * Creates a session (or resumes the current one based on the state of the session) 411 * 412 * @access private 413 * @return boolean $result true on success 414 */ 415 function _start() 416 { 417 // start session if not startet 418 if( $this->_state == 'restart' ) { 419 session_id( $this->_createId() ); 420 } 421 422 session_cache_limiter('none'); 423 session_start(); 424 425 // Send modified header for IE 6.0 Security Policy 426 header('P3P: CP="NOI ADM DEV PSAi COM NAV OUR OTRo STP IND DEM"'); 427 428 return true; 429 } 430 431 432 /** 433 * Frees all session variables and destroys all data registered to a session 434 * 435 * This method resets the $_SESSION variable and destroys all of the data associated 436 * with the current session in its storage (file or DB). It forces new session to be 437 * started after this method is called. It does not unset the session cookie. 438 * 439 * @static 440 * @access public 441 * @return void 442 * @see session_unset() 443 * @see session_destroy() 444 */ 445 function destroy() 446 { 447 // session was already destroyed 448 if( $this->_state === 'destroyed' ) { 449 return true; 450 } 451 452 // In order to kill the session altogether, like to log the user out, the session id 453 // must also be unset. If a cookie is used to propagate the session id (default behavior), 454 // then the session cookie must be deleted. 455 if (isset($_COOKIE[session_name()])) { 456 setcookie(session_name(), '', time()-42000, '/'); 457 } 458 459 session_unset(); 460 session_destroy(); 461 462 $this->_state = 'destroyed'; 463 return true; 464 } 465 466 /** 467 * restart an expired or locked session 468 * 469 * @access public 470 * @return boolean $result true on success 471 * @see destroy 472 */ 473 function restart() 474 { 475 $this->destroy(); 476 if( $this->_state !== 'destroyed' ) { 477 // @TODO :: generated error here 478 return false; 479 } 480 481 // Re-register the session handler after a session has been destroyed, to avoid PHP bug 482 $this->_store->register(); 483 484 $this->_state = 'restart'; 485 //regenerate session id 486 $id = $this->_createId( strlen( $this->getId() ) ); 487 session_id($id); 488 $this->_start(); 489 $this->_state = 'active'; 490 491 $this->_validate(); 492 $this->_setCounter(); 493 494 return true; 495 } 496 497 /** 498 * Create a new session and copy variables from the old one 499 * 500 * @abstract 501 * @access public 502 * @return boolean $result true on success 503 */ 504 function fork() 505 { 506 if( $this->_state !== 'active' ) { 507 // @TODO :: generated error here 508 return false; 509 } 510 session_regenerate_id(); 511 return true; 512 } 513 514 /** 515 * Writes session data and ends session 516 * 517 * Session data is usually stored after your script terminated without the need 518 * to call JSession::close(),but as session data is locked to prevent concurrent 519 * writes only one script may operate on a session at any time. When using 520 * framesets together with sessions you will experience the frames loading one 521 * by one due to this locking. You can reduce the time needed to load all the 522 * frames by ending the session as soon as all changes to session variables are 523 * done. 524 * 525 * @access public 526 * @see session_write_close() 527 */ 528 function close() { 529 session_write_close(); 530 } 531 532 /** 533 * Create a session id 534 * 535 * @static 536 * @access private 537 * @return string Session ID 538 */ 539 function _createId( ) 540 { 541 $id = 0; 542 while (strlen($id) < 32) { 543 $id .= mt_rand(0, mt_getrandmax()); 544 } 545 546 $id = md5( uniqid($id, true)); 547 return $id; 548 } 549 550 /** 551 * Set session cookie parameters 552 * 553 * @access private 554 */ 555 function _setCookieParams() { 556 $cookie = session_get_cookie_params(); 557 if($this->_force_ssl) { 558 $cookie['secure'] = true; 559 } 560 session_set_cookie_params( $cookie['lifetime'], $cookie['path'], $cookie['domain'], $cookie['secure'] ); 561 } 562 563 /** 564 * Create a token-string 565 * 566 * @access protected 567 * @param int $length lenght of string 568 * @return string $id generated token 569 */ 570 function _createToken( $length = 32 ) 571 { 572 static $chars = '0123456789abcdef'; 573 $max = strlen( $chars ) - 1; 574 $token = ''; 575 $name = session_name(); 576 for( $i = 0; $i < $length; ++$i ) { 577 $token .= $chars[ (rand( 0, $max )) ]; 578 } 579 580 return md5($token.$name); 581 } 582 583 /** 584 * Set counter of session usage 585 * 586 * @access protected 587 * @return boolean $result true on success 588 */ 589 function _setCounter() 590 { 591 $counter = $this->get( 'session.counter', 0 ); 592 ++$counter; 593 594 $this->set( 'session.counter', $counter ); 595 return true; 596 } 597 598 /** 599 * Set the session timers 600 * 601 * @access protected 602 * @return boolean $result true on success 603 */ 604 function _setTimers() 605 { 606 if( !$this->has( 'session.timer.start' ) ) 607 { 608 $start = time(); 609 610 $this->set( 'session.timer.start' , $start ); 611 $this->set( 'session.timer.last' , $start ); 612 $this->set( 'session.timer.now' , $start ); 613 } 614 615 $this->set( 'session.timer.last', $this->get( 'session.timer.now' ) ); 616 $this->set( 'session.timer.now', time() ); 617 618 return true; 619 } 620 621 /** 622 * set additional session options 623 * 624 * @access protected 625 * @param array $options list of parameter 626 * @return boolean $result true on success 627 */ 628 function _setOptions( &$options ) 629 { 630 // set name 631 if( isset( $options['name'] ) ) { 632 session_name( md5($options['name']) ); 633 } 634 635 // set id 636 if( isset( $options['id'] ) ) { 637 session_id( $options['id'] ); 638 } 639 640 // set expire time 641 if( isset( $options['expire'] ) ) { 642 $this->_expire = $options['expire']; 643 } 644 645 // get security options 646 if( isset( $options['security'] ) ) { 647 $this->_security = explode( ',', $options['security'] ); 648 } 649 650 if( isset( $options['force_ssl'] ) ) { 651 $this->_force_ssl = (bool) $options['force_ssl']; 652 } 653 654 //sync the session maxlifetime 655 ini_set('session.gc_maxlifetime', $this->_expire); 656 657 return true; 658 } 659 660 /** 661 * Do some checks for security reason 662 * 663 * - timeout check (expire) 664 * - ip-fixiation 665 * - browser-fixiation 666 * 667 * If one check failed, session data has to be cleaned. 668 * 669 * @access protected 670 * @param boolean $restart reactivate session 671 * @return boolean $result true on success 672 * @see http://shiflett.org/articles/the-truth-about-sessions 673 */ 674 function _validate( $restart = false ) 675 { 676 // allow to restart a session 677 if( $restart ) 678 { 679 $this->_state = 'active'; 680 681 $this->set( 'session.client.address' , null ); 682 $this->set( 'session.client.forwarded' , null ); 683 $this->set( 'session.client.browser' , null ); 684 $this->set( 'session.token' , null ); 685 } 686 687 // check if session has expired 688 if( $this->_expire ) 689 { 690 $curTime = $this->get( 'session.timer.now' , 0 ); 691 $maxTime = $this->get( 'session.timer.last', 0 ) + $this->_expire; 692 693 // empty session variables 694 if( $maxTime < $curTime ) { 695 $this->_state = 'expired'; 696 return false; 697 } 698 } 699 700 // record proxy forwarded for in the session in case we need it later 701 if( isset( $_SERVER['HTTP_X_FORWARDED_FOR'] ) ) { 702 $this->set( 'session.client.forwarded', $_SERVER['HTTP_X_FORWARDED_FOR']); 703 } 704 705 // check for client adress 706 if( in_array( 'fix_adress', $this->_security ) && isset( $_SERVER['REMOTE_ADDR'] ) ) 707 { 708 $ip = $this->get( 'session.client.address' ); 709 710 if( $ip === null ) { 711 $this->set( 'session.client.address', $_SERVER['REMOTE_ADDR'] ); 712 } 713 else if( $_SERVER['REMOTE_ADDR'] !== $ip ) 714 { 715 $this->_state = 'error'; 716 return false; 717 } 718 } 719 720 // check for clients browser 721 if( in_array( 'fix_browser', $this->_security ) && isset( $_SERVER['HTTP_USER_AGENT'] ) ) 722 { 723 $browser = $this->get( 'session.client.browser' ); 724 725 if( $browser === null ) { 726 $this->set( 'session.client.browser', $_SERVER['HTTP_USER_AGENT']); 727 } 728 else if( $_SERVER['HTTP_USER_AGENT'] !== $browser ) 729 { 730 // $this->_state = 'error'; 731 // return false; 732 } 733 } 734 735 return true; 736 } 737 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
| Generated: Wed Mar 28 15:54:07 2012 | Cross-referenced by PHPXref 0.7.1 |