zoukankan      html  css  js  c++  java
  • Session 知识点再整理(一)基本概念和原理

    Session 的概念

    Session 和 Cookie 一样,也是针对 HTTP 的局限性而提出的一种保持客户端和服务器端会话连接状态的机制。

    Session 被称为会话,指用户在进入网站到浏览器关闭(或退出网站)这段时间内与 Web 系统的会话过程。

    Session 的存储 

    Session 保存在服务器端,默认情况以文件的形式保存在服务器硬盘上,每个 Session 一个文件,文件名如:sess_j64kv3np0ft2u00aun0cilqdo2,里面保存的内容结构是:变量名 | 类型:长度:值;

    例如:

    name|s:3:"dee";level|i:2;

    在 php.ini 中,session.save_handler 定义了存储和获取 Session 数据的处理器的名字,默认为 files,表示使用文件形式保存 Session:

    session.save_handler = files

    也可以设置成用户自定义方式存储 Session 的 user 或者 memcache 来使 Session 保存到关系型数据库或者 Memcache 等内存服务器中。

    在 php.ini 中,session.save_path 表示 Session 存储的位置,在 WAMPSERVER 环境下的默认值是:

    session.save_path = "d:/wamp/tmp"

    表示 Session 文件存储在 d 盘 wamp/tmp 目录下; Windows 环境中在该配置被注释的情况下 Session 可能保存在 C:WindowsTemp 目录下,Linux 环境中在该配置被注释的情况下 Session 保存在 /tmp 或 /var/lib/php/session 目录下。

    当 Session 保存在 Memcache 中时可以修改该配置,例如:

    session.save_path = "tcp://127.0.0.1:11211,tcp://127.0.0.1:11212"

    以上配置代表将 Session 保存到两台 Memcache 服务器中。

    当 Session 以文件形式保存时,默认是保存在硬盘的一个目录下,当 Session 比较多时,磁盘读取文件会比较慢,通常一个目录下文件数量超过 2000 个时,读写这个目录就会比较慢。此时可以考虑将 Session 分目录存放。session.save_path 有一个可选的 N 参数来决定 Session 文件分布的目录深度,格式是:

    session.save_path = "N;MODE;/path"

    N 表示要设置的目录级数,MODE 表示目录的权限属性,默认为 600(Windows 中不需要设置),/path 表示 Session 文件存放的根目录路径每一级目录分别以 0 - 9 和 a - z 共 36 个字符作为目录名,这样存放 Session 的目录可以达到 36^36 个。创建文件夹的工作需要 PHP 来完成。

    例如,2 级目录即 N = 2 时可以这样设置:

    <?php
    //设置Session目录分级与保存路径
    ini_set('session.save_path', "2;/wamp/tmp");
    
    //创建2级目录
    $string = '0123456789abcdefghijklmnopqrstuvwxyz';
    $length = strlen($string);
    for($i = 0; $i < $length; $i++) {
        for($j = 0; $j < $length; $j++) {
            createfolder('d:/wamp/tmp/'.$string[$i].'/'.$string[$j]);
        }
    }
    
    function createfolder($path) {
        if(!@file_exists($path)) {
            createfolder(@dirname($path));
            @mkdir($path, 0777);
        }
    }
    
    session_start();
    $_SESSION['name'] = 'dee';
    
    echo session_id();

    打印出的 Session ID 为 3b9ptga94p7b5v1s33dnacrf95,那么 PHP 会根据该 ID 的前两位字符来存储 Session 文件,即该 Session 文件存储在 d:/wamp/tmp/3/b 下:

    如果使用了 N 参数并且大于 0,那么 PHP 将不会自动回收过期的 Session,需要通过 shell 或者 cron 来清除过期的文件。

    Session 的开启

    通过 session_start 函数创建新会话或者重用现有会话,在 session_start 函数之前页面不能有任何的输出内容(当 php.ini 中 的output_buffering = Off 时)。

    当自动开启会话或者通过 session_start() 手动开启会话的时候, PHP 内部会调用会话管理器(save_handler)的 open 、 read 和 gc 回调函数。

    会话管理器默认为文件(file), 也可以是 SQLite 或者  Memcached 扩展, 还可以通过 session_set_save_handler() 设定的用户自定义会话管理器,并通过 read 回调函数返回现有的(经过序列化的)会话数据, PHP 会自动反序列化数据并且赋给 $_SESSION 超级全局变量。

    Session ID 及其传递

    Session 的唯一标识 Session ID,是由 32 位十六进制数组成的字符串,php.ini 中 session.use_cookies 的默认值为 1,即默认通过 Cookie 来进行保存和传递:

    session.use_cookies = 1

    通过设置也能在客户端禁用了 Cookie 之后通过 URL 或者隐藏表单进行 session_id 的 GET 或 POST 传递。

    如果需要在 Cookie 被禁用时仍然能使用 Session,需要修改 php.ini 中的几个配置:session.use_only_cookies 和 session.use_trans_sid,这两个参数的默认值分别是 1 和 0,分别代表在客户端仅仅使用 Cookie 来存放 Session ID ,和指定不启用透明 Session ID 支持(即在 URL 中不自动加上 Session ID 的参数):

    session.use_only_cookies = 1
    session.use_trans_sid = 0

    需要把这两个配置修改为:

    session.use_only_cookies = 0
    session.use_trans_sid = 1

    此时如果禁用了 Cookie,则 URL 的格式为 格式为 a.php?PHPSESSID=session_id

    将 session_id 通过 URL 进行传递的缺点有:1. 安全性,将 session_id 暴露在了 URL 中 2. 当禁用了 Cookie 后,如果 URL 中没有传递 session_id(例如重复访问第一个设置 Session 的页面),就会使系统不能重用现有会话而重新生成新的会话。

    例 在 FireFox 40.0.3 下,设置禁用 Cookie:

    ”工具“ -- ”选项“ -- ”隐私“ -- ”使用自定义历史记录设置“ -- 取消勾选 ”接收来自站点的Cookie“

    session_url_set.php:

    <?php
    header("Content-type:text/html;charset=utf-8");
    
    ini_set('session.use_trans_sid', 1);
    ini_set('session.use_only_cookies', 0);
    
    session_start();
    
    $_SESSION['user'] = 'dee';
    
    echo session_id();
    echo '<pre>';
    print_r($_SESSION);
    echo '<a href="session_url_get.php" target="_blank">跳转</a>';

    输出:

    session_url_get.php

    <?php
    
    ini_set('session.use_trans_sid', 1);
    ini_set('session.use_only_cookies', 0);
    
    session_start();
    
    echo session_id();
    echo '<pre>';
    print_r($_SESSION);

    输出:

    session_id 自动成为 URL 参数。

    但是此时再次刷新 session_url_set.php 时,会重新生成新的 Session:

    当用户向服务器服务器发出请求时,服务器会首先检查请求中是否已经包含了 Session ID(通过请求头中 Cookie 中的 PHPSESSID 或者 URL 中的参数 PHPSESSID ),如果包含则服务器会重复使用该 Session ID,如果不包含,则生成一个新的 Session ID。

    注意:URL 自动带上 Session ID 参数的条件是 ① 当前 Cookie 中不包含 Session ID ;② session.use_trans_sid 设置为 1 ;③ session.use_only_cookies 设置为 0

    可以通过修改 php.ini 中的 session.name 来修改 Seeesion Name,默认这是 PHPSESSID:

    session.name = PHPSESSID

    可以通过在 PHP 脚本中输入 session_name() 来查看当点的 Session Name :

    echo session_name();

    可以通过 session_id() 来查看当前的 Session ID:

    echo session_id();

    输出的值和对应的 Session 文件名相对应,例如 Session ID 是 j64kv3np0ft2u00aun0cilqdo2,文件名是 sess_j64kv3np0ft2u00aun0cilqdo2。

    注销变量和销毁 Session

    Session 的注销包括 4 个步骤:

    <?php
    
    //1.开启 Session
    session_start();
    
    //2.删除所有的 Session 变量
    $_SESSION = array();
    
    //3.如果是基于 Cookie 的 Session,则删除该 Cookie
    if(isset($_COOKIE[session_name()])) {
        setcookie(session_name(), '', time() - 1, '/');
    }
    
    //4.彻底销毁 Session
    session_destroy();

    此时 保存 Session ID 的 Cookie已经被清除,Session 文件的内容已经被清空,但是服务器上的 Session 文件的删除则需要依赖 Session 的垃圾回收机制。

    Session 的生存周期和垃圾回收机制

    默认情况下,Session ID 存储在 Cookie 中,该 Cookie 默认设置过期时间为 0,即随着浏览器关闭而消失(Cookie 保存在内存中),php.ini 的设置:

    session.cookie_lifetime = 0

    关闭浏览器后该 Session ID 自动注销,如果重新请求该页面则会重新注册一个新的 Session ID。

    但是 Session 文件可能仍然存在,原因是 Session 的垃圾回收机制。和 Session 的垃圾回收机制相关的函数是:session_start(),在调用该函数时启动回收机制,相关的 3 个配置分别是 :session.gc_maxlifetime,表示 Session 文件的过期时间,默认为 1440 秒即 24分钟能、session.gc_probabilitysession.gc_divisor,后面两个配置的默认值分别是 1 和 1000,代表 session_start() 函数每调用 1000 次触发一次 Session 文件的全部扫描,把过期的 Session 文件删除:

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

    过期的 Session 文件的判断标准是:文件的修改时间和当前时间相差是否大于 session.gc_maxlifetime。当用户每进行一个操作哪怕是一个刷新页面的动作时,都会修改 Session 文件的修改时间。

    可以手动设置 Session 的生命周期:

    $life_time = 3600 * 24;
    setcookie(session_name(), session_id(), time() + $life_time, '/');

    经过设置,在关闭浏览器后,保存 Session ID 的 Cookie 的生命周期达到了 24 小时,也就是在 24 小时内即使关闭了浏览器,下次再访问该页面时 PHP 会重用该 Session。 

    可以通过设置较短的 session.gc_maxlifetime 和 较小的 session.gc_divisor 来观察 Session 的过期机制:

    把 session.gc_maxlifetime 设为 10(秒),即 10 秒内用户没有任何操作(包括刷新)的话,10 秒后该会话即成为过期 Session;把 session.gc_divisor 分别设为 1 和 2,也就是 session.gc_probability /  session.gc_divisor = 1 或 1/2,意思是每一 或 两次访问网站(页面),都将扫描所有的 Session 文件,同时将过期的 Session 文件从硬盘上删除(当 Session 以 files 形式存储时),来观察 Session 的垃圾回收机制。注意 session.cookie_lifetime 要和 session.gc_maxlifetime 设置为相同的值。

    session_cookie_set.php

    <?php
    header("Content-type:text/html;charset=utf-8");
    
    ini_set('session.cookie_lifetime', 10);
    ini_set('session.gc_maxlifetime', 10);
    ini_set('session.gc_divisor', 1);
    
    session_start();
    
    $_SESSION['username'] = 'deathmask';
    
    echo session_id();
    echo '<pre>';
    print_r($_SESSION);
    echo '<a href = "session_cookie_get.php" target="_blank">跳转</a>';

     session_cookie_get.php

    <?php
    
    ini_set('session.cookie_lifetime', 10);
    ini_set('session.gc_maxlifetime', 10);
    ini_set('session.gc_divisor', 1);
    
    session_start();
    
    echo session_id();
    echo '<pre>';
    print_r($_SESSION);

    观察硬盘上 Session 文件的删除情况。

    参考:

    session.save_path目录大量session临时文件带来的服务器效率问题 

    PHP设置session定期自动清理的例子

    PHP session 暫存檔過多的注意事項

    PHP Session文件的散列存储及过期删除

  • 相关阅读:
    JavaScript之数学对象Math
    JavaScript之数据类型转换
    JavaScript之操作符
    JavaScript之基本语句
    JavaScript之基本概念(二)
    JavaScript之基本概念(一)
    使用velero进行kubernetes灾备
    minikube配置CRI-O作为runtime并指定flannel插件
    使用thanos管理Prometheus持久化数据
    linux开启tcp_timestamps和tcp_tw_recycle引发的问题研究
  • 原文地址:https://www.cnblogs.com/dee0912/p/5049692.html
Copyright © 2011-2022 走看看