[ Index ]

PHP Cross Reference of Joomla 1.5.26 DE

title

Body

[close]

/libraries/joomla/session/ -> session.php (source)

   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  }


Generated: Wed Mar 28 15:54:07 2012 Cross-referenced by PHPXref 0.7.1