Perl 模块 CGI::Session

简介

在Perl的CGI程序中负责持久化 SESSION 数据。

CGI::Session 通过 HTTP 的 requests 提供了一个简单的、可靠的、模块化的 session 管理系统。

可用的方法

这里列出了所有在 CGI::Session 对象中可用的方法。

new

可用的形式如下:

new();
new($sid); ## $sid 是 SESSION 的 id,即唯一标识
new($query); ## $query 默认是 CGI->new() 临到的对象,也可以是其他任何拥有 param() 方法的对象。
new($dsn,$query||$sid);
new( $dsn, $query||$sid, \%dsn_args )
new( $dsn, $query||$sid, \%dsn_args, \%session_params )

总体说明

new 方法是 CGI::Session 模块的 构造函数。他返回一个新的 CGI::Session 对象。当然如果new方法执行失败或出错了会返回 undef。如果执行出错,错误信息可以通过类方法errstr()得到,调用方式为CGI::Session::errstr()

如果在一个已经初始化完成的 session 对象上调用 new 方法,将会根据这个已经初始化的 session 对象(的内部结构和数据)重新生成一个新的 session 对象。这种在已经初始化的对象上调用 new 的方式,仅在 调用 load 方法后使用。

允许以三个参数的形式调用 new 方法,$dsn(数据源名称),$query||$sid(查询对象或是一个字符串形式的session id),\%dsn_args$dsn组件使用的参数)。

如果以无参形式调用,$dsn 的默认值是 driver:file;serializer:default;id:md5$query||$sid 的默认值是CGI->new()\%dsn_args的默认值是 undef

所有参数都可以用 undef 作为占位,这时对应的参数将使用默认值。

传一个参数时的处理逻辑

如果调用 new() 方法时传了一个参数,new() 方法会根据这个参数的类型来确定它是 $query$sid

当参数是字符串类型时,new() 方法会把它当成 session id 并根据这个值尝试从“数据存储”中加载 session 数据。如果加载失败,将会调用 id() 方法创建一个新的 session id 并生成一个新的 CGI::Session 对象。

当参数是一个对象时,new() 会 这个对象的 cookie()param() 方法用于获取 session id,然后根据获取到的session id 从“数据存储”中加载 session 数据。如果失败(任何一个环节失败)了,将会调用 id() 方法创建一个新的 session id 并生成一个新的 CGI::Session 对象。

name() 方法会定义在 $query 对象中调用 peram() 方法和 cookie() 方法时使用参数的值,默认情况下是 "CGISESSID";

传二个参数时的处理逻辑

如果调用 new() 方法时传了两个参数,第一个参数将会被以为是 $dsn,第二个参数将会根据其类型判断其是 $query$sid(具体的处理逻辑参见【传一个参数时的处理逻辑】)

$s = CGI::Session->new("driver:mysql", undef);
$s = CGI::Session->new("driver:sqlite", $sid);
$s = CGI::Session->new("driver:db_file", $query);
$s = CGI::Session->new("serializer:storable;id:incr", $sid);
# etc...

支持以下数据源组件:

  1. dirver - CGI::Session 驱动,可用的驱动有 file,db_file,mysqlsqlite。当然你可以定义自己的驱动或使用第三方驱动,但它们必须符合 CGI::Session::Driver 规范。
  2. serializer - 在保存到磁盘之前,用于对 session 对象中的数据进行序列化。可用的序列化组件有 storable, freezethawdefault。默认使用的序列化组件是 Data::Dumper
  3. id - 用于生成 session 的唯一标识(即 session id)。可用的id生成器有 md5

使用 DB_File 作为 session 的驱动,使用 FreezThaw 作为序列化组件的示例代码如下:

$s = CGI::Session->new("driver:DB_File;serializer:FreezeThaw", undef);

传三个参数时的处理逻辑

