session 原理
PHP中的session在默認情況下是使用客戶端的Cookie來保存session id的,所以當客戶端的cookie出現問題的時候就會影響session了。必須注意的是:session不一定必須依賴cookie,這也是 session相比cookie的高明之處。當客戶端的Cookie被禁用或出現問題時,PHP會自動把session id附著在URL中,這樣再通過session id就能跨頁使用session變量了。但這種附著也是有一定條件的,即“php.ini中的session.use_trans_sid = 1或者編譯時打開打開了--enable-trans-sid選項”。
所以,我們可以拋開cookie使用session,即假定用戶關閉cookie的情況下使用session,其實現途徑有以下幾種
第一種方式:在每個超鏈接上添加一個PHPSESSID=$sid
//防止返回初始頁產生新的session
if(isset($_GET["PHPSESSID"])){
session_id($_GET["PHPSESSID"]);
}
//啟動一個session
session_start();
//獲取當前session的session_id()
$sid=session_id();
//在每個鏈接上添加參數PHPSESSID=$sid
其他頁面的獲取方式為:
if(isset($_GET["PHPSESSID"])){
//設置當前的session為初始的session,session_id()一致即可
session_id($_GET["PHPSESSID"])
}
session_start();
第二種方式:使用 SID 常量替換鏈接上的 PHPSESSID=$sid (SID的值類似:PHPSESSID=sddg34r593dfdlksrewr)
if(isset($_GET["PHPSESSID"])){
session_id($_GET["PHPSESSID"]);
}
//啟動一個session
session_start();
其他頁面的獲取方式為:
if(isset($_GET["PHPSESSID"])){
//設置當前的session為初始的session,session_id()一致即可
session_id($_GET["PHPSESSID"])
}
session_start();
第三種方式:使用session.use_trans_sid=1,php.ini中配置
1、設置php.ini中的session.use_trans_sid = 1或者編譯時打開打開了--enable-trans-sid選項,讓PHP自動跨頁傳遞session id。
2、手動通過URL傳值、隱藏表單傳遞session id。
3、用文件、數據庫等形式保存session_id,在跨頁過程中手動調用。
<?
session_start();?
? $_SESSION['name']="Aseoe";?
? $sn = session_id();?
? $url=".""index2.php?s=".$sn."">下一頁";?
? echo $url;?
?>?
?
index2.php?
? $_GET[’s’]);????
? session_start();????
? echo "傳遞的session變量name的值為:".$_SESSION['name'];??
?>
?
原理解析
之前在學校的時候,只知道session與cookie的區別在于:session是保存在服務器端,cookie保存在客戶端。session怎么樣保存的?以文件的形式保存。自己去測試過。有的忘記了。對應session的id號模糊不清。在開發中,非常有必要弄明白具體細節。不能停留在使用session_start()函數了,然后獲取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的名字。
結合自己實際開發中遇到的問題,總結一下:要說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;cityName|s:3:"all";”就是一個完整的session值結束
2、里面的讀取規則:符號“|”前面表示session名稱。符號后面是該session的具體信息。包括:數據類型,字符長度,內容。上面第一個就相當于使用如下php代碼訪問:$_SESSION['cityID']
?
后面的s表示數據值的長度,3表示字符長度。比如這一段:fanwe_lang|s:5:"zh-cn"; fanwe_lang是變量的名稱,變量值是"zh-cn",長度剛好是5,就是”s:5“標明的。
最后"all"就表示session的具體值了。就是使用代碼$_SESSION['cityID']后會得到的結果。
?
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共享。跟具體的服務器是無關的。
?
(2013年更新:實際上共享session不局限于數據庫中保存,關于session共享方案,根據自己的理解一年后寫了一篇總結文章,http://www.cnblogs.com/wangtao_20/p/3395518.html)
session文件是某個用戶整個會話過程中數據。那么,假如cs.test.com和daohang.test.com下的兩個程序運行在同一個服務器上。就意味著,訪問cs.test.com與訪問daohang.test.com是同一個會話。也就意味著,這兩邊訪問后設置的session數據是保存在同一個session文件中的。
可以將名為PHPSESSIONID的cookie,其值看成是一個會話的id。會話結束后,該cookie過期或者被刪。那么,服務器對應的session文件(名為"sess_[phpcookie值]")會被刪掉嗎?查看發現并不會被刪掉。所以才會有session文件很多,出現讀取性能的問題。session文件比較多的情況下,產生I/Q讀寫性能問題。了解到可以將session文件分多個目錄保存(參考http://www.jb51.net/article/27941.htm)。php.ini中的配置項session.save_path,前面一個值M可以指定目錄的深度級別。這個沒測試過。需要用到的時候,再去測試一下。
待解決疑問
一、session的過期時間是怎么確定的?
查看session文件內容,發現里面有個值設置了session文件的過期時間:__HTTP_Session_Expire_TS|i:1297750868;
已掌握的信息:
PHPSESSID該cookie的過期時間在瀏覽器中顯示:會話結束后過期
所有的session文件沒有被自動刪掉,只是有個過期時間,以此決定:是新生成一個session文件還是使用原來的。
原來:服務器定期session清理機制估計會用到這個東西
二、如果沒有設置php.ini中的參數。php默認會將session文件保存到什么位置?
附網文:php.ini中配置session參數的說明。
【Session】
[服務端]
session.save_handler = files
默認為file,定義session在服務端的保存方式,file意為把sesion保存到一個臨時文件里,如果我們想自定義別的方式保存
(比如用數據庫),則需要把該項設置為user;
session.save_path = "D:/APMServ5.2.0/PHP/sessiondata/"
定義服務端存儲session的臨時文件的位置。
session.auto_start = 0
如置1,則不用在每個文件里寫session_start(); session自動start :)
session.gc_probability = 1
session.gc_divisor = 100
session.gc_maxlifetime = 1440
這三個配置組合構建服務端session的垃圾回收機制
session.gc_probability與session.gc_divisor構成執行session清理的概率,理論上的解釋為服務端定期有一定的概率調用gc函數來對session進行清理,清理的概率為:gc_probability/gc_divisor 比如:1/100 表示每一個新會話初始化時,有
1%的概率會啟動垃圾回收程序,清理的標準為session.gc_maxlifetime定義的時間。
[客戶端]
session.use_cookies = 1
sessionid在客戶端采用的存儲方式,置1代表使用cookie記錄客戶端的sessionid,同時,$_COOKIE變量里才會有$_COOKIE[
‘PHPSESSIONID’]這個元素存在;
session.use_only_cookies = 1
也是定義sessionid在客戶端采用的存儲方式,置1代表僅僅使用 cookie 來存放會話 ID。一般來說,現在客戶端都會支持
cookie,所以建議設置成1,這樣可以防止有關通過 URL 傳遞會話 ID 的攻擊。
session.use_trans_sid = 0
相對應于上面那個設置,這里如果置1,則代表允許sessionid通過url參數傳遞,同理,建議設置成0;
session.referer_check =
這個設置在session.use_trans_sid = 1的時候才會生效,目的是檢查HTTP頭中的"Referer"以判斷包含于URL中的會話id是否
有效,HTTP_REFERER必須包含這個參數指定的字符串,否則URL中的會話id將被視為無效。所以一般默認為空,即不檢查。
session.name = PHPSESSID
定義sessionid的名稱,即變量名,所以通過瀏覽器http工具看到的http頭文件里的PHPSESSID=##############;
session.hash_function = 0
選擇session_name的加密方式,0代表md5加密,1代表sha1加密,默認是0,但是據說用sha1方式加密,安全性更高;
session.hash_bits_per_character = 4
指定在session_name字符串中的每個字符內保存多少位二進制數,這些二進制數是hash函數的運算結果。
4 bits: 0-9, a-f
5 bits: 0-9, a-v
6 bits: 0-9, a-z, A-Z, "-", ","
url_rewriter.tags = "a=href,area=href,frame=src,input=src,form=,fieldset="
指定重寫哪些HTML標簽來包含sid(session_id)(僅在"session.use_trans_sid"打開的情況下有效),URL重寫器將添加一個
隱藏的"<input>",它包含了本應當額外追加到URL上的信息。
session.cookie_lifetime = 0
保存sessionid的cookie文件的生命周期,如置0,代表會話結束,則sessionid就自動消失,常見的強行關閉瀏覽器,就會丟
失上一次的sessionid;
session.cookie_path = /
保存sessionid的cookie文件在客戶端的位置;
session.cookie_domain = /
保存sessionid的cookie的域名設置,這跟cookie允許的域名的訪問權限設置有關,一般來說想讓自己網站所有的目錄都能訪
問到客戶端的cookie,就應該設置成“/”如需要詳細了解,可以看下setcookie()函數的domain參數相關設置和使用方法;
session.bug_compat_42 = 1
session.bug_compat_warn = 1
這兩個可以說幾乎是快要被廢棄的設置,是為了老版本的php服務的,主要是針對 session_register函數,因為php5的
register_global默認是關閉狀態,所以在php5里根本用不到 session_register這個函數;并且php6就要廢除這個設置,直接定義為關閉,所以沒必要研究這兩個了;
?
2015.6.14
今天無意中看php手冊,注意到這句話:
在某些操作系統上,建議使用可以高效處理 大量小尺寸文件的文件系統上的路徑來保存會話數據。 例如,在 Linux 平臺上,對于會話數據保存的工作而言,reiserfs 文件系統會比 ext2fs 文件系統能夠提供更好的性能。
這個是好的方向。session的數據一般很小。適合小文件的文件系統來使用,而我們的傳統的文件系統不太適合。
轉載于:https://www.cnblogs.com/xw2169/p/6015005.html
總結
以上是生活随笔為你收集整理的session 原理的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 中英文对照 —— 经济、金融学、财务
- 下一篇: logback.xml配置详解