深入理解PHP中的SESSION技術

一、默認的存儲機制——文件

PHP默認使用磁盤文件來保存 SESSION數據,即默認存儲方式爲 files。

php.ini中關於 SESSION的基本配置:

1、session.save_handler = files  //SESSION的存儲方式
2、session.save_path = 'xxx'     //存放文件的路徑  
2、session.name = 'PHPSESSID'    //SESSION的名稱
3、session.use_trans_sid = 0     //爲1則表示給每個URL加上 SESSION名 = 會話Id,一般情況下不建議開啓,不安全
4、session.cookie.lifetime = 0   /*即存儲session_id的 COOKIE 的保存時間,只要 COOKIE還在,客戶端就能通過 session_id 來找到之前的 SESSION 數據。默認爲0,COOKIE保存在服務器內存中,因此關閉瀏覽器之後,就找不到之前的SESSION數據了,因爲保存會話id的COOKIE已經失效了,這也是爲什麼 SESSION數據只能在同一次會話中獲取了。設置爲大於0的數,則 SESSION 可以在多次會話中獲取,知道 COOKIE 過期*/

1、session_start

1、session_start() 是 session機制的開始,它有一定概率開啓垃圾回收機制,因爲 session是存放在文件中的,所以垃圾回收機制會去刪除那些已經過期了的磁盤文件。

這個開啓垃圾回收的概率是根據php.ini的配置決定的,但是有的系統是 session.gc_probability =0,這也就是說概率是0,而是通過cron腳本來實現垃圾回收。   

session.gc_probability =1
session.gc_divisor =1000
session.gc_maxlifetime =1440

啓動垃圾回收機制的概率是 session.gc_probability / session.gc_divisor,(網站訪問量很大時,建議把這個值設置小一點)。
而 session.gc_maxlifetime表示session默認最大生命週期,若在這個期間秒內訪問了該session,則重新計時。

2、如果在使用 session_start() 之前沒有通過 session_id() 函數手動設置id,session會判斷當前是否有 $_COOKIE[session_name()](session_name()返回session名)。

3、如果第2步中得到了id,則會去 session.save_path 指定的目錄裏尋找名爲 ‘SESS_’. session_id() 的文件,讀取文件的內容並反序列化成數組,然後賦給 $_SESSION數組。

4、如果第2步中沒有得到id,即既沒有手動設置,也沒有相應 COOKIE,或者找不到對應的 SESSION 文件,則生成一個UUID來作爲session_id,並在發送響應時將session_id以COOKIE的方式發送到客戶端。

相當於執行了下面 COOKIE 操作,注意的是,這只是模擬操作,COOKIE實際上是在header頭中發送的,因此這之前是不能有輸出的, 同理還有session_regenerate_id()。

    setcookie(session_name(),
              session_id(),              //生成一個id
              session.cookie_lifetime,  //默認0,即會話結束後就cookie就消失
              session.cookie_path,      //默認'/'當前程序根目錄下都有效
              session.cookie_domain,    //默認爲空
             )

2、爲$_SESSION賦值

比如新添加一個值 $_SESSION[‘t’] =’a’; 那麼這個$_SESSION 會先保存在內存中,當腳本執行結束的時候,再把 $_SESSION 數組序列化之後寫入到 ‘SESS_’ . session_id() 文件中,然後關閉相關資源。

這個階段可以執行更改 session_id 的操作,比如銷燬一箇舊的session_id,生成一個新的 session_id。一般用在自定義 SESSION 機制角色的轉換上,比如匿名用戶持有一個 session_id,當它登錄後需要更換新的 session_id:

 if (isset($_COOKIE[session_name()])) {
      setcookie(session_name(), '', time() - 42000, '/');  //舊session cookie過期
  }
  session_regenerate_id();//這一步會生成新的session_id
  //然後繼續操作 SESSION

3、寫入SESSION文件

在腳本結束的時候會將 $_SESSION 數組經序列化後寫入到’SESS_’. session_id() 文件中。

4、 銷燬SESSION

默認情況下,SESSION發出去的COOKIE屬於即時COOKIE,保存在客戶端內存中,當瀏覽器關閉後,就會消失。

假如有時需要人爲強制過期,而不是關閉瀏覽器時才過期,比如退出登錄等情況,那麼就需要在代碼裏手動銷燬 SESSION 數據,方法有幾種:

  1. setcookie(session_name(), ”, time() -8000000, ..);//讓客戶端保存的COOKIE過期
  2. unset($_SESSION); //直接刪除所有的 $_SESSION數據,用戶通過session_id取得的SESSION是空的
  3. session_destroy(); //直接刪除對應的SESSION文件

當不關閉瀏覽器的情況下,再次刷新,2和3情況下,用戶依然持有 session_id,但是已經得不到任何SESSION數據了。而1情況下,用戶的訪問已經找不到之前設置的SESSION了。

1.可以在 URL 裏添加一個PHPSESSID=>sesssion_id
在頁面加入:

      if(isset($_GET[‘PHPSESSID’]){
           //手動設置 sesssion_id
           session_id($_GET[‘PHPSESSID’]);
      }
      //程序會尋找該session_id對應的SESSION文件  
      session_start();
      //獲得數據 

2.可以啓用session.use_trans_sid來指定是否啓用透明 SID 支持 ,即在每個URL中的Query部分加上session_name=session_id。(對JS中的URL不起作用。)

php.ini中:

session.use_trans_sid = 1 

這樣,即使禁用了 COOKIE,也能在跨頁時傳遞 SESSION變量了。

二、自定義 SESSION 存儲方式

首先將 php.ini 文件中的 session.save_handler 設置爲 user。
然後通過 session_set_save_handler(‘open’,’close’,’read’,’write’,’destroy’,’gc’) 函數來實現。這6個回調函數必須返回 TRUE/FALSE 。

下面是個簡單的例子,與默認的files處理機制類似。可以通過下面的例子來進一步掌握默認機制的原理,也可以方便地擴展,比如使用數據庫保存SESSION。

注意,ssesion_id 的傳遞依然是使用COOKIE,只是保存 SESSION 數據的方式改變了。

//  執行 session_start() 後執行的第一個回調函數
function open($save_path, $session_name)
{
    global $sess_save_path;  //  聲明爲全局變量是爲了讓之後回調的函數能訪問該變量
    if (!is_dir($save_path)) {
        mkdir($save_path);
    }
    $sess_save_path = $save_path;  //  $save_path 爲 session.save_path
    return(true);
}

function close()
{
    return(true);
}

function read($id)
{
    global $sess_save_path;
    $sess_file = "$sess_save_path/yyy_$id";

    return (string) file_get_contents($sess_file);
}

function write($id, $sess_data)
{
    global $sess_save_path;

    $sess_file = "$sess_save_path/yyy_$id";

    return file_put_contents($sess_file, $sess_data) === false? false : true;

}

//  session_destory()函數的工作原理。
function destroy($id)
{
    global $sess_save_path;

    $sess_file = "$sess_save_path/yyy_$id";

    return(@unlink($sess_file));
}

//  執行session_start()時,一定機率執行該函數,$maxlifetime 爲配置項 session.gc_maxlifetime 的值
function gc($maxlifetime)
{
    global $sess_save_path;

    foreach (glob("$sess_save_path/yyy_*") as $filename) {
        if (filemtime($filename) + $maxlifetime < time()) {
            @unlink($filename);
        }
    }

    return true;
}

session_set_save_handler("open", "close", "read", "write", "destroy", "gc");

session_start();
/*
...
*/
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章