如果使用三个参数调用 new() 方法,前两个参数的处理逻辑可参见【传二个参数时的处理逻辑】,第三个参数\%dsn_args 将作为 $dsn 组件(driver/serializer/id)的初始化参数。因为所有的 $dsn 都有默认的初始化参数,所以这第三个参数在大多数情况下不是必须的。

传四个参数时的处理逻辑

如果使用四个参数调用 new() 方法,前三个参数的处理逻辑与前端介绍的相同,第四个参数必须是一个 hashref(哈希的引用)类型。它会被 CGI::Session 对象作为 “参数” 使用。详情参见对【\%session_params】的介绍。

下面列出第四个参数中,可用的键:

  1. name - 用于 query/cookie 查询的参数,默认值是CGISESSID。可以通过 name 访问器访问

load

可用的形式如下:

load();
load($sid); ## $sid 是 SESSION 的 id,即唯一标识
load($query); ## $query 默认是 CGI->new() 临到的对象,也可以是其他任何拥有 param() 方法的对象。
load($dsn,$query||$sid);
load( $dsn, $query||$sid, \%dsn_args )
load( $dsn, $query||$sid, \%dsn_args, \%session_params )

总体说明

与 new() 方法接受参数的方式和参数的处理逻辑完全相同。不同的是,new() 方法检测到不存在对应id的 session 或 session 过期时会创建一个新的 session。但 load() 方法不会这样做。

所以可以用 load 方法检测一个 session 是否过期、是否存在。然后像下面这样处理:

$s = CGI::Session->load() or die CGI::Session->errstr();
if ( $s->is_expired ) {
    print $s->header(),
        $cgi->start_html(),
        $cgi->p("Your session timed out! Refresh the screen to start new session!")
        $cgi->end_html();
    exit(0);
}
 
if ( $s->is_empty ) {
    $s = $s->new() or die $s->errstr;
}

注意:所有过期的 session 都是空的,但并不是所有空 session 都是过期 session!

load 方法与 new 方法的区别

简而言之,new() 方法返回一个初始化完成并拥有一个有效id的 session 对象,而 load() 方法返回一个空的未初始化的并拥有一个未定义id的 session 对象。

id

返回一个“有效的” session id。因为“有效的” session id 和你声明的 session id可能不同(当用你声明的id创建session 失败时),可以应该总结用此方法来得到 “有效的” session id。

param

此方法有以下四种调用形式

param($name);
param(-name=>$name);
param($name,$value);
parame(-name=>$name,-value=>$value);

其中前两种调用形式,是用于获取 session 中存储的信息的;如果存在对应于 $name 的值则返回,如果不存在,则返回undef。如果在一个"deleted"状态的对象上调用 param() 方法,会得到一个警告,但返回值是不确定的。

后两种调用形式,是用于设置 session 信息的,用这种方式设置到 session 中的信息,可以用前两种调用形式检索。$value的值可以是 scalar/arrayref/hashref。如果参数 $name 的值以 _SESION_ 为前缀,将会得到一个警告。

dataref

之前有一个方法 param_hashref()dataref() 方法的功能相同,但现在已经废弃了。

返回一个 hashref 类型的数据,里面存储的是 session 中的所有数据;

$params = $s->dataref();
$sid = $params->{_SESSION_ID};
$name= $params->{name};
# etc...

在返回的 hashref 中可以使用所有 session 数据。但是请不要用于更新 session 数据,因为这样做是不安全的。

save_param

此方法有以下三种调用形式:

save_param();
save_param($query);
save_param($query,\@list);

保存 “查询参数” 到session 对象中。这和分别为每个$query->param()返回的信息调用param($name,$value)是一样的。

第一个参数(如果存在的话)应该是一个 CGI 对象或是其他任何拥有param方法的对象。如果第一个参数是 undef ,默认情况下会使用 query() 方法返回的值(CGI->new)。如果第二个参数存在,它必须是一个 arrayref 类型的值。只有在数组中出现的“查询参数”会存储到 session中,而没有出现的不会存储。第二个参数也可以是undef,这样会执行默认行为,把“查询参数”中的所有内容存储到 session 中。

