概述
由于PHP的工作機(jī)制,它并沒有一個daemon線程,來定時地掃描session信息并判斷其是否失效。當(dāng)一個有效請求發(fā)生時,PHP會根據(jù)全局變量 session.gc_probability/session.gc_divisor(同樣可以通過php.ini或者ini_set()函數(shù)來修改) 的值,來決定是否啟動一個GC(Garbage Collector)。默認(rèn)情況下,session.gc_probability = 1,session.gc_divisor =100,也就是說有1%的可能性會啟動GC。GC的工作,就是掃描所有的session信息, 用當(dāng)前時間減去session的最后修改時間(modified date),同session.gc_maxlifetime參數(shù)進(jìn)行比較,如果生存時間已經(jīng)超過gc_maxlifetime,就把該session刪 除。
gc_maxlifetime無效
那為什么會發(fā)生gc_maxlifetime無效的情況呢?
在默認(rèn)情況下,session信息會以文本文件的形式,被保存在系統(tǒng) 的臨時文件目錄中。在Linux下,這一路徑通常為\tmp,在Windows下通常為C:\Windows\Temp。當(dāng)服務(wù)器上有多個PHP應(yīng)用時, 它們會把自己的session文件都保存在同一個目錄中。同樣地,這些PHP應(yīng)用也會按一定機(jī)率啟動GC,掃描所有的session文件。問 題在于,GC在工作時,并不會區(qū)分不同站點的session。舉例言之,站點A的gc_maxlifetime設(shè)置為2小時,站點B的 gc_maxlifetime設(shè)置為默認(rèn)的24分鐘。當(dāng)站點B的GC啟動時,它會掃描公用的臨時文件目錄,把所有超過24分鐘的session文件全部刪 除掉,而不管它們來自于站點A或B。這樣,站點A的gc_maxlifetime設(shè)置就形同虛設(shè)了。找到問題所在,解決起來就很簡單了。修改session.save_path參數(shù),或者使用session_save_path()函數(shù),把保存session的目錄指向一個專用的目錄,gc_maxlifetime參數(shù)工作正常了。
還有一個問題就是,gc_maxlifetime只能保證session生存的最短時間,并不能夠保存在超過這一時間之后session信息立即會得到 刪除。因為GC是按機(jī)率啟動的,可能在某一個長時間內(nèi)都沒有被啟動,那么大量的session在超過gc_maxlifetime以后仍然會有效。解決這 個問題的一個方法是,把session.gc_probability/session.gc_divisor的機(jī)率提高,如果提到100%,就會徹底解 決這個問題,但顯然會對性能造成嚴(yán)重的影響。另一個方法是自己在代碼中判斷當(dāng)前session的生存時間,如果超出了gc_maxlifetime,就清 空當(dāng)前session。
gc工作原理
php session GC功能,就是Garbage Collector。這個GC啟動的時候,會清除那些已經(jīng)“超時”的session。它的工作原理是這樣的:
- 用戶訪問并登陸網(wǎng)站,這時候后臺會調(diào)用session_start來嘗試生成一個會話(如果已經(jīng)有會話,則相當(dāng)于一次有效會話請求)
- 對于這樣的每一次有效會話請求(Request),apache的php模塊會根據(jù)session相關(guān)的全局變量gc_probability/gc_divisor =>計算出啟動GC的概率,并由此概率來決定在這次請求中是否應(yīng)該啟動GC。舉例來說,session.gc_probability的缺省值為1,session.gc_divisor的缺省值為100,則啟動“垃圾回收”器的概率是1%,這就意味著在每100次請求中,會有可能清理一次過期會話
- 如果GC啟動,則GC會掃描當(dāng)前會話所在路徑(session.save_path)下的所有會話文件,并根據(jù)另外一個全局變量session.gc_maxlifetime的多少來判斷哪些session已經(jīng)過期(“當(dāng)前時間”與“會話文件的atime或者mtime”之間的差大于gc_maxlifetime:過期),并刪除這些過期的session
- 如果你在一個session啟動后,長時間沒有任何交互操作(譬如,不停地碼字,沒有提交或者保存為草稿),那么你的保存在后臺的會話文件將得不到機(jī)會被修改或者訪問,在gc_maxlifetime(缺省值1440秒=24分鐘)時間后,它有可能因失效而被清理,這以后你再提交,就會因為會話失效而報錯
理解
- session_id保存在瀏覽器(客戶端)的cookie中,關(guān)閉瀏覽器保存sessiond_id的cookie失效,這時候無法訪問原來session文件。服務(wù)器端session文件可能存在,還未刪除。
- 當(dāng)一個用戶,24分鐘沒有任何操作(向服務(wù)器發(fā)送請求,瀏覽器打開著),session文件可能被gc垃圾回收了,24分鐘后訪問,將創(chuàng)建跟原session_id相同的session新文件,此時原有的session文件內(nèi)容將不存在了。
- 自動登錄,不是設(shè)置session_id的cookie的有效時間,是在瀏覽器端保存包含登錄信息(如用戶名,密碼)的cookie。
- 一個session_id的作用時間 到 瀏覽器關(guān)閉結(jié)束,再次打開瀏覽器,是生成了新的session_id(新的session文件)。
- 在服務(wù)器端判斷session文件是否無效(刪除),當(dāng)前時間-文件修改時間 > gc_maxlifetime,此時失效。
- 每次腳本執(zhí)行,都修改文件修改時間