zoukankan      html  css  js  c++  java
  • PHP的Session机制解析 1

    一、php的默认session机制


    php默认用磁盘文件来实现session
    在php.ini中session.save_handler = files定义session机制
    session.save_path="D:devxampp mp" 定义session的存储位置

    1.1、启动session
    session_start()。
    sesson_start()函数是启动session的开始,session默认存放在文件中,且具有一定概率触发session的垃圾回收机制。
    php自身的垃圾回收对session是无效的,因为默认session是存放在文件中的。
    session的垃圾回收概率是根据
    session.gc_probability =1
    session.gc_divisor =1000
    session.gc_maxlifetime =1440//过期时间 默认24分钟
    这三个参数去计算的。
    计算规则为:
    触发概率 = session.gc_probability / session.gc_divisor; 结果 1/1000,

    1.2、配置session.save_path
    session.save_path在php.ini中提供了不同的配置方式:
    session.save_path="D:devxampp mp"
    session.save_path="N;D:devxampp mp"
    其中N为正整数,表示目录分级存放:
    若N=2,假设此时sessionId为 63f2k77g4r0ls06g3p93t0cpkd
    那么,session信息的存放格式为:
    D:devxampp mp63sess_63f2k77g4r0ls06g3p93t0cpkd
    使用分级存放时,session的垃圾回收机制将会无效,需要自己写脚本处理过期session文件。
    且子目录php不会自己创建,需要手动去创建6/3/目录。
    如果分2级存放,可以通过脚本去事先创建好:

    function createSessionDir ()
    {
        $basePath = trim(explode(';', session_save_path())[1], '/\');
        $str = '0123456789abcdefghijklmnopqrstuvwxyz';
        $len = strlen($str);
        for ($i = 0; $i < $len; $i++) {
            for ($j = 0; $j < $len; $j++) {
                $path = $basePath . DIRECTORY_SEPARATOR . $str[$i] . DIRECTORY_SEPARATOR . $str[$j];
                if (!@file_exists($path)) {
                    mkdir($basePath . DIRECTORY_SEPARATOR . $str[$i] . DIRECTORY_SEPARATOR . $str[$j]);
                }
    
            }
        }
    }

    1.3、sessionId
    $_COOKIE[session_name()];中存放了当前session的sessionId信息。
    其中session_name()取的是php.ini中的session.name = PHPSESSID 的值。

    如果不存在会生成一个sessionId,然后将id作为cookie的值传递到客户端。
    相当于执行setcookie()函数:

    setcookie(session_name(),
        session_id(),
        session.cookie_lifetime,//默认0
        session.cookie_path,//默认'/',当前程序跟目录下都有效
        session.cookie_domain,//默认为空
    )

    按照php手册里的说明,使用setcookie()之前不能有任何输出,但是我测试时,在函数之前echo了内容是不会报错的。
    原因是php5.3版本以下时,php.ini有一项配置output_buffering,此配置项,在php5.3以下是默认为0,在5.3以上则默认是4096。
    因为使用的版本大于5.3,所以在测试的时候,默认是开启output_buffering的。
    开启output_buffering的时候,无论是echo,还是var_dump,print_r,任何输出,都会在php脚本结束时,统一随着http响应返回给客户端,(超过4096大小时,可能会分段返回)。所以不会报错。

    1.4、session赋值
    添加一个session值:$_SESSION['name]='zhangsan',此时这个值会在内存中存在,当脚本执行完毕时,会将其写入到指定sessionId的文件中,然后关闭资源。
    如网页的匿名用户存在一个session,当登录后需要更换session:

    //删除旧的session信息
    if (isset($_COOKIE[session_name()])) {
        setcookie(session_name(), '', time() - 86400);
    }
    session_regenerate_id();//重新生成sessionId

    1.5、销毁session信息
    cookie中携带的session信息为即时cookie,保存在浏览器中,当浏览器关闭后,才会过期。
    但是一般我们在用户退出登录时,就需要销毁其cookie和session信息,销毁的方式:

    a、setcookie(session_name(), session_id(), time() - 86400);//退出登录前执行
    b、unset($_SESSION);//会删除所有的$_SESSION数据,刷新后,有COOKIE传过来,但是没有数据
    c、session_destroy();//彻底删除$_SESSION并删除session文件和sessionId

    当不关闭浏览器的情况下,再次刷新,b和c都会有COOKIE传过来,但是找不到数据。

    二、用户自定义处理机制
    php.ini中配置session.save_handler = user 就会触发自定义处理机制其中user字符是随意的,不固定。
    自 PHP 5.4 开始,可以使用下面的方式来注册自定义会话存储函数:
    session_set_save_handler ( object $sessionhandler [, bool $register_shutdown = TRUE ] ) : bool
    sessionhandler为实现了 SessionHandlerInterface接口的对象

    MySession.php
    <?php
    /**
     * Desc: 自定义session处理机制,>5.4
     * Class: Session
     * User: zb
     * Date: 2019/6/14 18:32
     */
    
    class MySession implements SessionHandlerInterface
    {
        private $savePath;
    
        public function close ()
        {
            return true;
        }
    
        public function destroy ($sessionId)
        {
            $file = $this->savePath . '/sess_' . $sessionId;
            if (file_exists($file)) {
                @unlink($file);
            }
            return true;
        }
    
        public function gc ($maxlifetime)
        {
            $sessionFiles = glob($this->savePath . '/sess_*');
            foreach ($sessionFiles as $file) {
                if (file_exists($file) && filemtime($file) + $maxlifetime < time()) {
                    @unlink($file);
                }
            }
            return true;
        }
    
        public function open ($savePath, $sessionName)
        {
            $this->savePath = $savePath;
            if (!is_dir($this->savePath)) {
                mkdir($this->savePath, 0777);
            }
    
            return true;
        }
    
        public function read ($sessionId)
        {
            return (string)@file_get_contents($this->savePath . '/sess_' . $sessionId);
        }
    
        public function write ($sessionId, $sessionData)
        {
            return @file_put_contents($this->savePath . '/sess_' . $sessionId, $sessionData) === false ? false : true;
        }
    }

    使用自定义session机制:

    index.php
    <?php
    /**
     * Desc: xxx
     * User: zb
     * Date: 2019/6/14 18:32
     */
    include 'MySession.php';
    $mySession = new MySession();
    session_set_save_handler($mySession, true);
    session_start();
    if (!empty($_GET) && $_GET['user'] && $_GET['passwd']) {
        $_SESSION['user'] = $_GET['user'];
        $_SESSION['passwd'] = $_GET['passwd'];
        printInfo($_SESSION, 'allSessionData');
        printInfo($_COOKIE[session_name()], 'sessionId');
    } else {
        printInfo('get无数据');
    }
    
    function printInfo ($val, $key = '')
    {
        header('Content-Type', 'text/html; charset=UTF-8');
        $val = var_export($val, true);
        if ($key) {
            $val = $key . ' => ' . $val;
        }
        echo $val;
        echo "<br>";
    }
  • 相关阅读:
    AJPFX总结java开发常用类(包装,数字处理集合等)(三)
    AJPFX总结java开发常用类(包装,数字处理集合等)(二)
    AJPFX总结java开发常用类(包装,数字处理集合等)(一)
    AJPFX关于面向对象之封装,继承,多态 (下)
    AJPFX关于面向对象之封装,继承,多态 (上)
    Android IntentFilter匹配规则
    细说Activity与Task(任务栈)
    androidStudio 打包与混淆
    Android activity之间的跳转和数据传递
    android开发中的 Activity 与 Context 区别与联系
  • 原文地址:https://www.cnblogs.com/deverz/p/11028059.html
Copyright © 2011-2022 走看看