【PHP】深入理解PHP的session。

一、具体session是用来干嘛的。

这里不详细举例,可以看文章:http://www.cnblogs.com/wangtao_20/archive/2011/02/16/1955659.html。

二、$_SESSION到底是怎么存储的。

2.1、php.ini配置解析。

$_SESSION这个变量可以存在文件中、可以存在redis\memcache中,主要看你的设置。

下面讲述的所有逻辑都是基于$_SESSION存储在memcache中(也就是下面的所有逻辑讲述都是基本本人项目的配置)。

在php.ini中有如下配置:


从上面的配置中,我们可以知道,save_handler是memcache,使用cookie,而且cookie的key是PHPSESSID。gc_maxlifetime=7200。

我们在PHP服务端写下如下代码,通过打印session_name()可以知道session的cookie的key = PHPSESSID。至于为啥session要借助于

cookie,这里不描述,请大家自行搜索。

public function forTest() {
        echo session_name();// 打印结果 = PHPSESSID
        exit();
    }

2.2、PHPSESSID是啥,我们从哪里看PHPSESSID,这个cookie的value是如何生成的。


在chrome浏览器,F12模式下,可以看到如上红框所示的cookie。


2.3、我们怎么获取$_SESSION的值。

通过在PHP中,我们打印$_SESSION,我们可以知道存储在memcache中的值格式如下所示。

其中有个key = user_info,因为,我用user_info这个key来存储了用户的登录信息。

/*
* { 
     user_info: {
         uid: "1",
         user_name: "gz****",
         token: "06d9618a69891019000748b81577a7db",
         staff_name: "**",
         login_time: "2017-08-26 15:50:04",
         login_ip: "10.1.102.31"
    }
 }*/
 exit(json_encode($_SESSION));


我门使用另外一种方式来获取这个值,因为我们知道了这个值是存储在memcache中的,那么我们可以直接通过memcache的

接口来获取这个值。下面的值是序列化的结果,具体关于PHP序列化的也有一些坑点,http://blog.spoock.com/2016/10/16/php-serialize-problem/。
具体的坑点就是使用不同的引擎结果会不一样。

$key = $_COOKIE[session_name()];
/**
 * user_info|a:6:{s:3:"uid";s:1:"1";
 * s:9:"user_name";s:6:"gz****";
 * s:5:"token";s:32:"06d9618a69891019000748b81577a7db";
 * s:10:"staff_name";s:6:"**";
 * s:10:"login_time";s:19:"2017-08-26 15:50:04";
 * s:8:"login_ip";s:11:"10.1.102.31";}
*/
$str = PubCache::memcache('default', $key);

总结:

(1)从上面我们可以知道,PHP默认的session存储方式是,当会话开始(session_start())时,通过前端浏览器传输过来的域名、
浏览器的标志等其他参数加密后得到一个值,我们称这个值是PHPSESSID_VALUE,相应的key = PHPSESSID。
(2)很明显这个值,与浏览器相关(大家可以自行测试)、与时间相关,与登录的用户名其实无关的(因为此时PHP还不知道所谓登录的用户名)。
PHP知道PHPSESSID_VALUE这个值后,PHPer可以通过$_SESSION[$key]来设置不同的值。在memcache中的存储本质就是:
PHPSESSID_VALUE: {
        'key1' : {...},
        'key2': {...},
}
比如,如果key1 = 'user_info',你就可以用来存储用户当前的登录信息。
然后向前端发送cookie。set_cookie('PHPSESSID', PHPSESSID_VALUE, ...);
我们每次通过前端发送过来的cookie,先索引到PHPSESSID这个key对应的cookie值,然后通过对应值,就可以去缓存里查到相应的数据了。


2.4、上面的模式存在很多问题。
(1)memcache会存在内存不够的问题,所以对于用户量很大的站点,要多分配该memcache进程内存;

(2)前端浏览器可能设置不支持cookie;

(3)无法做到单机登录,因为不同的浏览器PHPSESSID对应的值不一样,也即是,你在chrome浏览器上退出后,在ie浏览器上还是登录的。



三、各种session相关的需求。
3.1、原本用户在线时长最多是2h,现在想改为30天。
首先,需要在php文件的执行入口执行如下代码。要在session_start()之前(必须在此之前)改变session.cookie_lifetime、session.gc_maxlifetime的生存时间。


define('SESSION_TIME', 2592000);
ini_set('session.cookie_lifetime', SESSION_TIME);
ini_set('session.gc_maxlifetime', SESSION_TIME);
session_start();


