页面正在施工中 先看看其他东西吧

模型 视图 控制器

THINKPHP 是一个MVC PHP框架

所谓MVC 是Model View Controller(模型 视图 控制器)的缩写

简单理解

模型主要负责数据处理 (数据库交互 为控制器提供数据 )

视图 负责渲染输出展示给客户端的HTML页面

控制器 接收用户请求 与客户端发生交互 处理基本的业务逻辑 决定要输出的视图

使用THINKPHP框架开发的项目 主要审计模型和控制器文件

目录结构

  1. www WEB部署目录(或者子目录)
  2. ├─application 应用目录
  3. ├─common 公共模块目录(可以更改)
  4. ├─module_name 模块目录
  5. ├─common.php 模块函数文件
  6. ├─controller 控制器目录
  7. ├─model 模型目录
  8. ├─view 视图目录
  9. └─ ... 更多类库目录
  10. ├─command.php 命令行定义文件
  11. ├─common.php 公共函数文件
  12. └─tags.php 应用行为扩展定义文件
  13. ├─config 应用配置目录
  14. ├─module_name 模块配置目录
  15. ├─database.php 数据库配置
  16. ├─cache 缓存配置
  17. └─ ...
  18. ├─app.php 应用配置
  19. ├─cache.php 缓存配置
  20. ├─cookie.php Cookie配置
  21. ├─database.php 数据库配置
  22. ├─log.php 日志配置
  23. ├─session.php Session配置
  24. ├─template.php 模板引擎配置
  25. └─trace.php Trace配置
  26. ├─route 路由定义目录
  27. ├─route.php 路由定义
  28. └─... 更多
  29. ├─public WEB目录(对外访问目录)
  30. ├─index.php 入口文件
  31. ├─router.php 快速测试文件
  32. └─.htaccess 用于apache的重写
  33. ├─thinkphp 框架系统目录
  34. ├─lang 语言文件目录
  35. ├─library 框架类库目录
  36. ├─think Think类库包目录
  37. └─traits 系统Trait目录
  38. ├─tpl 系统模板目录
  39. ├─base.php 基础定义文件
  40. ├─console.php 控制台入口文件
  41. ├─convention.php 框架惯例配置文件
  42. ├─helper.php 助手函数文件
  43. ├─phpunit.xml phpunit配置文件
  44. └─start.php 框架入口文件
  45. ├─extend 扩展类库目录
  46. ├─runtime 应用的运行时目录(可写,可定制)
  47. ├─vendor 第三方类库目录(Composer依赖库)
  48. ├─build.php 自动生成定义文件(参考)
  49. ├─composer.json composer 定义文件
  50. ├─LICENSE.txt 授权说明文件
  51. ├─README.md README 文件
  52. ├─think 命令行入口文件

./application/xxx/controller/xxxx.php 控制器文件默认位置

./application/xxx/model/xxxx.php 模型文件默认位置

application 目录名可以修改 (某些版本为app 可以在配置文件中自定义)

thinkphp问题大多都出在控制器 初学者建议重点审计控制器文件

对框架有一定了解后可以深入审计 不要太局限于控制器

THINKPHP5.1.14框架的处理流程

  1. 访问入口文件 例 public\index.php (入口文件名可自定义 可以有多个入口文件 )

入口文件一般与静态文件放在public目录下,并将web根目录设置在public目录供用户访问,与框架其他文件分开.
防止访问到应用目录下的敏感文件 (日志 临时文件 应用文件等)

<?php
  // [ 应用入口文件 ]
  namespace think;
// 加载基础文件
require __DIR__ . '/../thinkphp/base.php';

// 支持事先使用静态方法设置Request对象和Config对象

// 执行应用并响应
Container::get('app')->run()->send();

在入口文件中可以定义应用目录位置

<?php
namespace think;

// 定义应用目录
define('APP_PATH', __DIR__ . '/app/');// 修改应用目录为 程序目录下的app目录 (默认为application)
// 加载框架基础引导文件
require __DIR__ . '/thinkphp/base.php';
// 添加额外的代码
// ...

// 执行应用并响应
Container::get('app', [APP_PATH])->run()->send();
  1. 加载框架基础引导文件 thinkphp/base.php

载入Loader类 /thinkphp/library/think/Loader.php
注册自动加载 错误和异常处理机制
添加日志接口
注册类库别名 方便自动加载

  1. 执行应用

