php 的 session 運作流程,實驗觀察心得

看板PHP作者 (LifeIsKuso)時間14年前 (2009/11/15 13:02), 編輯推噓11(1100)
留言11則, 10人參與, 最新討論串1/4 (看更多)
一切是從這段話開始的 : "為什麼我修改了 gc_maxlifetime,還是沒有因為閒置而登出呢?" 隨便 google 一下就有很多討論區問過類似的問題 我自己本人對於 PHP 的 session 機制也是一知半解 所以打算以所學到的知識 + 動手實驗的方式 找出自己不清楚,疑惑的地方 作業環境是 Windows XP + Xampp 整合包 (http://tinyurl.com/lv287y) ★★★ 實驗開始 ★★★ 首先新增一個 php 程式,以 session_start() 啟動 session client browser 會寫入一個 cookie 叫做 "PHPSESSID" 內容是一長串亂碼 代表此 session 獨一無二的編號 server 端會在 "/tmp" (此數值設定在 php.ini 的 session.save_path) 這個目錄下寫 入 sess_* 的檔案 sess_* 後面的亂碼就是剛才 cookie 的編號,打開這個檔案,發現裡面沒有東西 再來我們在 php 程式中建立一個 session 變數,$_SESSION['user'] = 'guest' 打開 sess_* 這個檔案,發現裡面多了以下內容 : user|s:5:"guest"; 現在我們了解,PHP 藉由 sess_* 來儲存我們建立的 $_SESSION 變數 並且跨網頁傳遞這些變數 ★★★ 實驗二 : 觀察 session 垃圾回收機制 ★★★ 為了方便觀察,修改 php.ini 的以下設定 session.gc_probability = 100 session.gc_divisor = 100 session.gc_maxlifetime = 30 按照上面的設定。每次有人瀏覽網站時,PHP 就會檢查 "/tmp" 底下的 sess_* 檔案 如果有 "閒置" 超過 30 秒的 session,server 有 100% 的機率會將它刪除 有趣的部份在於 PHP 判斷 "閒置" 的條件是什麼呢? 我做了以下的實驗 第一步 : 寫兩個 php 程式 (1) login.php <?php session_start(); $_SESSION['login'] = 'user_id'; header('location: refresh.php'); ?> (2) refresh.php <?php session_start(); if (empty($_SESSION['expire'])) { echo '目前你已經登出'; } else { echo '目前你還在線上'; } ?> 開啟 login.php 註冊一個 $_SESSION 變數,然後導向到 refresh.php 我們用 refresh.php 觀察 $_SESSION 變數是否逾期 第二步 : 先用一種 browser 開啟 login.php,此時會直接導向到 refresh.php 30 秒後我們按 F5 重整頁面,發現 session 依然還在 第三步 : 我們在同一台電腦上,開啟三種不同的 browser,並且都開啟 login.php 30 秒後,我們先重整第一個 browser 的頁面,session 一樣還在,和第二步的結果相同 但是當我們換到第二個和第三個 browser 的時候,按 F5 重整頁面發現 session 已經消 失了,"/tmp" 底下,這兩個 browser 的 sess_* 也不見了 從這裡我們可以得到結論,session.gc_maxlifetime 的確是用來清除閒置 session 的機 制,只不過和一般人所想的有些不同,它是用來清除 "別人" 的閒置 session ★★★ 我們可以想像一下 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% 的機率被當成垃圾處理 * 那個 100% 的機率是我們在 php.ini 修改的設定 : session.gc_probability = 100 (分子) session.gc_divisor = 100 (分母) ★★★ 結論 ★★★ PHP 踢除閒置 session 的機制就是 "先搶先贏" 超過閒置時間誰先上來連線,就判定 safe 其餘的,就看 PHP 的心情 (機率) 而定,心情不好時 (100%) 就通通踢除 經過實驗我清楚的了解到,PHP 預設的 session 垃圾回收機制其實是蠻合理的 24 分鐘後,有 1% 的機率刪除沒來連線的 sess_* 這的確符合大部分網站的流量負荷 ★★★ 參考連結 ★★★ http://www.jollen.org/php/216_session_cookies/ (中文) http://blog.wu-boy.com/2008/11/18/608/ (中文) http://tinyurl.com/4fleql (中文) http://chensh.loxa.edu.tw/php/X_17.php (中文) http://www.captain.at/howto-php-sessions.php (英文) http://tinyurl.com/yk53ndb (英文) 如果我這篇心得有任何錯誤的地方,希望大家不吝指正,弄清楚觀念才我最想要的 如果你也是和我一樣對於 PHP 一知半解,也可以用我這篇的方法親自做個實驗 希望對你會有幫助 -- ※ 發信站: 批踢踢實業坊(ptt.cc) ◆ From: 114.32.69.181

11/15 14:24, , 1F
推心得
11/15 14:24, 1F

11/15 19:38, , 2F
Good 分析的非常清楚
11/15 19:38, 2F

11/16 02:08, , 3F
如果我是老師 我一定很愛這份報告="=
11/16 02:08, 3F

11/16 02:44, , 4F
路過再推
11/16 02:44, 4F

11/16 06:36, , 5F
推實驗XD
11/16 06:36, 5F

11/16 14:17, , 6F
好文推
11/16 14:17, 6F
※ 編輯: megabio 來自: 114.32.69.181 (11/16 20:34)

11/17 00:36, , 7F
用心推
11/17 00:36, 7F

11/17 14:49, , 8F
該M了,這篇很不錯
11/17 14:49, 8F

11/17 20:07, , 9F
推一個...
11/17 20:07, 9F

11/23 01:30, , 10F
不推不行
11/23 01:30, 10F

11/24 18:59, , 11F
大推 好文
11/24 18:59, 11F
文章代碼(AID): #1A_ujtoi (PHP)
討論串 (同標題文章)
文章代碼(AID): #1A_ujtoi (PHP)