PHP中如何將session存入資料庫並使用

不言
發布: 2023-04-03 17:08:02
原創
5869 人瀏覽過

PHP中如何將session存入資料庫並使用

這篇文章要介紹給大家的內容是關於PHP中如何將session存入資料庫並使用(附代碼),有一定的參考價值,有需要的朋友可以參考一下,希望對你有幫助。

實例說明:

#將SESSION資料變數儲存於伺服器是端是一種較安全的做法,但是設想一下,像校內網這樣的日訪問量過億,擁有用戶幾千萬的大型網站,如果將所有用戶SESSION數據全部存儲於伺服器端,將消耗巨大的伺服器資源。所以程式設計師在製作大型網站時將SESSION儲存在伺服器端雖然安全,但卻不是最好的選擇。如果將SESSION資料儲存於資料庫中,那麼就可以減輕伺服器的壓力同時資料也是比較安全的。

相關專題推薦php session(包含圖文、影片、案例)

設計流程

首先在Mysql資料庫建立儲存SESSION的表:

表名為t_session

表結構為

PHP中如何將session存入資料庫並使用

說明:session_key:是用來存會話ID的

  • <span style="color:#3a3737;">session_data</span>:是用來存經序列化後的$_SESSION[ ]裡的值;

  • <span style="color:#3a3737;">session_time</span>:是用來存時間戳記的,這個時間戳指的是當前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,若無,則這個參數返回空字串。注意,若資料庫中無對應的資料一定要傳回空字串,否則報錯!如果會話中有數據,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用户登录界面

<?php


include("session_set_save_handler.php");//引入自定义的会话存储机制


if(isset($_GET["login"])){//判断login是否有值,若有值则要进行注销,


session_start();//只要需要 用到$_session变量的地方,就需要开启回调函数open


session_destroy();//这里就是上文提到的 小细节了,当有session_destroy的时候,它是先于read回调函数执行的


}else{


session_start();


if(isset($_SESSION["user"])){//判断此值是否有定义,若有定义则说明 存入的session还未到期,则直接转到主内容


echo "<script>alert(&#39;您不久前刚来过&#39;);window.location.href=&#39;main.php&#39;;</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表单提交处理文件

<?php


include("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(&#39;登录成功!&#39;);window.location.href=&#39;main.php&#39;;</script>";

}

}


?>
登入後複製

main.php主内容页

<?php


include("session_set_save_handler.php");


session_start();


if(isset($_SESSION["user"])){


echo "欢迎".$_SESSION["user"];

echo "<a href=&#39;index.php?login=0&#39;>注销</a>";


}else{


echo "您还没登录,请先登录!";

echo "<a href=&#39;index.php&#39;>登录</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_data

function read($key){


global $con;

$time=time();

//不读取已过期的session

$sql="select session_data from t_session where session_key=&#39;$key&#39; 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


}


}

//存储session

function write($key,$data){



global $con;




$over_time=time()+60;//注意time()为时间戳,在mysql中的数据类型不可用用date,datetime,timestamp来存储


$sql="select session_data from t_session where session_key=&#39;$key&#39;";


$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(&#39;$key&#39;,&#39;$data&#39;,$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=&#39;$key&#39;,session_data=&#39;$data&#39;,session_time=$over_time where session_key=&#39;$key&#39;";


$result=mysqli_query($con,$sql);

}




return($result);


}

清楚相应的session数据

function destroy($key){




global $con;


$sql="delete from t_session where session_key=&#39;$key&#39;";


$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(&#39;open&#39;,&#39;close&#39;,&#39;read&#39;,&#39;write&#39;,&#39;destroy&#39;,&#39;overdue&#39;);


?>
登入後複製

相关文章推荐:

php使用PHPMailer如何发送邮件(附代码)

PHP中常用的一些功能总结(归纳)

以上是PHP中如何將session存入資料庫並使用的詳細內容。更多資訊請關注PHP中文網其他相關文章!

相關標籤:
來源:php.cn
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
作者最新文章
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板
關於我們 免責聲明 Sitemap
PHP中文網:公益線上PHP培訓,幫助PHP學習者快速成長!