Session(會(huì)話)類可以讓你保持一個(gè)用戶的 "狀態(tài)" ,并跟蹤他在瀏覽你的網(wǎng)站時(shí)的活動(dòng)。
CodeIgniter 自帶了幾個(gè)存儲(chǔ) session 的驅(qū)動(dòng):
另外,你也可以基于其他的存儲(chǔ)機(jī)制來(lái)創(chuàng)建你自己的自定義 session 存儲(chǔ)驅(qū)動(dòng), 使用自定義的驅(qū)動(dòng),同樣也可以使用 Session 類提供的那些功能。
[TOC=2.3]
Session 通常會(huì)在每個(gè)頁(yè)面載入的時(shí)候全局運(yùn)行,所以 Session 類必須首先被初始化。 您可以在 控制器 的構(gòu)造函數(shù)中初始化它, 也可以在系統(tǒng)中 自動(dòng)加載。Session 類基本上都是在后臺(tái)運(yùn)行, 你不會(huì)注意到。所以當(dāng)初始化 session 之后,系統(tǒng)會(huì)自動(dòng)讀取、創(chuàng)建和更新 session 數(shù)據(jù) 。
要手動(dòng)初始化 Session 類,你可以在控制器的構(gòu)造函數(shù)中使用 $this->load->library() 方法:
$this->load->library('session');
初始化之后,就可以使用下面的方法來(lái)訪問(wèn) Session 對(duì)象了:
$this->session
重要
由于 加載類 是在 CodeIgniter 的控制器基類中實(shí)例化的, 所以如果要在你的控制器構(gòu)造函數(shù)中加載類庫(kù)的話,確保先調(diào)用 parent::__construct()方法。
當(dāng)頁(yè)面載入后,Session 類就會(huì)檢查用戶的 cookie 中是否存在有效的 session 數(shù)據(jù)。 如果 session 數(shù)據(jù)不存在(或者與服務(wù)端不匹配,或者已經(jīng)過(guò)期), 那么就會(huì)創(chuàng)建一個(gè)新的 session 并保存起來(lái)。
如果 session 數(shù)據(jù)存在并且有效,那么就會(huì)更新 session 的信息。 根據(jù)你的配置,每一次更新都會(huì)生成一個(gè)新的 Session ID 。
有一點(diǎn)非常重要,你需要了解一下,Session 類一旦被初始化,它就會(huì)自動(dòng)運(yùn)行。 上面所說(shuō)的那些,你完全不用做任何操作。正如接下來(lái)你將看到的那樣, 你可以正常的使用 session 數(shù)據(jù),至于讀、寫和更新 session 的操作都是自動(dòng)完成的。
注解
在 CLI 模式下,Session 類將自動(dòng)關(guān)閉,這種做法完全是基于 HTTP 協(xié)議的。
如果你開(kāi)發(fā)的網(wǎng)站并不是大量的使用 AJAX 技術(shù),那么你可以跳過(guò)這一節(jié)。 如果你的網(wǎng)站是大量的使用了 AJAX,并且遇到了性能問(wèn)題,那么下面的注意事項(xiàng), 可能正是你需要的。
在 CodeIgniter 之前的版本中,Session 類并沒(méi)有實(shí)現(xiàn)鎖機(jī)制,這也就意味著, 兩個(gè) HTTP 請(qǐng)求可能會(huì)同時(shí)使用同一個(gè) session 。說(shuō)的更專業(yè)點(diǎn)就是, 請(qǐng)求是非阻塞的。(requests were non-blocking)
在處理 session 時(shí)使用非阻塞的請(qǐng)求同樣意味著不安全,因?yàn)樵谝粋€(gè)請(qǐng)求中修改 session 數(shù)據(jù)(或重新生成 Session ID)會(huì)對(duì)并發(fā)的第二個(gè)請(qǐng)求造成影響。這是導(dǎo)致很多問(wèn)題的根源, 同時(shí)也是為什么 CodeIgniter 3.0 對(duì) Session 類完全重寫的原因。
那么為什么要告訴你這些呢?這是因?yàn)樵谀悴檎倚阅軉?wèn)題的原因時(shí), 可能會(huì)發(fā)現(xiàn)加鎖機(jī)制正是導(dǎo)致性能問(wèn)題的罪魁禍?zhǔn)祝虼司拖胫绾稳サ翩i ...
請(qǐng)不要這樣做! 去掉加鎖機(jī)制是完全錯(cuò)誤的,它會(huì)給你帶來(lái)更多的問(wèn)題!
鎖并不是問(wèn)題,它是一種解決方案。你的問(wèn)題是當(dāng) session 已經(jīng)處理完畢不再需要時(shí), 你還將 session 保持是打開(kāi)的狀態(tài)。所以,你需要做的其實(shí)是,當(dāng)結(jié)束當(dāng)前請(qǐng)求時(shí), 將不再需要的 session 關(guān)閉掉。
簡(jiǎn)單來(lái)說(shuō)就是:當(dāng)你不再需要使用某個(gè) session 變量時(shí),就使用 session_write_close() 方法來(lái)關(guān)閉它。
Session 數(shù)據(jù)是個(gè)簡(jiǎn)單的數(shù)組,帶有一個(gè)特定的 session ID (cookie)。
如果你之前在 PHP 里使用過(guò) session ,你應(yīng)該對(duì) PHP 的 $_SESSION 全局變量 很熟悉(如果沒(méi)有,請(qǐng)閱讀下鏈接中的內(nèi)容)。
CodeIgniter 使用了相同的方式來(lái)訪問(wèn) session 數(shù)據(jù),同時(shí)使用了 PHP 自帶的 session 處理機(jī)制, 使用 session 數(shù)據(jù)和操作 $_SESSION 數(shù)組一樣簡(jiǎn)單(包括讀取,設(shè)置,取消設(shè)置)。
另外,CodeIgniter 還提供了兩種特殊類型的 session 數(shù)據(jù):flashdata 和 tempdata ,在下面將有介紹。
注解
在之前的 CodeIgniter 版本中,常規(guī)的 session 數(shù)據(jù)被稱之為 'userdata' ,當(dāng)文檔中出現(xiàn)這個(gè)詞時(shí)請(qǐng)記住這一點(diǎn)。 大部分都是用于解釋自定義 'userdata' 方法是如何工作的。
session 數(shù)組中的任何信息都可以通過(guò) $_SESSION 全局變量獲取:
$_SESSION['item']
或使用下面的方法(magic getter):
$this->session->item
同時(shí),為了和之前的版本兼容,也可以使用 userdata() 方法:
$this->session->userdata('item');
其中,item 是你想獲取的數(shù)組的鍵值。例如,將 'name' 鍵值對(duì)應(yīng)的項(xiàng)賦值給 $name 變量, 你可以這樣:
$name = $_SESSION['name'];
// or:
$name = $this->session->name
// or:
$name = $this->session->userdata('name');
注解
如果你訪問(wèn)的項(xiàng)不存在,userdata() 方法返回 NULL 。
如果你想獲取所有已存在的 userdata ,你可以忽略 item 參數(shù):
$_SESSION
// or:
$this->session->userdata();
假設(shè)某個(gè)用戶訪問(wèn)你的網(wǎng)站,當(dāng)他完成認(rèn)證之后,你可以將他的用戶名和 email 地址添加到 session 中, 這樣當(dāng)你需要的時(shí)候你就可以直接訪問(wèn)這些數(shù)據(jù),而無(wú)法查詢數(shù)據(jù)庫(kù)了。
你可以簡(jiǎn)單的將數(shù)據(jù)賦值給 $_SESSION 數(shù)組,或賦值給 $this->session 的某個(gè)屬性。
同時(shí),老版本中的通過(guò) "userdata" 來(lái)賦值的方法也還可以用,只不過(guò)是需要傳遞一個(gè)包含你的數(shù)據(jù)的數(shù)組 給 set_userdata() 方法:
$this->session->set_userdata($array);
其中,$array 是包含新增數(shù)據(jù)的一個(gè)關(guān)聯(lián)數(shù)組,下面是個(gè)例子:
$newdata = array(
'username' => 'johndoe',
'email' => 'johndoe@some-site.com',
'logged_in' => TRUE
);
$this->session->set_userdata($newdata);
如果你想一次只添加一個(gè)值,set_userdata() 也支持這種語(yǔ)法:
$this->session->set_userdata('some_name', 'some_value');
如果你想檢查某個(gè) session 值是否存在,可以使用 isset():
// returns FALSE if the 'some_name' item doesn't exist or is NULL,
// TRUE otherwise:
isset($_SESSION['some_name'])
或者,你也可以使用 has_userdata():
$this->session->has_userdata('some_name');
和其他的變量一樣,可以使用 unset() 方法來(lái)刪除 $_SESSION 數(shù)組中的某個(gè)值:
unset($_SESSION['some_name']);
// or multiple values:
unset(
$_SESSION['some_name'],
$_SESSION['another_name']
);
同時(shí),正如 set_userdata() 方法可用于向 session 中添加數(shù)據(jù),unset_userdata() 方法可用于刪除指定鍵值的數(shù)據(jù)。例如,如果你想從你的 session 數(shù)組中刪除 'some_name':
$this->session->unset_userdata('some_name');
這個(gè)方法也可以使用一個(gè)數(shù)組來(lái)同時(shí)刪除多個(gè)值:
$array_items = array('username', 'email');
$this->session->unset_userdata($array_items);
注解
在 CodeIgniter 之前的版本中,unset_userdata() 方法接受一個(gè)關(guān)聯(lián)數(shù)組, 包含 key => 'dummy value' 這樣的鍵值對(duì),這種方式不再支持。
CodeIgniter 支持 "flashdata" ,它指的是一種只對(duì)下一次請(qǐng)求有效的 session 數(shù)據(jù), 之后將會(huì)自動(dòng)被清除。
這用于一次性的信息時(shí)特別有用,例如錯(cuò)誤或狀態(tài)信息(諸如 "第二條記錄刪除成功" 這樣的信息)。
要注意的是,flashdata 就是常規(guī)的 session 變量,只不過(guò)以特殊的方式保存在 '__ci_vars' 鍵下 (警告:請(qǐng)不要亂動(dòng)這個(gè)值)。
將已有的值標(biāo)記為 "flashdata":
$this->session->mark_as_flash('item');
通過(guò)傳一個(gè)數(shù)組,同時(shí)標(biāo)記多個(gè)值為 flashdata:
$this->session->mark_as_flash(array('item', 'item2'));
使用下面的方法來(lái)添加 flashdata:
$_SESSION['item'] = 'value';
$this->session->mark_as_flash('item');
或者,也可以使用 set_flashdata() 方法:
$this->session->set_flashdata('item', 'value');
你還可以傳一個(gè)數(shù)組給 set_flashdata() 方法,和 set_userdata() 方法一樣。
讀取 flashdata 和讀取常規(guī)的 session 數(shù)據(jù)一樣,通過(guò) $_SESSION 數(shù)組:
$_SESSION['item']
重要
userdata() 方法不會(huì)返回 flashdata 數(shù)據(jù)。
如果你要確保你讀取的就是 "flashdata" 數(shù)據(jù),而不是其他類型的數(shù)據(jù),可以使用 flashdata() 方法:
$this->session->flashdata('item');
或者不傳參數(shù),直接返回所有的 flashdata 數(shù)組:
$this->session->flashdata();
注解
如果讀取的值不存在,flashdata() 方法返回 NULL 。
如果你需要在另一個(gè)請(qǐng)求中還繼續(xù)保持 flashdata 變量,你可以使用 keep_flashdata() 方法。 可以傳一個(gè)值,或包含多個(gè)值的一個(gè)數(shù)組。
$this->session->keep_flashdata('item');
$this->session->keep_flashdata(array('item1', 'item2', 'item3'));
CodeIgniter 還支持 "tempdata" ,它指的是一種帶有有效時(shí)間的 session 數(shù)據(jù), 當(dāng)它的有效時(shí)間已過(guò)期,或在有效時(shí)間內(nèi)被刪除,都會(huì)自動(dòng)被清除。
和 flashdata 一樣, tempdata 也是常規(guī)的 session 變量,只不過(guò)以特殊的方式保存在 '__ci_vars' 鍵下 (再次警告:請(qǐng)不要亂動(dòng)這個(gè)值)。
將已有的值標(biāo)記為 "tempdata" ,只需簡(jiǎn)單的將要標(biāo)記的鍵值和過(guò)期時(shí)間(單位為秒)傳給 mark_as_temp() 方法即可:
// 'item' will be erased after 300 seconds
$this->session->mark_as_temp('item', 300);
你也可以同時(shí)標(biāo)記多個(gè)值為 tempdata ,有下面兩種不同的方式, 這取決于你是否要將所有的值都設(shè)置成相同的過(guò)期時(shí)間:
// Both 'item' and 'item2' will expire after 300 seconds
$this->session->mark_as_temp(array('item', 'item2'), 300);
// 'item' will be erased after 300 seconds, while 'item2'
// will do so after only 240 seconds
$this->session->mark_as_temp(array(
'item' => 300,
'item2' => 240
));
使用下面的方法來(lái)添加 tempdata:
$_SESSION['item'] = 'value';
$this->session->mark_as_temp('item', 300); // Expire in 5 minutes
或者,也可以使用 set_tempdata() 方法:
$this->session->set_tempdata('item', 'value', 300);
你還可以傳一個(gè)數(shù)組給 set_tempdata() 方法:
$tempdata = array('newuser' => TRUE, 'message' => 'Thanks for joining!');
$this->session->set_tempdata($tempdata, NULL, $expire);
注解
如果沒(méi)有設(shè)置 expiration 參數(shù),或者設(shè)置為 0 ,將默認(rèn)使用 300秒(5分鐘)作為生存時(shí)間(time-to-live)。
要讀取 tempdata 數(shù)據(jù),你可以再一次通過(guò) $_SESSION 數(shù)組:
$_SESSION['item']
重要
userdata() 方法不會(huì)返回 tempdata 數(shù)據(jù)。
如果你要確保你讀取的就是 "tempdata" 數(shù)據(jù),而不是其他類型的數(shù)據(jù),可以使用 tempdata() 方法:
$this->session->tempdata('item');
或者不傳參數(shù),直接返回所有的 tempdata 數(shù)組:
$this->session->tempdata();
注解
如果讀取的值不存在,tempdata() 方法返回 NULL 。
如果你需要在某個(gè) tempdata 過(guò)期之前刪除它,你可以直接通過(guò) $_SESSION 數(shù)組來(lái)刪除:
unset($_SESSION['item']);
但是,這不會(huì)刪除這個(gè)值的 tempdata 標(biāo)記(會(huì)在下一次 HTTP 請(qǐng)求時(shí)失效),所以, 如果你打算在相同的請(qǐng)求中重用這個(gè)值,你可以使用unset_tempdata():
$this->session->unset_tempdata('item');
要清除當(dāng)前的 session(例如:退出登錄時(shí)),你可以簡(jiǎn)單的使用 PHP 自帶的 session_destroy() 函數(shù)或者 sess_destroy() 方法。 兩種方式效果完全一樣:
session_destroy();
// or
$this->session->sess_destroy();
注解
這必須是同一個(gè)請(qǐng)求中關(guān)于 session 的最后一次操作,所有的 session 數(shù)據(jù)(包括 flashdata 和 tempdata)都被永久性銷毀,銷毀之后,關(guān)于 session 的方法將不可用。
在之前的 CodeIgniter 版本中,session 數(shù)據(jù)默認(rèn)包含 4 項(xiàng):'session_id' 、 'ip_address' 、 'user_agent' 、 'last_activity' 。
這是由 session 具體的工作方式?jīng)Q定的,但是我們現(xiàn)在的實(shí)現(xiàn)沒(méi)必要這樣做了。 盡管如此,你的應(yīng)用程序可能還依賴于這些值,所以下面提供了訪問(wèn)這些值的替代方法:
- session_id: session_id()
- ip_address: $_SERVER['REMOTE_ADDR']
- user_agent: $this->input->user_agent() (unused by sessions)
- last_activity: 取決于 session 的存儲(chǔ)方式,沒(méi)有直接的方法,抱歉!
在 CodeIgniter 中通常所有的東西都是拿來(lái)直接就可以用的,盡管如此,session 對(duì)于所有的程序來(lái)說(shuō), 都是一個(gè)非常敏感的部分,所以必須要小心的配置它。請(qǐng)花點(diǎn)時(shí)間研究下下面所有的選項(xiàng)以及每個(gè)選項(xiàng)的作用。
你可以在你的配置文件 application/config/config.php 中找到下面的關(guān)于 session 的配置參數(shù):
參數(shù) | 默認(rèn)值 | 選項(xiàng) | 描述 |
---|---|---|---|
sess_driver | files | files/database/redis/memcached/custom | 使用的存儲(chǔ) session 的驅(qū)動(dòng) |
sess_cookie_name | ci_session | [A-Za-z_-] characters only | session cookie 的名稱 |
sess_expiration | 7200 (2 hours) | Time in seconds (integer) | 你希望 session 持續(xù)的秒數(shù) 如果你希望 session 不過(guò)期(直到瀏覽器關(guān)閉),將其設(shè)置為 0 |
sess_save_path | NULL | None | 指定存儲(chǔ)位置,取決于使用的存儲(chǔ) session 的驅(qū)動(dòng) |
sess_match_ip | FALSE | TRUE/FALSE (boolean) | 讀取 session cookie 時(shí),是否驗(yàn)證用戶的 IP 地址 注意有些 ISP 會(huì)動(dòng)態(tài)的修改 IP ,所以如果你想要一個(gè)不過(guò)期的 session,將其設(shè)置為 FALSE |
sess_time_to_update | 300 | Time in seconds (integer) | 該選項(xiàng)用于控制過(guò)多久將重新生成一個(gè)新 session ID 設(shè)置為 0 將禁用 session ID 的重新生成 |
sess_regenerate_destroy | FALSE | TRUE/FALSE (boolean) | 當(dāng)自動(dòng)重新生成 session ID 時(shí),是否銷毀老的 session ID 對(duì)應(yīng)的數(shù)據(jù) 如果設(shè)置為 FALSE ,數(shù)據(jù)之后將自動(dòng)被垃圾回收器刪除 |
注解
如果上面的某個(gè)參數(shù)沒(méi)有配置,Session 類將會(huì)試圖讀取 php.ini 配置文件中的 session 相關(guān)的配置 (例如 'sess_expire_on_close')。但是,請(qǐng)不要依賴于這個(gè)行為,因?yàn)檫@可能會(huì)導(dǎo)致不可預(yù)期的結(jié)果,而且 這也有可能在未來(lái)的版本中修改。請(qǐng)合理的配置每一個(gè)參數(shù)。
除了上面的這些參數(shù)之外,cookie 和 session 原生的驅(qū)動(dòng)還會(huì)公用下面這些 由 輸入類 和 安全類 提供的配置參數(shù)。
參數(shù) | 默認(rèn)值 | 描述 |
---|---|---|
cookie_domain | '' | session 可用的域 |
cookie_path | / | session 可用的路徑 |
cookie_secure | FALSE | 是否只在加密連接(HTTPS)時(shí)創(chuàng)建 session cookie |
注解
'cookie_httponly' 配置對(duì) session 沒(méi)有影響。出于安全原因,HttpOnly 參數(shù)將一直啟用。 另外,'cookie_prefix' 參數(shù)完全可以忽略。
正如上面提到的,Session 類自帶了 4 種不同的驅(qū)動(dòng)(或叫做存儲(chǔ)引擎)可供使用:
- files
- database
- redis
- memcached
默認(rèn)情況下,初始化 session 時(shí)將使用 文件驅(qū)動(dòng) ,因?yàn)檫@是最安全的選擇,可以在所有地方按預(yù)期工作 (幾乎所有的環(huán)境下都有文件系統(tǒng))。
但是,你也可以通過(guò) application/config/config.php 配置文件中的 $config['sess_driver'] 參數(shù)來(lái)使用任何其他的驅(qū)動(dòng)。特別提醒的是,每一種驅(qū)動(dòng)都有它自己的注意事項(xiàng),所以在你選擇之前, 確定你熟悉它們。
另外,如果默認(rèn)提供的這些不能滿足你的需求,你也可以創(chuàng)建和使用 自定義驅(qū)動(dòng) 。
注解
在之前版本的 CodeIgniter 中,只有 "cookie 驅(qū)動(dòng)" 這唯一的一種選擇, 因?yàn)檫@個(gè)我們收到了大量的負(fù)面的反饋。因此,我們吸取了社區(qū)的反饋意見(jiàn),同時(shí)也要提醒你, 因?yàn)樗?strong>不安全,所以已經(jīng)被廢棄了,建議你不要試著通過(guò) 自定義驅(qū)動(dòng) 來(lái)重新實(shí)現(xiàn)它。
文件驅(qū)動(dòng)利用你的文件系統(tǒng)來(lái)存儲(chǔ) session 數(shù)據(jù)。
可以說(shuō),文件驅(qū)動(dòng)和 PHP 自帶的默認(rèn) session 實(shí)現(xiàn)非常類似,但是有一個(gè)很重要的細(xì)節(jié)要注意的是, 實(shí)際上它們的代碼并不相同,而且有一些局限性(以及優(yōu)勢(shì))。
說(shuō)的更具體點(diǎn),它不支持 PHP 的 session.save_path 參數(shù)的 目錄分級(jí)(directory level)和 mode 格式 , 另外為了安全性大多數(shù)的參數(shù)都被硬編碼。只提供了 $config['sess_save_path'] 參數(shù)用于設(shè)置絕對(duì)路徑。
另一個(gè)很重要的事情是,確保存儲(chǔ) session 文件的目錄不能被公開(kāi)訪問(wèn)到或者是共享目錄,確保 只有你 能訪問(wèn)并查看配置的 sess_save_path 目錄中的內(nèi)容。否則,如果任何人都能訪問(wèn), 他們就可以從中竊取到當(dāng)前的 session (這也被稱為 session 固定(session fixation)攻擊)
在類 UNIX 操作系統(tǒng)中,這可以通過(guò)在該目錄上執(zhí)行 chmod 命令,將權(quán)限設(shè)置為 0700 來(lái)實(shí)現(xiàn), 這樣就可以只允許目錄的所有者執(zhí)行讀取和寫入操作。但是要注意的是,腳本的執(zhí)行者通常不是你自己, 而是類似于 'www-data' 這樣的用戶,所以只設(shè)置權(quán)限可能會(huì)破壞你的程序。
根據(jù)你的環(huán)境,你應(yīng)該像下面這樣來(lái)操作。
mkdir /<path to your application directory>/sessions/
chmod 0700 /<path to your application directory>/sessions/
chown www-data /<path to your application directory>/sessions/
有些人可能會(huì)選擇使用其他的 session 驅(qū)動(dòng),他們認(rèn)為文件存儲(chǔ)通常比較慢。其實(shí)這并不總是對(duì)的。
執(zhí)行一些簡(jiǎn)單的測(cè)試可能會(huì)讓你真的相信 SQL 數(shù)據(jù)庫(kù)更快一點(diǎn),但是在 99% 的情況下,這只是當(dāng)你的 session 并發(fā)非常少的時(shí)候是對(duì)的。當(dāng) session 的并發(fā)數(shù)越來(lái)越大,服務(wù)器的負(fù)載越來(lái)越高, 這時(shí)就不一樣了,文件系統(tǒng)將會(huì)勝過(guò)幾乎所有的關(guān)系型數(shù)據(jù)庫(kù)。
另外,如果性能是你唯一關(guān)心的,你可以看下 tmpfs (注意:外部資源),它可以讓你的 session 非???。
數(shù)據(jù)庫(kù)驅(qū)動(dòng)使用諸如 MySQL 或 PostgreSQL 這樣的關(guān)系型數(shù)據(jù)庫(kù)來(lái)存儲(chǔ) session , 這是一個(gè)非常常見(jiàn)的選擇,因?yàn)樗梢宰岄_(kāi)發(fā)者非常方便的訪問(wèn)應(yīng)用中的 session 數(shù)據(jù), 因?yàn)樗皇悄愕臄?shù)據(jù)庫(kù)中的一個(gè)表而已。
但是,還是有幾點(diǎn)要求必須滿足:
- 只有設(shè)置為 default 的數(shù)據(jù)庫(kù)連接可以使用(或者在控制器中使用 $this->db 來(lái)訪問(wèn)的連接)
- 你必須啟用 查詢構(gòu)造器
- 不能使用持久連接
- 使用的數(shù)據(jù)庫(kù)連接不能啟用 cache_on 參數(shù)
為了使用數(shù)據(jù)庫(kù)驅(qū)動(dòng),你還需要?jiǎng)?chuàng)建一個(gè)我們剛剛已經(jīng)提到的數(shù)據(jù)表,然后將 $config['sess_save_path'] 參數(shù)設(shè)置為表名。例如,如果你想使用 'ci_sessions' 這個(gè)表名,你可以這樣:
$config['sess_driver'] = 'database';
$config['sess_save_path'] = 'ci_sessions';
注解
如果你從 CodeIgniter 之前的版本中升級(jí)過(guò)來(lái)的,并且沒(méi)有配置 'sess_save_path' 參數(shù), Session 類將查找并使用老的 'sess_table_name' 參數(shù)替代。請(qǐng)不要依賴這個(gè)行為, 因?yàn)樗赡軙?huì)在以后的版本中移除。
然后,新建數(shù)據(jù)表 。
對(duì)于 MySQL:
CREATE TABLE IF NOT EXISTS `ci_sessions` (
`id` varchar(40) NOT NULL,
`ip_address` varchar(45) NOT NULL,
`timestamp` int(10) unsigned DEFAULT 0 NOT NULL,
`data` blob NOT NULL,
PRIMARY KEY (id),
KEY `ci_sessions_timestamp` (`timestamp`)
);
對(duì)于 PostgreSQL:
CREATE TABLE "ci_sessions" (
"id" varchar(40) NOT NULL,
"ip_address" varchar(45) NOT NULL,
"timestamp" bigint DEFAULT 0 NOT NULL,
"data" text DEFAULT '' NOT NULL,
PRIMARY KEY ("id")
);
CREATE INDEX "ci_sessions_timestamp" ON "ci_sessions" ("timestamp");
如果你想開(kāi)啟 sess_match_ip 參數(shù),你還應(yīng)該在新建表之后進(jìn)行如下操作:
// Works both on MySQL and PostgreSQL
ALTER TABLE ci_sessions ADD CONSTRAINT ci_sessions_id_ip UNIQUE (id, ip_address);
重要
只有 MySQL 和 PostgreSQL 數(shù)據(jù)庫(kù)是被正式支持的,因?yàn)槠渌麛?shù)據(jù)庫(kù)平臺(tái)都缺乏合適的鎖機(jī)制。 在沒(méi)鎖的情況下使用 session 可能會(huì)導(dǎo)致大量的問(wèn)題,特別是使用了大量的 AJAX , 所以我們并不打算支持這種情況。如果你遇到了性能問(wèn)題,請(qǐng)你在完成 session 數(shù)據(jù)的處理之后, 調(diào)用session_write_close() 方法。
注解
由于 Redis 沒(méi)有鎖機(jī)制,這個(gè)驅(qū)動(dòng)的鎖是通過(guò)一個(gè)保持 300 秒的值來(lái)模擬的 (emulated by a separate value that is kept for up to 300 seconds)。
Redis 是一種存儲(chǔ)引擎,通常用于緩存,并由于他的高性能而流行起來(lái),這可能也正是你使用 Redis 驅(qū)動(dòng)的原因。
缺點(diǎn)是它并不像關(guān)系型數(shù)據(jù)庫(kù)那樣普遍,需要你的系統(tǒng)中安裝了 phpredis 這個(gè) PHP 擴(kuò)展,它并不是 PHP 程序自帶的。 可能的情況是,你使用 Redis 驅(qū)動(dòng)的原因是你已經(jīng)非常熟悉 Redis 了并且你使用它還有其他的目的。
和文件驅(qū)動(dòng)和數(shù)據(jù)庫(kù)驅(qū)動(dòng)一樣,你必須通過(guò) $config['sess_save_path'] 參數(shù)來(lái)配置存儲(chǔ) session 的位置。 這里的格式有些不同,同時(shí)也要復(fù)雜一點(diǎn),這在 phpredis 擴(kuò)展的 README 文件中有很好的解釋,鏈接如下:
https://github.com/phpredis/phpredis#php-session-handler
警告
CodeIgniter 的 Session 類并沒(méi)有真的用到 'redis' 的 session.save_handler , 只是 采用了它的路徑的格式而已。
最常見(jiàn)的情況是,一個(gè)簡(jiǎn)單 host:port 對(duì)就可以了:
$config['sess_driver'] = 'redis';
$config['sess_save_path'] = 'tcp://localhost:6379';
注解
由于 Memcache 沒(méi)有鎖機(jī)制,這個(gè)驅(qū)動(dòng)的鎖是通過(guò)一個(gè)保持 300 秒的值來(lái)模擬的 (emulated by a separate value that is kept for up to 300 seconds)。
Memcached 驅(qū)動(dòng)和 Redis 驅(qū)動(dòng)非常相似,除了它的可用性可能要好點(diǎn),因?yàn)?PHP 的 Memcached 擴(kuò)展已經(jīng)通過(guò) PECL 發(fā)布了,并且在某些 Linux 發(fā)行版本中, 可以非常方便的安裝它。
除了這一點(diǎn),以及排除任何對(duì) Redis 的偏見(jiàn),關(guān)于 Memcached 要說(shuō)的真的沒(méi)什么區(qū)別, 它也是一款通常用于緩存的產(chǎn)品,而且以它的速度而聞名。
不過(guò),值得注意的是,使用 Memcached 設(shè)置 X 的過(guò)期時(shí)間為 Y 秒,它只能保證 X 會(huì)在 Y 秒過(guò)后被刪除 (但不會(huì)早于這個(gè)時(shí)間)。這個(gè)是非常少見(jiàn)的,但是應(yīng)該注意一下,因?yàn)樗赡軙?huì)導(dǎo)致 session 的丟失。
$config['sess_save_path'] 參數(shù)的格式相當(dāng)簡(jiǎn)單,使用 host:port 對(duì)即可:
$config['sess_driver'] = 'memcached';
$config['sess_save_path'] = 'localhost:11211';
也可以使用一個(gè)可選的 權(quán)重 參數(shù)來(lái)支持多服務(wù)器的配置,權(quán)重參數(shù)使用冒號(hào)分割(:weight), 但是我們并沒(méi)有測(cè)試這是絕對(duì)可靠的。
如果你想體驗(yàn)這個(gè)特性(風(fēng)險(xiǎn)自負(fù)),只需簡(jiǎn)單的將多個(gè)服務(wù)器使用逗號(hào)分隔:
// localhost will be given higher priority (5) here,
// compared to 192.0.2.1 with a weight of 1.
$config['sess_save_path'] = 'localhost:11211:5,192.0.2.1:11211:1';
你也可以創(chuàng)建你自己的自定義 session 驅(qū)動(dòng),但是要記住的是,這通常來(lái)說(shuō)都不是那么簡(jiǎn)單, 因?yàn)樾枰玫胶芏嘀R(shí)來(lái)正確實(shí)現(xiàn)它。
你不僅要知道 session 一般的工作原理,而且要知道它在 PHP 中是如何實(shí)現(xiàn)的, 還要知道它的內(nèi)部存儲(chǔ)機(jī)制是如何工作的,如何去處理并發(fā),如何去避免死鎖(不是通過(guò)去掉鎖機(jī)制), 以及最后一點(diǎn)但也是很重要的一點(diǎn),如何去處理潛在的安全問(wèn)題。
總的來(lái)說(shuō),如果你不知道怎么在原生的 PHP 中實(shí)現(xiàn)這些,那么你也不應(yīng)該在 CodeIgniter 中嘗試實(shí)現(xiàn)它。 我已經(jīng)警告過(guò)你了。
如果你只想給你的 session 添加一些額外的功能,你只要擴(kuò)展 Session 基類就可以了,這要容易的多。 要學(xué)習(xí)如何實(shí)現(xiàn)這點(diǎn),請(qǐng)閱讀 創(chuàng)建你的類庫(kù) 這一節(jié)。
言歸正傳,當(dāng)你為 CodeIgniter 創(chuàng)建 session 驅(qū)動(dòng)時(shí),有三條規(guī)則你必須遵循:
將你的驅(qū)動(dòng)文件放在 application/libraries/Session/drivers/ 目錄下,并遵循 Session 類所使用的命名規(guī)范。
例如,如果你想創(chuàng)建一個(gè)名為 'dummy' 的驅(qū)動(dòng),那么你需要?jiǎng)?chuàng)建一個(gè)名為 Session_dummy_driver 的類, 并將其放在application/libraries/Session/drivers/Session_dummy_driver.php 文件中。
擴(kuò)展 CI_Session_driver 類。
這只是一個(gè)擁有幾個(gè)內(nèi)部輔助方法的基本類,同樣可以和其他類庫(kù)一樣被擴(kuò)展。如果你真的需要這樣做, 我們并不打算在這里多做解釋,因?yàn)槿绻阒廊绾卧?CI 中擴(kuò)展或覆寫類,那么你已經(jīng)知道這樣做的方法了。 如果你還不知道,那么可能你根本就不應(yīng)該這樣做。
實(shí)現(xiàn) SessionHandlerInterface 接口。
注解
你可能已經(jīng)注意到 SessionHandlerInterface 接口已經(jīng)在 PHP 5.4.0 之后的版本中提供了。 CodeIgniter 會(huì)在你運(yùn)行老版本的 PHP 時(shí)自動(dòng)聲明這個(gè)接口。
參考連接中的內(nèi)容,了解為什么以及如何實(shí)現(xiàn)。
所以,使用我們上面的 'dummy' 驅(qū)動(dòng)的例子,你可能會(huì)寫如下代碼:
// application/libraries/Session/drivers/Session_dummy_driver.php:
class CI_Session_dummy_driver extends CI_Session_driver implements SessionHandlerInterface
{
public function __construct(&$params)
{
// DO NOT forget this
parent::__construct($params);
// Configuration & other initializations
}
public function open($save_path, $name)
{
// Initialize storage mechanism (connection)
}
public function read($session_id)
{
// Read session data (if exists), acquire locks
}
public function write($session_id, $session_data)
{
// Create / update session data (it might not exist!)
}
public function close()
{
// Free locks, close connections / streams / etc.
}
public function destroy($session_id)
{
// Call close() method & destroy data for current session (order may differ)
}
public function gc($maxlifetime)
{
// Erase data for expired sessions
}
}
如果一切順利,現(xiàn)在你就可以將 sess_driver 參數(shù)設(shè)置為 'dummy' ,來(lái)使用你自定義的驅(qū)動(dòng)。恭喜你!
classCI_Session
userdata([$key = NULL])
參數(shù):
返回: Value of the specified item key, or an array of all userdata
返回類型: mixed
從 $_SESSION 數(shù)組中獲取指定的項(xiàng)。如果沒(méi)有指定參數(shù),返回所有 "userdata" 的數(shù)組。
注解
這是個(gè)遺留方法,只是為了和老的應(yīng)用程序向前兼容而保留。 你可以直接使用 $_SESSION 替代它。
all_userdata()
返回: An array of all userdata
返回類型: array
返回所有 "userdata" 的數(shù)組。
注解
該方法已廢棄,使用不帶參數(shù)的 userdata() 方法來(lái)代替。
&get_userdata()
返回: A reference to $_SESSION
返回類型: array
返回一個(gè) $_SESSION 數(shù)組的引用。
注解
這是個(gè)遺留方法,只是為了和老的應(yīng)用程序向前兼容而保留。
has_userdata($key)
參數(shù):
返回: TRUE if the specified key exists, FALSE if not
返回類型: bool
檢查 $_SESSION 數(shù)組中是否存在某項(xiàng)。
注解
這是個(gè)遺留方法,只是為了和老的應(yīng)用程序向前兼容而保留。 它只是 isset($_SESSION[$key]) 的一個(gè)別名,請(qǐng)使用這個(gè)來(lái)替代它。
set_userdata($data[, $value = NULL])
參數(shù):
返回類型: void
將數(shù)據(jù)賦值給 $_SESSION 全局變量。
注解
這是個(gè)遺留方法,只是為了和老的應(yīng)用程序向前兼容而保留。
unset_userdata($key)
參數(shù):
返回類型: void
從 $_SESSION 全局變量中刪除某個(gè)值。
注解
這是個(gè)遺留方法,只是為了和老的應(yīng)用程序向前兼容而保留。 它只是 unset($_SESSION[$key]) 的一個(gè)別名,請(qǐng)使用這個(gè)來(lái)替代它。
mark_as_flash($key)
參數(shù):
返回: TRUE on success, FALSE on failure
返回類型: bool
將 $_SESSION 數(shù)組中的一項(xiàng)(或多項(xiàng))標(biāo)記為 "flashdata" 。
get_flash_keys()
返回: Array containing the keys of all "flashdata" items.
返回類型: array
獲取 $_SESSION 數(shù)組中所有標(biāo)記為 "flashdata" 的一個(gè)列表。
umark_flash($key)
參數(shù):
返回類型: void
將 $_SESSION 數(shù)組中的一項(xiàng)(或多項(xiàng))移除 "flashdata" 標(biāo)記。
flashdata([$key = NULL])
參數(shù):
返回: Value of the specified item key, or an array of all flashdata
返回類型: mixed
從 $_SESSION 數(shù)組中獲取某個(gè)標(biāo)記為 "flashdata" 的指定項(xiàng)。 如果沒(méi)有指定參數(shù),返回所有 "flashdata" 的數(shù)組。
注解
這是個(gè)遺留方法,只是為了和老的應(yīng)用程序向前兼容而保留。 你可以直接使用 $_SESSION 替代它。
keep_flashdata($key)
參數(shù):
返回: TRUE on success, FALSE on failure
返回類型: bool
將某個(gè)指定的 "flashdata" 設(shè)置為在下一次請(qǐng)求中仍然保持有效。
注解
這是個(gè)遺留方法,只是為了和老的應(yīng)用程序向前兼容而保留。 它只是 mark_as_flash() 方法的一個(gè)別名。
set_flashdata($data[, $value = NULL])
參數(shù):
返回類型: void
將數(shù)據(jù)賦值給 $_SESSION 全局變量,并標(biāo)記為 "flashdata" 。
注解
這是個(gè)遺留方法,只是為了和老的應(yīng)用程序向前兼容而保留。
mark_as_temp($key[, $ttl = 300])
參數(shù):
返回: TRUE on success, FALSE on failure
返回類型: bool
將 $_SESSION 數(shù)組中的一項(xiàng)(或多項(xiàng))標(biāo)記為 "tempdata" 。
get_temp_keys()
返回: Array containing the keys of all "tempdata" items.
返回類型: array
獲取 $_SESSION 數(shù)組中所有標(biāo)記為 "tempdata" 的一個(gè)列表。
umark_temp($key)
參數(shù):
返回類型: void
將 $_SESSION 數(shù)組中的一項(xiàng)(或多項(xiàng))移除 "tempdata" 標(biāo)記。
tempdata([$key = NULL])
參數(shù):
返回: Value of the specified item key, or an array of all tempdata
返回類型: mixed
從 $_SESSION 數(shù)組中獲取某個(gè)標(biāo)記為 "tempdata" 的指定項(xiàng)。 如果沒(méi)有指定參數(shù),返回所有 "tempdata" 的數(shù)組。
注解
這是個(gè)遺留方法,只是為了和老的應(yīng)用程序向前兼容而保留。 你可以直接使用 $_SESSION 替代它。
set_tempdata($data[, $value = NULL])
參數(shù):
返回類型: void
將數(shù)據(jù)賦值給 $_SESSION 全局變量,并標(biāo)記為 "tempdata" 。
注解
這是個(gè)遺留方法,只是為了和老的應(yīng)用程序向前兼容而保留。
sess_regenerate([$destroy = FALSE])
參數(shù):
返回類型: void
重新生成 session ID ,$destroy 參數(shù)可選,用于銷毀當(dāng)前的 session 數(shù)據(jù)。
注解
該方法只是 PHP 原生的 session_regenerate_id() 函數(shù)的一個(gè)別名而已。
sess_destroy()
返回類型: void
銷毀當(dāng)前 session 。
注解
這個(gè)方法必須在處理 session 相關(guān)的操作的最后調(diào)用。 如果調(diào)用這個(gè)方法,所有的 session 數(shù)據(jù)都會(huì)丟失。
注解
該方法只是 PHP 原生的 session_destroy() 函數(shù)的一個(gè)別名而已。
__get($key)
參數(shù):
返回: The requested session data item, or NULL if it doesn't exist
返回類型: mixed
魔術(shù)方法,根據(jù)你的喜好,使用 $this->session->item 這種方式來(lái)替代 $_SESSION['item'] 。
如果你訪問(wèn) $this->session->session_id 它也會(huì)調(diào)用 session_id() 方法來(lái)返回 session ID 。
__set($key, $value)
參數(shù):
返回: void
魔術(shù)方法,直接賦值給 $this->session 屬性,以此來(lái)替代賦值給 $_SESSION 數(shù)組:
$this->session->foo = 'bar';
// Results in:
// $_SESSION['foo'] = 'bar';
更多建議: