掃二維碼與項(xiàng)目經(jīng)理溝通
我們?cè)谖⑿派?4小時(shí)期待你的聲音
解答本文疑問(wèn)/技術(shù)咨詢(xún)/運(yùn)營(yíng)咨詢(xún)/技術(shù)建議/互聯(lián)網(wǎng)交流
. PHP 的Cookie

cookie 是一種在遠(yuǎn)程瀏覽器端儲(chǔ)存數(shù)據(jù)并以此來(lái)跟蹤和識(shí)別用戶(hù)的機(jī)制。
PHP 在http 協(xié)議的頭信息里發(fā)送cookie,因此 setcookie() 函數(shù)必須在其它信息被輸出到瀏覽器
前調(diào)用,這和對(duì) header() 函數(shù)的限制類(lèi)似。
1.1 設(shè)置cookie:
可以用 setcookie()或 setrawcookie()函數(shù)來(lái)設(shè)置 cookie。也可以通過(guò)向客戶(hù)端直接發(fā)送http 頭來(lái)設(shè)置。
1.1.1 使用 setcookie()函數(shù)設(shè)置cookie:
bool setcookie ( string name [, string value [, int expire [, string path [, string domain [, bool secure [, bool
httponly]]]]]] )
name: cookie 變量名
value:cookie 變量的值
expire: 有效期結(jié)束的時(shí)間
path: 有效目錄
domain: 有效域名,頂級(jí)域唯一
secure: 如果值為 1,則cookie 只能在https 連接上有效,如果為默認(rèn)值 0,則http 和 https 都可以。
例子:
代碼片段
- $value = 'something from somewhere';
- setcookie("TestCookie", $value); /* 簡(jiǎn)單 cookie設(shè)置 */
- setcookie("TestCookie", $value, time()+3600); /* 有效期 1個(gè)小時(shí) */
- setcookie("TestCookie", $value, time()+3600, "/~rasmus/",
- ".example.com", 1); /* 有效目錄 /~rasmus,有效域名 example.com及其所有子域名
- */
- ?>
設(shè)置多個(gè) cookie 變量:setcookie('var[a]','value'); 用數(shù)組來(lái)表示變量,但他的下標(biāo)不用引號(hào)。這
樣就可以用$_COOKIE[‘var’][‘a(chǎn)’]來(lái)讀取該COOKIE 變量。
1.1.2. 使用 header()設(shè)置cookie;
header("Set-Cookie: name=$value[;path=$path[;domain=xxx.com[;...]]");
后面的參數(shù)和上面列出 setcookie 函數(shù)的參數(shù)一樣。
比如:
代碼片段
- $value = 'something from somewhere';
- header("Set-Cookie:name=$value");
1.2 Cookie 的讀取:
直接用php 內(nèi)置超級(jí)全局變量$_COOKIE 就可以讀取瀏覽器端的cookie。
面例子中設(shè)置了cookie "TestCookie",現(xiàn)在我們來(lái)讀?。?/p>
代碼片段
- print $_COOKIE['TestCookie'];
COOKIE 是不是被輸出了?!
1.3 刪除cookie
只需把有效時(shí)間設(shè)為小于當(dāng)前時(shí)間,和把值設(shè)置為空。例如:
代碼片段
- setcookie("name", "", time()-1);
用header()類(lèi)似。
1.4 常見(jiàn)問(wèn)題解決:
1) 用 setcookie()時(shí)有錯(cuò)誤提示,可能是因?yàn)檎{(diào)用setcookie()前面有輸出或空格。也可能你的文
檔是從其他字符集轉(zhuǎn)換過(guò)來(lái),文檔后面可能帶有 BOM 簽名(就是在文件內(nèi)容添加一些隱藏
的BOM 字符)。解決的辦法就是使你的文檔不出現(xiàn)這種情況。還有通過(guò)使用ob_start()函數(shù)
也能處理一點(diǎn)。
2) $_COOKIE 受magic_quotes_gpc 影響,可能自動(dòng)轉(zhuǎn)義。
3) 使用的時(shí)候,有必要測(cè)試用戶(hù)是否支持cookie。
1.5 cookie 工作機(jī)理:
有些學(xué)習(xí)者比較沖動(dòng),沒(méi)心思把原理研究,所以我把它放后面。
a) 服務(wù)器通過(guò)隨著響應(yīng)發(fā)送一個(gè)http 的Set-Cookie 頭,在客戶(hù)機(jī)中設(shè)置一個(gè)cookie(多個(gè)cookie要多個(gè)頭)。
b) 客戶(hù)端自動(dòng)向服務(wù)器端發(fā)送一個(gè)http 的cookie 頭,服務(wù)器接收讀取。
HTTP/1.x 200 OK
X-Powered-By: PHP/5.2.1
Set-Cookie: TestCookie=something from somewhere; path=/
Expires: Thu, 19 Nov 2007 18:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Pragma: no-cache
Content-type: text/html
這一行實(shí)現(xiàn)了cookie 功能,收到這行后
Set-Cookie: TestCookie=something from somewhere; path=/
瀏覽器將在客戶(hù)端的磁盤(pán)上創(chuàng)建一個(gè)cookie 文件,并在里面寫(xiě)入:
TestCookie=something from somewhere;
/
這一行就是我們用 setcookie('TestCookie','something from somewhere','/'); 的結(jié)果。也就是用
header('Set-Cookie: TestCookie=something from somewhere; path=/');的結(jié)果。
2. PHP 的SESSION
session 使用過(guò)期時(shí)間設(shè)為0 的cookie,并且將一個(gè)稱(chēng)為session ID 的唯一標(biāo)識(shí)符(一長(zhǎng)串字符串),
在服務(wù)器端同步生成一些 session 文件(可以自己定義 session 的保存類(lèi)型),與用戶(hù)機(jī)關(guān)聯(lián)起來(lái)。web
應(yīng)用程序存貯與這些 session 相關(guān)的數(shù)據(jù),并且讓數(shù)據(jù)隨著用戶(hù)在頁(yè)面之間傳遞。
訪(fǎng)問(wèn)網(wǎng)站的來(lái)客會(huì)被分配一個(gè)唯一的標(biāo)識(shí)符,即所謂的 SESSION ID。它要么存放在客戶(hù)端的
cookie,要么經(jīng)由 URL 傳遞。
SESSION 允許用戶(hù)注冊(cè)任意數(shù)目的變量并保留給各個(gè)請(qǐng)求使用。當(dāng)來(lái)客訪(fǎng)問(wèn)網(wǎng)站時(shí),PHP 會(huì)自
動(dòng)(如果 session.auto_start 被設(shè)為 1 )或在用戶(hù)請(qǐng)求時(shí)(由 session_start() 明確調(diào)用或
session_register() 暗中調(diào)用)檢查請(qǐng)求中是否發(fā)送了特定的SESSION ID。如果是,則之前保存的環(huán)
境就被重建。
2.1 SESSION ID 的傳送
2.1.1 通過(guò) cookie 傳送 SESSION ID
使用 session_strt()調(diào)用 session,服務(wù)器端在生成session 文件的同時(shí),生成 session ID 哈希值和
默認(rèn)值為PHPSESSID 的session name,并向客戶(hù)端發(fā)送變量為(默認(rèn)的是)PHPSESSID(session name),
值為一個(gè) 128 位的哈希值。服務(wù)器端將通過(guò)該 cookie 與客戶(hù)端進(jìn)行交互。
session 變量的值經(jīng)php 內(nèi)部序列化后保存在服務(wù)器機(jī)器上的文本文件中,和客戶(hù)端的變量名默
認(rèn)情況下為PHPSESSID 的coolie 進(jìn)行對(duì)應(yīng)交互。
即服務(wù)器自動(dòng)發(fā)送了 http 頭:header('Set-Cookie: session_name()=session_id(); path=/'); 即
setcookie(session_name(),session_id());
當(dāng)從該頁(yè)跳轉(zhuǎn)到的新頁(yè)面并調(diào)用session_start()后,PHP 將檢查與給定ID 相關(guān)聯(lián)的服務(wù)器端存貯
的session 數(shù)據(jù),如果沒(méi)找到,則新建一個(gè)數(shù)據(jù)集。
2.1.2 通過(guò) URL 傳送 session ID
只有在用戶(hù)禁止使用cookie 的時(shí)候才用這種方法,因?yàn)闉g覽器cookie 已經(jīng)通用,為安全起見(jiàn),
可不用該方法。
xxx,也可以通過(guò)
POST 來(lái)傳遞 session 值。
2.2 session 基本用法實(shí)例
代碼片段
默認(rèn)php5.2.1下,SID只有在 cookie被寫(xiě)入的同時(shí)才會(huì)有值,如果該 session
對(duì)應(yīng)的 cookie 已經(jīng)存在,那么 SID將為 (未定義)空
- */
- ?>
- 代碼片段
- // page2.php
- session_start();
- print $_SESSION['animal']; // 打印出單個(gè) session
- var_dump($_SESSION); // 打印出page1.php傳過(guò)來(lái)的 session值
- ?>
2.3 使用session 函數(shù)控制頁(yè)面緩存
很多情況下,我們要確定我們的網(wǎng)頁(yè)是否在客戶(hù)端緩存,或要設(shè)置緩存的有效時(shí)間,比如我們
的網(wǎng)頁(yè)上有些敏感內(nèi)容并且要登錄才能查看,如果緩存到本地了,可以直接打開(kāi)本地的緩存就可以
不登錄而瀏覽到網(wǎng)頁(yè)了。
使用 session_cache_limiter('private');可以控制頁(yè)面客戶(hù)端緩存,必須在 session_start()之前調(diào)用。
更多參數(shù)見(jiàn)http://blog.chinaunix.net/u/27731/showart.php?id=258087 的客戶(hù)端緩存控制。
控制客戶(hù)端緩存時(shí)間用 session_cache_expire(int); 單位(s)。也要在session_start()前調(diào)用。
這只是使用 session 的情況下控制緩存的方法,我們還可以在header()中控制控制頁(yè)面的緩存。
2.4 刪除session
要三步實(shí)現(xiàn)。
代碼片段
- session_destroy(); // 第一步: 刪除服務(wù)器端 session文件,這使用
- setcookie(session_name(),'',time()-3600); // 第 二 步 : 刪 除 實(shí) 際 的
- session:
- $_SESSION = array(); // 第三步: 刪除$_SESSION全局變量數(shù)組
- ?>
2.5 session 在PHP 大型web 應(yīng)用中的使用
對(duì)于訪(fǎng)問(wèn)量大的站點(diǎn),用默認(rèn)的 session 存貯方式并不適合,目前最優(yōu)的方法是用數(shù)據(jù)庫(kù)存取
session。這時(shí),函數(shù)bool session_set_save_handler ( callback open, callback close, callback read, callback
write, callback destroy, callback gc )就是提供給我們解決這個(gè)問(wèn)題的方案。
該函數(shù)使用的6 個(gè)函數(shù)如下:
1. bool open() 用來(lái)打開(kāi)會(huì)話(huà)存儲(chǔ)機(jī)制。
2. bool close(-)關(guān)閉會(huì)話(huà)存儲(chǔ)操作。
3. mixde read() 從存儲(chǔ)中裝載session 數(shù)據(jù)時(shí)使用這個(gè)函數(shù)。
4. bool write() 將給定 session ID 的所有數(shù)據(jù)寫(xiě)到存儲(chǔ)中。
5. bool destroy() 破壞與指定的 session ID 相關(guān)聯(lián)的數(shù)據(jù)。
6. bool gc() 對(duì)存儲(chǔ)系統(tǒng)中的數(shù)據(jù)進(jìn)行垃圾收集。
例子見(jiàn)php 手冊(cè) session_set_save_handler() 函數(shù)。
如果用類(lèi)來(lái)處理,用
代碼片段
- session_set_save_handler(
- array('className','open'),
- array('className','close'),
- array('className','read'),
- array('className','write'),
- array('className','destroy'),
- array('className','gc'),
- )
調(diào)用className 類(lèi)中的 6 個(gè)靜態(tài)方法。className 可以實(shí)例化對(duì)象就不用調(diào)用靜態(tài)方法,但是用
靜態(tài)成員不用生成對(duì)象,性能更好。
2.6 常用session 函數(shù):
bool session_start(void) 初始化 session。
bool session_destroy(void) 刪除服務(wù)器端 session 關(guān)聯(lián)文件。
string session_id() 當(dāng)前session 的id。
string session_name() 當(dāng)前存取的session 名稱(chēng),也就是客戶(hù)端保存session ID 的cookie 名稱(chēng).默
認(rèn)PHPSESSID。
array session_get_cookie_params() 與這個(gè)session 相關(guān)聯(lián)的 session 的細(xì)節(jié)。
string session_cache_limiter() 控制使用 session 的頁(yè)面的客戶(hù)端緩存。
ini session_cache_expire() 控制客戶(hù)端緩存時(shí)間。
bool session_destroy() 刪除服務(wù)器端保存 session 信息的文件。
void session_set_cookie_params ( int lifetime [, string path [, string domain [, bool secure [, bool
httponly]]]] ) 設(shè)置與這個(gè)session 相關(guān)聯(lián)的 session 的細(xì)節(jié)。
bool session_set_save_handler ( callback open, callback close, callback read, callback write, callback
destroy, callback gc ) 定義處理session 的函數(shù)(不是使用默認(rèn)的方式)。
bool session_regenerate_id([bool delete_old_session]) 分配新的session id
2.7 session 安全問(wèn)題
攻擊者通過(guò)投入很大的精力嘗試獲得現(xiàn)有用戶(hù)的有效 session ID,有了session id,他們就有可能
能夠在系統(tǒng)中擁有與此用戶(hù)相同的能力。
因此,我們主要解決的思路是效驗(yàn)session ID 的有效性。
代碼片段
- if(!isset($_SESSION['user_agent'])){
- $_SESSION['user_agent'] = $_SERVER['REMOTE_ADDR'] .
- $_SERVER['HTTP_USER_AGENT'];
- }
- /* 如果用戶(hù) session ID是偽造 */
- elseif ($_SESSION['user_agent'] != $_SERVER['REMOTE_ADDR'] .
- $_SERVER['HTTP_USER_AGENT']) {
- session_regenerate_id();
- }
- ?>
2.8 Session 通過(guò)cookie 傳遞和通過(guò)SID 傳遞的不同
在 php5.2.1 的session 的默認(rèn)配置的情況下,當(dāng)生成session 的同時(shí),服務(wù)器端將在發(fā)送header
set-cookie 同時(shí)生成預(yù)定義超級(jí)全局變量 SID(也就是說(shuō),寫(xiě)入 cookie 和拋出 SID 是等價(jià)的),當(dāng)
$_COOKIE['PHPSESSID']存在以后,將不再寫(xiě)入 cookie,也不再生成超級(jí)全局變量SID,此時(shí),SID
將是空的。
2.9 session 使用實(shí)例
代碼片段
- /**
- * 效驗(yàn) session的合法性
- *
- */
- function sessionVerify() {
- if(!isset($_SESSION['user_agent'])){
- $_SESSION['user_agent'] = MD5($_SERVER['REMOTE_ADDR']
- .$_SERVER['HTTP_USER_AGENT']);
- }
- /* 如果用戶(hù) session ID是偽造,則重新分配 session ID */
- elseif ($_SESSION['user_agent']!=MD5($_SERVER['REMOTE_ADDR']
- . $_SERVER['HTTP_USER_AGENT'])) {
- session_regenerate_id();
- }
- }
- /**
- * 銷(xiāo)毀 session
- * 三步完美實(shí)現(xiàn),不可漏
- *
- */
- function sessionDestroy() {
- session_destroy();
- setcookie(session_name(),'',time()-3600);
- $_SESSION = array();
- }
- ?>
注明:
session 出現(xiàn)頭信息已經(jīng)發(fā)出的原因與cookie 一樣。
在php5 中,所有php session 的注冊(cè)表配置選項(xiàng)都是編程時(shí)可配置的,一般情況下,我們是不用
修改其配置的。要了解php 的session 注冊(cè)表配置選項(xiàng),請(qǐng)參考手冊(cè)的 Session 會(huì)話(huà)處理函數(shù)處。

我們?cè)谖⑿派?4小時(shí)期待你的聲音
解答本文疑問(wèn)/技術(shù)咨詢(xún)/運(yùn)營(yíng)咨詢(xún)/技術(shù)建議/互聯(lián)網(wǎng)交流