Drupal专业开发指南 第16章 会话生命周期

 

16-1展示了会话生命周期。当一个浏览器向服务器发送一个请求时,会话开始。在Drupal的引导指令流程(参看includes/bootstrap.inc)的DRUPAL_BOOTSTRAP_SESSION阶段,会话代码开始运行。如果浏览器没有出示一个已有的cookie,那么PHP的会话管理系统将为浏览器分配一个新cookie,里面包含了一个新的PHP会话ID。这个ID通常是一个32位的唯一的MD5哈希字符串。当然,PHP5允许你将配置指令session.hash_function设置为1,这样你就可以使用SHA-1哈希,来得到40位的字符串作为会话ID。
 
注意 MD5是一个计算文本字符串哈希值的算法,也是Drupal中选用的哈希算法。关于MD5和其它哈希算法的更多信息,请参看http://en.wikipedia.org/wiki/Cryptographic_hash_functions
 
    Drupal接着以该会话ID为键,来检查在表sessions中是否存在相应的记录。如果存在的话,那么includes/sessions.inc中的函数sess_read()将取回会话数据,并进行一次SQL JOIN操作,对sessions表中的记录与users表中的对应记录进行联合。这一联合的结果是得到了一个对象,它包含了两条记录的所有字段和值。这就是$user对象,在Drupal中经常使用的一个全局变量(参看第6章)。那么,通过查看$user对象,具体一点就是$user->session, $user->sid, $user->hostname, $user->timestamp,和$user->cache,也可以访问会话数据。在sess_read()中,当前用户的角色也被查找出来并分配给$user->roles。
    对于会话中的用户ID,如果在users表中,没有一个对应的用户ID与之匹配,那么会发生什么呢?这个问题具有欺骗性。由于Drupal的安装器在users表中创建了一个用户ID为0的记录,而且匿名用户在sessions表中的uid被指定为0,所以联合总是成功的。
 
警告 对于你的Drupal安装,永远不要删除users表中的所有记录。因为,为了让Drupal正常工作,该表中必须包含一条用户ID为0的记录。
 
    如果你想找出用户访问一个页面的最后时间,你可以使用$user->timestamp(记住,它来自于sessions表),或者使用$user->access,后者保存在users表中。对于这两者来说,$user->timestamp如果存在的话,那么它会更精确一点,这是因为$user->access的更新受限于节流,默认情况下180秒才更新一次。通过设置Drupal变量session_write_interval,可以修改这个值。这里是includes/session.inc中sess_write()函数的代码片断:
 
// Last access time is updated no more frequently than once every 180 seconds.
// This reduces contention in the users table.
$session_write_interval = variable_get('session_write_interval', 180);
if ($user->uid && time() - $user->access > $session_write_interval) {
    db_query("UPDATE {users} SET access = %d WHERE uid = %d", time(), $user->uid);
}
 
    当然,对于初次访问的用户,因为还没有保存时间戳,所以$user->timestamp和$user->access都不可用。
    当页面已被发送给浏览器时,最后一步工作就是关闭会话。PHP触发includes/session.inc里面的sess_write()函数,该函数将$_SESSION(请求期间的)中存放的所有东西都写入到sessions表中。只有当你确实需要时,还有最好能够确定该用户已被认证,这样才将数据存储在$_SESSION中。这样在网络爬虫抓取页面时,就不会向sessions表中写入数据了,而该表的大小能够直接影响到性能。
 
16-1 Drupal是如何使用会话来实例化$user对象的

老葛的Drupal培训班 Think in Drupal

Drupal版本: