PHP SESSION机制原理详解

    xiaoxiao2022-07-02  104

    SESSION基础

    session 即会话,它与cookie类似,是记录用户行为状态的机制,只不过cookie将用户状态信息放在客户端(浏览器),session是把信息以一定的数据结构(通常由sessionID和内容组成)放在服务端,存储容器可以是文件(最常用)、RDB(mysql,postgresql,sqlLite等)、NoSql(redis,memcache)等,它的正常工作依赖于http协议助其完成客户端与服务端的交流,最常见的是借用http header头的cookie,PHP默认就是用cookie,还可以借用url参数,html的隐藏表单域等,但后两者不够方便,并且实践证明用户很少会禁用cookie。其实单台服务器用文件存储seesion内容就可以了,多台的话一定要用数据库的,防止找不到相应的seesion。 工作原理如下图:

    PHP中一般借用session扩展(php内置)进行session的管理:

    session_id($sessionID);//设置或获取sessionID,放在session_start()之前 session_start();//开启session扩展 $_SESSION['token'] = 'shjsals1212klasssu80';//利用超全局变量$_SESSION设置session内容 echo $_SESSION['token'];//获取当前sessionID下的某一个session值

    SESSION(运行时)配置

    session运行时配置即在php.ini文件中进行session的配置。常用的如下:

    session.save_handler :string

    session.save_handler 确定了存储session用的处理器的名字,默认files,如果想改成memcache,可以这样写: session.save_handler = memcache,session.save_path = “tcp://127.0.0.1:8888”

    session.save_path :string

    session.save_path确认了传递给存储处理器的参数。如果选择了默认的 files 文件处理器,则此值是创建文件的路径。默认为 /tmp,此指令还有一个可选的 N 参数来决定会话文件分布的目录深度,如session.save_path=‘2;/tmp’。N不宜太大,不然I/O太多,很影响性能。

    session.name :string

    session.name定义了sessionID名以用做 cookie 的名字。只能由字母数字组成,默认为 PHPSESSID。

    session.auto_start :bool

    session.auto_start 定义了session扩展是否自动开启,默认0,所以我们在使用session时要session_start()。

    session.use_cookies : bool

    定义session是否指定客户端用cookie存储PHPSESSID

    session.use_only_cookies : bool

    定义session是否指定客户端只能用cookie存储PHPSESSID

    session.use_trans_sid : bool

    定义session是否启用透明 SID 支持,这样可以将PHPSESSID作为URl的参数来管理,默认为 0(禁用)

    session.gc_probability : int

    session.gc_probability 与 session.gc_divisor 合起来用来管理 gc(garbage collection 垃圾回收)进程启动的概率。默认为 1。

    session.gc_divisor :int

    session.gc_divisor 与 session.gc_probability 合起来定义了在每个会话初始化时启动 gc(garbage collection 垃圾回收)进程的概率。此概率用 gc_probability/gc_divisor 计算得来。例如 1/100 意味着在每个请求中有 1% 的概率启动 gc 进程。session.gc_divisor 默认为 100。

    session.gc_maxlifetime :int

    session.gc_maxlifetime 指定过了多少秒之后数据就会被视为“垃圾”并被清除。你可以将gc_divisor设为1,gc_maxlifetime设为10,来看gc回收的现象,如果save_handler值为files,就是将过期的session文件删除。

    这些是常用的,详情见官网session运行中配置

    SESSION函数

    函数也列出一些常用的,详情见官网session函数。

    session_id($sessionID);//设置或获取sessionID,放在session_start()之前session_start();//开启session扩展$_SESSION[‘token’] = ‘shjsals1212klasssu80’;//利用超全局变量$_SESSION设置$_SESSION[‘token’];//获取当前sessionID下的某一个session值unset($_SESSION[‘token’]);//释放指定的session变量,注意请不要使用unset($_SESSION)来释放整个$_SESSION, 因为它将会禁用通过全局$_SESSION去注册会话变量session_unset();//释放所有的session变量,等价于$_SESSION=[];session_destroy//销毁当前sessionID对应的数据(如果save_hander=files,则删除相应的文件), 但是不会重置当前会话所关联的全局变量, 就是不改变内存中$_SESSION值。 如果需要再次使用会话变量, 必须重新调用 session_start() 函数。可以通过isset($_SESSION[‘token’])来认识其差别

    SESSION类和接口

    php为用户提供了一个接口,SessionHandlerInterface,用户可以自定义seesion管理。

    官方提示:SessionHandlerInterface是一个接口,它定义了用于创建自定义会话处理程序的原型。自定义seesion处理类必须实现此接口,若需要调用自定义类,必须将该类的实例传递给session_set_save_handler()。 请注意,该类的回调方法设计为由PHP内部调用,而不是从用户空间代码调用。 SessionHandlerInterface定义了几个方法:

    SessionHandlerInterface { /* 方法 */ abstract public close ( void ) : bool abstract public destroy ( string $session_id ) : bool abstract public gc ( int $maxlifetime ) : int abstract public open ( string $save_path , string $session_name ) : bool abstract public read ( string $session_id ) : string abstract public write ( string $session_id , string $session_data ) : bool }

    接口的抽象方法作用如下: 简单代码实例(redis):

    class SessionManager{ private $redis; private $sessionSavePath; private $sessionName; private $sessionExpireTime = 30; public function __construct(){ $this->redis = new Redis(); $this->redis->connect('127.0.0.1',6379); //连接redis //注册类 ini_set('session.save_handler','user'); $retval = session_set_save_handler( array($this,"open"), array($this,"close"), array($this,"read"), array($this,"write"), array($this,"destory"), array($this,"gc") ); session_start(); } public function open($path,$name){ return true; } public function close(){ return true; } /** * read session by session_id * @param string $session_id * @return mixed */ public function read($id){ $value = $this->redis->get($id); if($value){ return $value; }else{ return ""; } } public function write($id,$data){ if($this->redis->set($id,$data)){ $this->redis->expire($id,$this->sessionExpireTime); //设置过期时间 return true; } return false; } public function destory($id){ if($this->redis->delete($id)){ return true; } return false; } /** * this function is no use because of redis expire * @param int $maxlifetime * @return bool */ public function gc($maxlifetime){ return true; } //析构函数 public function __destruct(){ session_write_close(); } } $session = new SessionManager(); $_SESSION['fpf'] = "pop"; echo $_SESSION['fpf'];

    就目前我所用到的php框架,CI和Laravel都基于这个接口对重新设计了seesion管理,可以下载源码进行学习,非常棒的学习资料。

    提示:

    php也允许开发者以很简单的方式将session存储器由默认的files替换为redis或memcache,只需要下载相应的扩展即可。以redis为例: ini_set(“session.save_handler”, “redis”); ini_set(“session.save_path”, “tcp://127.0.0.1:6379”); session_start(); $_SESSION[“user”]=“sgao”; 如果可以修改php.ini文明加密,可以直接改session.save_handler和session.save_path值。

    特别注意的是一定要有redis扩展,通过phpinfo()查看如下图: 如果没有redis扩展,红色圈定部分只有files和user这两个选项的,当然,你下了memcache扩展,这里就会出现memcache选项。

    PHP7 SESSION新特性

    php7之前session_start()函数是不可传参的,但php7可以了,例如:

    <?php session_start([ 'cache_limiter' => 'private', //在读取完毕会话数据之后马上关闭会话存储文件 'cookie_lifetime'=>3600, //SessionID在客户端Cookie储存的时间,默认是0,代表浏览器一关闭SessionID就作废 'read_and_close'=>true //在读取完会话数据之后, 立即关闭会话存储文件,不做任何修改 ]);
    最新回复(0)