Support Joomla!

Joomla! 1.5 Documentation

Packages

Package: Joomla-Framework

Developer Network License

The Joomla! Developer Network content is © copyright 2006 by the individual contributors and can be used in accordance with the Creative Commons License, Attribution- NonCommercial- ShareAlike 2.5
Source code for file /joomla/environment/session.php

Documentation is available at session.php

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

Documentation generated on Mon, 05 Mar 2007 21:21:39 +0000 by phpDocumentor 1.3.1