Container::get(‘app’)->run()->send();
加载Container类文件
由于先前没有引入这个类 触发之前注册的自动加载方法
引入library/think/Container.php
运行Container::get方法 获得一个App::class对象 (在Container.php容器绑定标识中app对应的是App::class)
引入library/think/App.php
运行App::run方法
初始化应用 加载环境变量 处理用户请求

    /**
     * 执行应用程序
     * @access public
     * @return Response
     * @throws Exception
     */
    public function run()
    {
        try {
            // 初始化应用  
            $this->initialize();

            // 监听app_init
            $this->hook->listen('app_init');

            if ($this->bindModule) {
                // 模块/控制器绑定
                $this->route->bind($this->bindModule);
            } elseif ($this->config('app.auto_bind_module')) {
                // 入口自动绑定
                $name = pathinfo($this->request->baseFile(), PATHINFO_FILENAME);
                if ($name && 'index' != $name && is_dir($this->appPath . $name)) {
                    $this->route->bind($name);
                }
            }

            // 监听app_dispatch
            $this->hook->listen('app_dispatch');

            $dispatch = $this->dispatch;

            if (empty($dispatch)) {
                // 路由检测
                $dispatch = $this->routeCheck()->init();
            }

            // 记录当前调度信息
            $this->request->dispatch($dispatch);

            // 记录路由和请求信息
            if ($this->appDebug) {
                $this->log('[ ROUTE ] ' . var_export($this->request->routeInfo(), true));
                $this->log('[ HEADER ] ' . var_export($this->request->header(), true));
                $this->log('[ PARAM ] ' . var_export($this->request->param(), true));
            }

            // 监听app_begin
            $this->hook->listen('app_begin');

            // 请求缓存检查
            $this->checkRequestCache(
                $this->config('request_cache'),
                $this->config('request_cache_expire'),
                $this->config('request_cache_except')
            );

            $data = null;
        } catch (HttpResponseException $exception) {
            $dispatch = null;
            $data     = $exception->getResponse();
        }

        $this->middleware->add(function (Request $request, $next) use ($dispatch, $data) {
            return is_null($data) ? $dispatch->run() : $data;
        });

        $response = $this->middleware->dispatch($this->request);

        // 监听app_end
        $this->hook->listen('app_end', $response);

        return $response;
    }
    /**
     * 初始化应用
     * @access public
     * @return void
     */
    public function initialize()
    {
        if ($this->initialized) {
            return;
        }

        $this->initialized = true;
        $this->beginTime   = microtime(true);
        $this->beginMem    = memory_get_usage();

        $this->rootPath    = dirname($this->appPath) . DIRECTORY_SEPARATOR;
        $this->runtimePath = $this->rootPath . 'runtime' . DIRECTORY_SEPARATOR;
        $this->routePath   = $this->rootPath . 'route' . DIRECTORY_SEPARATOR;
        $this->configPath  = $this->rootPath . 'config' . DIRECTORY_SEPARATOR;

        static::setInstance($this);

        $this->instance('app', $this);

        // 加载环境变量配置文件
        if (is_file($this->rootPath . '.env')) {
            $this->env->load($this->rootPath . '.env');
        }

        $this->configExt = $this->env->get('config_ext', '.php');

        // 加载惯例配置文件
        $this->config->set(include $this->thinkPath . 'convention.php');

        // 设置路径环境变量
        $this->env->set([
            'think_path'   => $this->thinkPath,
            'root_path'    => $this->rootPath,
            'app_path'     => $this->appPath,
            'config_path'  => $this->configPath,
            'route_path'   => $this->routePath,
            'runtime_path' => $this->runtimePath,
            'extend_path'  => $this->rootPath . 'extend' . DIRECTORY_SEPARATOR,
            'vendor_path'  => $this->rootPath . 'vendor' . DIRECTORY_SEPARATOR,
        ]);

        $this->namespace = $this->env->get('app_namespace', $this->namespace);
        $this->env->set('app_namespace', $this->namespace);

        // 注册应用命名空间
        Loader::addNamespace($this->namespace, $this->appPath);

        // 初始化应用
        $this->init();

        // 开启类名后缀
        $this->suffix = $this->config('app.class_suffix');

        // 应用调试模式
        $this->appDebug = $this->env->get('app_debug', $this->config('app.app_debug'));
        $this->env->set('app_debug', $this->appDebug);

        if (!$this->appDebug) {
            ini_set('display_errors', 'Off');
        } elseif (PHP_SAPI != 'cli') {
            //重新申请一块比较大的buffer
            if (ob_get_level() > 0) {
                $output = ob_get_clean();
            }
            ob_start();
            if (!empty($output)) {
                echo $output;
            }
        }

        // 注册异常处理类
        if ($this->config('app.exception_handle')) {
            Error::setExceptionHandler($this->config('app.exception_handle'));
        }

        // 注册根命名空间
        if (!empty($this->config('app.root_namespace'))) {
            Loader::addNamespace($this->config('app.root_namespace'));
        }

        // 加载composer autofile文件
        Loader::loadComposerAutoloadFiles();

        // 注册类库别名
        Loader::addClassAlias($this->config->pull('alias'));

        // 数据库配置初始化
        Db::init($this->config->pull('database'));

        // 设置系统时区
        date_default_timezone_set($this->config('app.default_timezone'));

        // 读取语言包
        $this->loadLangPack();

        // 路由初始化
        $this->routeInit();
    }
