CodeIgniter的Session问题

最近有个项目接触到CodeIgniter,让我很是惊叹它的精巧,于是决定用它来做下一个项目。果然,蜜月期过了,毛病就出来了,具体的就是Session的问题。CodeIgniter的Session有两种方式,默认的Session是用Cookie来存储的,也可以切换到数据库存储,但是无论哪种Session都会有些很致命的问题,就是丢失数据。

 

比如 Controller a.php

   1: <?php if (! defined('BASEPATH')) exit('No direct script access allowed');
   2:  
   3: class A extends CI_Controller {
   4:     function __construct()
   5:     {
   6:         parent::__construct();
   7:     }
   8:     function index()
   9:     {
  10:         $this->load->view('a');
  11:     }
  12:     function test()
  13:     {
  14:         $user_data=array();
  15:         $user_data['testval']=$this->input->post('testval');
  16:         $this->session->set_userdata($user_data);
  17:         redirect('b','refresh');
  18:     }
  19: }
  20: ?>
  21:         

Controller B:

   1: <?php if (! defined('BASEPATH')) exit('No direct script access allowed');
   2:  
   3: class B extends CI_Controller {
   4:     fucntion __construct()
   5:     {
   6:         parent::__construct();
   7:     }
   8:     function index()
   9:     {
  10:         echo('#'. $this->session->userdata('testval') . '#');
  11:         $this->load->view('a');
  12:     }
  13: }
  14: ?>

View A:

 

   1: <hr/>
   2: <form action="A/test" method="post">
   3: <input type="text" name="testval" id="testval" value="1234" />
   4: <input type="submit" value="submit"/>
   5: </form>

在autoload.php里面修改,加上对 Session的load

   1: $autoload['libraries']=array('database','session');

然后访问 A, 比如  http://localhost/A, 点提交之后应该刷新,在刷新后的页面上显示出来 1234, 然后神奇的事情发生了。。。 Session没了, 对于redirect, CodeIgniter自动的创建了一个新的session,同样的道理,如果用Ajax访问,也会有个新的Session被创立,结果导致了这个Session根本不能用!

 

