| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677 | 
							- <?php
 
- // +----------------------------------------------------------------------
 
- // | ThinkPHP [ WE CAN DO IT JUST THINK ]
 
- // +----------------------------------------------------------------------
 
- // | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
 
- // +----------------------------------------------------------------------
 
- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
 
- // +----------------------------------------------------------------------
 
- // | Author: liu21st <liu21st@gmail.com>
 
- // +----------------------------------------------------------------------
 
- namespace think;
 
- use think\exception\ClassNotFoundException;
 
- use think\exception\HttpException;
 
- use think\exception\HttpResponseException;
 
- use think\exception\RouteNotFoundException;
 
- /**
 
-  * App 应用管理
 
-  * @author liu21st <liu21st@gmail.com>
 
-  */
 
- class App
 
- {
 
-     /**
 
-      * @var bool 是否初始化过
 
-      */
 
-     protected static $init = false;
 
-     /**
 
-      * @var string 当前模块路径
 
-      */
 
-     public static $modulePath;
 
-     /**
 
-      * @var bool 应用调试模式
 
-      */
 
-     public static $debug = true;
 
-     /**
 
-      * @var string 应用类库命名空间
 
-      */
 
-     public static $namespace = 'app';
 
-     /**
 
-      * @var bool 应用类库后缀
 
-      */
 
-     public static $suffix = false;
 
-     /**
 
-      * @var bool 应用路由检测
 
-      */
 
-     protected static $routeCheck;
 
-     /**
 
-      * @var bool 严格路由检测
 
-      */
 
-     protected static $routeMust;
 
-     /**
 
-      * @var array 请求调度分发
 
-      */
 
-     protected static $dispatch;
 
-     /**
 
-      * @var array 额外加载文件
 
-      */
 
-     protected static $file = [];
 
-     /**
 
-      * 执行应用程序
 
-      * @access public
 
-      * @param  Request $request 请求对象
 
-      * @return Response
 
-      * @throws Exception
 
-      */
 
-     public static function run(Request $request = null)
 
-     {
 
-         $request = is_null($request) ? Request::instance() : $request;
 
-         try {
 
-             $config = self::initCommon();
 
-             // 模块/控制器绑定
 
-             if (defined('BIND_MODULE')) {
 
-                 BIND_MODULE && Route::bind(BIND_MODULE);
 
-             } elseif ($config['auto_bind_module']) {
 
-                 // 入口自动绑定
 
-                 $name = pathinfo($request->baseFile(), PATHINFO_FILENAME);
 
-                 if ($name && 'index' != $name && is_dir(APP_PATH . $name)) {
 
-                     Route::bind($name);
 
-                 }
 
-             }
 
-             $request->filter($config['default_filter']);
 
-             // 默认语言
 
-             Lang::range($config['default_lang']);
 
-             // 开启多语言机制 检测当前语言
 
-             $config['lang_switch_on'] && Lang::detect();
 
-             $request->langset(Lang::range());
 
-             // 加载系统语言包
 
-             Lang::load([
 
-                 THINK_PATH . 'lang' . DS . $request->langset() . EXT,
 
-                 APP_PATH . 'lang' . DS . $request->langset() . EXT,
 
-             ]);
 
-             // 监听 app_dispatch
 
-             Hook::listen('app_dispatch', self::$dispatch);
 
-             // 获取应用调度信息
 
-             $dispatch = self::$dispatch;
 
-             // 未设置调度信息则进行 URL 路由检测
 
-             if (empty($dispatch)) {
 
-                 $dispatch = self::routeCheck($request, $config);
 
-             }
 
-             // 记录当前调度信息
 
-             $request->dispatch($dispatch);
 
-             // 记录路由和请求信息
 
-             if (self::$debug) {
 
-                 Log::record('[ ROUTE ] ' . var_export($dispatch, true), 'info');
 
-                 Log::record('[ HEADER ] ' . var_export($request->header(), true), 'info');
 
-                 Log::record('[ PARAM ] ' . var_export($request->param(), true), 'info');
 
-             }
 
-             // 监听 app_begin
 
-             Hook::listen('app_begin', $dispatch);
 
-             // 请求缓存检查
 
-             $request->cache(
 
-                 $config['request_cache'],
 
-                 $config['request_cache_expire'],
 
-                 $config['request_cache_except']
 
-             );
 
-             $data = self::exec($dispatch, $config);
 
-         } catch (HttpResponseException $exception) {
 
-             $data = $exception->getResponse();
 
-         }
 
-         // 清空类的实例化
 
-         Loader::clearInstance();
 
-         // 输出数据到客户端
 
-         if ($data instanceof Response) {
 
-             $response = $data;
 
-         } elseif (!is_null($data)) {
 
-             // 默认自动识别响应输出类型
 
-             $type = $request->isAjax() ?
 
-             Config::get('default_ajax_return') :
 
-             Config::get('default_return_type');
 
-             $response = Response::create($data, $type);
 
-         } else {
 
-             $response = Response::create();
 
-         }
 
-         // 监听 app_end
 
-         Hook::listen('app_end', $response);
 
-         return $response;
 
-     }
 
-     /**
 
-      * 初始化应用,并返回配置信息
 
-      * @access public
 
-      * @return array
 
-      */
 
-     public static function initCommon()
 
-     {
 
-         if (empty(self::$init)) {
 
-             if (defined('APP_NAMESPACE')) {
 
-                 self::$namespace = APP_NAMESPACE;
 
-             }
 
-             Loader::addNamespace(self::$namespace, APP_PATH);
 
-             // 初始化应用
 
-             $config       = self::init();
 
-             self::$suffix = $config['class_suffix'];
 
-             // 应用调试模式
 
-             self::$debug = Env::get('app_debug', Config::get('app_debug'));
 
-             if (!self::$debug) {
 
-                 ini_set('display_errors', 'Off');
 
-             } elseif (!IS_CLI) {
 
-                 // 重新申请一块比较大的 buffer
 
-                 if (ob_get_level() > 0) {
 
-                     $output = ob_get_clean();
 
-                 }
 
-                 ob_start();
 
-                 if (!empty($output)) {
 
-                     echo $output;
 
-                 }
 
-             }
 
-             if (!empty($config['root_namespace'])) {
 
-                 Loader::addNamespace($config['root_namespace']);
 
-             }
 
-             // 加载额外文件
 
-             if (!empty($config['extra_file_list'])) {
 
-                 foreach ($config['extra_file_list'] as $file) {
 
-                     $file = strpos($file, '.') ? $file : APP_PATH . $file . EXT;
 
-                     if (is_file($file) && !isset(self::$file[$file])) {
 
-                         include $file;
 
-                         self::$file[$file] = true;
 
-                     }
 
-                 }
 
-             }
 
-             // 设置系统时区
 
-             date_default_timezone_set($config['default_timezone']);
 
-             // 监听 app_init
 
-             Hook::listen('app_init');
 
-             self::$init = true;
 
-         }
 
-         return Config::get();
 
-     }
 
-     /**
 
-      * 初始化应用或模块
 
-      * @access public
 
-      * @param string $module 模块名
 
-      * @return array
 
-      */
 
-     private static function init($module = '')
 
-     {
 
-         // 定位模块目录
 
-         $module = $module ? $module . DS : '';
 
-         // 加载初始化文件
 
-         if (is_file(APP_PATH . $module . 'init' . EXT)) {
 
-             include APP_PATH . $module . 'init' . EXT;
 
-         } elseif (is_file(RUNTIME_PATH . $module . 'init' . EXT)) {
 
-             include RUNTIME_PATH . $module . 'init' . EXT;
 
-         } else {
 
-             // 加载模块配置
 
-             $config = Config::load(CONF_PATH . $module . 'config' . CONF_EXT);
 
-             // 读取数据库配置文件
 
-             $filename = CONF_PATH . $module . 'database' . CONF_EXT;
 
-             Config::load($filename, 'database');
 
-             // 读取扩展配置文件
 
-             if (is_dir(CONF_PATH . $module . 'extra')) {
 
-                 $dir   = CONF_PATH . $module . 'extra';
 
-                 $files = scandir($dir);
 
-                 foreach ($files as $file) {
 
-                     if ('.' . pathinfo($file, PATHINFO_EXTENSION) === CONF_EXT) {
 
-                         $filename = $dir . DS . $file;
 
-                         Config::load($filename, pathinfo($file, PATHINFO_FILENAME));
 
-                     }
 
-                 }
 
-             }
 
-             // 加载应用状态配置
 
-             if ($config['app_status']) {
 
-                 Config::load(CONF_PATH . $module . $config['app_status'] . CONF_EXT);
 
-             }
 
-             // 加载行为扩展文件
 
-             if (is_file(CONF_PATH . $module . 'tags' . EXT)) {
 
-                 Hook::import(include CONF_PATH . $module . 'tags' . EXT);
 
-             }
 
-             // 加载公共文件
 
-             $path = APP_PATH . $module;
 
-             if (is_file($path . 'common' . EXT)) {
 
-                 include $path . 'common' . EXT;
 
-             }
 
-             // 加载当前模块语言包
 
-             if ($module) {
 
-                 Lang::load($path . 'lang' . DS . Request::instance()->langset() . EXT);
 
-             }
 
-         }
 
-         return Config::get();
 
-     }
 
-     /**
 
-      * 设置当前请求的调度信息
 
-      * @access public
 
-      * @param array|string  $dispatch 调度信息
 
-      * @param string        $type     调度类型
 
-      * @return void
 
-      */
 
-     public static function dispatch($dispatch, $type = 'module')
 
-     {
 
-         self::$dispatch = ['type' => $type, $type => $dispatch];
 
-     }
 
-     /**
 
-      * 执行函数或者闭包方法 支持参数调用
 
-      * @access public
 
-      * @param string|array|\Closure $function 函数或者闭包
 
-      * @param array                 $vars     变量
 
-      * @return mixed
 
-      */
 
-     public static function invokeFunction($function, $vars = [])
 
-     {
 
-         $reflect = new \ReflectionFunction($function);
 
-         $args    = self::bindParams($reflect, $vars);
 
-         // 记录执行信息
 
-         self::$debug && Log::record('[ RUN ] ' . $reflect->__toString(), 'info');
 
-         return $reflect->invokeArgs($args);
 
-     }
 
-     /**
 
-      * 调用反射执行类的方法 支持参数绑定
 
-      * @access public
 
-      * @param string|array $method 方法
 
-      * @param array        $vars   变量
 
-      * @return mixed
 
-      */
 
-     public static function invokeMethod($method, $vars = [])
 
-     {
 
-         if (is_array($method)) {
 
-             $class   = is_object($method[0]) ? $method[0] : self::invokeClass($method[0]);
 
-             $reflect = new \ReflectionMethod($class, $method[1]);
 
-         } else {
 
-             // 静态方法
 
-             $reflect = new \ReflectionMethod($method);
 
-         }
 
-         $args = self::bindParams($reflect, $vars);
 
-         self::$debug && Log::record('[ RUN ] ' . $reflect->class . '->' . $reflect->name . '[ ' . $reflect->getFileName() . ' ]', 'info');
 
-         return $reflect->invokeArgs(isset($class) ? $class : null, $args);
 
-     }
 
-     /**
 
-      * 调用反射执行类的实例化 支持依赖注入
 
-      * @access public
 
-      * @param string $class 类名
 
-      * @param array  $vars  变量
 
-      * @return mixed
 
-      */
 
-     public static function invokeClass($class, $vars = [])
 
-     {
 
-         $reflect     = new \ReflectionClass($class);
 
-         $constructor = $reflect->getConstructor();
 
-         $args        = $constructor ? self::bindParams($constructor, $vars) : [];
 
-         return $reflect->newInstanceArgs($args);
 
-     }
 
-     /**
 
-      * 绑定参数
 
-      * @access private
 
-      * @param \ReflectionMethod|\ReflectionFunction $reflect 反射类
 
-      * @param array                                 $vars    变量
 
-      * @return array
 
-      */
 
-     private static function bindParams($reflect, $vars = [])
 
-     {
 
-         // 自动获取请求变量
 
-         if (empty($vars)) {
 
-             $vars = Config::get('url_param_type') ?
 
-             Request::instance()->route() :
 
-             Request::instance()->param();
 
-         }
 
-         $args = [];
 
-         if ($reflect->getNumberOfParameters() > 0) {
 
-             // 判断数组类型 数字数组时按顺序绑定参数
 
-             reset($vars);
 
-             $type = key($vars) === 0 ? 1 : 0;
 
-             foreach ($reflect->getParameters() as $param) {
 
-                 $args[] = self::getParamValue($param, $vars, $type);
 
-             }
 
-         }
 
-         return $args;
 
-     }
 
-     /**
 
-      * 获取参数值
 
-      * @access private
 
-      * @param \ReflectionParameter  $param 参数
 
-      * @param array                 $vars  变量
 
-      * @param string                $type  类别
 
-      * @return array
 
-      */
 
-     private static function getParamValue($param, &$vars, $type)
 
-     {
 
-         $name  = $param->getName();
 
-         $class = $param->getClass();
 
-         if ($class) {
 
-             $className = $class->getName();
 
-             $bind      = Request::instance()->$name;
 
-             if ($bind instanceof $className) {
 
-                 $result = $bind;
 
-             } else {
 
-                 if (method_exists($className, 'invoke')) {
 
-                     $method = new \ReflectionMethod($className, 'invoke');
 
-                     if ($method->isPublic() && $method->isStatic()) {
 
-                         return $className::invoke(Request::instance());
 
-                     }
 
-                 }
 
-                 $result = method_exists($className, 'instance') ?
 
-                 $className::instance() :
 
-                 new $className;
 
-             }
 
-         } elseif (1 == $type && !empty($vars)) {
 
-             $result = array_shift($vars);
 
-         } elseif (0 == $type && isset($vars[$name])) {
 
-             $result = $vars[$name];
 
-         } elseif ($param->isDefaultValueAvailable()) {
 
-             $result = $param->getDefaultValue();
 
-         } else {
 
-             throw new \InvalidArgumentException('method param miss:' . $name);
 
-         }
 
-         return $result;
 
-     }
 
-     /**
 
-      * 执行调用分发
 
-      * @access protected
 
-      * @param array $dispatch 调用信息
 
-      * @param array $config   配置信息
 
-      * @return Response|mixed
 
-      * @throws \InvalidArgumentException
 
-      */
 
-     protected static function exec($dispatch, $config)
 
-     {
 
-         switch ($dispatch['type']) {
 
-             case 'redirect': // 重定向跳转
 
-                 $data = Response::create($dispatch['url'], 'redirect')
 
-                     ->code($dispatch['status']);
 
-                 break;
 
-             case 'module': // 模块/控制器/操作
 
-                 $data = self::module(
 
-                     $dispatch['module'],
 
-                     $config,
 
-                     isset($dispatch['convert']) ? $dispatch['convert'] : null
 
-                 );
 
-                 break;
 
-             case 'controller': // 执行控制器操作
 
-                 $vars = array_merge(Request::instance()->param(), $dispatch['var']);
 
-                 $data = Loader::action(
 
-                     $dispatch['controller'],
 
-                     $vars,
 
-                     $config['url_controller_layer'],
 
-                     $config['controller_suffix']
 
-                 );
 
-                 break;
 
-             case 'method': // 回调方法
 
-                 $vars = array_merge(Request::instance()->param(), $dispatch['var']);
 
-                 $data = self::invokeMethod($dispatch['method'], $vars);
 
-                 break;
 
-             case 'function': // 闭包
 
-                 $data = self::invokeFunction($dispatch['function']);
 
-                 break;
 
-             case 'response': // Response 实例
 
-                 $data = $dispatch['response'];
 
-                 break;
 
-             default:
 
-                 throw new \InvalidArgumentException('dispatch type not support');
 
-         }
 
-         return $data;
 
-     }
 
-     /**
 
-      * 执行模块
 
-      * @access public
 
-      * @param array $result  模块/控制器/操作
 
-      * @param array $config  配置参数
 
-      * @param bool  $convert 是否自动转换控制器和操作名
 
-      * @return mixed
 
-      * @throws HttpException
 
-      */
 
-     public static function module($result, $config, $convert = null)
 
-     {
 
-         if (is_string($result)) {
 
-             $result = explode('/', $result);
 
-         }
 
-         $request = Request::instance();
 
-         if ($config['app_multi_module']) {
 
-             // 多模块部署
 
-             $module    = strip_tags(strtolower($result[0] ?: $config['default_module']));
 
-             $bind      = Route::getBind('module');
 
-             $available = false;
 
-             if ($bind) {
 
-                 // 绑定模块
 
-                 list($bindModule) = explode('/', $bind);
 
-                 if (empty($result[0])) {
 
-                     $module    = $bindModule;
 
-                     $available = true;
 
-                 } elseif ($module == $bindModule) {
 
-                     $available = true;
 
-                 }
 
-             } elseif (!in_array($module, $config['deny_module_list']) && is_dir(APP_PATH . $module)) {
 
-                 $available = true;
 
-             }
 
-             // 模块初始化
 
-             if ($module && $available) {
 
-                 // 初始化模块
 
-                 $request->module($module);
 
-                 $config = self::init($module);
 
-                 // 模块请求缓存检查
 
-                 $request->cache(
 
-                     $config['request_cache'],
 
-                     $config['request_cache_expire'],
 
-                     $config['request_cache_except']
 
-                 );
 
-             } else {
 
-                 throw new HttpException(404, 'module not exists:' . $module);
 
-             }
 
-         } else {
 
-             // 单一模块部署
 
-             $module = '';
 
-             $request->module($module);
 
-         }
 
-         // 设置默认过滤机制
 
-         $request->filter($config['default_filter']);
 
-         // 当前模块路径
 
-         App::$modulePath = APP_PATH . ($module ? $module . DS : '');
 
-         // 是否自动转换控制器和操作名
 
-         $convert = is_bool($convert) ? $convert : $config['url_convert'];
 
-         // 获取控制器名
 
-         $controller = strip_tags($result[1] ?: $config['default_controller']);
 
-         if (!preg_match('/^[A-Za-z](\w|\.)*$/', $controller)) {
 
-             throw new HttpException(404, 'controller not exists:' . $controller);
 
-         }
 
-         $controller = $convert ? strtolower($controller) : $controller;
 
-         // 获取操作名
 
-         $actionName = strip_tags($result[2] ?: $config['default_action']);
 
-         if (!empty($config['action_convert'])) {
 
-             $actionName = Loader::parseName($actionName, 1);
 
-         } else {
 
-             $actionName = $convert ? strtolower($actionName) : $actionName;
 
-         }
 
-         // 设置当前请求的控制器、操作
 
-         $request->controller(Loader::parseName($controller, 1))->action($actionName);
 
-         // 监听module_init
 
-         Hook::listen('module_init', $request);
 
-         try {
 
-             $instance = Loader::controller(
 
-                 $controller,
 
-                 $config['url_controller_layer'],
 
-                 $config['controller_suffix'],
 
-                 $config['empty_controller']
 
-             );
 
-         } catch (ClassNotFoundException $e) {
 
-             throw new HttpException(404, 'controller not exists:' . $e->getClass());
 
-         }
 
-         // 获取当前操作名
 
-         $action = $actionName . $config['action_suffix'];
 
-         $vars = [];
 
-         if (is_callable([$instance, $action])) {
 
-             // 执行操作方法
 
-             $call = [$instance, $action];
 
-             // 严格获取当前操作方法名
 
-             $reflect    = new \ReflectionMethod($instance, $action);
 
-             $methodName = $reflect->getName();
 
-             $suffix     = $config['action_suffix'];
 
-             $actionName = $suffix ? substr($methodName, 0, -strlen($suffix)) : $methodName;
 
-             $request->action($actionName);
 
-         } elseif (is_callable([$instance, '_empty'])) {
 
-             // 空操作
 
-             $call = [$instance, '_empty'];
 
-             $vars = [$actionName];
 
-         } else {
 
-             // 操作不存在
 
-             throw new HttpException(404, 'method not exists:' . get_class($instance) . '->' . $action . '()');
 
-         }
 
-         Hook::listen('action_begin', $call);
 
-         return self::invokeMethod($call, $vars);
 
-     }
 
-     /**
 
-      * URL路由检测(根据PATH_INFO)
 
-      * @access public
 
-      * @param  \think\Request $request 请求实例
 
-      * @param  array          $config  配置信息
 
-      * @return array
 
-      * @throws \think\Exception
 
-      */
 
-     public static function routeCheck($request, array $config)
 
-     {
 
-         $path   = $request->path();
 
-         $depr   = $config['pathinfo_depr'];
 
-         $result = false;
 
-         // 路由检测
 
-         $check = !is_null(self::$routeCheck) ? self::$routeCheck : $config['url_route_on'];
 
-         if ($check) {
 
-             // 开启路由
 
-             if (is_file(RUNTIME_PATH . 'route.php')) {
 
-                 // 读取路由缓存
 
-                 $rules = include RUNTIME_PATH . 'route.php';
 
-                 is_array($rules) && Route::rules($rules);
 
-             } else {
 
-                 $files = $config['route_config_file'];
 
-                 foreach ($files as $file) {
 
-                     if (is_file(CONF_PATH . $file . CONF_EXT)) {
 
-                         // 导入路由配置
 
-                         $rules = include CONF_PATH . $file . CONF_EXT;
 
-                         is_array($rules) && Route::import($rules);
 
-                     }
 
-                 }
 
-             }
 
-             // 路由检测(根据路由定义返回不同的URL调度)
 
-             $result = Route::check($request, $path, $depr, $config['url_domain_deploy']);
 
-             $must   = !is_null(self::$routeMust) ? self::$routeMust : $config['url_route_must'];
 
-             if ($must && false === $result) {
 
-                 // 路由无效
 
-                 throw new RouteNotFoundException();
 
-             }
 
-         }
 
-         // 路由无效 解析模块/控制器/操作/参数... 支持控制器自动搜索
 
-         if (false === $result) {
 
-             $result = Route::parseUrl($path, $depr, $config['controller_auto_search']);
 
-         }
 
-         return $result;
 
-     }
 
-     /**
 
-      * 设置应用的路由检测机制
 
-      * @access public
 
-      * @param  bool $route 是否需要检测路由
 
-      * @param  bool $must  是否强制检测路由
 
-      * @return void
 
-      */
 
-     public static function route($route, $must = false)
 
-     {
 
-         self::$routeCheck = $route;
 
-         self::$routeMust  = $must;
 
-     }
 
- }
 
 
  |