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