Session 类別
Session 类別能让你为你的应用程序在無狀態(stateless)的 web 环境下保持狀態。
它能让你在伺服器上使用各種變数解決方案來儲存變数,并且在下个頁面請求再呼叫變数。
手动載入
在大多数情況下,配置所需的驅动是足夠的,使用方法記錄在 用法 頁面。
不過,也有一些情況你会想要更進一步控制 session 的行为方式。
你可能想要使用一个配置在 session 配置档案中不同的 session 驅动。
或你有多个驅动并行的需要。这就是为什么要有 forge 方法。
forge 方法回傳一个 session 类別的實例,使用定義在配置档案的驅动或透過參数。
你可以在回傳的物件使用紀錄在 用法 頁面的方法,使用动態呼叫。
forge($config = array())
forge 能让你手动實例化一个 session 驅动。
靜態 |
是 |
參数 |
參数 |
預設 |
描述 |
$config |
選擇性 |
你可以透過简单地傳遞驅动名稱到 forge 方法來選擇驅动。
如果你需要更多的自訂配置,定義一个 $config 陣列,使用記錄在 配置 頁面上的參数。
这裡你傳遞的配置設定将覆寫在配置文件中定義的。
|
|
回傳 |
物件 - 實例化的 session 物件。 |
範例 |
// 實例化一个資料庫 session
$session = Session::forge('db');
// 取得來自 session 的 counter
$counter = $session->get('counter');
// 如果不存在,設定一个預設值
if ($counter === false)
{
$counter = 0;
}
// 寫回 counter
$session->set('counter', $counter);
// 沒有需要明確寫入,Fuel 会打理好……
// 你也可以帶設定載入一个驅动,它将覆蓋在配置档案的預設值
$session = Session::forge( array('driver' => 'memcached', 'expiration_time' => 3600, 'memcached' = array('cookie_name' => 'appcookie')) );
|
請注意:當你想同時使用多个 session 驅动,这些驅动實例中的 cookie_name 必須是唯一的。
如果你试圖載入一个使用已经被使用的 cookie_name 的驅动,而且該實例使用與你嘗试載入的相同驅动,該實例会重複使用。
如果該實例使用不同的驅动,一个例外会被拋出。
rotate()
rotate 方法能让你手动強制一个 session id 的轉动。你可以使用它做为一个額外的安全對策,例如,當目前使用者的安全等級被修改時。
靜態 |
否 |
參数 |
無
|
回傳 |
空 |
範例 |
// 實例化一个資料庫 session
$session = Session::forge('db');
// 強制一个 session id 的轉动
$session->rotate();
|
get_config()
get_config 方法能檢索一个 session 驅动配置項目。
靜態 |
否 |
參数 |
參数 |
預設 |
描述 |
$name |
必要 |
session 配置變数的名稱。
|
|
回傳 |
混合,請求的值,或 null 當請求變数不存在。 |
範例 |
// 實例化一个資料庫 session
$session = Session::forge('db');
// 取得定義的 session cookie 名稱
$cookiename = $session->get_config('cookie_name');
|
set_config()
set_config 方法能在执行階段改變一个 session 驅动配置項目。
靜態 |
否 |
參数 |
參数 |
預設 |
描述 |
$name |
必要 |
session 配置變数的名稱。
|
|
回傳 |
空 |
範例 |
// 實例化一个資料庫 session
$session = Session::forge('db');
// 为此 session 設定逾期時間为 2 小時
$session->set_config('expiration_time', 7200);
|
在 Flash 使用 session
在網站中使用 Flash 物件的問題之一,是與你的 Web 应用程序互动時,他們不送回已儲存在瀏覽器的 cookie。
由於这个問題,就很難让他們明白應用程序的 session 狀態。
为了解決这个問題,Session 类別能让你使用一个 POST 變数,傳遞 cookie 到应用程序。
你可以使用 'post_cookie_name' 配置設定來設定該變数名稱。如果 Session 类別找到一个有此名稱的 $_POST 變数,
它将假設它包含 session cookie,并且不会使用該 session cookie。这能让你使用一點 javascript 來複製客戶端的
session cookie 的內容到該 POST 變数。
當你使用 Flash 为底的上傳程序時。你将必須設定 match_ua 为 false。
你必須这樣做,因为 Flash 使用一个不同的使用者代理,
这将阻止 Session 类別正確地識別使用者 session。
// 取得 session cookie 的函式
// 你可以使用自己的,或使用一个你喜愛的 javascript 框架提供的
function getCookie(c_name)
{
if (document.cookie.length > 0)
{
c_start = document.cookie.indexOf(c_name + "=");
if (c_start != -1)
{
c_start = c_start + c_name.length + 1;
c_end = document.cookie.indexOf(";", c_start);
if (c_end == -1) c_end = document.cookie.length;
return unescape(document.cookie.substring(c_start, c_end));
}
}
return "";
}
// 在这个範例中,我們正在使用 jquery 和 uploadify,而且我們正在
// formData 中傳遞 fuel cookie(这裡稱为 'fuelcid') 做为 'fuelcid'
// 注意:在產生此程式码時,不要硬寫 cookie 名稱,
// 而是從 session 配置档案取得 cookie 名稱。
// 注意:檢查下面的「無 cookie 的 session」段落
// 如果你沒有 cookie 可用來傳回 session id
// (參数與 Uploadify 3.2 版相關)
$(function()
{
$('#custom_file_upload').uploadify(
{
'swf' : '/uploadify/uploadify.swf',
'uploader' : '/uploadify/uploadify.php',
'multi' : true,
'auto' : true,
'fileTypeExts' : '*.jpg;*.gif;*.png',
'fileTypeDesc' : 'Image Files (.JPG, .GIF, .PNG)',
'queueID' : 'custom-queue',
'queueSizeLimit' : 3,
'removeCompleted': false,
'formData' : {'fuelcid': getCookie('fuelcid')},
'onSelect' : function(file)
{
alert('The file ' + file.name + ' was added to the queue.');
},
'onQueueComplete' : function(queueData)
{
alert(queueData.uploadsSuccessful + ' files were successfully uploaded.');
}
});
}
并行性
當論及 session、session cookie、和他們的行为,了解他們如何運作、
以及有什么可能性和侷限性是非常重要的。
當涉及到并行性時尤其如此。
對於 web 为底的应用程序,如果你在你的網頁上使用多个異步 ajax 呼叫,你会有并行性,
或如果你允許瀏覽器開啟多个相同应用程序的視窗(让我們面對它,你無法阻止)。
其他你需要知道的事是,預設情況下,session 类別会定期轉动(或重新產生)session id,
來防止由於 session id 固定的 session 劫持(有人偷取你的 session cookie 并用它來接手你的 session)。
你可以使用配置設定來控制轉动的時間,或甚至停用它,但從安全性的角度來看,这是个壞主意。
把这兩樣放在一起,你就有潛在的災難在手中!
一个實例:
- 你請求一个頁面,包含 ID-A 的 session cookie 被发送到伺服器。
- 你的頁面发送兩个 ajax 請求。包含 ID-A 的 session cookie 隨著每个請求再度被发送到伺服器。
- ajax 請求 1 完成,并轉动 ID。一个有 ID-B 的 cookie 被发送到瀏覽器。
- 现在 ajax 請求 2 完成。因为它发送相同的 cookie,它也判斷要旋轉,此時是 ID-C。
(你将取得一个不同的 ID,因为 session ID 是使用隨機演算法產生)
现在我們有个問題。session 类別嘗试更新儲存的 session 從 ID-A 到 ID-C,但它無法找到該 session。
請記住,它已经被第一个 ajax 呼叫從 ID-A 更新为 ID-B!所以它判斷該 session 無效,建立一个新的空 session,
并回傳該 cookie 到瀏覽器。现在你有效的 cookie 已经被新的空 session cookie 覆寫。
結果:你已经遺失 session。
这是一个大多数框架沒有解決的問題,進入 Fuel!
Fuel 的 session 类別包含兩个機制來偵测并減輕这个問題。
每个 session 鍵儲存包含兩个 session ID:目前 ID 及前一个 ID。
如果請求在 session id 剛被轉动之後進來,正確的 session 可以使用前一个儲存在鍵儲存區中的 session id 來定位。
并且在 session id 不能使用前一个 id 還原而不符合的情況下,沒有更新的 cookie 会被送回到瀏覽器。
結果是你遺失了該請求的 session 資料,但你不会遺失 session 本身。
無 cookie 的 session
在 session 資料變更後,Session 类別總是会產生一个 session cookie,并在 HTTP 回應表頭中发送它到客戶端。
然而,也有情況是不希望,甚至是不可能使用 cookie。
例如僅僅是因为客戶端不支援他們。
在这些情況下,有很多替代方案在請求中從客戶端傳遞 Session ID 回到应用程序:
- 经由一个 GET 變数。在 URL 中變数的名稱必須與定義在配置中的 cookie 名稱相等。
- 经由一个 POST 變数。你可以定義表单欄位名稱(post_cookie_name)包含配置中的 session-id。
- 经由 HTTP header。在客戶端建構 HTTP 請求時,你可以添加一个有 session id 的 "Session-Id" HTTP 表頭。
你可以使用 Session::key()
來檢索目前的 session id,如此你可以在回應中傳遞它到客戶端,
而不須使用 cookie。如果你已经在你的 session 配置中配置了加密,你需要加密 id:
// 取回 session ID 并加密
$session_id = \Crypt::encode(\Session::key());