用户
搜索
  • TA的每日心情
    奋斗
    2020-1-18 18:00
  • 签到天数: 2 天

    连续签到: 2 天

    [LV.1]初来乍到

    i春秋-脚本小子

    Rank: 2

    3

    主题

    4

    帖子

    98

    魔法币
    收听
    0
    粉丝
    0
    注册时间
    2017-11-14
    发表于 2020-1-17 10:21:10 13772
    本帖最后由 小透明yo 于 2020-1-17 02:22 编辑

    环境创建:

    1. 需要在全局文件开启Session:

    /app/middleware.php

    <?php
    // 全局中间件定义文件
    return [
        // 全局请求缓存
        // \think\middleware\CheckRequestCache::class,
        // 多语言加载
        // \think\middleware\LoadLangPack::class,
        // Session初始化
        // \think\middleware\SessionInit::class
        \think\middleware\SessionInit::class
    ];
    

    /app/controller/index.php:

    class Index extends BaseController
    {
        public function index()
        {
            session("demo","domo");
        }
    }

    问题:

    外面的分析文章已经很多了,但是我还是有一些不解之处。

    1. 从哪里写入了文件操作?为什么会调用save函数?
    2. session是从哪里判断已什么方式储存的?

    解决问题:

    要解决问题一,我们需要同时在自己调用的session以及sava函数同时下断,看下谁先断下:

    Snipaste_2020-01-16_17-13-20.png
    Snipaste_2020-01-16_17-14-00.png

    先被断下的是自己的session函数。我们直接跟吧:

        function session($name = '', $value = '')
        {
            if (is_null($name)) {
                // 清除
                Session::clear();
            } elseif ('' === $name) {
                return Session::all();
            } elseif (is_null($value)) {
                // 删除
                Session::delete($name);
            } elseif ('' === $value) {
                // 判断或获取
                return 0 === strpos($name, '?') ? Session::has(substr($name, 1)) : Session::get($name);
            } else {
                // 设置
                Session::set($name, $value);
            }
        }

    这里调用了Session::set这个静态函数.

    然后是TP的路由寻找,一直找到了这里:

    vendor/topthink/framework/src/think/Manager.php:

        public function __call($method, $parameters)
        {
            return $this->driver()->$method(...$parameters);
        }

    他在这里调用了本类的driver,我们先跟进driver:

        protected function driver(string $name = null)
        {
            $name = $name ?: $this->getDefaultDriver();
    
            if (is_null($name)) {
                throw new InvalidArgumentException(sprintf(
                    'Unable to resolve NULL driver for [%s].', static::class
                ));
            }
    
            return $this->drivers[$name] = $this->getDriver($name);
        }

    第一行获取了默认的driver,跟进看看:

        public function getDefaultDriver()
        {
            return $this->app->config->get('session.type', 'file');
        }

    到这里我的第二个问题就解决了,他是从config中获取到的存储方式。我们接着跟下去:

    return $this->drivers[$name] = $this->getDriver($name);

    跟进他的getDriver函数:

        protected function getDriver(string $name)
        {
            return $this->drivers[$name] ?? $this->createDriver($name);
        }

    然后这里说一下PHP7中的一个特性,就是双问号。双问号的意思就是:

    isset($this->drivers[$name])?$this->drivers[$name]:$this->createDriver($name)

    所以这里会直接返回dirver,可以看下此时driver的值:
    Snipaste_2020-01-16_17-58-23.png

    之后会调用这个:Arr::set($this->data, $name, $value);

    这个函数就是对$this->data赋值.

    之后函数直接返回了。这时候我们是在index中的哪个函数里面呢?
    打开文件:public/index.php 如图下断:
    Snipaste_2020-01-16_18-14-31.png
    第一次断下:

    $http = (new App())->http;

    我们按F9,看下第二次在哪里断下:

    $response = $http->run();

    再次F9看下第三次在哪里断下:

    session("demo","domo");

    然后再次F9,第四次断下位置:

    $response->send();

    再次F9,第五次断下位置:

    $http->end($response);

    再次F9,第六次断下位置:

        public function save(): void
        {
            $this->clearFlashData();
    
            $sessionId = $this->getId();
    
            if (!empty($this->data)) {
                $data = $this->serialize($this->data);
    
                $this->handler->write($sessionId, $data);
            } else {
                $this->handler->delete($sessionId);
            }
    
            $this->init = false;
        }
    

    现在才到了save函数,此时看堆栈:

    Store.php:256, think\session\Store->save()
    Manager.php:174, think\Session->__call()
    SessionInit.php:78, think\Session->save()
    SessionInit.php:78, think\middleware\SessionInit->end()
    Middleware.php:165, think\Middleware->end()
    Http.php:279, think\Http->end()
    index.php:24, {main}()

    Http.php:279, think\Http->end():

        public function end(Response $response): void
        {
            $this->app->event->trigger(HttpEnd::class, $response);
    
            //执行中间件
            $this->app->middleware->end($response);
    
            // 写入日志
            $this->app->log->save();
        }

    通过堆栈得知在低一级为:$this->app->middleware->end($response);
    此时我们需要直到middleware是从哪里来的,直接从新来在end下断查看变量:

    middleware = think\Middleware

    也就是说end是think\Middleware对象中的,跟入就行:

        public function end(Response $response)
        {
            foreach ($this->queue as $queue) {
                foreach ($queue as $middleware) {
                    [$call] = $middleware;
                    if (is_array($call) && is_string($call[0])) {
                        $instance = $this->app->make($call[0]);
                        if (method_exists($instance, 'end')) {
                            $instance->end($response);
                        }
                    }
                }
            }
        }

    此时会获取到我们之前写入的中间件类,也就是\think\middleware\SessionInit::class,然后调用\think\middleware\SessionInit::class的End函数,跟进end函数:

        public function end(Response $response)
        {
            $this->session->save();
        }

    发现它调用了save函数。自此我的两个疑惑点都解决完毕了。

    总结:

    1. 从哪里写入了文件操作?为什么会调用save函数?

    在程序退出时调用了save函数。

    1. session是从哪里判断已什么方式储存的?

    > 从配置项中获取,在设置Session时获取

    安全培训查看:http://www.0xnull.org/index.php/archives/3/
    学习了   
    使用道具 举报 回复
    发新帖
    您需要登录后才可以回帖 登录 | 立即注册