SESSION和COOKIE相關原理

cookie的工作流程:
客戶端訪問服務器,服務器調用response.addCookie()方法,產生響應時,會產生set-cookie響應頭,將cookie文本發送給客戶端,客戶端會將cookie文本保存起來,當客戶端再次請求服務器時,會產生cookie請求頭,將之前服務器發送的cookie信息,再發送給服務器,服務器就可以根據cookie信息跟蹤客戶端的狀態。
cookie的工作原理:
a.服務器通過隨着響應發送一個http 的Set-Cookie 頭,在客戶機中設置一個cookie(多個cookie 要多個頭)。 
b.客戶端自動向服務器端發送一個http 的cookie 頭,服務器接收讀取。 
C.如果是持久化cookie,瀏覽器將在客戶端的磁盤上創建一個cookie 文件,並在裏面寫入:
    TestCookie=something from somewhere; 
    這一行就是我們用 setcookie('TestCookie','something   from  somewhere','/'); 的結果。也可以用 
    header('Set-Cookie: TestCookie=something from somewhere; path=/');的結果。

cookie的分類:
1 存放在客戶端瀏覽器的緩存中,當瀏覽器不關閉,cookie信息一起存在,瀏覽器一關閉,cookie消失
2 存放在客戶端的文件中,並可以設置cookie過期時間,過期時間之內,即使瀏覽器關閉,也可以將cookie信息發送給服務器,超過過期時間,cookie消失。

cookie信息是以文本方式(不一定是txt文件,大多是二進制文件)存放在客戶端的,所以容易引起一些安全隱患,所以不要把隱祕信息以cookie方式保存。
 

cookie相關操作(新建+讀取+刪除)
設置cookie:
    ( 1 )  可以用 setcookie()

<?php         
     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 變量。
     ( 2 )  使用 header()設置cookie
             header("Set-Cookie: name=$value[;path=$path[;domain=xxx.com[;...]]")

<?php  
     header("Set-Cookie:name=$value"); 

刪除cookie

    只需把有效時間設爲小於當前時間,和把值設置爲空。例如:

<?php
setcookie("name", "", time()-1);

 

session的工作流程:
當用戶第一次訪問站點時,PHP會用session_start()函數爲用戶創建一個sessionID,這就是針對這個用戶的唯一標識,每一個訪問的用戶都會得到一個自己獨有的session ID,這個session ID會存放在響應頭裏的cookie中,之後發送給客戶端。這樣客戶端就會擁有一個該站點給他的session ID。

當用戶第二次訪問該站點時,瀏覽器會帶着本地存放的cookie(裏面存有上次得到的session ID)隨着請求一起發送到服務器,服務端接到請求後會檢測是否有session ID,如果有就會找到響應的session文件,把其中的信息讀取出來;如果沒有就跟第一次一樣再創建個新的。

通常站點的退出功能,實際上就是調用一下session_destroy()函數(也有可能更復雜些),把該用戶的session文件刪除,再把用戶的cookie清除。這樣客戶端和服務端就算沒有聯繫了。

圖中的紅框部分就是一次完整的HTTP請求,因爲HTTP是無狀態的,所以一次請求完成後客戶端和服務端就不再有任何關係了,誰也不認識誰。但由於一些需要(如保持登錄狀態等),必須讓服務端和客戶端保持聯繫,session ID就成了這種聯繫的媒介了。

session的工作原理:

最最核心的概念就是:網頁間跳轉的額外數據,保存在服務器,用一個id標識,瀏覽器要維持session,需要每次提交都帶上這個id.

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。如果是,則之前保存的環境就被重建。

session ID的傳遞有兩種方式:

( 1 )   通過 cookie 傳送 SESSION ID

使用 session_start()調用 session,服務器端在生成session文件的同時,生成變量session name(默認爲PHPSESSID)及其對應值爲唯一標識用戶的session ID(哈希值)(服務端和客戶端保存着同樣的session ID信息,這就是兩者保持聯繫的鑰匙。),並向客戶端發送該變量session name(默認爲PHPSESSID)及其對應值爲唯一標識用戶的session ID(哈希值)。服務器端將通過該 cookie 與客戶端進行交互。一個被sessionID唯一標識後的用戶創建的各種session變量及對應值經php內部序列化後保存在服務器機器上的文本文件中,和客戶端的變量名默認情況下爲PHPSESSID 的cookie 進行對應交互.即服務器自動發送了http 頭:

