CI框架SESSION重写

<?php   if  ( ! defined( 'BASEPATH' ))  exit ( 'No direct script access allowed' );
/**
  * CodeIgniter
  *
  * An open source application development framework for PHP 5.1.6 or newer
  *
  * @package     CodeIgniter
  * @author      EllisLab Dev Team
  * @copyright       Copyright (c) 2008 - 2014, EllisLab, Inc.
  * @copyright       Copyright (c) 2014 - 2015, British Columbia Institute of Technology (http://bcit.ca/)
  * @license     http://codeigniter.com/user_guide/license.html
  * @link        http://codeigniter.com
  * @since       Version 1.0
  * @filesource
  */
// ------------------------------------------------------------------------
/**
  * Session Class
  *
  * @package     CodeIgniter
  * @subpackage  Libraries
  * @category    Sessions
  * @author      EllisLab Dev Team
  * @link        http://codeigniter.com/user_guide/libraries/sessions.html
  */
class  CI_Session {
     var  $sess_encrypt_cookie         = FALSE;
     var  $sess_use_database           = FALSE;
     var  $sess_table_name             '' ;
     var  $sess_expiration             = 7200;
     var  $sess_expire_on_close        = FALSE;
     var  $sess_match_ip               = FALSE;
     var  $sess_match_useragent        = TRUE;
     var  $sess_cookie_name            'ci_session' ;
     var  $cookie_prefix               '' ;
     var  $cookie_path                 '' ;
     var  $cookie_domain               '' ;
     var  $cookie_secure               = FALSE;
     var  $sess_time_to_update         = 300;
     var  $encryption_key              '' ;
     var  $flashdata_key               'flash' ;
     var  $time_reference              'time' ;
     var  $gc_probability              = 5;
     var  $userdata                    array ();
     var  $CI ;
     var  $now ;
     /**
      * Session Constructor
      *
      * The constructor runs the session routines automatically
      * whenever the class is instantiated.
      */
     public  function  __construct( $params  array ())
     {
         log_message( 'debug' "Session Class Initialized" );
         // Set the super object to a local variable for use throughout the class
         $this ->CI =& get_instance();
         // Set all the session preferences, which can either be set
         // manually via the $params array above or via the config file
         foreach  ( array ( 'sess_encrypt_cookie' 'sess_use_database' 'sess_table_name' 'sess_expiration' 'sess_expire_on_close' 'sess_match_ip' 'sess_match_useragent' 'sess_cookie_name' 'cookie_path' 'cookie_domain' 'cookie_secure' 'sess_time_to_update' 'time_reference' 'cookie_prefix' 'encryption_key' as  $key )
         {
             $this -> $key  = (isset( $params [ $key ])) ?  $params [ $key ] :  $this ->CI->config->item( $key );
         }
         if  ( $this ->encryption_key ==  '' )
         {
             show_error( 'In order to use the Session class you are required to set an encryption key in your config file.' );
         }
         // Load the string helper so we can use the strip_slashes() function
         $this ->CI->load->helper( 'string' );
         // Do we need encryption? If so, load the encryption class
         if  ( $this ->sess_encrypt_cookie == TRUE)
         {
             $this ->CI->load->library( 'encrypt' );
         }
         // Are we using a database?  If so, load it
         if  ( $this ->sess_use_database === TRUE AND  $this ->sess_table_name !=  '' )
         {
             $this ->CI->load->database();
         }
         // Set the "now" time.  Can either be GMT or server time, based on the
         // config prefs.  We use this to set the "last activity" time
         $this ->now =  $this ->_get_time();
         // Set the session length. If the session expiration is
         // set to zero we'll set the expiration two years from now.
         if  ( $this ->sess_expiration == 0)
         {
             $this ->sess_expiration = (60*60*24*365*2);
         }
         // Set the cookie name
         $this ->sess_cookie_name =  $this ->cookie_prefix. $this ->sess_cookie_name;
         // Run the Session routine. If a session doesn't exist we'll
         // create a new one.  If it does, we'll update it.
         if  ( !  $this ->sess_read())
         {
             $this ->sess_create();
         }
         else
         {
             $this ->sess_update();
         }
         // Delete 'old' flashdata (from last request)
         $this ->_flashdata_sweep();
         // Mark all new flashdata as old (data will be deleted before next request)
         $this ->_flashdata_mark();
         // Delete expired sessions if necessary
         $this ->_sess_gc();
         log_message( 'debug' "Session routines successfully run" );
     }
     // --------------------------------------------------------------------
     /**
      * Fetch the current session data if it exists
      *
      * @access  public
      * @return  bool
      */
     function  sess_read()
     {
         // Fetch the cookie
         $session  $this ->CI->input->cookie( $this ->sess_cookie_name);
         // No cookie?  Goodbye cruel world!...
         if  ( $session  === FALSE)
         {
             log_message( 'debug' 'A session cookie was not found.' );
             return  FALSE;
         }
         // HMAC authentication
         $len  strlen ( $session ) - 40;
         if  ( $len  <= 0)
         {
             log_message( 'error' 'Session: The session cookie was not signed.' );
             return  FALSE;
         }
         // Check cookie authentication
         $hmac  substr ( $session $len );
         $session  substr ( $session , 0,  $len );
         // Time-attack-safe comparison
         $hmac_check  = hash_hmac( 'sha1' $session $this ->encryption_key);
         $diff  = 0;
         for  ( $i  = 0;  $i  < 40;  $i ++)
         {
             $xor  = ord( $hmac [ $i ]) ^ ord( $hmac_check [ $i ]);
             $diff  |=  $xor ;
         }
         if  ( $diff  !== 0)
         {
             log_message( 'error' 'Session: HMAC mismatch. The session cookie data did not match what was expected.' );
             $this ->sess_destroy();
             return  FALSE;
         }
         // Decrypt the cookie data
         if  ( $this ->sess_encrypt_cookie == TRUE)
         {
             $session  $this ->CI->encrypt->decode( $session );
         }
         // Unserialize the session array
         $session  $this ->_unserialize( $session );
         // Is the session data we unserialized an array with the correct format?
         if  ( !  is_array ( $session ) OR ! isset( $session [ 'session_id' ]) OR ! isset( $session [ 'ip_address' ]) OR ! isset( $session [ 'user_agent' ]) OR ! isset( $session [ 'last_activity' ]))
         {
             $this ->sess_destroy();
             return  FALSE;
         }
         // Is the session current?
         if  (( $session [ 'last_activity' ] +  $this ->sess_expiration) <  $this ->now)
         {
             $this ->sess_destroy();
             return  FALSE;
         }
         // Does the IP Match?
         if  ( $this ->sess_match_ip == TRUE AND  $session [ 'ip_address' ] !=  $this ->CI->input->ip_address())
         {
             $this ->sess_destroy();
             return  FALSE;
         }
         // Does the User Agent Match?
         if  ( $this ->sess_match_useragent == TRUE AND trim( $session [ 'user_agent' ]) != trim( substr ( $this ->CI->input->user_agent(), 0, 120)))
         {
             $this ->sess_destroy();
             return  FALSE;
         }
         // Is there a corresponding session in the DB?
         if  ( $this ->sess_use_database === TRUE)
         {
             $this ->CI->db->where( 'session_id' $session [ 'session_id' ]);
             if  ( $this ->sess_match_ip == TRUE)
             {
                 $this ->CI->db->where( 'ip_address' $session [ 'ip_address' ]);
             }
             if  ( $this ->sess_match_useragent == TRUE)
             {
                 $this ->CI->db->where( 'user_agent' $session [ 'user_agent' ]);
             }
             $query  $this ->CI->db->get( $this ->sess_table_name);
             // No result?  Kill it!
             if  ( $query ->num_rows() == 0)
             {
                 $this ->sess_destroy();
                 return  FALSE;
             }
             // Is there custom data?  If so, add it to the main session array
             $row  $query ->row();
             if  (isset( $row ->user_data) AND  $row ->user_data !=  '' )
             {
                 $custom_data  $this ->_unserialize( $row ->user_data);
                 if  ( is_array ( $custom_data ))
                 {
                     foreach  ( $custom_data  as  $key  =>  $val )
                     {
                         $session [ $key ] =  $val ;
                     }
                 }
             }
         }
         // Session is valid!
         $this ->userdata =  $session ;
         unset( $session );
         return  TRUE;
     }
     // --------------------------------------------------------------------
     /**
      * Write the session data
      *
      * @access  public
      * @return  void
      */
     function  sess_write()
     {
         // Are we saving custom data to the DB?  If not, all we do is update the cookie
         if  ( $this ->sess_use_database === FALSE)
         {
             $this ->_set_cookie();
             return ;
         }
         // set the custom userdata, the session data we will set in a second
         $custom_userdata  $this ->userdata;
         $cookie_userdata  array ();
         // Before continuing, we need to determine if there is any custom data to deal with.
         // Let's determine this by removing the default indexes to see if there's anything left in the array
         // and set the session data while we're at it
         foreach  ( array ( 'session_id' , 'ip_address' , 'user_agent' , 'last_activity' as  $val )
         {
             unset( $custom_userdata [ $val ]);
             $cookie_userdata [ $val ] =  $this ->userdata[ $val ];
         }
         // Did we find any custom data?  If not, we turn the empty array into a string
         // since there's no reason to serialize and store an empty array in the DB
         if  ( count ( $custom_userdata ) === 0)
         {
             $custom_userdata  '' ;
         }
         else
         {
             // Serialize the custom data array so we can store it
             $custom_userdata  $this ->_serialize( $custom_userdata );
         }
         // Run the update query
         $this ->CI->db->where( 'session_id' $this ->userdata[ 'session_id' ]);
         $this ->CI->db->update( $this ->sess_table_name,  array ( 'last_activity'  =>  $this ->userdata[ 'last_activity' ],  'user_data'  =>  $custom_userdata ));
         // Write the cookie.  Notice that we manually pass the cookie data array to the
         // _set_cookie() function. Normally that function will store $this->userdata, but
         // in this case that array contains custom data, which we do not want in the cookie.
         $this ->_set_cookie( $cookie_userdata );
     }
     // --------------------------------------------------------------------
     /**
      * Create a new session
      *
      * @access  public
      * @return  void
      */
     function  sess_create()
     {
         $sessid  '' ;
         while  ( strlen ( $sessid ) < 32)
         {
             $sessid  .= mt_rand(0, mt_getrandmax());
         }
         // To make the session ID even more secure we'll combine it with the user's IP
         $sessid  .=  $this ->CI->input->ip_address();
         $this ->userdata =  array (
                             'session_id'     => md5(uniqid( $sessid , TRUE)),
                             'ip_address'     =>  $this ->CI->input->ip_address(),
                             'user_agent'     =>  substr ( $this ->CI->input->user_agent(), 0, 120),
                             'last_activity'  =>  $this ->now,
                             'user_data'      =>  ''
                             );
         // Save the data to the DB if needed
         if  ( $this ->sess_use_database === TRUE)
         {
             $this ->CI->db->query( $this ->CI->db->insert_string( $this ->sess_table_name,  $this ->userdata));
         }
         // Write the cookie
         $this ->_set_cookie();
     }
     // --------------------------------------------------------------------
     /**
      * Update an existing session
      *
      * @access  public
      * @return  void
      */
     function  sess_update()
     {
         // We only update the session every five minutes by default
         if  ( $this ->CI->input->is_ajax_request() OR ( $this ->userdata[ 'last_activity' ] +  $this ->sess_time_to_update) >=  $this ->now)
         {
             return ;
         }
         // Save the old session id so we know which record to
         // update in the database if we need it
         $old_sessid  $this ->userdata[ 'session_id' ];
         $new_sessid  '' ;
         while  ( strlen ( $new_sessid ) < 32)
         {
             $new_sessid  .= mt_rand(0, mt_getrandmax());
         }
         // To make the session ID even more secure we'll combine it with the user's IP
         $new_sessid  .=  $this ->CI->input->ip_address();
         // Turn it into a hash
         $new_sessid  = md5(uniqid( $new_sessid , TRUE));
         // Update the session data in the session data array
         $this ->userdata[ 'session_id' ] =  $new_sessid ;
         $this ->userdata[ 'last_activity' ] =  $this ->now;
         // _set_cookie() will handle this for us if we aren't using database sessions
         // by pushing all userdata to the cookie.
         $cookie_data  = NULL;
         // Update the session ID and last_activity field in the DB if needed
         if  ( $this ->sess_use_database === TRUE)
         {
             // set cookie explicitly to only have our session data
             $cookie_data  array ();
             foreach  ( array ( 'session_id' , 'ip_address' , 'user_agent' , 'last_activity' as  $val )
             {
                 $cookie_data [ $val ] =  $this ->userdata[ $val ];
             }
             $this ->CI->db->query( $this ->CI->db->update_string( $this ->sess_table_name,  array ( 'last_activity'  =>  $this ->now,  'session_id'  =>  $new_sessid ),  array ( 'session_id'  =>  $old_sessid )));
         }
         // Write the cookie
         $this ->_set_cookie( $cookie_data );
     }
     // --------------------------------------------------------------------
     /**
      * Destroy the current session
      *
      * @access  public
      * @return  void
      */
     function  sess_destroy()
     {
         // Kill the session DB row
         if  ( $this ->sess_use_database === TRUE && isset( $this ->userdata[ 'session_id' ]))
         {
             $this ->CI->db->where( 'session_id' $this ->userdata[ 'session_id' ]);
             $this ->CI->db-> delete ( $this ->sess_table_name);
         }
         // Kill the cookie
         setcookie(
                     $this ->sess_cookie_name,
                     addslashes (serialize( array ())),
                     ( $this ->now - 31500000),
                     $this ->cookie_path,
                     $this ->cookie_domain,
                     0
                 );
         // Kill session data
         $this ->userdata =  array ();
     }
     // --------------------------------------------------------------------
     /**
      * Fetch a specific item from the session array
      *
      * @access  public
      * @param   string
      * @return  string
      */
     function  userdata( $item )
     {
         return  ( ! isset( $this ->userdata[ $item ])) ? FALSE :  $this ->userdata[ $item ];
     }
     // --------------------------------------------------------------------
     /**
      * Fetch all session data
      *
      * @access  public
      * @return  array
      */
     function  all_userdata()
     {
         return  $this ->userdata;
     }
     // --------------------------------------------------------------------
     /**
      * Add or change data in the "userdata" array
      *
      * @access  public
      * @param   mixed
      * @param   string
      * @return  void
      */
     function  set_userdata( $newdata  array (),  $newval  '' )
     {
         if  ( is_string ( $newdata ))
         {
             $newdata  array ( $newdata  =>  $newval );
         }
         if  ( count ( $newdata ) > 0)
         {
             foreach  ( $newdata  as  $key  =>  $val )
             {
                 $this ->userdata[ $key ] =  $val ;
             }
         }
         $this ->sess_write();
     }
     // --------------------------------------------------------------------
     /**
      * Delete a session variable from the "userdata" array
      *
      * @access  array
      * @return  void
      */
     function  unset_userdata( $newdata  array ())
     {
         if  ( is_string ( $newdata ))
         {
             $newdata  array ( $newdata  =>  '' );
         }
         if  ( count ( $newdata ) > 0)
         {
             foreach  ( $newdata  as  $key  =>  $val )
             {
                 unset( $this ->userdata[ $key ]);
             }
         }
         $this ->sess_write();
     }
     // ------------------------------------------------------------------------
     /**
      * Add or change flashdata, only available
      * until the next request
      *
      * @access  public
      * @param   mixed
      * @param   string
      * @return  void
      */
     function  set_flashdata( $newdata  array (),  $newval  '' )
     {
         if  ( is_string ( $newdata ))
         {
             $newdata  array ( $newdata  =>  $newval );
         }
         if  ( count ( $newdata ) > 0)
         {
             foreach  ( $newdata  as  $key  =>  $val )
             {
                 $flashdata_key  $this ->flashdata_key. ':new:' . $key ;
                 $this ->set_userdata( $flashdata_key $val );
             }
         }
     }
     // ------------------------------------------------------------------------
     /**
      * Keeps existing flashdata available to next request.
      *
      * @access  public
      * @param   string
      * @return  void
      */
     function  keep_flashdata( $key )
     {
         // 'old' flashdata gets removed.  Here we mark all
         // flashdata as 'new' to preserve it from _flashdata_sweep()
         // Note the function will return FALSE if the $key
         // provided cannot be found
         $old_flashdata_key  $this ->flashdata_key. ':old:' . $key ;
         $value  $this ->userdata( $old_flashdata_key );
         $new_flashdata_key  $this ->flashdata_key. ':new:' . $key ;
         $this ->set_userdata( $new_flashdata_key $value );
     }
     // ------------------------------------------------------------------------
     /**
      * Fetch a specific flashdata item from the session array
      *
      * @access  public
      * @param   string
      * @return  string
      */
     function  flashdata( $key )
     {
         $flashdata_key  $this ->flashdata_key. ':old:' . $key ;
         return  $this ->userdata( $flashdata_key );
     }
     // ------------------------------------------------------------------------
     /**
      * Identifies flashdata as 'old' for removal
      * when _flashdata_sweep() runs.
      *
      * @access  private
      * @return  void
      */
     function  _flashdata_mark()
     {
         $userdata  $this ->all_userdata();
         foreach  ( $userdata  as  $name  =>  $value )
         {
             $parts  explode ( ':new:' $name );
             if  ( is_array ( $parts ) &&  count ( $parts ) === 2)
             {
                 $new_name  $this ->flashdata_key. ':old:' . $parts [1];
                 $this ->set_userdata( $new_name $value );
                 $this ->unset_userdata( $name );
             }
         }
     }
     // ------------------------------------------------------------------------
     /**
      * Removes all flashdata marked as 'old'
      *
      * @access  private
      * @return  void
      */
     function  _flashdata_sweep()
     {
         $userdata  $this ->all_userdata();
         foreach  ( $userdata  as  $key  =>  $value )
         {
             if  ( strpos ( $key ':old:' ))
             {
                 $this ->unset_userdata( $key );
             }
         }
     }
     // --------------------------------------------------------------------
     /**
      * Get the "now" time
      *
      * @access  private
      * @return  string
      */
     function  _get_time()
     {
         if  ( strtolower ( $this ->time_reference) ==  'gmt' )
         {
             $now  = time();
             $time  mktime ( gmdate ( "H" $now ),  gmdate ( "i" $now ),  gmdate ( "s" $now ),  gmdate ( "m" $now ),  gmdate ( "d" $now ),  gmdate ( "Y" $now ));
         }
         else
         {
             $time  = time();
         }
         return  $time ;
     }
     // --------------------------------------------------------------------
     /**
      * Write the session cookie
      *
      * @access  public
      * @return  void
      */
     function  _set_cookie( $cookie_data  = NULL)
     {
         if  ( is_null ( $cookie_data ))
         {
             $cookie_data  $this ->userdata;
         }
         // Serialize the userdata for the cookie
         $cookie_data  $this ->_serialize( $cookie_data );
         if  ( $this ->sess_encrypt_cookie == TRUE)
         {
             $cookie_data  $this ->CI->encrypt->encode( $cookie_data );
         }
         $cookie_data  .= hash_hmac( 'sha1' $cookie_data $this ->encryption_key);
         $expire  = ( $this ->sess_expire_on_close === TRUE) ? 0 :  $this ->sess_expiration + time();
         // Set the cookie
         setcookie(
             $this ->sess_cookie_name,
             $cookie_data ,
             $expire ,
             $this ->cookie_path,
             $this ->cookie_domain,
             $this ->cookie_secure
         );
     }
     // --------------------------------------------------------------------
     /**
      * Serialize an array
      *
      * This function first converts any slashes found in the array to a temporary
      * marker, so when it gets unserialized the slashes will be preserved
      *
      * @access  private
      * @param   array
      * @return  string
      */
     function  _serialize( $data )
     {
         if  ( is_array ( $data ))
         {
             foreach  ( $data  as  $key  =>  $val )
             {
                 if  ( is_string ( $val ))
                 {
                     $data [ $key ] =  str_replace ( '\\' '{{slash}}' $val );
                 }
             }
         }
         else
         {
             if  ( is_string ( $data ))
             {
                 $data  str_replace ( '\\' '{{slash}}' $data );
             }
         }
         return  serialize( $data );
     }
     // --------------------------------------------------------------------
     /**
      * Unserialize
      *
      * This function unserializes a data string, then converts any
      * temporary slash markers back to actual slashes
      *
      * @access  private
      * @param   array
      * @return  string
      */
     function  _unserialize( $data )
     {
         $data  = @unserialize(strip_slashes( $data ));
         if  ( is_array ( $data ))
         {
             foreach  ( $data  as  $key  =>  $val )
             {
                 if  ( is_string ( $val ))
                 {
                     $data [ $key ] =  str_replace ( '{{slash}}' '\\' $val );
                 }
             }
             return  $data ;
         }
         return  ( is_string ( $data )) ?  str_replace ( '{{slash}}' '\\' $data ) :  $data ;
     }
     // --------------------------------------------------------------------
     /**
      * Garbage collection
      *
      * This deletes expired session rows from database
      * if the probability percentage is met
      *
      * @access  public
      * @return  void
      */
     function  _sess_gc()
     {
         if  ( $this ->sess_use_database != TRUE)
         {
             return ;
         }
         srand(time());
         if  ((rand() % 100) <  $this ->gc_probability)
         {
             $expire  $this ->now -  $this ->sess_expiration;
             $this ->CI->db->where( "last_activity < {$expire}" );
             $this ->CI->db-> delete ( $this ->sess_table_name);
             log_message( 'debug' 'Session garbage collection performed.' );
         }
     }
}
// END Session Class
/* End of file Session.php */
/* Location: ./system/libraries/Session.php */
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值