折腾了整整一天也没什么效果,后来在github上面找到了一个大牛自己改写的Session Library, 核心就是弃用cookie,转而使用php native session, 保留了一些基本功能,比如 set_userdata(),这需要用下面的代码 覆盖 system/libraries/Session.php 文件

   1: <?php  if (!defined('BASEPATH')) exit('No direct script access allowed');
   2: /**
   3:  * Code Igniter
   4:  *
   5:  * An open source application development framework for PHP 4.3.2 or newer
   6:  *
   7:  * @package        CodeIgniter
   8:  * @author        Dariusz Debowczyk
   9:  * @copyright    Copyright (c) 2006, D.Debowczyk
  10:  * @license        http://www.codeignitor.com/user_guide/license.html 
  11:  * @link        http://www.codeigniter.com
  12:  * @since        Version 1.0
  13:  * @filesource
  14:  */
  15:  
  16: // ------------------------------------------------------------------------
  17:  
  18: /**
  19:  * Session class using native PHP session features and hardened against session fixation.
  20:  * 
  21:  * @package        CodeIgniter
  22:  * @subpackage    Libraries
  23:  * @category    Sessions
  24:  * @author        Dariusz Debowczyk
  25:  * @link        http://www.codeigniter.com/user_guide/libraries/sessions.html
  26:  */
  27: //class Native_session {
  28: class CI_Session {
  29:     var $session_id_ttl; // session id time to live (TTL) in seconds
  30:     var $flash_key = 'flash'; // prefix for "flash" variables (eg. flash:new:message)
  31:     
  32:    // function Native_session()
  33:     function CI_Session()
  34:     {
  35:         $this->object =& get_instance();
  36:         log_message('debug', "Native_session Class Initialized");
  37:         $this->_sess_run();
  38:     }
  39:  
  40:     /**
  41:     * Regenerates session id
  42:     */
  43:     function regenerate_id()
  44:     {
  45:         // copy old session data, including its id
  46:         $old_session_id = session_id();
  47:         $old_session_data = $_SESSION;
  48:  
  49:         // regenerate session id and store it
  50:         session_regenerate_id();
  51:         $new_session_id = session_id();
  52:         
  53:         // switch to the old session and destroy its storage
  54:         session_id($old_session_id);
  55:         session_destroy();
  56:         
  57:         // switch back to the new session id and send the cookie
  58:         session_id($new_session_id);
  59:         session_start();
  60:         
  61:         // restore the old session data into the new session
  62:         $_SESSION = $old_session_data;
  63:         
  64:         // update the session creation time
  65:         $_SESSION['regenerated'] = time();
  66:  
  67:         // session_write_close() patch based on this thread
  68:         // http://www.codeigniter.com/forums/viewthread/1624/
  69:         // there is a question mark ?? as to side affects
  70:  
  71:         // end the current session and store session data.
  72:         session_write_close();
  73:     }
  74:     
  75:     /**
  76:     * Destroys the session and erases session storage
  77:     */
  78:     function destroy()
  79:     {
  80:         unset($_SESSION);
  81:         if ( isset( $_COOKIE[session_name()] ) )
  82:         {
  83:               setcookie(session_name(), '', time()-42000, '/');
  84:         }
  85:         session_destroy();
  86:     }
  87:     
  88:     /**
  89:     * Reads given session attribute value
  90:     */    
  91:     function userdata($item)
  92:     {
  93:         if($item == 'session_id'){ //added for backward-compatibility
  94:             return session_id();
  95:         }else{
  96:             return ( ! isset($_SESSION[$item])) ? false : $_SESSION[$item];
  97:         }
  98:     }
  99:     
 100:     /**
 101:     * Sets session attributes to the given values
 102:     */
 103:     function set_userdata($newdata = array(), $newval = '')
 104:     {
 105:         if (is_string($newdata))
 106:         {
 107:             $newdata = array($newdata => $newval);
 108:         }
 109:     
 110:         if (count($newdata) > 0)
 111:         {
 112:             foreach ($newdata as $key => $val)
 113:             {
 114:                 $_SESSION[$key] = $val;
 115:             }
 116:         }
 117:     }
 118:     
 119:     /**
 120:     * Erases given session attributes
 121:     */
 122:     function unset_userdata($newdata = array())
 123:     {
 124:         if (is_string($newdata))
 125:         {
 126:             $newdata = array($newdata => '');
 127:         }
 128:     
 129:         if (count($newdata) > 0)
 130:         {
 131:             foreach ($newdata as $key => $val)
 132:             {
 133:                 unset($_SESSION[$key]);
 134:             }
 135:         }        
 136:     }
 137:     
 138:     /**
 139:     * Starts up the session system for current request
 140:     */
 141:     function _sess_run()
 142:     {
 143:         $session_id_ttl = $this->object->config->item('sess_expiration');
 144:         
 145:         if (is_numeric($session_id_ttl))
 146:         {
 147:             if ($session_id_ttl > 0)
 148:             {
 149:                 $this->session_id_ttl = $this->object->config->item('sess_expiration');
 150:             }
 151:             else
 152:             {
 153:                 $this->session_id_ttl = (60*60*24*365*2);
 154:             }
 155:         }
 156:         session_start();
 157:         
 158:         // check if session id needs regeneration
 159:         if ( $this->_session_id_expired() )
 160:         {
 161:             // regenerate session id (session data stays the
 162:             // same, but old session storage is destroyed)
 163:             $this->regenerate_id();
 164:         }
 165:         
 166:         // delete old flashdata (from last request)
 167:         $this->_flashdata_sweep();
 168:         
 169:         // mark all new flashdata as old (data will be deleted before next request)
 170:         $this->_flashdata_mark();
 171:     }
 172:     
 173:     /**
 174:     * Checks if session has expired
 175:     */
 176:     function _session_id_expired()
 177:     {
 178:         if ( !isset( $_SESSION['regenerated'] ) )
 179:         {
 180:             $_SESSION['regenerated'] = time();
 181:             return false;
 182:         }
 183:         
 184:         $expiry_time = time() - $this->session_id_ttl;
 185:         
 186:         if ( $_SESSION['regenerated'] <=  $expiry_time )
 187:         {
 188:             return true;
 189:         }
 190:  
 191:         return false;
 192:     }
 193:     
 194:     /**
 195:     * Sets "flash" data which will be available only in next request (then it will
 196:     * be deleted from session). You can use it to implement "Save succeeded" messages
 197:     * after redirect.
 198:     */
 199:     function set_flashdata($key, $value)
 200:     {
 201:         $flash_key = $this->flash_key.':new:'.$key;
 202:         $this->set_userdata($flash_key, $value);
 203:     }
 204:     
 205:     /**
 206:     * Keeps existing "flash" data available to next request.
 207:     */
 208:     function keep_flashdata($key)
 209:     {
 210:         $old_flash_key = $this->flash_key.':old:'.$key;
 211:         $value = $this->userdata($old_flash_key);
 212:  
 213:         $new_flash_key = $this->flash_key.':new:'.$key;
 214:         $this->set_userdata($new_flash_key, $value);
 215:     }
 216:  
 217:     /**
 218:     * Returns "flash" data for the given key.
 219:     */
 220:     function flashdata($key)
 221:     {
 222:         $flash_key = $this->flash_key.':old:'.$key;
 223:         return $this->userdata($flash_key);
 224:     }
 225:     
 226:     /**
 227:     * PRIVATE: Internal method - marks "flash" session attributes as 'old'
 228:     */
 229:     function _flashdata_mark()
 230:     {
 231:         foreach ($_SESSION as $name => $value)
 232:         {
 233:             $parts = explode(':new:', $name);
 234:             if (is_array($parts) && count($parts) == 2)
 235:             {
 236:                 $new_name = $this->flash_key.':old:'.$parts[1];
 237:                 $this->set_userdata($new_name, $value);
 238:                 $this->unset_userdata($name);
 239:             }
 240:         }
 241:     }
 242:  
 243:     /**
 244:     * PRIVATE: Internal method - removes "flash" session marked as 'old'
 245:     */
 246:     function _flashdata_sweep()
 247:     {
 248:         foreach ($_SESSION as $name => $value)
 249:         {
 250:             $parts = explode(':old:', $name);
 251:             if (is_array($parts) && count($parts) == 2 && $parts[0] == $this->flash_key)
 252:             {
 253:                 $this->unset_userdata($name);
 254:             }
 255:         }
 256:     }
 257: }
 258: ?>

 

问题解决了,但是也有局限,

第一 $this->session->sess_create() 和$this->session->sess_destroy() 不见了, 这倒无所谓,没太大影响, 可以用 $this->session->destroy(),

第二,这修改了CodeIgniter的system library,并不是特别好的解决方法。。。

 

哎~ 不过不管怎么说,解决了, 浪费了整整1天的时间。。。

 

点击这里下载Session.php ,修改自 https://github.com/EllisLab/CodeIgniter/wiki/Native-session

posted @ 2012-10-10 21:29  lei1016cn  阅读(3062)  评论(2编辑  收藏  举报