header('Set-Cookie: session_name()=session_id();  path=/'); 或setcookie(session_name(),session_id()); 

即:header('Set-Cookie: PHPSESSID=pcnnftkmkm9nua33uot8fmb8a3;  path=/'); 或setcookie(PHPSESSID,pcnnftkmkm9nua33uot8fmb8a3); 

當從該頁跳轉到的新頁面並調用session_start()後,PHP 將檢查與給定ID 相關聯的服務器端存貯的session數據,如果沒找到,則新建一個數據集。

( 2 )通過URL傳送 session ID

只有在用戶禁止使用cookie的時候才用這種方法,因爲瀏覽器cookie 已經通用,爲安全起見,可不用該方法。 
    <a href="p.php?<?php print session_name()?>=<?php print session_id() ?>">xxx</a>,也可以通過 POST 來傳遞session 值。

 

如果客戶端禁止使用cookie,可以使用如下辦法:

( 1 )  設置php.ini中的session.use_trans_sid= 1或者編譯時打開打開了--enable-trans-sid選項,讓PHP自動跨頁傳遞session id。 
( 2 )  手動通過URL傳值、隱藏表單傳遞session id。 
( 3 )  用文件、數據庫等形式保存session_id,在跨頁過程中手動調用。

session也可以在禁用cookie的情況下使用:
php.ini中session.use_cookies=1,改爲0,session會保存在服務器端,而不是客戶端的cookie。
可以通過session.save_path來查看服務器的session存放位置

session相關操作(新建+讀取+刪除)

設置session page1.php

<?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將爲 (未定義)空   

讀取session    page2.php

<?php
session_start();  
var_dump($_SESSION); // 打印出page1.php傳過來的 session值

刪除session

<?php
session_destroy();      // 第一步: 刪除服務器端 session文件,這使用   
setcookie(session_name(),'',time()-3600);      //  第 二 步 : 刪 除 實 際 的session:  
$_SESSION = array();     // 第三步: 刪除$_SESSION全局變量數組 

第一次請求服務器

GET /test.php HTTP/1.1 
Accept: */* 
Referer: http://localhost/ 
Accept-Language: zh-cn 
Accept-Encoding: gzip, deflate 
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Maxthon; .NET CLR 1.1.4322) 
Host: localhost 
Connection: Keep-Alive

服務器第一次返回

HTTP/1.1 200 OK 
Date: Fri, 26 Aug 2005 07:44:22 GMT 
Server: Apache/2.0.54 (Win32) SVN/1.2.1 PHP/5.0.4 DAV/2 
X-Powered-By: PHP/5.0.4 
Set-Cookie: PHPSESSID=bmmc3mfc94ncdr15ujitjogma3; path=/ 
Expires: Thu, 19 Nov 1981 08:52:00 GMT 
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0 
Pragma: no-cache 
Content-Length: 1 
Keep-Alive: timeout=15, max=99 
Connection: Keep-Alive 
Content-Type: text/html; charset=utf-8 
Content-Language: Off

第二次請求服務器

GET /test.php HTTP/1.1 
Accept: */* 
Referer: http://localhost/ 
Accept-Language: zh-cn 
Accept-Encoding: gzip, deflate 
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Maxthon; .NET CLR 1.1.4322) 
Host: localhost 
Connection: Keep-Alive 
Cookie: PHPSESSID=bmmc3mfc94ncdr15ujitjogma3

服務器第二次返回

HTTP/1.1 200 OK 
Date: Fri, 26 Aug 2005 07:44:23 GMT 
Server: Apache/2.0.54 (Win32) SVN/1.2.1 PHP/5.0.4 DAV/2 
X-Powered-By: PHP/5.0.4 
Set-Cookie: PHPSESSID=bmmc3mfc94ncdr15ujitjogma3; path=/ 
Expires: Thu, 19 Nov 1981 08:52:00 GMT 
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0 
Pragma: no-cache 
Content-Length: 1 
Keep-Alive: timeout=15, max=98 
Connection: Keep-Alive 
Content-Type: text/html; charset=utf-8 
Content-Language: Off

