1. PHP 的 COOKIE
cookie 是一種在遠程瀏覽器端儲存資料並以此來跟蹤和識別使用者的機制。
PHP 在 http 協議的頭資訊裡發送 cookie,因此 setcookie() 函數必須在其它資訊被輸出到瀏覽器前調用,這和對 header() 函數的限制類似。
1.1 設定 cookie:
可以用 setcookie()或 setrawcookie()函數來設定 cookie。也可以通過向用戶端直接發送 http 頭來
設定。
1.1.1 使用 setcookie()函數設定 cookie:
bool setcookie ( string name [, string value [, int expire [, string path [, string domain [, bool secure [, bool
httponly]]]]]] )
name: cookie 變數名
value: cookie 變數的值
expire: 有效期間結束的時間
path: 有效目錄
domain: 有效網域名稱,頂級域唯一
secure: 如果值為 1,則 cookie 只能在 https 串連上有效,如果為預設值 0,則 http 和 https 都可以。
例子:
程式碼片段
〈?php
$value = ’something from somewhere’;
setcookie(“TestCookie“, $value); /*
簡單cookie設定
*/
setcookie(“TestCookie“, $value, time()+3600); /*
有效期間1個小時
*/
setcookie(“TestCookie“, $value, time()+3600, “/~rasmus/“,
“.example.com“, 1); /*
有效目錄
/~rasmus,
有效網域名稱
example.com
及其所有子網域名稱
*/
?〉
設定多個 cookie 變數:setcookie(’var[a]’,’value’); 用數組來表示變數,但他的下標不用引號。這樣就可以用$_COOKIE[‘var’][‘a’]來讀取該 COOKIE 變數。
1.1.2. 使用 header()設定 cookie;
header(“Set-Cookie: name=$value[;path=$path[;domain=xxx.com[;...]]“);
後面的參數和上面列出 setcookie 函數的參數一樣。
比如:
程式碼片段
$value = ’something from somewhere’;
header(“Set-Cookie:name=$value“);
1.2 Cookie 的讀取:
直接用 php 內建超級全域變數$_COOKIE 就可以讀取瀏覽器端的 cookie。
上面例子中設定了 cookie “TestCookie“,現在我們來讀取:
程式碼片段
print $_COOKIE[’TestCookie’];
COOKIE 是不是被輸出了?!
1.3 刪除 cookie
只需把有效時間設為小於目前時間,和把值設定為空白。例如:
程式碼片段
setcookie(“name“, ““, time()-1);
用 header()類似。
1.4 常見問題解決:
1) 用 setcookie()時有錯誤提示,可能是因為調用 setcookie()前面有輸出或空格。也可能你的文檔是從其他字元集轉換過來,文檔後面可能帶有 BOM 簽名(就是在檔案內容添加一些隱藏的 BOM 字元)。解決的辦法就是使你的文檔不出現這種情況。還有通過使用 ob_start()函數也能處理一點。
2) $_COOKIE 受 magic_quotes_gpc 影響,可能自動轉義。
3) 使用的時候,有必要測試使用者是否支援 cookie。
1.5 cookie 工作機理:
有些學習者比較衝動,沒心思把原理研究,所以我把它放後面。
a) 伺服器通過隨著響應發送一個 http 的 Set-Cookie 頭,在客戶機中設定一個 cookie(多個 cookie要多個頭)。
b) 用戶端自動向伺服器端發送一個 http 的 cookie 頭,伺服器接收讀取。
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
這一行實現了 cookie 功能,收到這行後 Set-Cookie: TestCookie=something from somewhere; path=/
瀏覽器將在用戶端的磁碟上建立一個 cookie 檔案,並在裡面寫入:
TestCookie=something from somewhere;
/
這一行就是我們用 setcookie(’TestCookie’,’something from somewhere’,’/’);的結果。也就是用header(’Set-Cookie: TestCookie=something from somewhere; path=/’);的結果。
2. PHP 的 SESSION
session 使用到期時間設為 0 的 cookie,並且將一個稱為 session ID 的唯一識別碼(一長串字串),在伺服器端同步處理產生一些 session 檔案(可以自己定義 session 的檔案類型),與使用者機關聯起來。web應用程式存貯與這些 session 相關的資料,並且讓資料隨著使用者在頁面之間傳遞。
訪問網站的來客會被分配一個唯一的標識符,即所謂的 SESSION ID。它要麼存放在用戶端的cookie,要麼經由 URL 傳遞。
SESSION 允許使用者註冊任意數目的變數並保留給各個請求使用。當來客訪問網站時,PHP 會自動(如果 session.auto_start 被設為 1 )或在使用者請求時(由 session_start() 明確調用或session_register() 暗中調用)檢查請求中是否發送了特定的 SESSION ID。如果是,則之前儲存的環境就被重建。
2.1 SESSION ID 的傳送
2.1.1 通過 cookie 傳送 SESSION ID
使用 session_start()調用 session,伺服器端在產生 session 檔案的同時,產生 session ID 雜湊值和預設值為 PHPSESSID 的 session name,並向用戶端發送變數為(預設的是)PHPSESSID(session name),值為一個 128 位的雜湊值。伺服器端將通過該 cookie 與用戶端進行互動。
session 變數的值經 php 內部序列化後儲存在伺服器機器上的文字檔中,和用戶端的變數名預設情況下為 PHPSESSID 的 coolie 進行對應互動。
即伺服器自動發送了 http 頭:header(’Set-Cookie: session_name()=session_id(); path=/’); 即
setcookie(session_name(),session_id());
當從該頁跳轉到的新頁面並調用 session_start()後,PHP 將檢查與給定 ID 相關聯的伺服器端存貯的 session 資料,如果沒找到,則建立一個資料集。
2.1.2 通過 URL 傳送 session ID
只有在使用者禁止使用 cookie 的時候才用這種方法,因為瀏覽器 cookie 已經通用,為安全起見,可不用該方法。
〈a href=“p.php?〈?php print session_name() ?〉=〈?php print session_id() ?〉“〉xxx〈/a〉,也可以通過POST 來傳遞 session 值。
2.2 session 基本用法執行個體
程式碼片段
〈?php
// page1.php
session_start();
echo ’Welcome to page #1’;
/*
建立session變數並給session變數賦值
*/
$_SESSION[’favcolor’] = ’green’;
$_SESSION[’animal’] = ’cat’;
$_SESSION[’time’] = time();
//
如果用戶端使用cookie,可直接傳遞session到page2.php
echo ’〈br /〉〈a href=“page2.php“〉page 2〈/a〉’;
//
如果用戶端禁用cookie
echo ’〈br /〉〈a href=“page2.php?’ . SID . ’“〉page 2〈/a〉’;
/*
預設php5.2.1下,SID只有在cookie被寫入的同時才會有值,如果該session對應的cookie已經存在,那麼SID將為
(
未定義
)
空
*/
?〉
程式碼片段
〈?php
// page2.php
session_start();
print $_SESSION[’animal’]; //列印出單個session
var_dump($_SESSION); //列印出page1.php傳過來的session值
?〉
2.3 使用 session 函數控制頁面緩衝
很多情況下,我們要確定我們的網頁是否在用戶端緩衝,或要設定緩衝的有效時間,比如我們的網頁上有些敏感內容並且要登入才能查看,如果緩衝到本地了,可以直接開啟本地的緩衝就可以不登入而瀏覽到網頁了。
使用 session_cache_limiter(’private’);可以控制頁面用戶端緩衝,必須在 session_start()之前調用。更多參數見 http://blog.chinaunix.net/u/27731/showart.php?id=258087 的用戶端緩衝控制。
控制用戶端緩衝時間用 session_cache_expire(int); 單位(s)。也要在 session_start()前調用。
這隻是使用 session 的情況下控制緩衝的方法,我們還可以在 header()中控制控制頁面的緩衝。
2.4 刪除 session
要三步實現。
程式碼片段
〈?php
session_destroy(); //
第一步:
刪除伺服器端session檔案,這使用
setcookie(session_name(),’’,time()-3600); //
第二步:
刪除實際的session:
$_SESSION = array(); //
第三步:
刪除$_SESSION全域變數數組
?〉
2.5 session 在 PHP 大型 web 應用中的使用
對於訪問量大的網站,用預設的 session 存貯方式並不適合,目前最優的方法是用資料庫存取session。這 時 ,函 數 bool session_set_save_handler ( callback open, callback close, callback read, callback write, callback destroy, callback gc )就是提供給我們解決這個問題的方案。
該函數使用的 6 個函數如下:
1. bool open() 用來開啟會話儲存機制。
2. bool close() 關閉會話儲存操作。
3. mixde read() 從儲存中裝載 session 資料時使用這個函數。
4. bool write() 將給定 session ID 的所有資料寫到儲存中。
5. bool destroy() 破壞與指定的 session ID 相關聯的資料。
6. bool gc() 對儲存系統中的資料進行垃圾收集。
例子見 php 手冊 session_set_save_handler() 函數。
如果用類來處理,用程式碼片段
session_set_save_handler(
array(’className’,’open’),
array(’className’,’close’),
array(’className’,’read’),
array(’className’,’write’),
array(’className’,’destroy’),
array(’className’,’gc’),
)
調用 className 類中的 6 個靜態方法。className 可以執行個體化對象就不用調用靜態方法,但是用靜態成員不用產生對象,效能更好。
2.6 常用 session 函數:
bool session_start(void) 初始化 session。
bool session_destroy(void) 刪除伺服器端 session 關聯檔案。
string session_id() 當前 session 的 id。
string session_name() 當前存取的 session 名稱,也就是用戶端儲存 session ID 的 cookie 名稱.默
認 PHPSESSID。
array session_get_cookie_params() 與這個 session 相關聯的 session 的細節。
string session_cache_limiter() 控制使用 session 的頁面的用戶端緩衝。
ini session_cache_expire() 控制用戶端緩衝時間。
bool session_destroy() 刪除伺服器端儲存 session 資訊的檔案。
void session_set_cookie_params ( int lifetime [, string path [, string domain [, bool secure [, bool
httponly]]]] ) 設定與這個 session 相關聯的 session 的細節。
bool session_set_save_handler ( callback open, callback close, callback read, callback write, callback
destroy, callback gc ) 定義處理 session 的函數(不是使用預設的方式)。
bool session_regenerate_id([bool delete_old_session]) 分配新的 session id
2.7 session 安全問題
攻擊者通過投入很大的精力嘗試獲得現有使用者的有效 session ID,有 了 session id,他們就有可能能夠在系統中擁有與此使用者相同的能力。
因此,我們主要解決的思路是效驗 session ID 的有效性。
程式碼片段
〈?php
if(!isset($_SESSION[’user_agent’])){
$_SESSION[’user_agent’] = $_SERVER[’REMOTE_ADDR’] .
$_SERVER[’HTTP_USER_AGENT’];
}
/*
如果使用者session ID是偽造
*/
elseif ($_SESSION[’user_agent’] != $_SERVER[’REMOTE_ADDR’] .
$_SERVER[’HTTP_USER_AGENT’]) {
session_regenerate_id();
}
?〉
2.8 Session 通過 cookie 傳遞和通過 SID 傳遞的不同在 php5.2.1 的 session 的預設配置的情況下,當產生 session 的同時,伺服器端將在發送 headerset-cookie 同時產生預定義超級全域變數 SID(也就是說,寫入 cookie 和拋出 SID 是等價的),當$_COOKIE[’PHPSESSID’]存在以後,將不再寫入 cookie,也不再產生超級全域變數 SID,此時,SID將是空的。
2.9 session 使用執行個體
程式碼片段
〈?php
/**
*效驗session的合法性*
*/
function sessionVerify() {
if(!isset($_SESSION[’user_agent’])){
$_SESSION[’user_agent’] = MD5($_SERVER[’REMOTE_ADDR’]
.$_SERVER[’HTTP_USER_AGENT’]);
}
/*如果使用者session ID是偽造,則重新分配session ID */
elseif ($_SESSION[’user_agent’]!=MD5($_SERVER[’REMOTE_ADDR’]
. $_SERVER[’HTTP_USER_AGENT’])) {
session_regenerate_id();
}
}
/**
*銷毀session*
三步完美實現,不可漏*
*/
function sessionDestroy() {
session_destroy();
setcookie(session_name(),’’,time()-3600);
$_SESSION = array();
}
?〉
註明:
session 出現頭資訊已經發出的原因與 cookie 一樣。
在 php5 中,所有 php session 的註冊表配置選項都是編程時可配置的,一般情況下,我們是不用修改其配置的。要瞭解 php 的 session 註冊表配置選項,請參考手冊的 Session 會話處理函數處。