再次,为了保证,还需要在设置$_SESSION时,再次设置。
if ( !isset($_SESSION) ) {
            ini_set("session.cookie_lifetime", defined('SESSION_TIME')?SESSION_TIME:7200);
            ini_set("session.gc_maxlifetime", defined('SESSION_TIME')?SESSION_TIME:7200);
            session_start();//判断session是否开启
        }
        if ( isset($value) ) {
            $_SESSION[$key] = $value;//设置session
            return true;
        } else {
            return isset($_SESSION[$key]) ? $_SESSION[$key] : '';//取得session
        }

就是我们在设置$_SESSION时,首先判断该变量是否存在,然后设置。


3.2、实现单一设备的登录。

当user_name = A(在系统中用户名肯定是唯一的)的用户在chrome上登录后,此时我们就要记录下用户名、PHPSESSID的对应关系。1H后

当user_name = A用户换成在ie浏览器上登录,此时应该通过用户名去检查上一个PHPSESSID,并将上一个PHPSESSID对应memcache中的

数据清理掉,然后再存储目前的PHPSESSID。

这样,就可以实现单一设备登录。


3.3、实现主动T用户下线。

(1)直接通过用户的user_name对应的几个PHPSESSID(假设可以多客户端登录,这个事先存储在缓存或者mysql中)。

去清除这些PHPSESSID对应的缓存。但是,这样无法清除掉前端的cookie。需要用户下一次访问接口时,如果检查到服务端

已经清除掉session的缓存了,再次set_cookie()设置过期来清除掉前端的cookie。

(2)因为考虑到用户可以多浏览器登录的问题,所以每次用户登录时,要根据其user_name当作key,记录下此时的PHPSESSID。

当每当系统主动T除用户下线时,给该用户在后端的缓存中设置一个标记。每当这个用户不管在哪个浏览器下一次访问时,先检查

此时的PHPSESSID,如果此PHPSESSID对应的session还存在,则在服务端执行session_destroy();可以同时清除存储在服务端的

session和客户端的cookie。当某个用户所有的PHPSESSID都清除完成后,就可以在缓存中清除掉这个标记了。标记在缓存中的记录,

要合理分配过期时间,以及合理延长过期时间。这样逻辑才严谨。


但是,以上所有的方式都有个问题,就是需要用户下次访问时,去检查,才可以正式知道。


(3)当然了,对于一般长在线的系统(比如在线游戏)。都是保留了一个socket与服务端进行通信。每当心跳的时候去检查,可以做到实时T除该用户

下线。不过当系统做T除下线操作时,此时该用户没有开启该页面的话,也需要他下次访问时,才会实时T除。这些都是WEB与客户端实时在线,完全

不同的地方。


也就是说,我们考虑这个问题时,不仅仅要考虑同时清除cookie、后端缓存(如果是存在文件里,就是清除文件),也要考虑当前用户是否打开了页面。

如果当前没有打开页面,下次该用户访问页面时如何处理。还要考虑用户可以在多个浏览器上访问的因素。


3.4、用户在选购商品时,不需要登录。

我们浏览京东商城、天猫时,可以在不登录的情况下选购商品加入购物车,并且下次进来还有。只是当我们去支付的时候,才会提示登录。

这种,用session很好实现。当用户选购时,直接将用户选购的商品放入session中,直到他登录后,再从session中转移到mysql中。



四、其他语言的session的实现,或者是我们自己实现。

4.1、从上面,我们可以知道,PHP默认是有一套session的实现机制,而且在底层也封装了session_id的实现,

而且封装了变量$_SESSION等。我们除了使用PHP默认的实现方式外,就无其他办法了吗。

可以搜索关键字 PHP 、session_set_save_handler来查询相关资料。http://www.cnblogs.com/xingmeng/p/3223043.html。

这篇文章也介绍他自己写的处理机制。也可以上github上搜索相关的文章。


4.2、其他语言也有自己的实现方式。

比如,我们经常听到token来实现用户的登录。所谓token也就是服务端根据用户名、客户端标记、时间以及一定的算法来生成的value。

然后每次发送服务端时,都带上这个token。类似的就是移动客户端开发(非web),我们怎么实现类似于浏览器session机制呢。 

就可以采用token的方式。其实,这个token就是类似于上面的PHPSESSID,只是这个值,需要我们自己来实现。

token与cookie有哪些异同呢。

(1)两者都是在http传输过程中,带到服务端去;

(2)两者都可以加密生成;

(3)两者都可以设置过期时间;

(4)但是cookie存储在cookie中,容易xss攻击,token可以存储在 client-side 中的 cookie 或 localstorage(数据库);

token的这种思维,可以不仅仅应用在web中,也可以应用在其他需要认证的逻辑中。

比如在微信公众号开发、jenkins的开发中,会发现很多权限验证时,都使用了token。比如接口调用权限、整个用户的验证权限等。

而且这些token还可以设置过期时间,以及具体应用的粒度,就看你的需求和实现方式了。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值