仔細對比這些輸出,第二次請求比第一次請求多出來的就是: 
Cookie: PHPSESSID=bmmc3mfc94ncdr15ujitjogma3 
這個header將會向服務器發送一個cookie信息,告訴服務器我有一個cookie,名字叫PHPSESSID,內容是bmmc3mfc94ncdr15ujitjogma3。 
這個cookie是怎麼來的呢?看第一次服務器返回的信息裏邊有: 
Set-Cookie: PHPSESSID=bmmc3mfc94ncdr15ujitjogma3; path=/ 
這是服務器向客戶端瀏覽器寫一個cookie,名字是PHPSESSID,值是bmmc3mfc94ncdr15ujitjogma3,這個值實際就是所謂的session_id。 
繼續看第二次向服務器發出的請求,仍然向服務器發送了PHPSESSID這個cookie 

可以得到以下結論: 
1、只要使用了session,就會通過cookie的方式向客戶端瀏覽器發送session 
2、每次向服務器發出請求的時候,本地瀏覽器會把cookie附帶在請求信息中

session常見問題

一、session是怎麼保存的?怎麼去查看其內容?

session是以文件的形式保存的。php.ini中有個配置項--session.save_path="";這個裏面填寫的路徑,將會使session文件保存在該路徑下。session文件的命名格式是:"sess_[PHPSESSID的值]"。每一個文件,裏面保存了一個會話的數據。其實只要使用代碼$_SESSION['user_id'] = $value;就會促發php的session機制,結果往對應的session文件中寫入一個值。

二、session.save_path路徑下這麼多的session文件,php是如何確定要調用哪個session文件的?

php是依據,一個名爲PHPSESSID的cookie,根據它的值,確定要調用哪個session文件的。去瀏覽器中,可以看到一個cookie名爲PHPSESSID,假如它的值爲"sess_adbjsf2q1ass26oootd163sf84",那麼,當訪問服務器的時候,就會調用session目錄下名爲"sess_sess_adbjsf2q1ass26oootd163sf84"的文件。其實,PHPSESSID就是一個會話id,以此來確定,哪個是你的會話數據。

以下是在瀏覽器查看cookie所看到的 :

cookie的名字PHPSESSID是可以改的,在php.ini中 session.name = PHPSESSID就是設置該cookie的名字。php.ini中有個配置項--session.save_path= "";這個裏面填寫的路徑,將會使session文件保存在該路徑下。

三、說說session跟cookie有關聯的地方

PHPSESSID這個cookie有綁定關係。其他,不管你設置什麼cookie,使用session的時候是不會用到這些值的。也無法獲取到。比如同步登陸,設置即使設置了cookie,而你的應用是依據session判斷是否爲登陸狀態的(事實上也必須如此,因爲session保存在服務器端,安全性更高,哪個依據cookie認爲你已經登陸,那麼很慘)。所以,這樣的情況就會出現,即使成功設置了cookie。也還是不能同步登陸。

四、經常遇到的現象:爲什麼刪除一個session文件,之後生成一個session文件,新的文件名字還是與原來一樣?(但是文件裏面的內容會變化)

理解到session文件的命名規則是:“sess_PHPSESSID值“。那麼,就很容易明白了。因爲,客戶端存在cookie:PHPSESSID。客戶端發送請求後,會將該cookie發送給服務器(php可以使用$_COOKIE['PHPSESSID']看到其內容),這樣的話,還是會根據PHPSESSID生成一個session文件的。

五、如何查看session文件中的session值?

我在開發中發現,如果僅僅依靠session_start()和$_SESSION['user_id']這樣的代碼,去調試,還不夠全面的瞭解問題所在。比如,我想知道,session_start()到底在完成哪些操作?如果,想動態,實時知道session的值是如何被改寫的,打開一個session文件,查看是很瞭然的。原來,裏面就是保存的是一些被序列化後的值。也明白一個知識點,"php聖經"中講解session的時候,提到session值做被序列化了。下面看到的session內容就是被序列化了。

