长沙发上的对话
开始治疗心理医生: 好。你今天感觉怎么样,维克多?
病人: 不太好,医生。我近来感到有点忧郁...
心理医生: 那是为什么,维克多?
病人: 我不知道,医生。我睡眠不太好,而且我一点胃口也没有。有一天我们去一个意大利餐馆,要了通心
面 -- 但时当他们把它端上来的时候,我一点也吃不下去。我就一直看着它,在我的头里一直回荡着“女高
音”的主题曲...
心理医生: 家里怎么样?
病人: 都很好,我想。Marge大部分时间都在厨房,试她从网上下载的菜谱。孩子们每天很早就出去了,一
般在吃饭时才看得见他们,但是现在他们开始在Burger King吃了。那我也不能责备他们。
心理医生: 工作 - 都很好吧?
病人: 不太好 - 我有一个虐待成性的魔鬼老板,他打算打我的生活变成象Dilbert Zone一样!
心理医生: 跟我说一说他吧。
病人: 好,你知道我是做什么的 - 我是一个在Used Socks. Inc.的web程序员。下个星期我们的新网站就要
使用了,我们正在做着完全不同的东西 -- 一个在线商店,供人们出售他们的旧物。我们得到了一些好心人
的投资 - 6百万元,如果我们成为在web最受欢迎的旧物门户,我们还可得到更多的投资。
心理医生: 听上去对你不错嘛。
病人: 你说的对。但是,然后有一天老板进来,他说他交给我一项开发在线商店购物车的工作。他明确地要
求我用什么叫“session”的东西。当然,只不过让事情变得有趣,他说他想在两天内做完并能运行...虐待
狂、变态!
心理医生: 有问题吗?
病人: 有,特别是首先我根本不知道“session”是什么,或怎么去用它。我意思是说,我原以为一个session
就是对一个病人的短期治疗 - 有一点象我们正在做的一样。
心理医生: 哦, 维克多, 维克多...这就是麻烦你的事吗?我想我可能有东西能帮助你...
西雅图无状态
开低级玩笑的人为了给能听到谈话的年轻女性留下印象,互相之间最经常说的事情之一就是:“HTTP是
一种无状态协议,Internet是无状态开发环境”。用简单的话来讲,HTTP(HyperText Transfer Protocal )
协议,作为web的骨干,不能够记住与一个网站连接用户的身份,所以对web页的请求被看作是唯一和独立的
连接,与在它之前的连接无论如何都没有关系 -- 这一点与今天很多爱冒险的十几岁的年轻人的行为很象,
他们每天喝到深夜,第二天早晨醒来对发生过什么都不记得了,晚上再出去做同样的事,一遍又一遍...
现在,如果你是漫无目的地从一个站点冲浪到另一个,没有什么问题。但是当你想从Amazon.com上买几
本书会怎么样呢?“在一个无状态的环境中,记住所有在你的购物单上的物品是非常困难的,因为HTTP协议
的这种无状态的性质使得跟踪选中物品是不可能的。
因此就要求一种能够使记住状态成为可能的方法,能够跟踪用户的连接并且保存连接特定数据的东西。
因此产生了“cookie”,它可以允许Web 站点在客户系统的一个文件中保存客户特定信息,并且当任何时候
请求时都可以从文件中取出信息。所以,在上面的购物车例子中,被选中的商品可以加到cookie中,并且在
消费者结帐时,可以被取出并呈现在购物单中。
基于cookie的解决方案存在一个问题,那就是它要求cookie能够被客户所接受。所以,有另一种解决办
法就是使用“session”,当一个客户访问一个Web站点时,用它来保存特定的一小块数据。这个会话
(session)数据在整个访问期间被保存下来。一个session可以被看成一个信息篮,它保存着主机的变量对。
这些变量对在整个访间期间都存在,并且可以在任何时刻被处理。这个方法对协议的无状态的特点提供了一
流的解决办法,并且在今天很多大型的网站上,可以跟踪和保存信息,用于个人和商业交易。
每一个被创建的session 都有一个唯一的标识串,这个串被发送到客户端,同时在服务端也生成了同样
唯一标识串的入口,或者放在文本文件或者在一个数据库中。现在就可以注册任何的session 变量 -- 这些
普通的变量可以保存文本或数值信息,可以通过session 被读出,或写入。
现在,如果你已经跟随着开放源码运动,你已经知道了PHP ,在这个星球上最热门的脚本语言。最新的
版本是PHP4,包括了对session 的创建和管理的支持,在下面的几页中,我们将向你展示如何使用它。如果
你还在使用PHP3,不要失望 -- 我们也将涉及PHPLIB,它包括一组强大的PHP对象,可以在基于PHP3 的站点
上加入无缝的session管理。
在下面几页中,我们假设你已经有一个支持PHP4或PHPLIB的站点。如果还没有,你应该下载这些包,并
且将它们安装到你的开发机器上去。PHP4,是一个质量优良的代码,可以在PHP站点 http://www.php.net找
到,最新的PHPLIB版本可以在http://phplib.netuse.de/找到。
长沙发上的对话
第一个session关于演示session是如何工作的标准例子之一就是点击计数的应用 -- 这是一个简单的基于session的计数
器,在你第一次访问一个web页面时初始化一个变量,每一次当你重新装入这个页面时增加它的计数。代码如下:
--------------------------------------------------------------------------------
<?php
//初始化一个session
session_start();
//注册一个session变量
session_register('counter');
?>
--------------------------------------------------------------------------------
在PHP4中每一个session都通过调用session_start()函数开始,这个函数检查一个session是否存在,如果
不存在则创建一个新的。接着,用session_register()函数来注册一个变量,它将生存在整个session中 -- 在
上面的例子中,变量名为"counter",并且没有给它赋任何值。
现在,让我们在上面的例子中加几行代码,点击计数将开始工作了:
--------------------------------------------------------------------------------
<?php
//初始化一个session
session_start();
//注册一个session变量
session_register('counter');
//增加计数器
$counter++;
echo("You have visited this page $counter times! Don't you have anything else to do, you bum?!");
?>
--------------------------------------------------------------------------------
试一试它!当你每一次重装这个页面时,计数器的值都在增加,这个说明了在session中变量是如何被保存
的。
为什么为发会生这样的情况呢?唔,每次一个session被创建,一个session的cookie[叫做PHPSESSID]会在
客户系统中被创建,并且被赋了一个随机数;同时,在服务器端一个相似的入口被创建,它包含着在session中
注册过的变量。在客户与服务器之间的通讯就通过这个有相同命名的session的标识号(id)来实现,这样就可以
在整个session期间保存不同的变量。
让我们再看一下复杂一点的吧?看这个例子,它演示了一个使用session变量的计时器,它将告诉你在重新
装入页面时过了多长的时间。
--------------------------------------------------------------------------------
<?php
session_start();
//session变量用于保存计数器
session_register('counter');
//session变量用于保存最后装入的时间值
//这个值被保存以便比较两次的不同
session_register('timeAtLastLoad');
//当前时间
$timeNow = time();
//增加计数
$counter++;
//计算两次时间间隔
$timeLapsed = $timeNow - $timeAtLastLoad;
//显示信息
if($counter > 1)
{
echo "<b>It's been $timeLapsed seconds since you last viewed
this page.</b>";
}
else
{
echo "<b>First time here? Reload this page to see how the
session works!</b>";
}
$timeAtLastLoad = $timeNow;
?>
长沙发上的对话
市场游戏现在你已经知道了基本的东西,再来点复杂的吧,演示一个现实生活中的session 应用。让我们假设一
下,你有一个金融门户,它允许它的用户选择四支股票,然后显示每支股票的当前市场价格,并且在每一页
上显示用户在这个站点上的过程。
在下面的例子中,我们假定用户已经被验证过身份并且登录到站点上来了。我们使用了MySQL 数据库,
里面有一个名为user_info的表,用于存储用户的四支股票和唯一用户名。一旦一个session被初始化了,我
们注册变量保存用户名和四支股票,然后同数据库进行连接,取回值并显示在页面上。
代码如下:
--------------------------------------------------------------------------------
<?php
//初始化一个session
session_start();
//注册session变量
//用户名
session_register('username');
//选择的股票变量
session_register('stock1');
session_register('stock2');
session_register('stock3');
session_register('stock4');
//连接MySQL
$db = mysql_connect("someserver.com", "tom", "jones");
//选择数据库
mysql_select_db("stock_db", $db);
//使用SQL查询数据库
$query = "select stock_pref1,stock_pref2,stock_pref3,stock_pref4
from user_info where username='$username'";
$result = mysql_query($query,$db);
//从数据库中取股票代码,并赋值给session变量
list($stock1,$stock2,$stock3,$stock4) = mysql_fetch_row($result);
echo "Hi $username!<br>";
echo "Your selected stocks are:<br>";
echo "$stock1<br>";
echo "$stock2<br>";
echo "$stock3<br>";
echo "$stock4<br>";
// code to generate rest of page
?>
--------------------------------------------------------------------------------
PHP4有许多与session相关的函数 -- 大部分都不需要解释,把他们列在下面。
session_destroy()
释放所有的session数据(当一个用户从一个站点注销时非常有用,你需要释放掉在他访问期间的所创建
的所有变量)。
session_name()
设置或读取当前session的名字。
session_id()
设置或读取当前session的id值。
session_unregister(session_variable_name)
从一个特别的session注销一个变量。
session_is_registered()
检查是否一个session变量已经注册了。例如:
--------------------------------------------------------------------------------
<?php
session_start();
if(session_is_registered(username))
{
echo "A session variable by the name "username"
already exists";
}
else
{
echo "No variable named "username" registered yet.
Registering...";
session_register(username);
}
?>
--------------------------------------------------------------------------------
session_encode() and session_decode()
将session数据编码成字符串或将字符串解码成session数据。在这里你可能使用他们:
--------------------------------------------------------------------------------
<?php
session_start();
session_register('someString');
$someString="I hate cats!";
//将所有的session变量编成一个字符串
$sessStr = session_encode();
//可以在这里看到
echo $sessStr;
echo "<br><br>";
//在出现cats的地方用dogs进行替换
$sessStr = ereg_replace("cats","dogs",$sessStr);
//解码后更新了session变量
session_decode($sessStr);
//再显示一次$sessstr
echo $someString;
?>
--------------------------------------------------------------------------------
最后,在开始PHPLIB之前,有一个技术性问题你应该知道的 -- 上面所有的例子都使用了cookies在客
户端来保存session id值。但是如果用户的浏览器被设成拒绝cookies会怎么样呢?
如果发生这种情况,那就需要将一个session id通过嵌在url中从一页传递到另一页上去。例如:
--------------------------------------------------------------------------------
<a href="http://www.someserver.com/admin/preferences.php3?
PHPSESSID=<? echo "$PHPSESSID"; ?>">Edit Your Portfolio!
</a>
--------------------------------------------------------------------------------
这个就可以保证在后面的页面中session变量是有效的。
长沙发上的对话
有很多给猫换肤的办法...当然,如果你的站点仍然运行着PHP3,你就无法使用迄今为止的任何代码。但是不要沮丧 -- 有另一种
提供给PHP3用户的解决办法。它就叫做PHPLIB,它提供了一组有用的类,允许在你的PHP3中增加对session
的管理。可以按照包中的指示进行安装,你还需要修改"local.inc"配置文件来创建你自已的类。
象在PHP4中一样,在每次你初始化一个session时,你需要预先调用page_open()函数。PHPLIB返回一个
缺省的名为Example_Session的类 -- 你可以在"local.inc"文件中修改这个值 -- 它将用在下面的例子中:
--------------------------------------------------------------------------------
<?php
page_open(array("sess" => "Example_Session"));
?>
--------------------------------------------------------------------------------
在任何发给浏览器的输出之前调用page_open()非常重要。为了注册你的session变量,下面的语句可以
完成这个工作。
--------------------------------------------------------------------------------
<?php
//初始化一个session
page_open(array("sess" => "Example_Session"));
//注册一个session变量
$sess->register('username');
?>
--------------------------------------------------------------------------------
每一个页面也必须包含相应的page_close()函数,用来确认所以的改变量被保存在数据库中。
--------------------------------------------------------------------------------
<?php
page_close();
?>
--------------------------------------------------------------------------------
除了这些,大部分的代码都是一样的。看一下以前例子的PHPLIB版本:
--------------------------------------------------------------------------------
<?php
//初始化一个session
page_open(array("sess" => "Custom_Session"));
//注册session变量 - 注意语法
$sess->register('username');
$sess->register('stock1');
$sess->register('stock2');
$sess->register('stock3');
$sess->register('stock4');
//连接MySQL
$db = mysql_connect("someserver.com", "tom", "jones");
//选择数据库
mysql_select_db("stock_db",$db);
//使用SQL查询数据库
$query = "select stock_pref1,stock_pref2,stock_pref3,stock_pref4
from user_info where username='$username'";
$result = mysql_query($query,$db);
// 从数据库中取股票代码,并赋值给session变量
list($stock1,$stock2,$stock3,$stock4) = mysql_fetch_row($result);
//输出
echo "Hi $username!<br>";
echo "Your selected stocks are:<br>";
echo "$stock1<br>";
echo "$stock2<br>";
echo "$stock3<br>";
echo "$stock4<br>";
//生成页面其余代码
//将数据保存到数据库中
page_close();
?>
--------------------------------------------------------------------------------
如你所见,一旦你放下PHP4版本,理解PHPLIB版并不因难 -- 当你知道了PHP4中的对session的内部支
持很大程度上基于PHPLIB模块你就不会感到奇怪了。如果你感兴趣,PHPLIB实际上在对session的管理中,
对身份认证和权限的类更加深入,它允许你在基于数据库的认证管理上,给一个用户允许或禁止处理的权力
-- 可以看一下文档中关于如何使用这些特性的例子。
PHPLIB也提供一些有趣的内建函数。
unregister(variable)
允许你从一个特别的session中注销一个变量。注意在那种情况下,变量并没有被删除,可是它的值将
会在页尾丢失,因为它不再被保存到数据库中。
--------------------------------------------------------------------------------
<?php
page_open(array("sess" => "Example_Session"));
//注册一个变量
$sess->register('username');
//检查是否它已经被注册了
if($sess->is_registered('username'))
{
echo "Variable "username" is registered!<br>";
}
else
{
echo "Variable "username" is unregistered!<br>";
}
//注销一个变量
$sess->unregister('username');
//检查是否已经被注销
if($sess->is_registered('username'))
{
echo "Variable "username" is registered!<br>";
}
else
{
echo "Variable "username" is unregistered!<br>";
}
page_close();
?>
--------------------------------------------------------------------------------
is_registered(variable)
如果在一个session已经被注册了,返回true,否则返回false。
--------------------------------------------------------------------------------
<?php
page_open(array("sess" => "Example_Session"));
if($sess->is_registered('username'))
{
echo "A session variable by the name "username" already
exists";
}
else
{
$sess->register('username');
}
page_close();
?>
--------------------------------------------------------------------------------
delete()
释放当前的session。
要注意地有趣的一点是:在PHPLIB的cookie模式中,有可能在调用过delete()之后开始一个新的session,
在客户端设置一个新的cookie,甚至重新注册一些以前session的变量 -- 可以从根本上使改变session象飞
一样。当然,你象这样做事情,你需要让你的生活...快起来!
url($url)
充许你将用户重定向到一个新的页面。
self_url()
返回一个当前页的URL的引用,包括PHP_SELF和QUERY_STRING信息。
那么在最后,对那些不幸拥有一个不提供PHP4和PHPLIB的ISP的你来说 -- 记住,通过好的cookie 技术
总是可能模拟出session来的。你所要做的只是设置一个带有信息的cookie ,用来长期保留用户对你的站点
的访问过程,每次在用户访问一个新页面的时候处理这个信息。很原始 -- 但是它可以工作,而且有时你也
不能将能够做成一件事的简单方法打死!
病人离开医院
病人: 哇哦,医生 -- 太好了!非常感谢你做的一切!
心理医生: 没问题,维克多。我很乐意帮助你。现在感觉好点吗?
病人: 噢,轻松!当我刚进来时,整个天看上去都是灰色和阴沉的 -- 现在,这个雨蓬窗户外面的景色从来
没有那么好过...
心理医生: 恩...维克多...如果我是你在外面会很小心,扶手有一点坏了,在那可能不太安全。
病人: 别担心,医生 -- 象这样的天,我感到神...圣...啊啊!!!!
责任编辑:semirock