這篇文章給大家介紹的內容是關於PHP中如何將session存入資料庫並使用(附代碼),有一定的參考價值,有需要的朋友可以參考一下,希望對你有所協助。
執行個體說明:
將SESSION資料變數儲存於伺服器是端是一種較安全的做法,但是設想一下,像校內網這樣的日訪問量過億,擁有使用者幾千萬的大型網站,如果將所有使用者SESSION資料全部儲存於伺服器端,將消耗巨大的伺服器資源。所以程式員在製作大型網站時將SESSION儲存於伺服器端雖然安全,但卻不是最好的選擇。如果將SESSION資料存放區於資料庫中,那麼就可以減輕伺服器的壓力同時資料也是比較安全的。
設計過程
首先在Mysql資料庫建立儲存SESSION的表:
表名為t_session
表結構為
說明:session_key:是用來存會話ID的
session_data:是用來存經序列化後的$_SESSION[]裡的值;
session_time:是用來存時間戳記的,這個時間戳記指的是當前session在建立時的 time()+session的有效期間。需要注意的是這 裡的session_time的類型是int,這樣可以在操作資料庫時,進行大小比較!
那麼什麼是序列化呢?
序列化 (Serialization)就是將對象的狀態資訊轉換為可以儲存或傳輸的形式的過程。在序列化期間,對象將其目前狀態寫入到臨時或持久性儲存區。以後,可以通過從儲存區中讀取或還原序列化對象的狀態,重新建立該對象。
比如說
$_SESSION[“user”]=”張三”$_SESSION[“pwd”]=”zhangsan”
序列話後成為一個字串
user|s:6:"張三";pwd|s:8:"zhangsan";
其中s表示類型為string,數字表示字串長度,這樣就可以對這個字串操作了。
接下來就是本文部分了
session.save_handler 定義儲存和擷取與會話關聯的資料的處理器的名字。預設為 files。如果設定為files(session.save_handler = files),則採用的是php內建機制,如果想自訂儲存方式(比如儲存到資料庫中),則使用session_set_save_handler()進行自訂設定,我們這裡說的則是第二種。
所以我們得修改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的時候可以不用理他,但當你修改 了,你不得不面對他。這是一個很特殊的函數,因為一般的函數的參數都是變數,但是該函數的參數為6個函數(後面的三個參數為選擇性參數,可忽略)不用怕,一個一個來:
第一個參數: open(save_path,session_name),這裡面的兩個參數是php自動傳遞的。save_path 在session.save_handler = files的情況下它就是session.save_path,session_name則是伺服器用來識別用戶端的會話ID,但是如果使用者自定的話,這個兩個參數都用不上,只在其中串連資料庫,open 回呼函數類似於類的建構函式,在會話開啟的時候會被調用。 這是自動開始會話或者通過調用 session_start() 手動開始會話之後第一個被調用的回呼函數。 此回呼函數操作成功返回 TRUE,反之返回 FALSE。
第二個參數: close(),這個函數不需要參數,用來關閉資料庫。close 回呼函數類似於類的解構函式。 在 write 回呼函數調用之後調用。 當調用 session_write_close() 函數之後,也會調用 close 回呼函數。 此回呼函數操作成功返回 TRUE,反之返回 FALSE。
第三個參數: read($key),這裡面的參數是會話ID,php自動傳遞的,傳遞的前提是有會話ID,若無,則這個參數返回Null 字元串。注意,若資料庫中無對應的資料一定要返回Null 字元串,否則報錯!如果會話中有資料,read 回呼函數必須返回將會話資料編碼(序列化)後的字串(在此處就是從表t_session裡取出的session_data)。在自動開始會話或者通過調用 session_start()函數手動開始會話之後,PHP 內部調用 read 回呼函數來擷取會話資料。 在調用 read 之前,PHP 會調用 open 回呼函數。read 回調返回的序列化之後的字串格式必須與 write 回呼函數儲存資料 時的格式完全一致。 PHP 會自動還原序列化返回的字串並填充 $_SESSION 超級全域變數。
第四個參數: write($key,$data), 這兩個參數也是php自動傳遞給這個函數的,$key對應會話ID,$data對應當前(因為write函數一般是在指令碼執行結束後才被調用的)指令碼被序列化處理器處理的session變數(如上文提到的$_SESSION[“user”]=”張三”$_SESSION[“pwd”]=”zhangsan”),序列化會話資料的過程由 PHP 根據 session.serialize_handler 設定值來完成。序列化後的資料將和會話 ID 關聯在一起進行儲存。 當調用 read 回呼函數擷取資料時,所返回的資料必須要和 傳入 write 回呼函數的資料完全保持一致。PHP 會在指令碼執行完畢或調用 session_write_close() 函數之後調用此回調 函數。注意,在調用完此回呼函數之後,PHP 內部會調用 close 回呼函數。
NOTE:PHP 會在輸出資料流寫入完畢並且關閉之後 才調用 write 回呼函數, 所以在 write 回呼函數中的調試資訊不會輸出到瀏覽器中。 如果需要在 write 回呼函數中使用調試輸出, 建議將調試輸出寫入到檔案。
第五個參數: destroy($key),當調用 session_destroy() 函數, 或者調用 session_regenerate_id() 函數並且設定 destroy 參數為 TRUE 時, 會調用此回呼函數。用來登出session對應的SESSION索引值,此回呼函數操作成功返回 TRUE,反之返回 FALSE。它就是人們常常在點擊登出登入的時候用到的函數。後面會有這個小細節。
第六個參數: gc(expire_time),這個函數的參數在預設機制下就是session.gc_maxlifetime設定的session有效時間。但是,user機制下session的到期時間在就是表裡session_time,所以這裡不需要傳遞參數的。為了清理會話中的舊資料,PHP 會不時的調用垃圾收集回呼函數。 調用周期由 session.gc_probability 和 session.gc_pisor 參數控制。此回呼函數操作成功返回 TRUE,反之返回 FALSE。
至此六個函數已經介紹完了,但是其中有許多需要說明的:
1、在open函數中本來是要傳遞save__path,目的是用來在這個路徑下找到與session_name相對應的檔案,然後通過read()函數來讀取其中的資料,然後通過還原序列化處理器將取到的字串還原序列化,在通過php自動填滿各個$_session超全域變量。或者write函數來將序列化的資料存入這個路徑下的檔案。那麼這裡面的路徑在非預設機制下難道就不需要嗎,答案是肯定的*_*。當在非預設機制下,調試輸出session_save_path,其結果為空白值;而且如果未設定儲存的路徑,那被填充的$_session變數也只能在當前頁面使用,而不能在別的頁面使用,可以這樣測試:在另一個頁面利用session_start()函數開啟會話,然後輸出session_id和var_dump($_session),得到的是上一次瀏覽時伺服器給用戶端的session_id,但是$_session輸出的是空數組(當然我這裡只是大概的說一下我在驗證時的過程)。其實我想說的就是我們在自訂會話存儲機制的時候,是不需要自訂路徑的,不然為什麼還要存入資料庫呢?
那麼怎麼在其他頁面也能讀取到$_session[]裡面的值呢?
引入這個函數,即將六個 回呼函數和session_set_save_handler放入一個檔案裡,然後在session_start()前用include()引入!
2、那他們的執行順序是怎樣呢?有點暈吧,來總結一下:首先session_start()函數開啟session操作控制代碼,然後read函數讀取資料,當指令碼執行結束的時候執行write函數然後是close函數若有session_destroy()則執行完。
3、上面我提到過PHP 會在輸出資料流寫入完畢並且關閉之後才調用 write 回呼函數,這個可把我玩壞啦,小編在上面可繞了不久呀,不然我也不會在write函數裡調試那麼久了!不過我也因此瞭解了register_shutdown_function這個函數,下面附上這個函數的特點吧:register_shutdown_function()是指在執行完所有PHP語句後再調用函數,不要理解成用戶端關閉流瀏覽器頁面時調用函數。
可以這樣理解調用條件:
1、當頁面被使用者強制停止時
2、當程式碼運行逾時時
3、當PHP代碼執行完成時,代碼執行存在異常和錯誤、警告
好了以上該說的都說完了,附上代碼吧:
index.php使用者登入介面
<?phpinclude("session_set_save_handler.php");//引入自訂的會話儲存機制if(isset($_GET["login"])){//判斷login是否有值,若有值則要進行登出,session_start();//只要需要 用到$_session變數的地方,就需要開啟回呼函數opensession_destroy();//這裡就是上文提到的 小細節了,當有session_destroy的時候,它是先於read回呼函數執行的}else{session_start();if(isset($_SESSION["user"])){//判斷此值是否有定義,若有定義則說明 存入的session還未到期,則直接轉到主內容echo "<script>alert('您不久前剛來過');window.location.href='main.php';</script>";}}?><html><meta charset="utf-8"><body><form action="index_ok.php" method="post">賬 戶:<input type="text" name="user"><br>密 碼:<input type="text" name="pwd"><input type="submit" name="sub"></form></body></html>
index_ok.php表單提交處理檔案
<?phpinclude("session_set_save_handler.php");session_start();if($_POST["sub"]){//$_post["sub"]它若有值就是 提交查詢echo $_POST["sub"];if($_POST["user"]!=""&&$_POST["pwd"]!=""){$_SESSION["user"]=$_POST["user"];$_SESSION["pwd"]=$_POST["pwd"];//這裡自訂的會話管理機制將會調用回呼函數write,將已由序列化處理器處理好的(由$_session[]變數形成)字串寫入資料庫echo "<script>alert('登入成功!');window.location.href='main.php';</script>";}}?>
main.php主內容頁
<?phpinclude("session_set_save_handler.php");session_start();if(isset($_SESSION["user"])){echo "歡迎".$_SESSION["user"];echo "<a href='index.php?login=0'>登出</a>";}else{echo "您還沒登入,請先登入!";echo "<a href='index.php'>登入</a>";}?>
session_set_save_handler.php自訂session儲存機制函數檔案
<?php//開啟會話function open(){global $con;//使用全域變數$con=mysqli_connect("localhost","root","123456","mysql")or die("資料庫連接失敗!");mysqli_query($con,"set names utf8");return(true);}//關閉資料庫function close(){global $con;mysqli_close($con);return(true);}//讀取session_datafunction read($key){global $con;$time=time();//不讀取已到期的session$sql="select session_data from t_session where session_key='$key' and session_time>$time";$result=mysqli_query($con,$sql)or die("查詢失敗!");if (!$result) {//用來檢查出現再資料庫部分的錯誤,很有用printf("Error: %s\n", mysqli_error($con));//%s表示的是字串,這是c裡面的exit();}$row=mysqli_fetch_array($result);//or die()會終止後面的程式!if($row!=false){return($row["session_data"]);}else{return "";//再次強調如果空值 ,則一定 要返回”“而不是false}}//儲存sessionfunction write($key,$data){global $con;$over_time=time()+60;//注意time()為時間戳記,在mysql中的資料類型不可用用date,datetime,timestamp來儲存$sql="select session_data from t_session where session_key='$key'";$re=mysqli_query($con,$sql);$result=mysqli_fetch_array($re);//若$result為false,即結果 為空白,說明資料庫中未存有相應的session_id,那麼就插入,如果不為空白,那即使還有未到期的session_id,這是應更新if($result==false){$sql="insert into t_session(session_key,session_data,session_time ) values('$key','$data',$over_time)";//字串的時候要加單引號,數位時候是不用加的$result=mysqli_query($con,$sql);if (!$result) {//用來檢查出現再資料庫部分的錯誤,很有用printf("Error: %s\n", mysqli_error($con));//%s表示的是字串,這是c裡面的exit();}}else{$sql="update t_session set session_key='$key',session_data='$data',session_time=$over_time where session_key='$key'";$result=mysqli_query($con,$sql);}return($result);}清楚相應的session資料function destroy($key){global $con;$sql="delete from t_session where session_key='$key'";$result=mysqli_query($con,$sql);return($result);}//執行記憶體回收function overdue($expire_time){//這個參數是自動傳進去的,就是session.gc_maxlifetime最大有效時間,例如1440s;global $con;$time=time();$sql="delete from t_session where session_time<$time";$result=mysqli_query($sql);return($result);}session_set_save_handler('open','close','read','write','destroy','overdue');?>
相關文章推薦:
php使用PHPMailer如何發送郵件(附代碼)
PHP中常用的一些功能總結(歸納)