Session詳解
1、Session簡介
一個PHP session可以讓應用存儲當前"會話"的信息,它可以定義為一個喲過戶登錄你的應用。
一個會話是通過一個唯一的session ID來標識的。
PHP為每一個會話創建一個session ID,它是一個通過MD5對遠程IP地址、當前時間和一些附加數據進行散列處理的一個顯示為十六進制的字符串。這個session ID可以傳遞到一個cookie中或者添加到所有的URL來跨越你的應用。
為了安全考慮,讓用戶使用cookie會比通過URL(通常手動增加?PHP_SESSID=<session_id>或者打開php.ini中的session.use_trans_sid選項)傳遞session ID更好,因為通過URL傳輸會在Web服務器的log中以HTTP_REFERER顯示出來或者讓一些不懷好意的人通過監控你的瀏覽獲取到ID。不懷好意的人還可以看到session cookie數據,當然,你可能會使用SSL的服務器來確保真正的安全。
2、Session的工作原理
當啟動一個Session會話時,會生成一個隨機且唯一的session_id,也就是Session的文件名,此時session_id存儲在服務器的內存中,當關閉頁面時此id會自動註銷,重新登錄此頁面,會再次生成一個隨機且唯一的id。
3、Session的功能
由於網頁是一種無狀態的連接程序,因此無法得知用戶的瀏覽狀態。通過Session則可記錄用戶的有關信息,以供用戶再次以此身份對web服務器提交時作確認。
例如,在電子上午網站中,通過session記錄用戶登錄的信息,以及用戶所購買的商品,如果沒有Session,那麽用戶每進入一個頁面都需要登錄一次用戶名和密碼。
4、創建會話步驟:啟動會話 —>註冊會話—>使用會話—>刪除會話。
啟動會話:①使用session_start()函數 ② 使用session_register()函數 //為會話登錄一個變量來隱含地啟動會話
註意:在使用session_start()函數之前瀏覽器不能有任何輸出,否則會產生類似錯誤"cannot send session cookie-headers already send by ..."。
但有時我們發現在之前有其他輸出時,並沒有報上面的錯誤,原因是php.ini配置文件裏開啟了緩存機制,如果想要有上面的提示,需要把配置項output_buffering設置為off,所以我們在寫session_start()函數或header()函數的時候,因為不能保證配置項到底有沒有開啟緩存機制,所以為了避免錯誤,習慣性在session_start()或header()之前,不要有任何其他輸出。
而使用session_register()函數時,不需要調用session_start()函數,PHP會在註冊變量之後隱含地調用session_start()函數,但是需要設置php.ini文件的選項,將register_globals指令設置為"on",然後重啟Apache服務器。
註冊會話:會話變量被啟動過後,全部保存在數組$_SESSION中。通過數組$_SESSION創建一個會話變量很容易,只要直接給該數組添加一個元素即可。
使用會話:通過全局數組$_SESSION進行訪問或創建。
<?php /** *判斷存儲用戶名的Session會話變量是否存在,如果不存在則將字符串賦值給Session */ session_start(); //啟動Session $string="apache"; if(!isset($_SESSION[‘name‘])){ //判斷用於存儲用戶名的Session會話變量是否存在 $_SESSION[‘name‘]=$string; echo $_SESSION[‘name‘]; }else{ echo $_SESSION[‘name‘]; } ?>
刪除會話:方法主要有刪除單個會話、刪除多個會話和結束會話3種。
刪除單個會話:同數組的操作一樣,可以使用unset()直接註銷$_SESSION數組的某個元素即可。
註意:使用unset()函數時,要註意$_SESSION數組種某元素不能省略,即不可以一次註銷整個數組,否則會禁止整個會話。如unset($_SESSION)會將全局變量$_SESSION銷毀,而且沒有辦法恢復,用戶也再不能註冊$_SESSION變量。
刪除多個會話:如果想要一次註銷所有的會話變量,可以將一個空的數組賦值給$_SESSION,如$_SESSION=array()。
結束當前會話:如果整個會話已經結束,首先應該註銷所有的會話變量,然後使用session_destroy()函數清除結束當前的會話,並清空會話中的所有資源,徹底銷毀Session。
5、Session應用
①Session臨時文件
在服務器中,如果將所有的Session都保存到臨時目錄中,會降低服務器的安全性和效率,打開服務器存儲的站點會非常慢。
可以通過session_save_path()函數存儲Session臨時文件,可緩解因臨時文件的存儲導致服務器效率降低和站點打開緩慢的問題。
註意:session_save_path()函數應在session_start()函數之前調用。
②Session緩存
Session的緩存是將網頁中的內容臨時存儲到IE客戶端的Temporary Internet Files文件夾下,並且可以設置緩存的時間。
當第一次瀏覽網頁後,頁面的部分內容在規定的時間內就被臨時存儲在客戶端的臨時文件夾中,這樣在下次訪問這個頁面時,就可以直接讀取緩存中的內容,從而提高網站的瀏覽效率。
session_cache_limiter(‘private’); //開啟客戶端緩存
session_cache_expire(分鐘); //設置客戶端緩存時間,單位是分鐘
<?php session_cache_limiter(‘private‘); //讀取或設置緩存限制器,public標識允許客戶端或代理服務器緩存內容,private標表示允許客戶端緩存,但是不允許代理服務器緩存內容 $cache_limit=session_cache_limiter(); //開啟客戶端緩存 session_cache_expire(30); $cache_expire=session_cache_expire(); //設置客戶端緩存時間,默認180分鐘 session_start(); echo $cache_limit; //private echo ‘<br />‘; echo $cache_expire;//30 ?>
③Session數據庫存儲
雖然通過改變Session存儲文件夾使Session不至於將臨時文件夾填滿而造成站點癱瘓,但是可以計算一下如果一個大型網站一天登錄1000人,一個月登錄了30000人,這時站點中存在30000個Session文件,要在30000個文件中查詢一個session_id應該不是件輕松的事情,那麽這時就可以應用Session數據庫存儲,也就是PHP中的session_set_save_handler()函數。
語法:bool session_set_save_handler(string open,string close,string read,string write,string destroy,string gc)
參數說明:
參數 | 說明 |
open(save_path,session_name) | 找到Session存儲地址,取出變量名稱 |
close() | 不需要參數,關閉數據庫 |
read(key) | 讀取Session鍵值,key對應session_id |
write(key,data) | 其中data對應設置的Session變量 |
destroy(key) | 註銷Session對應Session鍵值 |
gc(expiry_time) | 清除過期Session記錄 |
一般應用參數直接使用變量,但是此函數中參數為6個函數,而且在調用時只是調用函數名稱的字符串。
session數據表
下面開始講解這6個參數(函數),最後把這些封裝進類中。
<?php //封裝_session_open() //這裏並沒有用到$save_path和$session_name,可以將它們去掉,但還是建議輸入,因為一般使用時都是存在這兩個變量的,應該養成一個好的習慣 function _session_open($save_path,$session_name){ global $handle; $handle=mysql_connect(‘localhost‘,‘root‘,‘123‘)or die(‘數據庫連接失敗‘); //連接MySQL數據庫 mysql_select_db(‘mydb8‘,$handle)or die(‘數據庫中沒有此庫名‘); //找到數據庫 return (true); } //封裝_session_close()函數,關閉數據庫連接 //在這個函數中不需要任何參數,所以不論是Session存儲到數據庫還是文件中,只需返回true即可 //但是如果是MySQL數據庫,最好是將數據庫關閉,以保證以後不會出現麻煩。 function _session_close(){ global $handle; mysql_close($handle); return(true); } //封裝_session_read()函數,在函數中設定當前時間的UNIX時間戳,根據$key值查找Session名稱及內容 function _session_read($key){ global $handle; //全局變量$handle連接數據庫 $time=time(); //設定當前時間 $sql="select session_data from t_session where session_key=‘$key‘ and lapse_time>$time"; $result=mysql_query($sql,$handle); $row=mysql_fetch_array($result); if($row){ return ($row[‘session_data‘]); //返回Session名稱及內容 }else{ return (false); } } //封裝_session_write()函數,函數中設定Session失效時間,查找到Session名稱及內容 //如果查詢結果為空,則將頁面中的Session根據session_id、session_name、失效時間插入數據庫 //如果查詢結果不為空,則根據$key修改數據庫中Session的存儲信息,返回執行結果 function _session_write($key,$data){ global $handle; $time=60*60; $lapse_time=time()+$time; //設置生效時間 $handle=mysql_connect(‘localhost‘,‘root‘,‘123‘) or die(‘數據庫連接失敗‘); //連接MySQL數據庫 mysql_select_db(‘mydb8‘,$handle); //選擇數據庫 $sql="select session_data from t_session where session_key=‘$key‘ and lapse_time>$lapse_time"; $result =mysql_query($sql,$handle); if(mysql_num_rows($result)==0){ $sql="insert into t_seession values(‘$key‘,‘$data‘,$lapse_time)"; //插入數據庫sql語句 $result=mysql_query($sql,$handle); }else{ $sql="update t_session set session_key =‘$key‘,session_data=‘$data‘,session_time=$lapse_time where session_key=‘$key‘"; } return ($result); } //封裝_session_destroy()函數,根據$key值將數據庫中的session刪除 function _session_destroy($key){ global $handle; $sql="delete from t_session where session_key =‘$key‘"; //刪除數據庫sql語句 $result=mysql_query($sql,$handle); return ($result); } //封裝_session_gc()函數,根據給出的失效時間刪除過期Session function _session_gc(){ global $handle; $lapse_time=time(); //將參數$lapse_time賦值為當前時間戳 $sql="delete from t_session where session_time <$lapse_time"; //刪除數據庫sql語句 $result=mysql_query($sql,$handle); return ($result); } //ini_set(‘session.save_handler‘,‘user‘); session_set_save_handler(‘_session_open‘,‘_session_close‘,‘_session_read‘,‘_session_write‘,‘_session_destroy‘,‘_session_gc‘); session_start(); //下面通過函數session_set_save_handler()實現Session存儲數據庫 //定義Session $_SESSION[‘user‘]=‘mr‘; $_SESSION[‘pwd‘]=‘mrsoft‘;
Session詳解