打開一個session文件,內容如下:

cityID|i:0;cityName|s:3:"all";fanwe_lang|s:5:"zh-cn";fanwe_currency|a:4:{s:2:"id";s:1:"1";s:6:"name_1";s:9:"人民幣";s:4:"unit";s:3:"¥";s:5:"radio";s:6:"1.0000";}_fanwe_hash__|s:32:"77c18770c6cb5d89444c407aaa3e8477";

讀取規則如下:

( 1 )  每一個session的值是以分號";"分開的。比如“cityID|i:0;”就是一個完整的session值結束

( 2 )  裏面的讀取規則:符號“|”前面表示session名稱。符號後面是該session的具體信息。包括:數據類型,字符長度,內容。上面第二個就相當於使用如下php代碼訪問:$_SESSION['cityName'],後面的s表示數據值的長度,3表示字符長度,變量值爲all。

( 3 )  一個session可以保存一個數組。符號{}表示數組的內容。上面的花括號{}$_SESSION['fanwe_currency']所保存的內容。要想查看id的值,就使用代碼:$_SESSION['fanwe_currency']['id']

 

六、怎麼樣理解session_start等函數所做的實際操作是什麼?

我是這樣理解的:session_start,可以看成是創建一個session文件。假如有原來的session文件,或許沒有創建。引入一個。往session文件中寫值,那是代碼“$_SESSION['']=""; 賦值所完成的操作。
session_start()生成一個新的session文件名時。會判斷是否存在cookie名爲PHPSESSID的值。如果存在,那麼就會按照它的值,組合成一個文件名"sess_[phpcookie值]"。所以,在目錄下,老是能夠看到之前刪除過的session文件名。如果將瀏覽器中對應的cookie(PHPSESSID)刪掉。那麼就不會生成同樣的名字了。如果不存在名爲PHPSESSID的cookie。php所做的估計爲:先發送一個cookie,然後按照cookie的值生成一個(我可以在瀏覽器中馬上看到一個名爲PHPSESSID的cookie)

其實,現在也更加深刻地理解了一個知識:在調用session_start()之前不能有任何輸出。有輸出就會報錯。

session_start()已經封裝了發送cookie的操作(發送一個名稱爲PHPSESSID的cookie到瀏覽器)。涉及到http的一個原理:頭部信息必須在內容之前發送纔行。所以,使用echo '內容';

header('Content-type:text/xml; charset=gb2312');//頭部信息,不算內容

可以這樣認爲:session_start()內部已經進行了一次發送頭部動作。所以之前不能有任何輸出內容。
手冊中的英文大致是這樣說的:創建一個session,或者恢復當前一個session(基於request請求傳遞的session id,這裏應該值的就是http請求時傳遞的名爲PHPSESSID的cookie)

七、只要是同一個用戶的操作。導航程序訪問記錄和團購程序訪問的記錄都是保存在同一個session文件中。如果是不同的域呢?假如用戶訪問cs.test.com和daohang.test.com,兩方程序都設置了session。那麼session的結果保存在同一個session文件中嗎?

是的!因爲:服務器是統一管理session文件的存放的。而php引擎是根據phpsessionid的值確定要操作哪個session文件。session文件名的格式是:"sess_[phpcookie值]"。依次尋找對應的session文件(於是在瀏覽器查看名爲PHPSESSIONID的cookie,過期時間是在會話結束後)。所以,只要cs.test.com和daohang.test.com使用的是同一臺服務器。就算是不同的域,兩方程序都設置了session。那麼session的結果保存在同一個session文件中。

這樣的話,假如是多臺服務器的情況。那麼就不得不將session保存在數據庫中去。這樣實現session共享。

 

http://www.birdol.com/php/4272.html

http://blog.csdn.net/wangzhkai/article/details/4187496

http://www.cnblogs.com/wangtao_20/archive/2011/02/16/1955659.html

http://blog.csdn.net/fangaoxin/article/details/6954925

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章