原文鏈接https://blog.csdn.net/xihuangwutong/article/details/9819033
1. session概念
2. http協議與狀態保持
3. 理解cookie
4. php中session的生成機制
5. php中session的過期回收機制
6. php中session的客戶端存儲機制
1. session概念
在web服務器蓬勃發展的時代,session在web開發語境下的語義是指一類用來在客戶端與服務器之間保持狀態的解決方案。
2. http協議與狀態保持
http協議本身是無狀態的,客戶端只需要簡單的向服務器請求下載某些文件,無論是客戶端還是服務器都沒有必要紀錄彼此過去的行為,每一次請求之間都是獨立的。
然而人們很快發現如果能夠提供一些按需生成的動態信息會使web變得更加有用,就像給有線電視加上點播功能一樣。這種需求一方面迫使HTML逐步添加了表單、腳本、DOM等客戶端行為,另一方面在服務器端則出現了CGI規范以響應客戶端的動態請求,作為傳輸載體的HTTP協議也添加了文件上載、cookie這些特性。其中cookie的作用就是為了解決HTTP協議無狀態的缺陷所作出的努力。至於后來出現的session機制則是又一種在客戶端與服務器之間保持狀態的解決方案。
session機制可能需要借助於cookie機制來達到保存標識的目的。所以有必要了解下cookie。
3. 理解cookie
cookie分發是通過擴展HTTP協議來實現的,服務器通過在HTTP的響應頭中加上一行特殊的指示以提示瀏覽器按照指示生成相應的cookie。然而純粹的客戶端腳本如JavaScript或者VBScript也可以生成cookie。
而cookie 的使用是由瀏覽器按照一定的原則在后台自動發送給服務器的。瀏覽器檢查所有存儲的cookie,如果某個cookie所聲明的作用范圍大於等於將要請求的資源所在的位置,則把該cookie附在請求資源的HTTP請求頭上發送給服務器。
cookie的內容主要包括:名字,值,過期時間,路徑和域。
其中域可以指定某一個域比如.google.com,相當於總店招牌,比如寶潔公司,也可以指定一個域下的具體某台機器比如www.google.com或者froogle.google.com,可以用飄柔來做比。路徑就是跟在域名后面的URL路徑,比如/或者/foo等等,可以用某飄柔專櫃做比。
路徑與域合在一起就構成了cookie的作用范圍。
如果不設置過期時間,則表示這個cookie的生命期為瀏覽器會話期間,只要關閉瀏覽器窗口,cookie就消失了。這種生命期為瀏覽器會話期的 cookie被稱為會話cookie。會話cookie一般不存儲在硬盤上而是保存在內存里,當然這種行為並不是規范規定的。如果設置了過期時間,瀏覽器就會把cookie保存到硬盤上,關閉后再次打開瀏覽器,這些cookie仍然有效直到超過設定的過期時間
存儲在硬盤上的cookie 不可以在不同的瀏覽器間共享,可以在同一瀏覽器的不同進程間共享,比如兩個IE窗口。
這是因為每中瀏覽器存儲cookie的位置不一樣,比如
Chrome下的cookie放在:
C:\Users\sharexie\AppData\Local\Google\Chrome\User Data\Default\Cache
Firefox下的cookie放在:
C:\Users\sharexie\AppData\Roaming\Mozilla\Firefox\Profiles\tq2hit6m.default\cookies.sqlite (倒數第二個文件名是隨機的文件名字)
Ie下的cookie放在:
C:\Users\Administrator\AppData\Roaming\Microsoft\Windows\Cookies
(網上都說是在這里,但是我一直沒找到)
我在這里也有一個測試,在firefox下用httplook軟件進行嗅探:
1、在本機上第一次打開必應網站,抓包:
返回的數據如下:
HTTP/1.1 200 OK
Cache-Control: private, max-age=0
Content-Type: text/html; charset=utf-8
Content-Encoding: gzip
Set-Cookie: _FS=NU=1; domain=.bing.com; path=/
Set-Cookie: _SS=SID=442E36ABF8F5431E8DFF0CAC018437E3; domain=.bing.com; path=/
Set-Cookie: MUID=32B1FE9DB0EB65B52006FD50B1E86565; expires=Sun, 31-Aug-2014 11:35:51 GMT; domain=.bing.com; path=/
Set-Cookie: OrigMUID=32B1FE9DB0EB65B52006FD50B1E86565%2c15deb35b84a74788ae2d9978e3e657b1; expires=Sun, 31-Aug-2014 11:35:51 GMT; domain=.bing.com; path=/
Set-Cookie: SRCHD=D=2454455&MS=2454455&AF=NOFORM; expires=Sun, 31-Aug-2014 11:35:51 GMT; domain=.bing.com; path=/
Set-Cookie: SRCHUID=V=2&GUID=F6DCC04B2CC54139928925763DAEE04A; expires=Sun, 31-Aug-2014 11:35:51 GMT; path=/
Set-Cookie: SRCHUSR=AUTOREDIR=0&GEOVAR=&DOB=20120831; expires=Sun, 31-Aug-2014 11:35:51 GMT; domain=.bing.com; path=/
P3P: CP=”NON UNI COM NAV STA LOC CURa DEVa PSAa PSDa OUR IND”
Date: Fri, 31 Aug 2012 11:35:50 GMT
Content-Length: 12787
X-Cache-Lookup: MISS from proxy:8080
我們可以看到sessionId為442E36ABF8F5431E8DFF0CAC018437E3,domain為.bing.com; path為/。服務器為本用戶建立一個session,id為442E36ABF8F5431E8DFF0CAC018437E3作為客服端的cookie中的SID的值。
2、第二次請求必應網站,請求內容如下:
看到請求中帶有sid為442E36ABF8F5431E8DFF0CAC018437E3的cookie。
服務器返回數據:
HTTP/1.1 200 OK
Cache-Control: private, max-age=0
Content-Type: text/html; charset=utf-8
Content-Encoding: gzip
P3P: CP=”NON UNI COM NAV STA LOC CURa DEVa PSAa PSDa OUR IND”
Date: Fri, 31 Aug 2012 11:41:12 GMT
Content-Length: 12437
X-Cache-Lookup: MISS from proxy:8080
服務器查看本tmp目錄中有一個文件的名字和SID匹配,知道是一個老用戶,沒有新建session,直接返回數據。
當然也有很多304的返回,表示在expires內直接用用戶的緩存即可。
4. php中session的生成機制
我們先來分析一下PHP中是怎么生成一個session的。設計出session的目的是保持每一個用戶的各種狀態來彌補HTTP協議的不足(無狀態)。session是保存在服務器的,既然它用於保持每一個用戶的狀態那它利用什么來區別用戶的呢?這個時候就得借助cookie了。當我們在代碼中調用session_start();時,PHP會同時往SESSION的存放目錄(默認為/tmp/)和客戶端的cookie目錄各生成一個文件。session文件名稱像這樣:
格式為sess_{SESSIONID} ,這時session文件中沒有任何內容,當我們在session_start();添加了這兩行代碼:
$_SESSION['name'] =’sharexie’;
$_SESSION['webUlr'] = ’www.qq.com’;
這時文件就有內容了:
name|s:8:”sharexie”;webUlr|s:10:”www.qq.com”;
這時再看看cookie:
可以看到服務器為我們自動生成了一個cookie,cookie名稱為”PHPSESSID”,cookie內容是一串字符,其實這串字符就是{SESSIONID}。當我們使用session時,PHP就先生成一個唯一的SESSIONID號(如2bd170b3f86523f1b1b60b55ffde0f66),再在我們服務器的默認目錄下生成一個文件,文件名為sess_{SESSIONID},同時在當前用戶的客戶端生成一個cookie,內容已經說過了。這樣PHP會為每一個用戶生成一個SESSIONID,也就是說一個用戶一個session文件。PHP第一次為某個用戶使用session時就向客戶端寫入了cookie,當這個用戶以后訪問時,瀏覽器會帶上這個cookie,PHP在拿到cookie后就讀出里面的SESSIONID,拿着這個SESSIONID去session目錄下找session文件。
5. php中session的過期回收機制
我們明白了session的生成及工作原理,發現在session目錄下會有許多session文件。當然這些文件一定不是永遠存在的,PHP一定提供了一種過期回收機制。在php.ini中session.gc_maxlifetime為session設置了生存時間(默認為1440s)。如果session文件的最后更新時間到現在超過了生存時間,這個session文件就被認為是過期的了。在下一次session回收的時候就會被刪除。那下一次session回收是在什么時候呢?這和php請求次數有關的。在PHP內部機制中,當php被請求了N次后就會有一次觸發回收機制。到底是請求多少次觸發一次是通過以下兩個參數控制的:
session.gc_probability = 1
session.gc_divisor = 100
這是php.ini的默認設置,意思是每100次PHP請求就有一次回收發生。概率是gc_probability/gc_divisor (這里我把session.gc_divisor改為1,好像訪問了很多次都沒有觸發回收事件,不知道什么原因)。我們了解了服務器端的session過期機制,再來看看客戶端的cookie的過期機制。
如果cookie失效了瀏覽器自然發送不了cookie到服務器,這時即使服務器的session文件存在也沒用,因為PHP不知道要讀取哪個session文件。我們知道PHP的cookie過期時間是在創建時設置的,那么PHP在創建session的同時為客戶端創建的cookie的生命周期是多久呢?這個在php.ini中有設置:session.cookie_lifetime 。這個值默認是0,代表瀏覽器一關閉SESSIONID就失效。那就是說我們把session.gc_maxlifetime和session.cookie_lifetime設置成同一個值就可以控制session的失效時間了。
6. php中session的客戶端存儲機制
由於cookie可以被人為的禁止,必須有其他機制以便在cookie被禁止時仍然能夠把session id傳遞回服務器。解決辦法有:
1、URL重寫,就是把session id直接附加在URL路徑的后面,一種是作為URL路徑的附加信息,表現形式為http://…../xxx;jsessionid= ByOK3vjFD75aPnrF7C2HmdnV6QZcEbzWoWiBYEnLerjQ99zWpBng!-145788764
2、另一種是作為查詢字符串附加在URL后面,表現形式為http://…../xxx?jsessionid=ByOK3vjFD75aPnrF7C2HmdnV6QZcEbzWoWiBYEnLerjQ99zWpBng!-145788764
這兩種方式對於用戶來說是沒有區別的,只是服務器在解析的時候處理的方式不同,采用第一種方式也有利於把session id的信息和正常程序參數區分開來。
為了在整個交互過程中始終保持狀態,就必須在每個客戶端可能請求的路徑后面都包含這個session id。
3、表單隱藏字段。就是服務器會自動修改表單,添加一個隱藏字段,以便在表單提交時能夠把session id傳遞回服務器。比如下面的表單
<form name=”testform” action=”/xxx”>
<input type=”text”>
</form>
在被傳遞給客戶端之前將被改寫成
<form name=”testform” action=”/xxx”>
<input type=”hidden” name=”jsessionid” value=”ByOK3vjFD75aPnrF7C2HmdnV6QZcEbzWoWiBYEnLerjQ99zWpBng!-145788764″>
<input type=”text”>
</form>
實際上這種技術可以簡單的用對action應用URL重寫來代替。