load_param

有以下三种调用形式

load_param()
load_param($query);
load_param($query,\@list);

把 session 中的数据加载到 query 对象中。

如果第一个参数存在,它必须是一个 query 对象或者是提供了 param() 方法的对象。第二个参数如果存在,则必须是一个 arrayref 类型的参数。并且只会加载这个数组中指定的 参数 到 query 对象中。

clear

有以下三种调用形式

clear();
clear("field");
clear(\@list);

从 session 中清除参数。

如果调用时不传参数,则会把 session 中的所有 “参数” 清除。如果传一个字符串参数或一个数组引用,则只清楚那些参数中指定的“参数”。

flush

通过驱动把内在中的数据同步序列化到持久的存储器中(如:硬盘)。如果你需要从外部访问当前的 session 对象,你需要先调用 flush 把session 序列化到硬盘中。并且在每次程序退出之前你都需要调用 flush 以确保下次用户访问你的程序时,session 是可以恢复的。

CGI::Session 有自动 flush 机制,但它只在你将要退出程序或 session 对象被回收(超出了变量作用域)才起作用。在 CGI::Session 3.x 版本中,自动fluash是不可靠的。

推荐总是在程序退出前调用 flush();为了更安全的使用 session ,需要在每次重要的session 数据更新后显式调用 flush()

atime

只读方法;返回从最后一次访问后到现在的时间,单位是秒。这个时间提供给内部使用,用作对 session 过期的判断。

ctime

只读方法;返回从session 被创建 到现在的时间,单位是秒。

expire

有以下三种调用形式可用:

expire();
expire($time);
expire($param,$time);

设置相对于 atime() 的过期时间。

如果没有参数,则返回之前设置过的“过期时间”;如果之前没有设置过,则返回 undef。名为 etime() 的方法与 expire() 功能完全相对,仅是为了提供向后兼容性。

当传一个参数时,是用于设置一个过期时间。当事先序列化的 session 被重新加载,并且通过这个值判断发现已经过期,那么这个 session 将会从磁盘上删除。

过期时间为 0 时,表示永不过期;可用于清除已经设置的过期时间。

当传两个参数时,它允许你为一个特定的参数设置过期时间。这样做之后,会在时间到时自动调用 clear() 方法。注意:只有把这个过期时间设置得比 session 的过期时间早才有意义。过期时间为 0 时表示永不过期,可用于清除已经设置的过期时间。

所有时间值需要以秒以单位提供,当然为了方便还提供了以下单位的支持:

+-----------+---------------+
|   alias   |   meaning     |
+-----------+---------------+
|     s     |   Second      |
|     m     |   Minute      |
|     h     |   Hour        |
|     d     |   Day         |
|     w     |   Week        |
|     M     |   Month       |
|     y     |   Year        |
+-----------+---------------+

例子:

$session->expire("2h");                # expires in two hours
$session->expire(0);                   # cancel expiration
$session->expire("~logged-in", "10m"); # expires '~logged-in' parameter after 10 idle minutes

注意:所有的过期时间都是相对于会话的最后一次访问时间的,而不是相对于它的创建时间。如果要立即过期一个会话,可以调用 delete() 方法。如果要立即过期一个 session 参数,可以调用 clear([$name]) 方法。

is_new

只有一个全新的会话,才返回 true

is_expired

用于对使用 load() 方法初始化的 session 进行判断是否已经过期。这个方法只有在使用 load() 方法初始化的 session 中调用才有意义。

$s = CGI::Session->load() or die CGI::Session->errstr;
if ( $s->is_expired ) {
    die "Your session expired. Please refresh";
}
if ( $s->is_empty ) {
    $s = $s->new() or die $s->errstr;
}

is_empty

如果是一个空会话,则返回 true;这是测试 session 是否加载成为的 首选方法。

$s = CGI::Session->load($sid);
if ( $s->is_empty ) {
    $s = $s->new();
}

