實(shí)例說明:
將SESSION數(shù)據(jù)變量存儲(chǔ)于服務(wù)器是端是一種較安全的做法,但是設(shè)想一下,像校內(nèi)網(wǎng)這樣的日訪問量過億,擁有用戶幾千萬的大型網(wǎng)站,如果將所有用戶SESSION數(shù)據(jù)全部存儲(chǔ)于服務(wù)器端,將消耗巨大的服務(wù)器資源。所以程序員在制作大型網(wǎng)站時(shí)將SESSION存儲(chǔ)于服務(wù)器端雖然安全,但卻不是最好的選擇。如果將SESSION數(shù)據(jù)存儲(chǔ)于數(shù)據(jù)庫中,那么就可以減輕服務(wù)器的壓力同時(shí)數(shù)據(jù)也是比較安全的。設(shè)計(jì)過程
首先在Mysql數(shù)據(jù)庫創(chuàng)建存儲(chǔ)SESSION的表:
表名為t_session
表結(jié)構(gòu)為

說明:session_key:是用來存會(huì)話ID的
session_data:是用來存經(jīng)序列化后的$_SESSION[]里的值;
session_time:是用來存時(shí)間戳的,這個(gè)時(shí)間戳指的是當(dāng)前session在創(chuàng)建時(shí)的 time()+session的有效期。需要注意的是這 里的session_time的類型是int,這樣可以在操作數(shù)據(jù)庫時(shí),進(jìn)行大小比較!
那么什么是序列化呢?
序列化 (Serialization)就是將對象的狀態(tài)信息轉(zhuǎn)換為可以存儲(chǔ)或傳輸?shù)男问降倪^程。在序列化期間,對象將其當(dāng)前狀態(tài)寫入到臨時(shí)或持久性存儲(chǔ)區(qū)。以后,可以通過從存儲(chǔ)區(qū)中讀取或反序列化對象的狀態(tài),重新創(chuàng)建該對象。
比如說
$_SESSION[“user”]=”張三”$_SESSION[“pwd”]=”zhangsan”
序列話后成為一個(gè)字符串
user|s:6: 張三 pwd|s:8: zhangsan
其中s表示類型為string,數(shù)字表示字符串長度,這樣就可以對這個(gè)字符串操作了。
接下來就是正文部分了
session.save_handler 定義存儲(chǔ)和獲取與會(huì)話關(guān)聯(lián)的數(shù)據(jù)的處理器的名字。默認(rèn)為 files。如果設(shè)定為files(session.save_handler = files),則采用的是php內(nèi)置機(jī)制,如果想自定義存儲(chǔ)方式(比如存儲(chǔ)到數(shù)據(jù)庫中),則使用session_set_save_handler()進(jìn)行自定義設(shè)置,我們這里說的則是第二種。
所以我們得修改php.ini文件里session_set_save_handler的值,將其修改為user,如圖:

