摘要:會在腳本執行完畢或調用函數之后調用此回調函數。此回調函數操作成功返回,反之返回。在回調函數中,以傳入的作為,以的值作為中的值存入,并設置過期時間為秒方法以傳入的為從取出相應的的值。
1 Session的基本概念和設置
Session存儲在服務端,本質上和Cookie沒有區別,都是針對http協議的局限性而提出的一種保持客戶端和服務端間會話狀態的機制。Session經常用來網站的上下文間實現頁面變量的傳遞,用戶身份認證,程序狀態記錄等。常見的有配合cookie使用,實現保存用戶的登陸狀態,或者記錄用戶的購物下單信息等。
在使用session之前必須先開啟session,可使用session_start()開啟session,同cookie一樣,在開始之前不能有任何輸出內容,否則會出現如下警告:
Warning: session_start(): Cannot send session cookie - headers already sent
也可以修改php.ini中的session.auto_start = 0 為 session.auto_start = 1,設置自動開啟session支持,這樣就不必每次在使用session的時候都要加上session_start()了。
Session的設置非常簡單,可以直接使用$_SESSION[key]=value 的形式進行設置,其中key表示session的鍵,所有設置的session都存儲在全局數組$_SESSION中。當在代碼中設置了session時,在http請求的消息頭中會攜帶一個名為PHPSESSID的cookie,其值是一個32位16進制的字符串。每個客戶端向服務器請求時都會產生一個不同的值,如果清除掉瀏覽器的cookie,再次刷新頁面將會重新設置一個PHPSESSID的值。服務端接收到這個cookie,根據其值在服務器中找到對應的session文件,從而實現保持與客戶端鏈接狀態的信息,其中session中存儲著序列化的session鍵值等信息。設置了session的http請求消息頭如下:
Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,/;q=0.8
Accept-Encoding:gzip, deflate, sdch, br
Accept-Language:zh-CN,zh;q=0.8
Cache-Control:max-age=0
Connection:keep-alive
Cookie:PHPSESSID=4680c9df2ce9ac4d1aa7f366bd92d83a
Host:localhost
Upgrade-Insecure-Requests:1
User-Agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.71 Safari/537.36
2 Session的工作原理和存儲機制
前文說到,session是通過一個名為PHPSESSID的cookie來和服務器取得聯系的,session通過sessionID(即PHPSESSID的值)來找到對應服務器中session的文件名的。sessionID時在客戶端和服務端是通過 HTTP Requset 和 HTTP Response 傳來傳去的。sessionID按照一定的算法生成,保證其值的唯一性和隨機性。Cookie里存儲著session的sessionID和session的生存期,如果沒有設置session的生存期,則sessionID存儲在內存中,關閉瀏覽器時session失效,重新請求頁面時回重新注冊一個sessionID。
默認情況下,Session是存儲在服務器硬盤上的,在php.ini可通過session.save_path設置session文件的存儲路徑,默認為服務器上/tmp目錄。此配置指令還有一個可選的 N 參數來決定會話文件分布的目錄深度。例如,設定為 "5;/tmp" 將使創建的會話文件和路徑類似于 /tmp/4/b/1/e/3/sess_4b1e384ad74619bd212e236e52a5a174If。要使用 N 參數,必須在使用前先創建好這些目錄。在 ext/session 目錄下有個小的 shell 腳本名叫 mod_files.sh,windows 版本是 mod_files.bat 可以用來做這件事。此外注意如果使用了 N 參數并且大于 0,那么將不會執行自動垃圾回收。文件儲存模塊默認使用 mode 600 創建文件。通過 修改可選參數 MODE 來改變這種默認行為: N;MODE;/path ,其中 MODE 是 mode 的八進制表示。使用以上描述的可選目錄層級參數 N 時請注意,對于絕大多數站點,大于1或者2的值會不太合適——因為這需要創建大量的目錄:例如,值設置為 3 需要在文件系統上創建 64^3 個目錄,將浪費很多空間和 inode。僅僅在絕對肯定站點足夠大時,才可以設置 N 大于2。一個session文件的內容如下:
siteadmin_username|s:7:"special";siteadmin_truename|s:6:"特殊";siteadmin_usertype|i:1;
內容的格式為:session名|值類型:長度:值; 。
3 使用Redis存儲Session
對于大訪問量的網站來說,會有許多的客戶端和服務端建立鏈接,那么將會生成許多的session文件,由于session文件是存儲在硬盤上的,每次服務器去讀取這些session文件都要經過許多的I/O操作。PHP中可使用session_set_save_handle()函數自定義session保存函數(如打開,關閉,寫入,讀取等)。session_set_save_handle()語法如下:
bool session_set_save_handler ( callable $open , callable $close , callable $read , callable $write , callable $destroy , callable $gc [, callable $create_sid ] )
如果想使用 PHP 內置的會話存儲機制之外的方式, 可以使用本函數。 例如,可以自定義會話存儲函數來將會話數據存儲到數據庫。該函數的參數解析如下。
open(string $savePath, string $sessionName):open 回調函數類似于類的構造函數, 在會話打開的時候會被調用。 這是自動開始會話或者通過調用 session_start() 手動開始會話 之后第一個被調用的回調函數。 此回調函數操作成功返回 TRUE,反之返回 FALSE。
close():close 回調函數類似于類的析構函數。 在 write 回調函數調用之后調用。 當調用 session_write_close() 函數之后,也會調用 close 回調函數。 此回調函數操作成功返回 TRUE,反之返回 FALSE。
read(string $sessionId):如果會話中有數據,read 回調函數必須返回將會話數據編碼(序列化)后的字符串。 如果會話中沒有數據,read 回調函數返回空字符串。在自動開始會話或者通過調用 session_start() 函數手動開始會話之后,PHP 內部調用 read 回調函數來獲取會話數據。 在調用 read 之前,PHP 會調用 open 回調函數。read 回調返回的序列化之后的字符串格式必須與 write 回調函數保存數據時的格式完全一致。 PHP 會自動反序列化返回的字符串并填充 $_SESSION 超級全局變量。 雖然數據看起來和 serialize() 函數很相似, 但是需要提醒的是,它們是不同的。
write(string $sessionId, string $data):在會話保存數據時會調用 write 回調函數。 此回調函數接收當前會話 ID 以及 $_SESSION 中數據序列化之后的字符串作為參數。 序列化會話數據的過程由 PHP 根據 session.serialize_handler 設定值來完成。序列化后的數據將和會話 ID 關聯在一起進行保存。 當調用 read 回調函數獲取數據時,所返回的數據必須要和 傳入 write 回調函數的數據完全保持一致。PHP 會在腳本執行完畢或調用 session_write_close() 函數之后調用此回調函數。 注意,在調用完此回調函數之后,PHP 內部會調用 close 回調函數。
PHP 會在輸出流寫入完畢并且關閉之后 才調用 write 回調函數, 所以在 write 回調函數中的調試信息不會輸出到瀏覽器中。 如果需要在 write 回調函數中使用調試輸出, 建議將調試輸出寫入到文件。
destroy($sessionId):當調用 session_destroy() 函數, 或者調用 session_regenerate_id() 函數并且設置 destroy 參數為 TRUE 時, 會調用此回調函數。此回調函數操作成功返回 TRUE,反之返回 FALSE。
gc($lifetime):為了清理會話中的舊數據,PHP 會不時的調用垃圾收集回調函數。 調用周期由 session.gc_probability 和 session.gc_divisor 參數控制。 傳入到此回調函數的 lifetime 參數由 session.gc_maxlifetime 設置。 此回調函數操作成功返回 TRUE,反之返回 FALSE。
create_sid():當需要新的會話 ID 時被調用的回調函數。 回調函數被調用時無傳入參數, 其返回值應該是一個字符串格式的、有效的會話 ID。
一個關于使用Redis代替文件存儲session的例子如下:
首先編寫一個管理session的類sessionmanager,代碼如下:
redis = new Redis(); $this->redis->connect("10.116.19.14",6400); $reval = session_set_save_handler( array($this,"open"), array($this,"close"), array($this,"read"), array($this,"write"), array($this,"destroy"), array($this,"gc") ); session_start(); } public function open($patn,$name){ return true; } public function close(){ return true; } public function read($id){ $value = $this->redis->get($id); if($value) { return $value; } else { return false; } } public function write($id,$data){ if($this->redis->set($id,$data)) { $this->redis->expire($id,60); return true; } else { return false; } } public function destroy($id) { if($this->redis->delete($id)) { return true; } return false; } public function gc($maxlifetime){ return true; } public function __destruct() { session_write_close(); // TODO: Implement __destruct() method. } } ?>
在該類的構造函數中,使用session_set_save_handler()設置session的處理函數,實例化該類時便完成了用指定函數接管系統處理session的工作。將以上代碼保存為sessionmanager.php文件。在write回調函數中,以傳入的sessionID作為key,以session的值作為redis中key的值存入redis,并設置過期時間為60秒;read方法以傳入的sessionID為key從redis取出相應的session的值。destroy可根據傳入的sessionID刪除redis中的session。
我們編寫另外一個設置session的腳本,并引入sessionmanager.php文件,示例化sessionmanager類。代碼如下:
1,2,3,4,4); ?>
保存以上代碼為set.php,另外編寫一個可訪問session的腳本,代碼如下:
保存以上代碼為get.php文件。測試時,先訪問set.php,然后再訪問get.php,會在瀏覽器輸出以下結果:
array(4) { ["namehaha"]=> string(10) "lixiaolong" ["namehah"]=> string(10) "lixiaolong" ["namehaa"]=> string(10) "lixiaolong" ["namhaha"]=> array(5) { ["a"]=> int(1) [0]=> int(2) [1]=> int(3) [2]=> int(4) [3]=> int(4) } }
可見已經成功的設置并獲得了session。查看redis中存儲的session信息,
redis 127.0.0.1:6400> get ruevh62hlm809d1p2lg2o0fbv7
“namehaha|s:10:"lixiaolong";namehah|s:10:"lixiaolong";namehaa|s:10:"lixiaolong";namhaha|a:5:{s:1:"a";i:1;i:0;i:2;i:1;i:3;i:2;i:4;i:3;i:4;}"
Redis中是以string的數據類型存儲session的,其key遍是sessionID,也是HTTP Request中的cookie名為PHPSESSID的值。session在redis和在文件中的存儲形式都是一樣的,只不過在redis對雙引號做了轉義。
本文節選自 《php7實踐指南》 陳小龍著
微信掃一掃,發現更多內容
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/22538.html
摘要:協議是無狀態的,一旦數據交換完畢,客戶端與服務器端的連接就會關閉,再次交換建立新的連接,也就是說,服務器無法跟蹤會話。而和就是用與解決這種問題。值得一提的是是建立在的基礎上創建的。注意在的文件中,設置了的生命周期最長為分鐘。 在將cookie 和 session 之前需要先理解什么是會話會話: 用戶打開一個瀏覽器,點擊多個超鏈接,訪問多個web資源,然后關閉瀏覽器,整個過程稱為一個...
摘要:例如要想在多個二級域名中共享,需要設置為頂級域名,這樣就可以在所有二級域名里面或者到這個的值了。頂級域名只能獲取到設置為頂級域名的,設置為其他子級域名的無法獲取。 Cookie和Session詳解 Cookie Cookie只存儲在客服端 Cookie是什么:Cookies是web服務器存放在用戶硬盤的一段文本,Cookies允許一個wen站點在用戶的機器存放一些文本的信息,并可以在以...
摘要:目前大多數的應用都是用實現跟蹤的。的安全性一般,他人可通過分析存放在本地的并進行欺騙。在安全性第一的前提下,選擇更優。考慮到減輕服務器性能方面,應當適時使用。因此,維持一個會話的核心就是客戶端的唯一標識,即。 showImg(https://segmentfault.com/img/bV8riL?w=800&h=444); 在技術面試中,經常被問到說說Cookie和Session的區別...
摘要:依賴注入并不限于構造函數作為經驗,注入最適合必須的依賴關系,比如示例中的情況注入最適合可選依賴關系,比如緩存一個對象實例。 本文翻譯自 Symfony 作者 Fabien Potencier 的 《Dependency Injection in general and the implementation of a Dependency Injection Container in P...
摘要:什么是用來存儲客戶端的一小段文本是一門客戶端的技術因為是存儲在客戶端瀏覽器中的是為了實現客戶端與服務器端之間的狀態的保持技術,不安全,不要使用存儲敏感信息比如登錄狀態和登錄信息一些敏感的數據應該存儲在服務器端的值從哪里來的當你訪問一個網站這 什么是cookie, 用來存儲客戶端的一小段文本是一門客戶端的技術 因為cookie是存儲在客戶端瀏覽器中的是為了實現 客戶端與服務器端之間的狀態...
閱讀 3057·2021-11-16 11:45
閱讀 3577·2021-09-29 09:34
閱讀 701·2021-08-16 10:50
閱讀 1567·2019-08-30 15:52
閱讀 1961·2019-08-30 15:45
閱讀 858·2019-08-29 15:23
閱讀 1922·2019-08-26 13:51
閱讀 3298·2019-08-26 12:23