/**
* 初始化应用或模块
* @access public
* @param  string $module 模块名
* @return void
*/
public function init($module = '')
{
  // 定位模块目录
  $module = $module ? $module . DIRECTORY_SEPARATOR : '';
  $path   = $this->appPath . $module;

  // 加载初始化文件
  if (is_file($path . 'init.php')) {
    include $path . 'init.php';
  } elseif (is_file($this->runtimePath . $module . 'init.php')) {
    include $this->runtimePath . $module . 'init.php';
  } else {
    // 加载行为扩展文件
    if (is_file($path . 'tags.php')) {
      $tags = include $path . 'tags.php';
      if (is_array($tags)) {
        $this->hook->import($tags);
      }
    }

    // 加载公共文件
    if (is_file($path . 'common.php')) {
      include_once $path . 'common.php';
    }

    if ('' == $module) {
      // 加载系统助手函数
      include $this->thinkPath . 'helper.php';
    }

    // 加载中间件
    if (is_file($path . 'middleware.php')) {
      $middleware = include $path . 'middleware.php';
      if (is_array($middleware)) {
        $this->middleware->import($middleware);
      }
    }

    // 注册服务的容器对象实例
    if (is_file($path . 'provider.php')) {
      $provider = include $path . 'provider.php';
      if (is_array($provider)) {
        $this->bindTo($provider);
      }
    }

    // 自动读取配置文件
    if (is_dir($path . 'config')) {
      $dir = $path . 'config' . DIRECTORY_SEPARATOR;
    } elseif (is_dir($this->configPath . $module)) {
      $dir = $this->configPath . $module;
    }

    $files = isset($dir) ? scandir($dir) : [];

    foreach ($files as $file) {
      if ('.' . pathinfo($file, PATHINFO_EXTENSION) === $this->configExt) {
        $this->config->load($dir . $file, pathinfo($file, PATHINFO_FILENAME));
      }
    }
  }

  $this->setModulePath($path);

  if ($module) {
    // 对容器中的对象实例进行配置更新
    $this->containerConfigUpdate($module);
  }
    }

