最近在學習Laravel 這套框架,發現對PHP的會話不是很瞭解,因而乎看了PHP官網手冊,也看了慕課網的SESSION視頻教程,看完後總以爲缺點什麼,咦~,缺點在掘金上寫篇讀書筆記,嘮叨嘮叨,也能夠檢驗一下本身學習的怎麼樣,廢話很少說,直接切入正題php
在瞭解PHP會話技術前,咱們先討論一件事情,那就是什麼是會話。從字面意義上來講,應該是一次會談,一次交流,沒錯就是一次談話,若是是談話的話就須要有兩個談話對象,對計算機世界而言,談話對象就是客戶端和服務器端,客戶端說一句話,服務器回答一句。程序員
上面的話說得太直白了,若是用計算機專業術語來解釋會話,就是這樣子的:算法
會話是瀏覽器和服務器之間的屢次請求和響應數組
好像似懂非懂的樣子,解釋一下的話,就是客戶端訪問服務器,到服務器作出響應,最後客戶端關閉退出,在這段時間裏產生的請求和響應,稱爲客戶端和服務器的一次會話瀏覽器
會話的出現,對程序員來講又有一個知識點要考了(哈哈),可不能夠不用會話呢?答案是不能夠的,除非你能證實你是本身。這就和現實世界是同樣的,你能證實你本身嘛,不能,你要拿出你的身份證才能夠證實你本身。緩存
在計算時間裏是怎麼解決你是你本身的這個世界難題的呢?使用HTTP協議,好像不行,HTTP協議是無狀態的,它是沒得期望的了。怎麼辦呢,計算機大佬們設計了一套會話技術,專門來處理「記住我」的問題安全
若是要理解起來仍是很麻煩的,用一張圖來解釋是最合適不過的 服務器
我模擬一下圖中操做,就能夠大體的瞭解PHP會話的工做原理了cookie
咱們第一次訪問PHP官網,瀏覽器發出一個HTTP請求到服務器,服務器接收到客戶端的請求。服務器發現尚未和客戶端創建會話,進行session初始化操做,建立session_id,session文件等操做網絡
執行代碼,若是在執行的過程當中有session數據產生,則將數據存放在超全局數組$_SESSION
中,代碼執行完畢,把$_SESSION
中的數據序列化後存放在session文件中,並設置一個會話cookie,cookie名爲session_name()
,cookie值爲session_id()
,把cookie信息攜帶在對客戶端的響應中,一併返回給客戶端
第二次你訪問了PHP官網,仍是會執行session初始化,發現你發出的HTTP請求攜帶有session_id
,同時去讀取這個session_id
對應的session文件,並把文件中的數據讀取到$_SESSION
數組中,繼續執行代碼,若是有設置session數據,把數據暫存在$_SESSION
數組中,最後代碼執行完畢,把數組中的數據序列化後存放在session文件裏,一樣的把sesion_id經過cookie方式存放在客戶端 ,下次在訪問網站的時候,發送給服務器端就是了
網站訪問完了退出登陸,這個時候服務器會銷燬session,把客戶端的cookie設置過時,並刪除服務器端的session文件
若是下次還訪問PHP官網,重複以上操做
經過上面的介紹,我發現了這樣一個問題,爲何服務器在第一次已經給客戶端發送了cookie後,在第二次、第三次...都發送cookie呢,並且內容仍是同樣的,這會致使網絡開銷的啊。
確實如此,每次發送也很差,爲何這麼作呢?
我大體猜一下這其中的緣由,首先會話是有時間限制的,有的瀏覽器關閉退出後結束會話,有的會話是兩個小時內的活躍用戶
每次重置cookie,使客戶端的cookie一直處於活躍狀態,這樣瀏覽器就不會清除cookie了
若是不更新的話,cookie一旦過時,用戶就不能使用這個cookie,這樣將致使用戶必須從新登陸網站後才能夠繼續使用。
經過每次對用戶的響應攜帶着cookie信息,重置cookie的過時時間,讓客戶端的cookie處於活躍狀態。
第二種狀況就是,經過每次發送cookie到客戶端,重置客戶端的cookie,防止客戶端的cookie被篡改,這種作法是頗有限的,並不能徹底的杜絕
以上就是我想到的爲何要每次都給客戶端發送cookie的緣由,我也沒有去驗證這兩種說法,後面我會去找找看是什麼緣由
這篇文章不是在說session的嗎,怎麼上面一直在提cookie,cookie又是什麼東西。cookie簡單的來講就是實現session的一種方式,session的實現也可使用URL來實現,只不過cookie要好一些,這裏暫時不展開去說cookie,我會用另外一篇文章去作介紹
php中已經爲咱們實現了不少處理session的方法,經過這些方法就能夠去實現session的初始化、設置session數據、session銷燬等等操做
這裏我列出了經常使用的session方法,不知道如何使用的,能夠隨時在php官網進行查找,還有其餘方法,你能夠經過連接進行訪問
在PHP中使用session_start()
就能夠開始一個會話了,固然若是請求中的cookie攜帶了會話ID,會重用這個會話,不會建立新的會話
在PHP具體的工做會作什麼工做呢,經過PHP手冊咱們能夠獲得這些:
當會話開始的時候,PHP內部會使用會話管理器的open和read回調函數,這個會話管理器能夠是PHP自帶的,也能夠是你本身定義的(後面我會實現一個本身的會話管理器),經過session_set_save_handler
來設置自定義的會話管理器,使用read回調函數返回的會話數據,經過反序列化數據並把數據填充到$_SESSION
全局變量中
在開啓會話以前咱們能夠調用session_name()
對會話命名,使用session_id()
得到sessionID
咱們在開啓一個會話的時候,PHP會使用會話管理器來對會話數據進行處理,默認的PHP會話管理器是files,這將致使一個問題,它會鎖定會話文件,對併發請求很大的網站來說,這將是致命的。一個比較但簡單的作法是,每次修改完會話數據後,使用session_write_close()
來保存會話並釋放文件鎖,這種作法是很是不建議的。
推薦使用能夠併發操做的會話管理器來代替文件保存管理器,首選固然是推薦Redis做爲session的會話管理操做,爲何不使用memcached存儲session呢?網上的說法是memcaced是緩存數據而不是存儲數據的,memcached的LAR算法針對每一個slab類執行,而不是針對總體,這樣致使session最老的用戶會掉線,具體的緣由這裏就不在深究,我也沒有用過memcached做爲session管理
在第二次訪問網站的時候,會把sessionID發送給服務器,發送sessionID方式有兩種:
極力推薦使用Cookie的方式來傳遞會話ID,若是用戶禁用Cookie,友情提示用戶開啓,Cookie相關的設置選項我會在會話安全中列出來
用戶登出的時候要清除會話,銷燬會話操做比起建立來講是比較麻煩的,具體分爲三部分,
php中的會話數據存放在全局變量$_SESSION
中,須要先把全局變量重置,重置的方法以下:
$_SESSION = array();
複製代碼
不要使用unset($_SESSION)
來複位超級變量,由於這樣致使沒法繼續使用$_SESSION
來註冊會話變量
爲了完全的銷燬會話,須要把客戶端的會話cookie刪除掉
$params= session_get_cookie_params();
setcookie(session_name(),'',time()-1,$params['path'],$params['domain'],$params['secure'],$params['httponly']);
複製代碼
讓cookie過時就能夠,這樣瀏覽器會自動刪除過時的cookie
若是開啓了session.use_strict_mode配置項後,能夠不用手動刪除cookie,由於會話模塊不會接受已通過期會話ID的cookie了,它會生產一個新的會話ID cookie,建議開啓這個配置項
最後使用函數session_destroy
來刪除會話數據
session_destroy();
複製代碼
若是你使用的是file做爲會話管理器,那麼還會刪除session文件
php默認會使用gc(garbage collection 垃圾回收)管理會話數據,何時啓動gc進程呢?
首先經過session.gc_maxlifetime 指定了過多少秒後的數據視爲垃圾會話並進行清除
垃圾收集器會在會話開啓的時候,根據session.gc_probability與 session.gc_divisor 的設置來啓動垃圾收集器gc。 好比,session.gc_probability 爲 1,session.gc_divisor爲 100,那麼就有1/100的機率來啓動垃圾收集器gc
若是gc_probability/gc_divisor設置的過大,會頻繁的啓動gc來管理會話數據;設置的過小會有不少的過時會話數據沒有即時清除,浪費存儲空間
gc進程處理過時會話數據也是比較粗糙的,它會遍歷全部的session文件,查看文件修改時間和當前系統時間,來判斷文件是否過時而刪除文件
因此php自帶的file會話管理器工做效率是很低的,同時也不支持併發訪問會話文件,而 Redis 或 Memcached 天生就支持 key/value 過時機制的,用於做爲會話處理器很是合適
至此php中的會話基本操做就是這些了,但對會話如何使用,如何保證會話是安全的,這也是很是重要的,防人之心不可無啊。
後面我會用兩個章節來學習會話安全,以及Laravel中的session