bool session_set_save_handler ( callable open , callable $close , callable read , callable write , callable destroy , callable gc [, callable $create_sid [, callable validate_sid [, callable update_timestamp ]]] )
如果不修改,那你在使用session的時(shí)候可以不用理他,但當(dāng)你修改 了,你不得不面對他。這是一個(gè)很特殊的函數(shù),因?yàn)橐话愕暮瘮?shù)的參數(shù)都是變量,但是該函數(shù)的參數(shù)為6個(gè)函數(shù)(后面的三個(gè)參數(shù)為可選參數(shù),可忽略)不用怕,一個(gè)一個(gè)來:
第一個(gè)參數(shù): open(save_path,session_name),這里面的兩個(gè)參數(shù)是php自動(dòng)傳遞的。save_path 在session.save_handler = files的情況下它就是session.save_path,session_name則是服務(wù)器用來識(shí)別客戶端的會(huì)話ID,但是如果用戶自定的話,這個(gè)兩個(gè)參數(shù)都用不上,只在其中連接數(shù)據(jù)庫,open 回調(diào)函數(shù)類似于類的html' target='_blank'>構(gòu)造函數(shù),在會(huì)話打開的時(shí)候會(huì)被調(diào)用。 這是自動(dòng)開始會(huì)話或者通過調(diào)用 session_start() 手動(dòng)開始會(huì)話之后第一個(gè)被調(diào)用的回調(diào)函數(shù)。 此回調(diào)函數(shù)操作成功返回 TRUE,反之返回 FALSE。
第二個(gè)參數(shù): close(),這個(gè)函數(shù)不需要參數(shù),用來關(guān)閉數(shù)據(jù)庫。close 回調(diào)函數(shù)類似于類的析構(gòu)函數(shù)。 在 write 回調(diào)函數(shù)調(diào)用之后調(diào)用。 當(dāng)調(diào)用 session_write_close() 函數(shù)之后,也會(huì)調(diào)用 close 回調(diào)函數(shù)。 此回調(diào)函數(shù)操作成功返回 TRUE,反之返回 FALSE。
第三個(gè)參數(shù): read($key),這里面的參數(shù)是會(huì)話ID,php自動(dòng)傳遞的,傳遞的前提是有會(huì)話ID,若無,則這個(gè)參數(shù)返回空字符串。注意,若數(shù)據(jù)庫中無對應(yīng)的數(shù)據(jù)一定要返回空字符串,否則報(bào)錯(cuò)!如果會(huì)話中有數(shù)據(jù),read 回調(diào)函數(shù)必須返回將會(huì)話數(shù)據(jù)編碼(序列化)后的字符串(在此處就是從表t_session里取出的session_data)。在自動(dòng)開始會(huì)話或者通過調(diào)用 session_start()函數(shù)手動(dòng)開始會(huì)話之后,PHP 內(nèi)部調(diào)用 read 回調(diào)函數(shù)來獲取會(huì)話數(shù)據(jù)。 在調(diào)用 read 之前,PHP 會(huì)調(diào)用 open 回調(diào)函數(shù)。read 回調(diào)返回的序列化之后的字符串格式必須與 write 回調(diào)函數(shù)保存數(shù)據(jù) 時(shí)的格式完全一致。 PHP 會(huì)自動(dòng)反序列化返回的字符串并填充 $_SESSION 超級全局變量。
第四個(gè)參數(shù): write($key,$data), 這兩個(gè)參數(shù)也是php自動(dòng)傳遞給這個(gè)函數(shù)的,$key對應(yīng)會(huì)話ID,$data對應(yīng)當(dāng)前(因?yàn)閣rite函數(shù)一般是在腳本執(zhí)行結(jié)束后才被調(diào)用的)腳本被序列化處理器處理的session變量(如上文提到的$_SESSION[“user”]=”張三”$_SESSION[“pwd”]=”zhangsan”),序列化會(huì)話數(shù)據(jù)的過程由 PHP 根據(jù) session.serialize_handler 設(shè)定值來完成。序列化后的數(shù)據(jù)將和會(huì)話 ID 關(guān)聯(lián)在一起進(jìn)行保存。 當(dāng)調(diào)用 read 回調(diào)函數(shù)獲取數(shù)據(jù)時(shí),所返回的數(shù)據(jù)必須要和 傳入 write 回調(diào)函數(shù)的數(shù)據(jù)完全保持一致。PHP 會(huì)在腳本執(zhí)行完畢或調(diào)用 session_write_close() 函數(shù)之后調(diào)用此回調(diào) 函數(shù)。注意,在調(diào)用完此回調(diào)函數(shù)之后,PHP 內(nèi)部會(huì)調(diào)用 close 回調(diào)函數(shù)。
NOTE:PHP 會(huì)在輸出流寫入完畢并且關(guān)閉之后 才調(diào)用 write 回調(diào)函數(shù), 所以在 write 回調(diào)函數(shù)中的調(diào)試信息不會(huì)輸出到瀏覽器中。 如果需要在 write 回調(diào)函數(shù)中使用調(diào)試輸出, 建議將調(diào)試輸出寫入到文件。
第五個(gè)參數(shù): destroy($key),當(dāng)調(diào)用 session_destroy() 函數(shù), 或者調(diào)用 session_regenerate_id() 函數(shù)并且設(shè)置 destroy 參數(shù)為 TRUE 時(shí), 會(huì)調(diào)用此回調(diào)函數(shù)。用來注銷session對應(yīng)的SESSION鍵值,此回調(diào)函數(shù)操作成功返回 TRUE,反之返回 FALSE。它就是人們常常在點(diǎn)擊注銷登錄的時(shí)候用到的函數(shù)。后面會(huì)有這個(gè)小細(xì)節(jié)。
第六個(gè)參數(shù): gc(expire_time),這個(gè)函數(shù)的參數(shù)在默認(rèn)機(jī)制下就是session.gc_maxlifetime設(shè)置的session有效時(shí)間。但是,user機(jī)制下session的過期時(shí)間在就是表里session_time,所以這里不需要傳遞參數(shù)的。為了清理會(huì)話中的舊數(shù)據(jù),PHP 會(huì)不時(shí)的調(diào)用垃圾收集回調(diào)函數(shù)。 調(diào)用周期由 session.gc_probability 和 session.gc_pisor 參數(shù)控制。此回調(diào)函數(shù)操作成功返回 TRUE,反之返回 FALSE。
至此六個(gè)函數(shù)已經(jīng)介紹完了,但是其中有許多需要說明的:
1、在open函數(shù)中本來是要傳遞save__path,目的是用來在這個(gè)路徑下找到與session_name相對應(yīng)的文件,然后通過read()函數(shù)來讀取其中的數(shù)據(jù),然后通過反序列化處理器將取到的字符串反序列化,在通過php自動(dòng)填充各個(gè)$_session超全局變量。或者write函數(shù)來將序列化的數(shù)據(jù)存入這個(gè)路徑下的文件。那么這里面的路徑在非默認(rèn)機(jī)制下難道就不需要嗎,答案是肯定的*_*。當(dāng)在非默認(rèn)機(jī)制下,調(diào)試輸出session_save_path,其結(jié)果為空值;而且如果未設(shè)置存儲(chǔ)的路徑,那被填充的$_session變量也只能在當(dāng)前頁面使用,而不能在別的頁面使用,可以這樣測試:在另一個(gè)頁面利用session_start()函數(shù)打開會(huì)話,然后輸出session_id和var_dump($_session),得到的是上一次瀏覽時(shí)服務(wù)器給客戶端的session_id,但是$_session輸出的是空數(shù)組(當(dāng)然我這里只是大概的說一下我在驗(yàn)證時(shí)的過程)。其實(shí)我想說的就是我們在自定義會(huì)話存儲(chǔ)機(jī)制的時(shí)候,是不需要自定義路徑的,不然為什么還要存入數(shù)據(jù)庫呢?
那么怎么在其他頁面也能讀取到$_session[]里面的值呢?
引入這個(gè)函數(shù),即將六個(gè) 回調(diào)函數(shù)和session_set_save_handler放入一個(gè)文件里,然后在session_start()前用include()引入!
2、那他們的執(zhí)行順序是怎樣呢?有點(diǎn)暈吧,來總結(jié)一下:首先session_start()函數(shù)打開session操作句柄,然后read函數(shù)讀取數(shù)據(jù),當(dāng)腳本執(zhí)行結(jié)束的時(shí)候執(zhí)行write函數(shù)然后是close函數(shù)若有session_destroy()則執(zhí)行完。
3、上面我提到過PHP 會(huì)在輸出流寫入完畢并且關(guān)閉之后才調(diào)用 write 回調(diào)函數(shù),這個(gè)可把我玩壞啦,小編在上面可繞了不久呀,不然我也不會(huì)在write函數(shù)里調(diào)試那么久了!不過我也因此了解了register_shutdown_function這個(gè)函數(shù),下面附上這個(gè)函數(shù)的特點(diǎn)吧:register_shutdown_function()是指在執(zhí)行完所有PHP語句后再調(diào)用函數(shù),不要理解成客戶端關(guān)閉流瀏覽器頁面時(shí)調(diào)用函數(shù)。
可以這樣理解調(diào)用條件:
1、當(dāng)頁面被用戶強(qiáng)制停止時(shí)
2、當(dāng)程序代碼運(yùn)行超時(shí)時(shí)
3、當(dāng)PHP代碼執(zhí)行完成時(shí),代碼執(zhí)行存在異常和錯(cuò)誤、警告
好了以上該說的都說完了,附上代碼吧:
index.php用戶登錄界面
?php
session_destroy();//這里就是上文提到的 小細(xì)節(jié)了,當(dāng)有session_destroy的時(shí)候,它是先于read回調(diào)函數(shù)執(zhí)行的
if(isset($_SESSION[ user ])){//判斷此值是否有定義,若有定義則說明 存入的session還未到期,則直接轉(zhuǎn)到主內(nèi)容
$_SESSION[ pwd ]=$_POST[ pwd //這里自定義的會(huì)話管理機(jī)制將會(huì)調(diào)用回調(diào)函數(shù)write,將已由序列化處理器處理好的(由$_session[]變量形成)字符串寫入數(shù)據(jù)庫
$sql= select session_data from t_session where session_key= $key and session_time $time
$over_time=time()+60;//注意time()為時(shí)間戳,在mysql中的數(shù)據(jù)類型不可用用date,datetime,timestamp來存儲(chǔ)
//若$result為false,即結(jié)果 為空,說明數(shù)據(jù)庫中未存有相應(yīng)的session_id,那么就插入,如果不為空,那即使還有未過期的session_id,這是應(yīng)更新
$sql= insert into t_session(session_key,session_data,session_time ) values( $key , $data ,$over_time) //字符串的時(shí)候要加單引號,數(shù)字的時(shí)候是不用加的
$sql= update t_session set session_key= $key ,session_data= $data ,session_time=$over_time where session_key= $key
function overdue($expire_time){//這個(gè)參數(shù)是自動(dòng)傳進(jìn)去的,就是session.gc_maxlifetime最大有效時(shí)間,例如1440s;
獨(dú)孤九賤(5)_ThinkPHP5視頻教程ThinkPHP是國內(nèi)最流行的中文PHP開發(fā)框架,也是您Web項(xiàng)目的最佳選擇。《VeVb.com獨(dú)孤九賤(5)-ThinkPHP5視頻教程》課程以ThinkPHP5最新版本為例,從最基本的框架常識(shí)開始,將...
Peter-Zhu 2017-05-16 12:03:57
獨(dú)孤九賤(4)_PHP視頻教程江湖傳言:PHP是世界上最好的編程語言。真的是這樣嗎?這個(gè)梗究竟是從哪來的?學(xué)會(huì)本課程,你就會(huì)明白了。PHP 出品的PHP入門系統(tǒng)教學(xué)視頻,完全從初學(xué)者的角度出發(fā),絕不玩虛的,一切以實(shí)用、有用...
Peter-Zhu 2017-03-20 22:47:17
獨(dú)孤九賤(1)_HTML5視頻教程《VeVb.com原創(chuàng)html5視頻教程》課程特色:php 原創(chuàng)幽默段子系列課程,以惡搞,段子為主題風(fēng)格的php視頻教程!輕松的教學(xué)風(fēng)格,簡短的教學(xué)模式,讓同學(xué)們在不知不覺中,學(xué)會(huì)了HTML知識(shí)。...
Peter-Zhu 2017-03-13 10:15:11
ThinkPHP5實(shí)戰(zhàn)之[教學(xué)管理系統(tǒng)]本套教程,以一個(gè)真實(shí)的學(xué)校教學(xué)管理系統(tǒng)為案例,手把手教會(huì)您如何在一張白紙上,從零開始,一步一步的用ThinkPHP5框架快速開發(fā)出一個(gè)商業(yè)項(xiàng)目。
Peter-Zhu 2017-07-24 16:48:56
PHP入門視頻教程之一周學(xué)會(huì)PHP所有計(jì)算機(jī)語言的學(xué)習(xí)都要從基礎(chǔ)開始,《PHP入門視頻教程之一周學(xué)會(huì)PHP》不僅是PHP的基礎(chǔ)部分更主要的是PHP語言的核心技術(shù),是學(xué)習(xí)PHP必須掌握的內(nèi)容,任何PHP項(xiàng)目的實(shí)現(xiàn)都離不開這部分的內(nèi)容,通...
PHP教程鄭重聲明:本文版權(quán)歸原作者所有,轉(zhuǎn)載文章僅為傳播更多信息之目的,如作者信息標(biāo)記有誤,請第一時(shí)間聯(lián)系我們修改或刪除,多謝。
新聞熱點(diǎn)
疑難解答
圖片精選