理解PHP中的Session及对Session有效期的控制


Posted in PHP onJanuary 08, 2016

0.什么是session?
       Session的中文译名叫做“会话”,其本来的含义是指有始有终的一系列动作/消息,比如打电话时从拿起电话拨号到挂断电话这中间的一系列过程可以称之为一个session。目前社会上对session的理解非常混乱:有时候我们可以看到这样的话“在一个浏览器会话期间,...”,这里的会话是指从一个浏览器窗口打开到关闭这个期间;也可以看到“用户(客户端)在一次会话期间”这样一句话,它可能指用户的一系列动作(一般情况下是同某个具体目的相关的一系列动作,比如从登录到选购商品到结账登出这样一个网上购物的过程;然而有时候也可能仅仅是指一次连接;其中的差别只能靠上下文来推断了。
       然而当session一词与网络协议相关联时,它又往往隐含了“面向连接”和/或“保持状态”这样两个含义,“面向连接”指的是在通信双方在通信之前要先建立一个通信的渠道,比如打电话,直到对方接了电话通信才能开始。“保持状态”则是指通信的一方能够把一系列的消息关联起来,使得消息之间可以互相依赖,比如一个服务员能够认出再次光临的老顾客并且记得上次这个顾客还欠店里一块钱。这一类的例子有“一个TCP session”或者“一个POP3 session”。
       鉴于这种混乱已不可改变,要为session下个定义就很难有统一的标准。而在阅读session相关资料时,我们也只有靠上下文来推断理解了。不过我们可以这样理解:例如我们打电话,从拨通的那一刻起到挂断电话期间,因为电话一直保持着接通的状态,所以把这种接通的状态叫做session。它是访客与整个网站交互过程中一直存在的公有变量,在客户端不支持COOKIE的时候,为了保证数据正确、安全,就采用SESSION变量。访问网站的来客会被分配一个唯一的标识符,即所谓的会话 ID。它要么存放在客户端的 cookie,要么经由 URL 传递。
       SESSION的发明填补了HTTP协议的局限:HTTP协议被认为是无状态协议,无法得知用户的浏览状态,当它在服务端完成响应之后,服务器就失去了与该浏览器的联系。这与HTTP协议本来的目的是相符的,客户端只需要简单的向服务器请求下载某些文件,无论是客户端还是服务器都没有必要纪录彼此过去的行为,每一次请求之间都是独立的,好比一个顾客和一个自动售货机或者一个普通的(非会员制)大卖场之间的关系一样。
       因此通过SESSION(cookie是另外一种解决办法)记录用户的有关信息,以供用户再次以此身份对web服务器提起请求时作确认。会话的发明使得一个用户在多个页面间切换时能够保存他的信息。网站编程人员都有这样的体会,每一页中的变量是不能在下一页中使用的(虽然form,url也可以实现,但这都是非常不理想的办法),而SESSION中注册的变量就可以作为全局变量使用了。
       那么SESSION到底有什么用处呢?网上购物时大家都用过购物车,你可以随时把你选购的商品加入到购物车中,最后再去收银台结帐。在整个过程中购物车一直扮演着临时存贮被选商品的角色,用它追踪用户在网站上的活动情况,这就是SESSION的作用,它可以用于用户身份认证,程序状态记录,页面之间参数传递等。
       SESSION 的实现中采用COOKIE技术,SESSION会在客户端保存一个包含session_id(SESSION编号)的COOKIE;在服务器端保存其他 session变量,比如session_name等等。当用户请求服务器时也把session_id一起发送到服务器,通过session_id提取所保存在服务器端的变量,就能识别用户是谁了。同时也不难理解为什么SESSION有时会失效了。
       当客户端禁用COOKIE时(点击IE中的“工具”—“internet="">Internet选项”,在弹出的对话框里点击“安全”—“自定义级别”项,将“允许每个对话COOKIE”设为禁用),session_id将无法传递,此时SESSION失效。不过php5在linux/unix平台可以自动检查cookie状态,如果客户端设置了禁用,则系统自动把session_id附加到url上传递。windows主机则无此功能。    

1.php session 有效期

php的session有效期默认是1440秒(24分钟),如果客户端超过24分钟没有刷新,当前session会被回收,失效。
当用户关闭浏览器,会话结束,session也会失效。

可以修改php.ini的session.gc_maxlifetime来设置session的生命周期,但并不能保证在超过这一时间后session信息立即会删除。因为GC是按机率启动的,可能在某一个长时间内都没有被启动。那么大量的session在超过session.gc_maxlifetime后仍然有效。

2.session.gc_maxlifetime,session.gc_probability,session.gc_divisor说明

session.gc_maxlifetime = 30 表示当session文件在30秒后没有被访问,则视为过期session,等待GC回收。

GC进程调用的概率是通过session.gc_probability/session.gc_divisor计算得来的,而session.gc_divisor默认是1000,
如果session.gc_probability = 1000,那么GC进程在每次执行session_start()时都会调用,执行回收。

把session.gc_probability/session.gc_divisor的机率提高,会有帮助,但会对性能造成严重影响。

3.严格控制session过期方法

(1).使用memcache/redis来保存session,设置过期时间,因为memcache/redis的回收机制不是按机率的,可以确保session过期后失效。

(2).只使用php实现,创建一个session类,在session写入时,把过期时间也写入。读取时,根据过期时间判断是否已过期。

<?php
/**
 * Session控制类
 */
class Session{

  /**
   * 设置session
   * @param String $name  session name
   * @param Mixed $data  session data
   * @param Int  $expire 超时时间(秒)
   */
  public static function set($name, $data, $expire=600){
    $session_data = array();
    $session_data['data'] = $data;
    $session_data['expire'] = time()+$expire;
    $_SESSION[$name] = $session_data;
  }

  /**
   * 读取session
   * @param String $name session name
   * @return Mixed
   */
  public static function get($name){
    if(isset($_SESSION[$name])){
      if($_SESSION[$name]['expire']>time()){
        return $_SESSION[$name]['data'];
      }else{
        self::clear($name);
      }
    }
    return false;
  }

  /**
   * 清除session
   * @param String $name session name
   */
  private static function clear($name){
    unset($_SESSION[$name]);
  }

}
?>

demo:

<?php
session_start();

$data = '123456';
session::set('test', $data, 10);
echo session::get('test'); // 未过期,输出
sleep(10);
echo session::get('test'); // 已过期
?>
PHP 相关文章推荐
提升PHP执行速度全攻略(下)
Oct 09 PHP
PHP调用三种数据库的方法(1)
Oct 09 PHP
php获取中文拼音首字母类和函数分享
Apr 24 PHP
PHP中使用gettext解决国际化问题的例子(i18n)
Jun 13 PHP
php验证session无效的解决方法
Nov 04 PHP
php集成套件服务器xampp安装使用教程(适合第一次玩PHP的新手)
Jun 03 PHP
微信公众平台DEMO(PHP)
May 04 PHP
PHP性能优化大全(php.ini)
May 20 PHP
Thinkphp结合AJAX长轮询实现PC与APP推送详解
Jul 31 PHP
PHP实现八皇后算法
May 06 PHP
php实现快速对二维数组某一列进行组装的方法小结
Dec 04 PHP
tp5.0框架隐藏index.php入口文件及模块和控制器的方法分析
Feb 11 PHP
PHP实现搜索地理位置及计算两点地理位置间距离的实例
Jan 08 #PHP
PHP使用数组依次替换字符串中匹配项
Jan 08 #PHP
PHP 7.0.2 正式版发布
Jan 08 #PHP
深入浅析php中sprintf与printf函数的用法及区别
Jan 08 #PHP
PHP中each与list用法分析
Jan 08 #PHP
PHP中list()函数用法实例简析
Jan 08 #PHP
PHP图像裁剪缩略裁切类源码及使用方法
Jan 07 #PHP
You might like
实现 win2003 下 mysql 数据库每天自动备份
2006/12/06 PHP
php 前一天或后一天的日期
2008/06/28 PHP
joomla内置的表单验证功能使用方法
2010/06/11 PHP
setcookie中Cannot modify header information-headers already sent by错误的解决方法详解
2013/05/08 PHP
PHP自定义函数实现格式化秒的方法
2016/09/14 PHP
用JavaScript脚本实现Web页面信息交互
2006/10/11 Javascript
js中判断用户输入的值是否为空的简单实例
2013/12/23 Javascript
JavaScript事件委托用法分析
2015/01/24 Javascript
JavaScript常用脚本汇总(二)
2015/03/04 Javascript
Javascript数组Array基础介绍
2016/03/13 Javascript
jquery实现网站列表切换效果的2种方法
2016/08/12 Javascript
原生js实现返回顶部缓冲效果
2017/01/18 Javascript
jQuery获取Table某列的值(推荐)
2017/03/03 Javascript
ES6中Proxy与Reflect实现重载(overload)的方法
2017/03/30 Javascript
详解vue中computed 和 watch的异同
2017/06/30 Javascript
nodeJS(express4.x)+vue(vue-cli)构建前后端分离实例(带跨域)
2017/07/05 NodeJs
vue.js中$set与数组更新方法
2018/03/08 Javascript
vue-cli4.x创建企业级项目的方法步骤
2020/06/18 Javascript
Python科学画图代码分享
2017/11/29 Python
浅谈Tensorflow由于版本问题出现的几种错误及解决方法
2018/06/13 Python
对Python 两大环境管理神器 pyenv 和 virtualenv详解
2018/12/31 Python
对Python信号处理模块signal详解
2019/01/09 Python
python实现一个简单的ping工具方法
2019/01/31 Python
Python 解决相对路径问题:&quot;No such file or directory&quot;
2020/06/05 Python
Python基于Faker假数据构造库
2020/11/30 Python
PyQt实现计数器的方法示例
2021/01/18 Python
详解CSS3中常用的样式【基本文本和字体样式】
2020/10/20 HTML / CSS
html5 Canvas画图教程(1)—画图的基本常识
2013/01/09 HTML / CSS
特罗佩亚包官方网站:Tropea
2017/01/03 全球购物
发现世界上最好的珠宝设计师:JewelStreet
2017/12/17 全球购物
英国户外装备商店:Ultimate Outdoors
2019/05/07 全球购物
What's the difference between Debug and Trace class? (Debug类与Trace类有什么区别)
2013/09/10 面试题
马智宇结婚主持词
2014/04/01 职场文书
社区平安建设方案
2014/05/25 职场文书
音乐节策划方案
2014/06/09 职场文书
保密工作整改报告
2014/11/06 职场文书