上面的代码与下面的代码是等效的:

$s = CGI::Session->new( $sid );

只有在你想查看一个 请求中 session 是否过期,然后根据情况创建新的会话时 is_empty() 方法才是有用的,详情参见【is_expired】

ip_match

如果 $ENV{REMOTE_ADDR} 与存储在 session 中的远程地址匹配,则返回 true;

如果你能确定,你的用户在一个 session 期间,ip是保持不变的;你可以考虑像下面的代码这样启用这个选项:

use CGI::Session '-ip_match';

通常情况下,你不用直接调用 ip_match() 方法,而是像上面的代码这样使用;如果你需要通过在 find() 方法中传递的 coderef 来调用它,这个 ip_match() 方法才是有用的。

delete

设置这个对象的状态为"deleted"。设置为"deleted"后,所有对这个对象的 读与写 操作都将失败。想要在磁盘上删除这个 session 还需要调用 flush() 方法才能完成。通常情况下在脚本退出时,CGI::Session 会自动调用 flush()

find

有三种调用方式:

find(\&code);
find($dsn,\&code);
find($dsn,\&code,\%dsn_args);

这是一个实验性的方法,具体细节请参见 CPAN 上的英文文档。

name

name($new_name);

参数 $new_name 参数是可选的,如果提供了则设置为用于在 query 或 cookie 中查询 session 唯一标识的键名。
它的默认值是 $CGI::Session::NAME,其中存储的是字符串:"CGISESSID"。
不推荐使用 全局变量 $CGI::Session::NAME,因为以后它会被废弃。并且在新版中会从这个模块中移除。
返回值:当前从 query 或 cookie 中获取 sid 的键名。

其他可用方法

remote_addr

返回用户第一次创建 session 时的远程ip地址。如果在第一次创建 session 时 REMOTE_ADDR 不在当前的环境变量中,则返回 undef。

errstr

类方法,返回最近一次的错误信息。

dump

返回 session 对象的 dump 信息,只在做程序调试时用得着。

header

封闭了 CGI的 header 方法,调用这个方法相当于下面这样:

$cookie = CGI::Cookie->new(-name=>$session->name, -value=>$session->id);
print $cgi->header(-cookie=>$cookie, @_);

你可以直接简化成如下写法:

print $session->header();

它将会从 sesison 中 调用 $session->name() 找到 cookie 的键名,默认值是$CGI::Session::NAME中存储的“CGISESSID”。如果你想使用一个不同的名字作为你 cookie 中的 session id,你可以像下面这样做:

CGI::Session->name("MY_SID");
$session = CGI::Session->new(undef, $cgi, \%attrs);

现在,$session->header(),使用 "MY_SID" 作为 cookie 中的session id的键名。

对于其他选择,你可以查看 CGI 模块 中的 header() 方法了解更多。

query

返回当前 session 中的 query 对象。 默认查询对象是CGI类的对象。

总结

还有很多不常用的信息没有在这里列出,有兴趣的您可以去CPAN上查看CGI::Session模块的英文文档。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,080评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,422评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,630评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,554评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,662评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,856评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,014评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,752评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,212评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,541评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,687评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,347评论 4 331
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,973评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,777评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,006评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,406评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,576评论 2 349

推荐阅读更多精彩内容

  • 从三月份找实习到现在,面了一些公司,挂了不少,但最终还是拿到小米、百度、阿里、京东、新浪、CVTE、乐视家的研发岗...
    时芥蓝阅读 42,214评论 11 349
  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,598评论 18 399
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,633评论 18 139
  • 这部分主要是开源Java EE框架方面的内容,包括Hibernate、MyBatis、Spring、Spring ...
    杂货铺老板阅读 1,357评论 0 2
  • 2016.12.08我报名了写手圈新媒体组写作训练营,报名的时候信誓旦旦的,这将是我追梦的起点。 一晃今天已是20...
    21不思量阅读 301评论 0 0