提到SESSION时,对我的第一印象就是存储在服务器端;比存储在客户端的cookie来说很安全----书上和老师都是这么说的。
后来慢慢发现SESSION实际上也是要借助COOKIE的,只不过保存在COOKIE中的只是客户端的唯一SESSION标识。
那么服务器是怎么把客户端与SESSION数据关联起来的呢?
比如我们在PHP中通过“$_SESSION[键名] = 值” 的方式进行存储SESSION与“$aa = $_SESSION[键名]”的方式进行读取SESSION值。我在刚开始接触和使用SESSION时,就有一种疑惑“同样的代码却获取到不同的数据”.
如代码$uid = $_SESSION['uid'], 张三用户访问时$uid的值为15, 而李四用户访问时$uid的值为88。其中肯定有一种机制是把不同客户端访问SESSION时进行了唯一性映射。进行唯一性映射就肯定需要一个唯一的标识,而此标识正是SESSION标识。
下图是我通过firefox查看到的SESSION标识在COOKIE中的存储:
通过上图我们也得出PHP在COOKIE中保存SESSION标识时用的是PHPSESSID键名。
客户端每次向服务器发送HTTP请求时,会带上COOKIE一块发过去,这样服务器就可以把客户端与SESSION关联起来。
通过firefox查看到的客户端HTTP请求数据如下:
客户端实际上也就是指浏览器了,不同的浏览器SESSION标识是不同的,同一个浏览器的多个实例的SESSION标识是一致的。这也就是为什么我们在“IE浏览器下”登录了某个站点,在“FIREFOX”打开站点还需要重新登录下,就拿QQ空间举例来说吧:
我首先在“淘宝浏览器”进行了登录界面如下:
然后我复制浏览地址打开火狐浏览器粘贴上地址,提示让我登录,打开界面如下:
PHP提供了一个自定义SESSION存储的接口函数session_set_save_handler.通过此函数我们可以自定义SESSION的存储,例如我们可以把SESSION保存在数据库或缓存文件里。
函数说明如下:
session_set_save_handler
(PHP 4, PHP 5)
session_set_save_handler — Sets user-level session storage functions
Description
$open
,
callable$close
,
callable$read
,
callable$write
,
callable$destroy
,
callable$gc
)
Since PHP 5.4 it is possible to register the following prototype:
$sessionhandler
[,
bool $register_shutdown
= true ] )
session_set_save_handler() sets the user-level session storage functions which are used for storing and retrieving data associated with a session. This is most useful when a storage method other than those supplied by PHP sessions is preferred. i.e. Storing the session data in a local database.
Parameters
This function has two prototypes.
-
An instance of a class implementing SessionHandlerInterface, such asSessionHandler, to register as the session handler. Since PHP 5.4 only.
-
Register session_write_close() as aregister_shutdown_function() function.
sessionhandler
register_shutdown
-
The open callback works like a constructor in classes and is executed when the session is being opened. It is the first callback function executed when the session is started automatically or manually withsession_start(). Return value is
TRUE
for success,FALSE
for failure. -
The close callback works like a destructor in classes and is executed after the session write callback has been called. It is also invoked whensession_write_close() is called. Return value should be
TRUE
for success,FALSE
for failure. -
The
read
callback must always return a session encoded (serialized) string, or an empty string if there is no data to read.This callback is called internally by PHP when the session starts or whensession_start() is called. Before this callback is invoked PHP will invoke the
open
callback.The value this callback returns must be in exactly the same serialized format that was originally passed for storage to the
write
callback. The value returned will be unserialized automatically by PHP and used to populate the$_SESSION superglobal. While the data looks similar toserialize() please note it is a different format which is speficied in thesession.serialize_handler ini setting. -
The
write
callback is called when the session needs to be saved and closed. This callback receives the current session ID a serialized version the$_SESSION superglobal. The serialization method used internally by PHP is specified in thesession.serialize_handler ini setting.The serialized session data passed to this callback should be stored against the passed session ID. When retrieving this data, the
read
callback must return the exact value that was originally passed to thewrite
callback.This callback is invoked when PHP shuts down or explicitly when session_write_close() is called. Note that after executing this function PHP will internally execute the
close
callback.Note:
The "write" handler is not executed until after the output stream is closed. Thus, output from debugging statements in the "write" handler will never be seen in the browser. If debugging output is necessary, it is suggested that the debug output be written to a file instead.
-
This callback is executed when a session is destroyed with session_destroy() or withsession_regenerate_id() with the destroy parameter set to
TRUE
. Return value should beTRUE
for success,FALSE
for failure. -
The garbage collector callback is invoked internally by PHP periodically in order to purge old session data. The frequency is controlled bysession.gc_probability andsession.gc_divisor. The value of lifetime which is passed to this callback can be set insession.gc_maxlifetime. Return value should be
TRUE
for success,FALSE
for failure.
open(string $savePath, string $sessionName)
close()
read(string $sessionId)
write(string $sessionId, string $data)
destroy($sessionId)
gc($lifetime)
下面我们通过一个实例来进行观察学习。
<?php
class DatabaseSession
{
public function open()
{
session_set_save_handler (
array($this, 'openSession'),
array($this, 'closeSession'),
array($this, 'readSession'),
array($this, 'writeSession'),
array($this, 'destroySession'),
array($this, 'gcSession')
);
}
public function openSession($savePath, $sessionName)
{
echo 'openSession---> savePath:'.$savePath.' sessionName:'.$sessionName.'<br />';
return true;
}
public function closeSession()
{
echo 'closeSession---><br />';
return true;
}
public function readSession($sessionId)
{
echo 'readSession---> sessionId:'.$sessionId.'<br />';
// 通过$sessionId从数据库中拉取出数据
}
public function writeSession($sessionId, $data)
{
echo 'writeSession---> sessionId:'.$sessionId.', data:'.$data.'<br />';
// 保存数据到数据库
}
public function destroySession($sessionId)
{
echo 'destroySession---> sessionId:'.$sessionId.'<br />';
return true;
}
public function gcSession()
{
echo 'gcSession---><br />';
}
}
$seesion = new DatabaseSession();
$seesion->open();
session_start();
$_SESSION['uid']=99;
$_SESSION['name']='kite';
// session_destroy();
运行结果如下:
这里要特别注意的一点是write(string $sessionId, string $data)回调函数中$data的格式,还有就是它的调用时机。它的调用时间并不是每次$_SESSION赋值就会调用,PHP手册文档是这么解释的:This callback is invoked when PHP shuts down or explicitly when session_write_close() is called. Note that after executing this function PHP will internally execute theclose
callback.
总结:
- SESSION的数据是存储在服务器端
- SESSION需要借助COOKIE来保存客户端唯一标识
- PHP中提供的session_set_save_handler函数允许我们自定义SESSION的存储