深入讲解PHP Session及如何保持其不过期的方法


Posted in PHP onAugust 18, 2015

SESSION的实现中采用COOKIE技术,SESSION会在客户端保存一个包含session_id(SESSION编号)的COOKIE;在服务器端保存其他session变量,比如session_name等等。当用户请求服务器时也把session_id一起发送到服务器,通过 session_id提取所保存在服务器端的变量,就能识别用户是谁了。同时也不难理解为什么SESSION有时会失效了。

当客户端禁用COOKIE时(点击IE中的“工具”—“Internet选项”,在弹出的对话框里点击“安全”—“自定义级别”项,将“允许每个对话COOKIE”设为禁用),session_id将无法传递,此时 SESSION失效。不过php5在linux/unix平台可以自动检查cookie状态,如果客户端设置了禁用,则系统自动把session_id附加到url上传递。windows主机则无此功能。

Session常见函数及用法?
Session_start() :开始一个会话或者返回已经存在的会话。
说明:这个函数没有参数,且返回值均为true。如果你使用基于cookie的session(cookie-based sessions),那么在使用Session_start()之前浏览器不能有任何输出,否则会发生以下错误:
Warning: Cannot send session cache limiter - headers already sent (output started at /usr/local/apache/htdocs/cga/member/1.php:2)…………

你可以在php.ini里启动session.auto_start=1,这样就无需每次使用session之前都要调用session_start()。但启用该选项也有一些限制,如果确实启用了 session.auto_start,则不能将对象放入会话中,因为类定义必须在启动会话之前加载以在会话中重建对象。
请求结束后所有注册的变量都会被序列化。已注册但未定义的变量被标记为未定义。在之后的访问中这些变量也未被会话模块定义,除非用户以后定义它们。

警告: 有些类型的数据不能被序列化因此也就不能保存在会话中。包括 resource 变量或者有循环引用的对象(即某对象将一个指向自己的引用传递给另一个对象)。

