现在稍微大一点的网站基本上都有好几个子域名,比如www.motui8.cn,blog.motui8.cn,这些网站如果需要共享用户的登录信息,就必须session共享。PHP又是如何做到多个服务器,session共享的呢?

要解决这个问题我们首先要明白session的工作原理是什么?
session原理
客户端访问PHP服务器时,执行session_start生成session_id,一般我们会把session_id存储到cookie中,根据session_id关联内容并保存在服务器文件系统中,每一次请求通过cookie获取session_id,再通过session_id获取session内容。

但是客户端访问不同服务器时,每一台服务器都会生成一个session_id,这就导致不同服务器之前无法共享session了。
解决session共享其时就两个步骤

  1. 多台服务器对于同一个客户端生成同一个session_id

这个比较好解决,只要我们针对主域名来生成session_id即可。实现的方式有两种:

1.1 通过php配置文件设置session_id的cookie域名。找到php.ini文件添加如下配置:

session.cooke_domain = .motui8.cn

1.2 通过代码设置session_id的cookie域名,代码如下:

ini_set( 'session.cookie_domain' , 'motui8.cn' );
  1. 多台服务器之前的session内容互通有无,可以通过同一个session_id获取到内容
    这一点实现起来比较麻烦,主要就是把session存储在所有服务器都可以访问的地方。默认的存储在服务器的文件中,我们也可以存储在 Redis 这类缓存服务器中。对于文件系统我们可以通过 NFS 来统一存储。

2.1 文件系统
这种方式的session依赖于PHP垃圾收集器进行销毁,在高并发下session存储的目录下会产生大量的文件。这种方式会导致查找文件缓慢,并且session缓存目录可存储的文件数是有限的,有可能导致session存储失败,因此,我们不建议使用文件系统存储session。

2.2 数据库存储
这种方式虽然不依赖PHP的垃圾收集器,但是会加大数据库的IO问题,增加数据的压力,导致数据读写速度变慢,因此这种方式,我们也不建议大家使用。

2.3 Redis 缓存存储
缓存数据都在内存中,读写速度快,redis还可以单独设置过期时间,自动删除无效的session。

现有的PHP框架基本都支持Redis存储session,我们只需要配置好session相关配置即可。当然如果你想自己但对编写session相关代码也可以,我给大家一个示例:

<?php

//启动session
session_start();

//设置session最大存活时间,单位【秒】
ini_set('session.gc_maxlifetime',60*60);

//设置session存储方法
ini_set('session.save_handler','redis');

//设置session存储路径,存储方式为redis时,路径就是redis的连接(如果不需要授权,直接使用 tpc://127.0.0.1:6379 即可)
ini_set('session.save_path','tpc://127.0.0.1:6379?persistent=1&auth=授权密码&database=redis数据库');

//设置session内容,在内容中存储当前key的过期时间
$_SESSION['user_info'] = [
    'data'=>['id'=>1],
    'expire'=>time()+60*30
];

//获取session内容
$data = $_SESSION['user_info'];

//判断当前session是否过期
if($data['expire']>time()){
    //删除session中已过期的key
    unset($_SESSION['user_info']);
    echo 'session已过期';
}else{
    print_r($data['data']);
}