深入理解PHP中的SESSION技术

来源:互联网 发布:2017淘宝流量突然暴跌 编辑:程序博客网 时间:2024/06/05 19:46

一、默认的存储机制——文件

PHP默认使用磁盘文件来保存 SESSION数据,即默认存储方式为 files。

php.ini中关于 SESSION的基本配置:

1、session.save_handler = files  //SESSION的存储方式2、session.save_path = 'xxx'     //存放文件的路径  2、session.name = 'PHPSESSID'    //SESSION的名称3、session.use_trans_sid = 0     //为1则表示给每个URL加上 SESSION名 = 会话Id,一般情况下不建议开启,不安全4、session.cookie.lifetime = 0   /*即存储session_id的 COOKIE 的保存时间,只要 COOKIE还在,客户端就能通过 session_id 来找到之前的 SESSION 数据。默认为0,COOKIE保存在服务器内存中,因此关闭浏览器之后,就找不到之前的SESSION数据了,因为保存会话id的COOKIE已经失效了,这也是为什么 SESSION数据只能在同一次会话中获取了。设置为大于0的数,则 SESSION 可以在多次会话中获取,知道 COOKIE 过期*/

1、session_start

1、session_start() 是 session机制的开始,它有一定概率开启垃圾回收机制,因为 session是存放在文件中的,所以垃圾回收机制会去删除那些已经过期了的磁盘文件。

这个开启垃圾回收的概率是根据php.ini的配置决定的,但是有的系统是 session.gc_probability =0,这也就是说概率是0,而是通过cron脚本来实现垃圾回收。   

session.gc_probability =1session.gc_divisor =1000session.gc_maxlifetime =1440

启动垃圾回收机制的概率是 session.gc_probability / session.gc_divisor,(网站访问量很大时,建议把这个值设置小一点)。
而 session.gc_maxlifetime表示session默认最大生命周期,若在这个期间秒内访问了该session,则重新计时。

2、如果在使用 session_start() 之前没有通过 session_id() 函数手动设置id,session会判断当前是否有 $_COOKIE[session_name()](session_name()返回session名)。

3、如果第2步中得到了id,则会去 session.save_path 指定的目录里寻找名为 ‘SESS_’. session_id() 的文件,读取文件的内容并反序列化成数组,然后赋给 $_SESSION数组。

4、如果第2步中没有得到id,即既没有手动设置,也没有相应 COOKIE,或者找不到对应的 SESSION 文件,则生成一个UUID来作为session_id,并在发送响应时将session_id以COOKIE的方式发送到客户端。

相当于执行了下面 COOKIE 操作,注意的是,这只是模拟操作,COOKIE实际上是在header头中发送的,因此这之前是不能有输出的, 同理还有session_regenerate_id()。

    setcookie(session_name(),              session_id(),              //生成一个id              session.cookie_lifetime,  //默认0,即会话结束后就cookie就消失              session.cookie_path,      //默认'/'当前程序根目录下都有效              session.cookie_domain,    //默认为空             )

2、为$_SESSION赋值

比如新添加一个值 $_SESSION[‘t’] =’a’; 那么这个$_SESSION 会先保存在内存中,当脚本执行结束的时候,再把 $_SESSION 数组序列化之后写入到 ‘SESS_’ . session_id() 文件中,然后关闭相关资源。

这个阶段可以执行更改 session_id 的操作,比如销毁一个旧的session_id,生成一个新的 session_id。一般用在自定义 SESSION 机制角色的转换上,比如匿名用户持有一个 session_id,当它登录后需要更换新的 session_id:

 if (isset($_COOKIE[session_name()])) {      setcookie(session_name(), '', time() - 42000, '/');  //旧session cookie过期  }  session_regenerate_id();//这一步会生成新的session_id  //然后继续操作 SESSION

3、写入SESSION文件

在脚本结束的时候会将 $_SESSION 数组经序列化后写入到’SESS_’. session_id() 文件中。

4、 销毁SESSION

默认情况下,SESSION发出去的COOKIE属于即时COOKIE,保存在客户端内存中,当浏览器关闭后,就会消失。

假如有时需要人为强制过期,而不是关闭浏览器时才过期,比如退出登录等情况,那么就需要在代码里手动销毁 SESSION 数据,方法有几种:

  1. setcookie(session_name(), ”, time() -8000000, ..);//让客户端保存的COOKIE过期
  2. unset($_SESSION); //直接删除所有的 $_SESSION数据,用户通过session_id取得的SESSION是空的
  3. session_destroy(); //直接删除对应的SESSION文件

当不关闭浏览器的情况下,再次刷新,2和3情况下,用户依然持有 session_id,但是已经得不到任何SESSION数据了。而1情况下,用户的访问已经找不到之前设置的SESSION了。

1.可以在 URL 里添加一个PHPSESSID=>sesssion_id
在页面加入:

      if(isset($_GET[‘PHPSESSID’]){           //手动设置 sesssion_id           session_id($_GET[‘PHPSESSID’]);      }      //程序会寻找该session_id对应的SESSION文件        session_start();      //获得数据 

2.可以启用session.use_trans_sid来指定是否启用透明 SID 支持 ,即在每个URL中的Query部分加上session_name=session_id。(对JS中的URL不起作用。)

php.ini中:

session.use_trans_sid = 1 

这样,即使禁用了 COOKIE,也能在跨页时传递 SESSION变量了。

二、自定义 SESSION 存储方式

首先将 php.ini 文件中的 session.save_handler 设置为 user。
然后通过 session_set_save_handler(‘open’,’close’,’read’,’write’,’destroy’,’gc’) 函数来实现。这6个回调函数必须返回 TRUE/FALSE 。

下面是个简单的例子,与默认的files处理机制类似。可以通过下面的例子来进一步掌握默认机制的原理,也可以方便地扩展,比如使用数据库保存SESSION。

注意,ssesion_id 的传递依然是使用COOKIE,只是保存 SESSION 数据的方式改变了。

//  执行 session_start() 后执行的第一个回调函数function open($save_path, $session_name){    global $sess_save_path;  //  声明为全局变量是为了让之后回调的函数能访问该变量    if (!is_dir($save_path)) {        mkdir($save_path);    }    $sess_save_path = $save_path;  //  $save_path 为 session.save_path    return(true);}function close(){    return(true);}function read($id){    global $sess_save_path;    $sess_file = "$sess_save_path/yyy_$id";    return (string) file_get_contents($sess_file);}function write($id, $sess_data){    global $sess_save_path;    $sess_file = "$sess_save_path/yyy_$id";    return file_put_contents($sess_file, $sess_data) === false? false : true;}//  session_destory()函数的工作原理。function destroy($id){    global $sess_save_path;    $sess_file = "$sess_save_path/yyy_$id";    return(@unlink($sess_file));}//  执行session_start()时,一定几率执行该函数,$maxlifetime 为配置项 session.gc_maxlifetime 的值function gc($maxlifetime){    global $sess_save_path;    foreach (glob("$sess_save_path/yyy_*") as $filename) {        if (filemtime($filename) + $maxlifetime < time()) {            @unlink($filename);        }    }    return true;}session_set_save_handler("open", "close", "read", "write", "destroy", "gc");session_start();/*...*/
1 0