初始化应用过程中一些需要注意到的步骤
读取项目根目录下的环境变量配置文件 设置THINKPHP内部的环境变量 .env (攻击者可不可以通过写入覆盖.env文件达成一定的目的?)
一些初始化过程引入的文件
引入惯例配置文件
thinkphp/convention.php (默认配置值)
引入模块目录下的文件
路径为 应用名/模块名/ (模块可无)
初始化 init.php
行为扩展 tags.php
公共文件 common.php
助手函数 helper.php (模块名为空时引入)
中间件 middleware.php
引入配置文件
应用名/模块名(可为空)/config/. php配置文件(后缀可以由环境变量config_ext定义)
目录不存在时引入 应用名/config/模块名/
. php
加载应用和thinkphp目录下的语言包
lang/语言.php (thinkphp 默认语言为zh-cn)
初始化路由
应用目录/route/*.php

初始化之后就开始处理用户的请求:
绑定模块控制器
检测访问路由

    public function path()
    {
        if (is_null($this->path)) {
            $suffix   = $this->config['url_html_suffix'];
            $pathinfo = $this->pathinfo();

            if (false === $suffix) {
                // 禁止伪静态访问
                $this->path = $pathinfo;
            } elseif ($suffix) {
                // 去除正常的URL后缀
                $this->path = preg_replace('/\.(' . ltrim($suffix, '.') . ')$/i', '', $pathinfo);
            } else {
                // 允许任何后缀访问
                $this->path = preg_replace('/\.' . $this->ext() . '$/i', '', $pathinfo);
            }
        }

        return $this->path;
    }

注册路由中间件
执行路由调度

   public function pathinfo()
    {
        if (is_null($this->pathinfo)) {
            if (isset($_GET[$this->config['var_pathinfo']])) {
                // 判断URL里面是否有兼容模式参数
                $pathinfo = $_GET[$this->config['var_pathinfo']];
                unset($_GET[$this->config['var_pathinfo']]);
                unset($this->get[$this->config['var_pathinfo']]);
            } elseif ($this->isCli()) {
                // CLI模式下 index.php module/controller/action/params/...
                $pathinfo = isset($_SERVER['argv'][1]) ? $_SERVER['argv'][1] : '';
            } elseif ('cli-server' == PHP_SAPI) {
                $pathinfo = strpos($this->server('REQUEST_URI'), '?') ? strstr($this->server('REQUEST_URI'), '?', true) : $this->server('REQUEST_URI');
            } elseif ($this->server('PATH_INFO')) {
                $pathinfo = $this->server('PATH_INFO');
            }

            // 分析PATHINFO信息
            if (!isset($pathinfo)) {
                foreach ($this->config['pathinfo_fetch'] as $type) {
                    if ($this->server($type)) {
                        $pathinfo = (0 === strpos($this->server($type), $this->server('SCRIPT_NAME'))) ?
                        substr($this->server($type), strlen($this->server('SCRIPT_NAME'))) : $this->server($type);
                        break;
                    }
                }
            }

            if (!empty($pathinfo)) {
                unset($this->get[$pathinfo], $this->request[$pathinfo]);
            }

            $this->pathinfo = empty($pathinfo) || '/' == $pathinfo ? '' : ltrim($pathinfo, '/');
        }

        return $this->pathinfo;
    }

protected function parseUrl($url)
    {
        $depr = $this->rule->getConfig('pathinfo_depr');
        $bind = $this->rule->getRouter()->getBind();

        if (!empty($bind) && preg_match('/^[a-z]/is', $bind)) {
            $bind = str_replace('/', $depr, $bind);
            // 如果有模块/控制器绑定
            $url = $bind . ('.' != substr($bind, -1) ? $depr : '') . ltrim($url, $depr);
        }

        list($path, $var) = $this->rule->parseUrlPath($url);
        if (empty($path)) {
            return [null, null, null];
        }

        // 解析模块
        $module = $this->rule->getConfig('app_multi_module') ? array_shift($path) : null;

        if ($this->param['auto_search']) {
            $controller = $this->autoFindController($module, $path);
        } else {
            // 解析控制器
            $controller = !empty($path) ? array_shift($path) : null;
        }

        if ($controller && !preg_match('/^[A-Za-z0-9][\w|\.]*$/', $controller)) {
            throw new HttpException(404, 'controller not exists:' . $controller);
        }

        // 解析操作
        $action = !empty($path) ? array_shift($path) : null;

        // 解析额外参数
        if ($path) {
            if ($this->rule->getConfig('url_param_type')) {
                $var += $path;
            } else {
                preg_replace_callback('/(\w+)\|([^\|]+)/', function ($match) use (&$var) {
                    $var[$match[1]] = strip_tags($match[2]);
                }, implode('|', $path));
            }
        }

        $panDomain = $this->request->panDomain();

        if ($panDomain && $key = array_search('*', $var)) {
            // 泛域名赋值
            $var[$key] = $panDomain;
        }

        // 设置当前请求的参数
        $this->request->setRouteVars($var);

        // 封装路由
        $route = [$module, $controller, $action];

        if ($this->hasDefinedRoute($route, $bind)) {
            throw new HttpException(404, 'invalid request:' . str_replace('|', $depr, $url));
        }

        return $route;
    }



public function exec()
    {
        // 监听module_init
        $this->app['hook']->listen('module_init');

        try {
            // 实例化控制器
            $instance = $this->app->controller($this->controller,
                $this->rule->getConfig('url_controller_layer'),
                $this->rule->getConfig('controller_suffix'),
                $this->rule->getConfig('empty_controller'));
        } catch (ClassNotFoundException $e) {
            throw new HttpException(404, 'controller not exists:' . $e->getClass());
        }

        $this->app['middleware']->controller(function (Request $request, $next) use ($instance) {
            // 获取当前操作名
            $action = $this->actionName . $this->rule->getConfig('action_suffix');

            if (is_callable([$instance, $action])) {
                // 执行操作方法
                $call = [$instance, $action];

                // 严格获取当前操作方法名
                $reflect    = new ReflectionMethod($instance, $action);
                $methodName = $reflect->getName();
                $suffix     = $this->rule->getConfig('action_suffix');
                $actionName = $suffix ? substr($methodName, 0, -strlen($suffix)) : $methodName;
                $this->request->setAction($actionName);

                // 自动获取请求变量
                $vars = $this->rule->getConfig('url_param_type')
                ? $this->request->route()
                : $this->request->param();
                $vars = array_merge($vars, $this->param);
            } elseif (is_callable([$instance, '_empty'])) {
                // 空操作
                $call    = [$instance, '_empty'];
                $vars    = [$this->actionName];
                $reflect = new ReflectionMethod($instance, '_empty');
            } else {
                // 操作不存在
                throw new HttpException(404, 'method not exists:' . get_class($instance) . '->' . $action . '()');
            }

            $this->app['hook']->listen('action_begin', $call);

            $data = $this->app->invokeReflectMethod($instance, $reflect, $vars);

            return $this->autoResponse($data);
        });

        return $this->app['middleware']->dispatch($this->request, 'controller');
    }

未完待续