注册SESSION变量 :
PHP5使用$_SESSION[‘xxx']=xxx注册SESSION全局变量。和GET,POST,COOKIE的使用方法相似。
注意:session_register(),session_unregister ,session_is_registered在php5下不再使用,除非在php.ini里把register_globle设为on,不过出于安全考虑,强烈建议关闭register_globle。HTTP_SESSION_VARS也不提倡使用了,官方建议用$_SESSION代替之。例如:

    Page1.php

<?php
  Session_start(); //使用SESSION前必须调用该函数。

  $_SESSION[‘name']=”我是黑旋风李逵!”; //注册一个SESSION变量

  $_SESSION[‘passwd']=”mynameislikui”;
  $_SESSION[‘time']=time();
  echo '
  通过COOKIE传递SESSION'; //如果客户端支持cookie,可通过该链接传递session到下一页。

  echo '
  . SID . '">通过URL传递SESSION';//客户端不支持cookie时,使用该办法传递session.

  ?>

    Page2.php

<?php
  session_start();
  echo $_SESSION['name']; //

  echo $_SESSION['passwd']; //

  echo date('Y m d H:i:s', $_SESSION['time']);
  echo '
  返回山一页';
  ?>

有两种方法传递一个会话 ID:

  1. cookie
  2. URL 参数

会话模块支持这两种方法。cookie 更优化,但由于不总是可用,也提供替代的方法。第二种方法直接将会话 ID 嵌入到 URL 中间去。

PHP 可以透明地转换连接。除非是使用 PHP 4.2 或更新版本,需要手工在编译 PHP 时激活。在 Unix 下,用 --enable-trans-sid 配置选项。如果此配置选项和运行时选项 session.use_trans_sid 都被激活(修改php.ini),相对 URI 将被自动修改为包含会话 ID。

session_id
session_id() 用于设定或取得当前session_id。php5中既可以使用session_id(),也可以通过附加在url上的SID取得当前会话的session_id和session_name。
如果session_id()有具体指定值的话,将取代当前的session_id值。使用该函数前必须启动会话:session_start();
当我们使用session cookies时,如果指定了一个session_id()值,每次启动session_start()都会往客户端发送一个cookie值。不论当前session_id是否与指定值相等。
session_id()如果没有指定值,则返回当前session_id();当前会话没有启动的话,则返回空字符串。

检查session是否存在?
在以往的php版本中通常使用session_is_register()检查session是否存在,如果您使用$_SESSION[‘XXX']=XXX来注册会话变量,则session_is_register()函数不再起作用。你可以使用
isset($_SESSION[‘xxx'])来替代。

更改session_id session_regenerate_id() 更改成功则返回true,失败则返回false。
使用该函数可以为当前session更改session_id,但不改变当前session的其他信息。例如:

<?php
  session_start();
  $old_sessionid = session_id();
  session_regenerate_id();
  $new_sessionid = session_id();
  echo "原始 SessionID: $old_sessionid
  ";
  echo "新的 SessionID: $new_sessionid
  ";
  echo"

  ";

  print_r($_SESSION);
  echo"";
  ?>

session_name() 返回当前session的name或改变当前session的name。如果要改变当前session的name,必须在session_start() 之前调用该函数。注意:session_name不能只由数字组成,它至少包含一个字母。否则会在每时每刻都生成一个新的session id.
session改名示例:

$previous_name = session_name("WebsiteID");
echo "新的session名为: $previous_name
";
?>

如何删除session?
1、unset ($_SESSION['xxx']) 删除单个session,unset($_SESSION['xxx']) 用来unregister一个已注册的session变量。其作用和session_unregister()相同。 session_unregister()在PHP5中不再使用,可将之打入冷宫。
unset($_SESSION) 此函数千万不可使用,它会将全局变量$_SESSION销毁,而且还没有可行的办法将其恢复。用户也不再可以注册$_SESSION变量。
2、$_SESSION=array() 删除多个session
3、 session_destroy()结束当前的会话,并清空会话中的所有资源。。该函数不会unset(释放)和当前session相关的全局变量 (globalvariables),也不会删除客户端的session cookie.PHP默认的session是基于cookie的,如果要删除cookie的话,必须借助setcookie()函数。
返回值:布尔值。
功能说明:这个函数结束当前的session,此函数没有参数,且返回值均为true

session_unset() 如果使用了$_SESSION,则该函数不再起作用。由于PHP5必定要使用$_SESSION,所以此函数可以打入冷宫了。

下面是PHP官方关于删除session的案例:

<?php
  // 初始化session.

  session_start();
  /*** 删除所有的session变量..也可用unset($_SESSION[xxx])逐个删除。****/
  $_SESSION = array();
  /***删除sessin id.由于session默认是基于cookie的,所以使用setcookie删除包含session id的cookie.***/
  if (isset($_COOKIE[session_name()])) {
  setcookie(session_name(), '', time()-42000, '/');
  }

// 最后彻底销毁session.

  session_destroy();
  ?>

由此我们可以得出删除Session的步骤:

  1. session_start()
  2. $_SESSION=array()/unset($_SESSION['xxx'])
  3. session_destroy()

解决PHP Session不过期以及SessionId保持不变的问题

session 回收机制:
 
PHP采用Garbage Collection process对过期session进行回收,然而并不是每次session建立时,都能够唤起 ‘garbage collection' process ,gc是按照一定概率启动的。这主要是出于对服务器性能方面的考虑,每个session都触发gc,浏览量大的话,服务器吃不消,然而按照一定概率开启gc,当流览量大的时候,session过期机制能够正常运行,而且服务器效率得到节省。细节应该都是多年的经验积累得出的。
 
三个与PHP session过期相关的参数(php.ini中):
 

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

gc启动概率 = gc_probability / gc_divisor = 0.1%
 
session过期时间 gc_maxlifetime 单位:秒
 
当web服务正式提供时,session过期概率就需要根据web服务的浏览量和服务器的性能来综合考虑session过期概率。为每个session都开启gc,显然是不明智的,感觉有点“碰运气”的感觉,要是访问量小命中几率就小。我在本机测试过程中,几乎都没有被命中过,sessionid几天都不变,哪怕机器重启。测试过程中,这个过期概率值要设置大一点命中几率才高点。
 
通过修改php配置文件的过期概率值,可以“碰运气”式的设置session过期,那有没有更好的办法呢?
 

下面写的这个session类可以彻底解决session不过期以及sessionid不变的问题。
 

<?php
 /**
 * 扩展Session类(简单封装)
 * 
 * @author slimboy
 *
 */
class Session { 
 
   /**
   * 初始化
   */
  static function _init(){ 
    ini_set('session.auto_start', 0); 
    //Session::start(); 
   } 
   
   /**
   * 启动Session
   */
  static function start() { 
    session_start(); 
  } 
 
   /**
   * 设置Session
   * 
   * @param $name Session名称
   * @param $value 值
   * @param $time 超时时间(秒)
   */
  public static function set($name,$value,$time){ 
    if(empty($time)){ 
      $time = 1800; //默认值 
     } 
    $_SESSION[$name] = $value; 
    $_SESSION[$name.'_Expires'] = time() + $time; 
  } 
   
   /**
   * 获取Session值
   * 
   * @param $name Session名称
   */
  public static function get($name){ 
    //检查Session是否已过期 
     if(isset($_SESSION[$name.'_Expires']) && $_SESSION[$name.'_E
 xpires']>time()){ 
      return $_SESSION[$name]; 
    }else{ 
      Session::clear($name); 
      return null; 
    } 
  } 
   
    
   /**
   * 设置Session Domain
   * 
   * @param $sessionDomain 域
   * @return string
   */
  static function setDomain($sessionDomain = null) { 
    $return = ini_get('session.cookie_domain'); 
    if(!empty($sessionDomain)) { 
      ini_set('session.cookie_domain', $sessionDomain);//跨
 域访问Session 
     } 
    return $return; 
  } 
   
    
   /**
   * 清除某一Session值
   * 
   * @param $name Session名称
   */
  static function clear($name){ 
    unset($_SESSION[$name]); 
    unset($_SESSION[$name.'_Expires']); 
  } 
   
    
   /**
   * 重置销毁Session
   */
  static function destroy(){ 
    unset($_SESSION); 
    session_destroy(); 
  } 
   
    
   /**
   * 获取或设置Session id
   */
  static function sessionid($id=null){ 
    return session_id($id); 
  } 
 
}
?>
简单调用:
 
<?php
  //设置session 
  Session::set('UserId', $userid, 3600); 
  //读取session
  $userId = Session::get('UserId');
?>
PHP 相关文章推荐
模板引擎Smarty深入浅出介绍
Dec 06 PHP
一些使用频率比较高的php函数
Oct 03 PHP
php连接mssql数据库的几种方法
Feb 21 PHP
关于PHP的curl开启问题探讨
Apr 08 PHP
一个php短网址的生成代码(仿微博短网址)
May 07 PHP
让CodeIgniter的ellipsize()支持中文截断的方法
Jun 12 PHP
PHP+jQuery 注册模块开发详解
Oct 14 PHP
PHP使用ob_start生成html页面的方法
Nov 07 PHP
php实现比较两个字符串日期大小的方法
May 12 PHP
php使用APC实现实时上传进度条功能
Oct 26 PHP
Yii视图操作之自定义分页实现方法
Jul 14 PHP
Zend Framework入门教程之Zend_Config组件用法详解
Dec 09 PHP
php微信公众平台开发之获取用户基本信息
Aug 17 #PHP
PHP添加图片水印、压缩、剪切的封装类
Aug 17 #PHP
php中switch语句用法详解
Aug 17 #PHP
Linux系统下PHP-FPM的安装和配置教程
Aug 17 #PHP
PHP连接Nginx服务器并解析Nginx日志的方法
Aug 16 #PHP
ThinkPHP开发框架函数详解:C方法
Aug 14 #PHP
提高php编程效率技巧
Aug 13 #PHP
You might like
PHP生成树的方法
2015/07/28 PHP
php搜索文件程序分享
2015/10/30 PHP
php实现统计目录文件大小的函数
2015/12/25 PHP
php导出csv文件,可导出前导0实例代码
2016/11/16 PHP
浅谈关于PHP解决图片无损压缩的问题
2017/09/01 PHP
php微信公众号开发之微信企业付款给个人
2018/10/04 PHP
PHP addAttribute()函数讲解
2019/02/03 PHP
jquery ajax jsonp跨域调用实例代码
2013/12/11 Javascript
三种方式获取XMLHttpRequest对象
2014/04/21 Javascript
javascript制作坦克大战全纪录(2)
2014/11/27 Javascript
JS根据生日算年龄的方法
2015/05/05 Javascript
js中 计算两个日期间的工作日的简单实例
2016/08/08 Javascript
基于JavaScript实现移动端无限加载分页
2017/03/27 Javascript
Node.js  REPL (交互式解释器)实例详解
2017/08/06 Javascript
vue.js异步上传文件前后端实现代码
2017/08/22 Javascript
JS闭包经典实例详解
2018/12/20 Javascript
详解使用mocha对webpack打包的项目进行&quot;冒烟测试&quot;的大致流程
2020/04/27 Javascript
Python中操作MySQL入门实例
2015/02/08 Python
Python实现SSH远程登陆,并执行命令的方法(分享)
2017/05/08 Python
pycharm远程调试openstack的图文教程
2017/11/21 Python
python版学生管理系统
2018/01/10 Python
python numpy 显示图像阵列的实例
2018/07/02 Python
python获取交互式ssh shell的方法
2019/02/14 Python
python实现的读取网页并分词功能示例
2019/10/29 Python
Python稀疏矩阵及参数保存代码实现
2020/04/18 Python
Python多分支if语句的使用
2020/09/03 Python
Python如何使用vars返回对象的属性列表
2020/10/17 Python
Python的轻量级ORM框架peewee使用教程
2021/02/05 Python
详解canvas.toDataURL()报错的解决方案全都在这了
2020/03/31 HTML / CSS
美国韩国化妆品和护肤品购物网站:Beautytap
2018/07/29 全球购物
基层干部2014全国两会学习心得体会
2014/03/10 职场文书
租赁意向书范本
2014/04/01 职场文书
岗位职责说明书
2014/05/07 职场文书
电影红河谷观后感
2015/06/11 职场文书
请学会珍惜眼前,因为人生没有下辈子!
2019/11/12 职场文书
pandas:get_dummies()与pd.factorize()的用法及区别说明
2021/05/21 Python