Support Joomla!

Packages

Package: Joomla-Framework

License

Content on this site is copyright © 2005 - 2008 Open Source Matters Inc and can be used in accordance with the Joomla! Electronic Documentation License. Some parts of this website may be subject to other licenses.
Source code for file /joomla/session/session.php

Documentation is available at session.php

  1. <?php
  2. /**
  3. @version        $Id: session.php 12694 2009-09-11 21:03:02Z ian $
  4. @package        Joomla.Framework
  5. @subpackage    Session
  6. @copyright    Copyright (C) 2005 - 2008 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 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->_createToken12 );
  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($handler0strrpos($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_arrayarraytrim($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 === {
  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][$namenull;
  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.         ifisset$_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->_createIdstrlen$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.  
  511.         // save values
  512.         $values    $_SESSION;
  513.  
  514.         // keep session config
  515.         $trans    =    ini_get'session.use_trans_sid' );
  516.         if$trans {
  517.             ini_set'session.use_trans_sid');
  518.         }
  519.         $cookie    =    session_get_cookie_params();
  520.  
  521.         // create new session id
  522.         $id    =    $this->_createIdstrlen$this->getId() ) );
  523.  
  524.         // kill session
  525.         session_destroy();
  526.  
  527.         // re-register the session store after a session has been destroyed, to avoid PHP bug
  528.         $this->_store->register();
  529.  
  530.         // restore config
  531.         ini_set'session.use_trans_sid'$trans );
  532.         session_set_cookie_params$cookie['lifetime']$cookie['path']$cookie['domain']$cookie['secure');
  533.  
  534.         // restart session with new id
  535.         session_id$id );
  536.         session_start();
  537.  
  538.         return true;
  539.     }
  540.  
  541.      /**
  542.      * Writes session data and ends session
  543.      *
  544.      * Session data is usually stored after your script terminated without the need
  545.      * to call JSession::close(),but as session data is locked to prevent concurrent
  546.      * writes only one script may operate on a session at any time. When using
  547.      * framesets together with sessions you will experience the frames loading one
  548.      * by one due to this locking. You can reduce the time needed to load all the
  549.      * frames by ending the session as soon as all changes to session variables are
  550.      * done.
  551.      *
  552.      * @access public
  553.      * @see    session_write_close()
  554.      */
  555.     function close({
  556.         session_write_close();
  557.     }
  558.  
  559.      /**
  560.      * Create a session id
  561.      *
  562.      * @static
  563.      * @access private
  564.      * @return string Session ID
  565.      */
  566.     function _createId)
  567.     {
  568.         $id 0;
  569.         while (strlen($id32)  {
  570.             $id .= mt_rand(0mt_getrandmax());
  571.         }
  572.  
  573.         $id    md5uniqid($idtrue));
  574.         return $id;
  575.     }
  576.  
  577.      /**
  578.      * Set session cookie parameters
  579.      *
  580.      * @access private
  581.      */
  582.     function _setCookieParams({
  583.         $cookie    =    session_get_cookie_params();
  584.         if($this->_force_ssl{
  585.             $cookie['secure'true;
  586.         }
  587.         session_set_cookie_params$cookie['lifetime']$cookie['path']$cookie['domain']$cookie['secure');
  588.     }
  589.  
  590.     /**
  591.     * Create a token-string
  592.     *
  593.     * @access protected
  594.     * @param int $length lenght of string
  595.     * @return string $id generated token
  596.     */
  597.     function _createToken$length 32 )
  598.     {
  599.         static $chars    =    '0123456789abcdef';
  600.         $max            =    strlen$chars 1;
  601.         $token            =    '';
  602.         $name             =  session_name();
  603.         for$i 0$i $length++$i {
  604.             $token .=    $chars(rand0$max )) ];
  605.         }
  606.  
  607.         return md5($token.$name);
  608.     }
  609.  
  610.     /**
  611.     * Set counter of session usage
  612.     *
  613.     * @access protected
  614.     * @return boolean $result true on success
  615.     */
  616.     function _setCounter()
  617.     {
  618.         $counter $this->get'session.counter');
  619.         ++$counter;
  620.  
  621.         $this->set'session.counter'$counter );
  622.         return true;
  623.     }
  624.  
  625.     /**
  626.     * Set the session timers
  627.     *
  628.     * @access protected
  629.     * @return boolean $result true on success
  630.     */
  631.     function _setTimers()
  632.     {
  633.         if!$this->has'session.timer.start' ) )
  634.         {
  635.             $start    =    time();
  636.  
  637.             $this->set'session.timer.start' $start );
  638.             $this->set'session.timer.last'  $start );
  639.             $this->set'session.timer.now'   $start );
  640.         }
  641.  
  642.         $this->set'session.timer.last'$this->get'session.timer.now' ) );
  643.         $this->set'session.timer.now'time() );
  644.  
  645.         return true;
  646.     }
  647.  
  648.     /**
  649.     * set additional session options
  650.     *
  651.     * @access protected
  652.     * @param array $options list of parameter
  653.     * @return boolean $result true on success
  654.     */
  655.     function _setOptions&$options )
  656.     {
  657.         // set name
  658.         ifisset$options['name') ) {
  659.             session_namemd5($options['name']) );
  660.         }
  661.  
  662.         // set id
  663.         ifisset$options['id') ) {
  664.             session_id$options['id');
  665.         }
  666.  
  667.         // set expire time
  668.         ifisset$options['expire') ) {
  669.             $this->_expire    =    $options['expire'];
  670.         }
  671.  
  672.         // get security options
  673.         ifisset$options['security') ) {
  674.             $this->_security    =    explode','$options['security');
  675.         }
  676.  
  677.         ifisset$options['force_ssl') ) {
  678.             $this->_force_ssl = (bool) $options['force_ssl'];
  679.         }
  680.  
  681.         //sync the session maxlifetime
  682.         ini_set('session.gc_maxlifetime'$this->_expire);
  683.  
  684.         return true;
  685.     }
  686.  
  687.     /**
  688.     * Do some checks for security reason
  689.     *
  690.     * - timeout check (expire)
  691.     * - ip-fixiation
  692.     * - browser-fixiation
  693.     *
  694.     * If one check failed, session data has to be cleaned.
  695.     *
  696.     * @access protected
  697.     * @param boolean $restart reactivate session
  698.     * @return boolean $result true on success
  699.     * @see http://shiflett.org/articles/the-truth-about-sessions
  700.     */
  701.     function _validate$restart false )
  702.     {
  703.         // allow to restart a session
  704.         if$restart )
  705.         {
  706.             $this->_state    =    'active';
  707.  
  708.             $this->set'session.client.address'    null );
  709.             $this->set'session.client.forwarded'    null );
  710.             $this->set'session.client.browser'    null );
  711.             $this->set'session.token'                null );
  712.         }
  713.  
  714.         // check if session has expired
  715.         if$this->_expire )
  716.         {
  717.             $curTime =    $this->get'session.timer.now' 0  );
  718.             $maxTime =    $this->get'session.timer.last'+  $this->_expire;
  719.  
  720.             // empty session variables
  721.             if$maxTime $curTime {
  722.                 $this->_state    =    'expired';
  723.                 return false;
  724.             }
  725.         }
  726.  
  727.         // record proxy forwarded for in the session in case we need it later
  728.         ifisset$_SERVER['HTTP_X_FORWARDED_FOR') ) {
  729.             $this->set'session.client.forwarded'$_SERVER['HTTP_X_FORWARDED_FOR']);
  730.         }
  731.  
  732.         // check for client adress
  733.         ifin_array'fix_adress'$this->_security && isset$_SERVER['REMOTE_ADDR') )
  734.         {
  735.             $ip    $this->get'session.client.address' );
  736.  
  737.             if$ip === null {
  738.                 $this->set'session.client.address'$_SERVER['REMOTE_ADDR');
  739.             }
  740.             else if$_SERVER['REMOTE_ADDR'!== $ip )
  741.             {
  742.                 $this->_state    =    'error';
  743.                 return false;
  744.             }
  745.         }
  746.  
  747.         // check for clients browser
  748.         ifin_array'fix_browser'$this->_security && isset$_SERVER['HTTP_USER_AGENT') )
  749.         {
  750.             $browser $this->get'session.client.browser' );
  751.  
  752.             if$browser === null {
  753.                 $this->set'session.client.browser'$_SERVER['HTTP_USER_AGENT']);
  754.             }
  755.             else if$_SERVER['HTTP_USER_AGENT'!== $browser )
  756.             {
  757. //                $this->_state    =    'error';
  758. //                return false;
  759.             }
  760.         }
  761.  
  762.         return true;
  763.     }
  764. }

Documentation generated on Sat, 14 Nov 2009 11:18:54 +0000 by phpDocumentor 1.3.1