当前位置: 首页 > 文档资料 > FuelPHP 中文文档 >

Session 進階 - 类別

优质
小牛编辑
116浏览
2023-12-01

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_uafalse。 你必须这样做,因为 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());