看板 PHP 關於我們 聯絡資訊
關於session運作原理, 我曾看過某部落格寫得還挺詳細的, 不過一來是 簡體中文, 二來遣詞用字的習慣跟台灣頗有差異, 所以要看完得多點耐心. 一回生, 二回熟, 看熟後對於session運作原理的觀念肯定有提升. http://blog.chinaunix.net/u/27731/showart_259031.html 這篇文章應該是原文, 但也可能不知從哪裏轉來的, 大陸的論壇只要一有好 文, 馬上就被轉貼到到處都是.(這也算是各網站搞流量惡性競爭的關係吧?) 是不是原文就恕不進一步求證了. 這邊我再補充幾點: 1 關於php將 $_SESSION變數的內容 寫入session檔案(或是資料庫)的時機: 程設師若不在程式當中採用session_write_close()函式處理的話, 那麼 預設情況就是php script執行完後(包括以exit方式結束), php會自動寫入 session檔案(當然前提是session要有開). 1.1 session可以檔案形式儲存, 也可存在程設師所自定的媒體(包括資料庫) 當中, 這是session較進階的應用, 可參考 session_set_save_handler , 以下不特別強調的話, 皆以session檔案為討論對象. 2 作業系統記錄session檔案被'讀寫'的時刻: 2.1 php在session初始化(呼叫session_start(),或是在組態中設定自動開啟session) 時, 會自session檔案將存在裏面的那串資料透過"解序列化"(unserialization) 程序, 將之載入$_SESSION變數. 這時候, 作業系統會修改session檔案被存取的 時刻. 2.2 php在php script終結前, 會將$_SESSION變數的內容透過"序列化"(serialization) 程序, 轉成一段文本字串(格式跟json很像), 寫入session檔案. 這時候, 作業 系統也會修改session檔案的存取時刻. 3 判斷session檔案是否過期的根據: 以上 2 要特意提出來, 正是因為session檔案被'讀寫'的時刻, 就是後來php用來 判斷session檔案是否過期的根據. 判斷方式為: 3.1 session檔案最近被讀寫的時刻 + maxlifetime(單位為秒) < 目前時刻 符合上述3.1 所描述者, 代表這session檔案已過期. 否則, 代表未過期. 用戶掛網不動, 自然不會觸動php script, 也就不會觸動php去讀寫其所屬 的session檔, 作業系統也就不會更新session檔被修改的時刻. 直到php要 做gc(garbage collection, 垃圾回收, 簡寫為 gc.)時, 就對所有的 session檔逐個套公式檢查是否過期? 可以想像一下, 如果這是一個萬人 大站, php要做gc是多麼耗費資源的事, 所以才必須以機率方式 (用gc_probability及gc_divisor控制發生頻率)來做. 另外, 檔案的讀寫 效能受限於作業系統, 所以又提供 session_set_save_handler 讓程設師 可以自訂session的儲存方式: 包括'開啟','關閉','讀取','寫入','摧毁', '垃圾回收'的行為定義. (session的實作, 在大型網站上, 用資料庫是優 於檔案的, 甚至是用記憶體來存session.) 4 關於過期session的處理機制: 原則上, 用gc_probability, 以及gc_divisor這兩個組態變數來控制發生頻率 是沒錯. (其實這也很容易理解, 就相當於用rand(1,gc_divisor)取值, 只要 這個值小於等於gc_probaility, 就bingo了.) 它的運作原理是: 4.1 用戶觸動一個php script, 這個php script要有進行session初始化(就是將 session檔案的內容載入到$_SESSION變數)的動作才算. 4.2 session初始化完成後, 緊接著php根據gc_probability及gc_divisor所設定 機率來決定要不要進行gc的動作? 若要清除的話, 則砍除掉所有過期的 session檔案. 大致上是這樣, 不過session的運作機制若不花點時間還真的有點不太好搞懂. 有 時候run起來'很奇怪', 多半就是運作上的盲點, 或是還有些細節沒弄清楚. 最後貼段程式短碼讓大家玩玩, 看看心裏所想跟實際行為是否一致? :) <?php //執行gc的機率100%, session檔案只要1秒沒動就算逾期. ini_set("session.gc_probability",1); ini_set("session.gc_divisor", 1); ini_set("session.gc_maxlifetime", 1); session_start(); if(empty($_SESSION['i'])): $_SESSION['i']=0; endif; $_SESSION['i']+=1; echo $_SESSION['i']; ?> ※ 引述《megabio (LifeIsKuso)》之銘言: : 一切是從這段話開始的 : : "為什麼我修改了 gc_maxlifetime,還是沒有因為閒置而登出呢?" (中略) : ★★★ 我們可以想像一下 PHP 的處理過程 ★★★ : (1) browser A,B,C 都連上 server 開啟 session : 並且在 server 的 "/tmp" 當中留下 sess_* 檔案 : (2) 30 過後,browser A 先重整頁面,對 server 提出連線要求 : (3) server 檢查 "/tmp" 底下的 sess_* 發現有 browser A 的 session id : 於是判定這個 sess_* 不是垃圾 : (4) 至於其他的 sess_*,由於都已經超過 gc_maxlifetime 沒上來連線 : 所以這些 sess_* 有 100% 的機率被當成垃圾處理 ※ 編輯: bobju 來自: 58.115.151.184 (11/17 10:42)