Thursday, July 30, 2009

自定义Session handler时 session_id() 发送 set-cookie头的处理

自定义的Session Handler,在 session_start 之前,做了如下处理
<?php
static protected function _config()
{
session_name(SS_SESSION_NAME);

session_set_cookie_params(
SS_SESSION_EXPIRATION ? SS_SESSION_EXPIRATION + parent::$buclass->timestamp : 0,
SS_COOKIE_PATH,
SS_COOKIE_DOMAIN,
SS_COOKIE_SECURE,
SS_COOKIE_HTTPONLY
);

global $table_sessions;
self::$_table_sessions = & $table_sessions;

# 如果要通过URL传递Session ID
if (SS_SESSION_PASSSIDVIAURL)
{
$sess_id = parent::$buclass->gpc->get(SS_SESSION_NAME);
}
else
{
$sess_id = parent::$buclass->gpc->cookie(SS_SESSION_NAME);
}

if (!empty($sess_id))
{
if (!preg_match('#^[a-zA-Z0-9]+$#', $sess_id))
{
throw new Exception('不合法的SESSION ID');
}

session_id($sess_id);
}
} ?>


每次刷新页面的时候,都发现http响应中有Set-Cookie的头,设置session name的。翻了翻php手册,http://www.php.net/session_id,参数的地方,有个Note
Note: When using session cookies, specifying an id for session_id() will always send a new cookie when session_start() is called, regardless if the current session id is identical to the one being set. 


于是,每次调用 session_id($sess_id); 这句的时候,都会发送一个set-cookie头。

回到代码,代码的设计是为了考虑到URL传递Session ID的情况,所以分别允许GET方式和COOKIE方式获取session name的值。
而代码里明显可以看到,这里获取 $_GET 和 $_COOKIE的值,并不是直接用这些超级全局变量的,而是通过了一个 gpc的类对象。自己写的一个gpc变量的封装,里边把$_GET, $_POST, $_COOKIE, $_FILES, $_REQUEST的值先加了引用,然后unset了。

结果。。。默认设置情况下,unset了$_COOKIE的值,或者说unlink了$_COOKIE对cookie变量的引用,session机制无法获取 session id,从而代码里会反复地设置session 的cookie变量。

Newborn Project里,gpc的unset变量环节是独立的,也就是
系统初始化->初始化核心类->初始化gpc->初始化session->清理gpc的变量(unset)...
而这里,
系统初始化->初始化核心类->初始化gpc(外加清理gpc的变量(unset))->初始化session...

结果又出问题了。。。

暂时没想出不增加gpc类与其他类耦合度的方法


==================================================================

Update:
最终还是决定跟Newborn Project一样把unset vars的操作单提出来

<?php
static protected function _config()
{
session_name(SS_SESSION_NAME);

session_set_cookie_params(
SS_SESSION_EXPIRATION ? SS_SESSION_EXPIRATION + parent::$buclass->timestamp : 0,
SS_COOKIE_PATH,
SS_COOKIE_DOMAIN,
SS_COOKIE_SECURE,
SS_COOKIE_HTTPONLY
);
global $table_sessions;
self::$_table_sessions = & $table_sessions;

# 如果要通过URL传递Session ID
if (SS_SESSION_PASSSIDVIAURL)
{
$sess_id = parent::$buclass->gpc->get(SS_SESSION_NAME);
if (!empty($sess_id))
{
session_id($sess_id);
}
}
else
{
if (!($sess_id = parent::$buclass->gpc->cookie(SS_SESSION_NAME))==$_COOKIE[SS_SESSION_NAME])
{
session_id($sess_id);
}
}
}



<?php
public function s_init()
{
buComponent::$buclass = & $this;

$this->_init_vars();

$this->filter = buFilter::instance();
$this->cache = buCache::instance();

$this->_init_gpc();
$this->_init_cookie();

if (SS_INTERFACE == SS_INTERFACE_WEB)
{
$this->_init_session();
}
else
{
$this->db_open();
}

$this->gpc->unset_vars();
}

No comments:

Post a Comment