/** * 调试输出接口 * @access public * @param Response $response Response对象 * @param array $log 日志信息 * @return bool */ public function output(Response $response, array $log = []) { $request = Request::instance(); $contentType = $response->getHeader('Content-Type'); $accept = $request->header('accept'); if (strpos($accept, 'application/json') === 0 || $request->isAjax()) { return false; } elseif (!empty($contentType) && strpos($contentType, 'html') === false) { return false; } // 获取基本信息 $runtime = number_format(microtime(true), 8, '.', '') - THINK_START_TIME; $reqs = number_format(1 / $runtime, 2); $mem = number_format((memory_get_usage() - THINK_START_MEM) / 1024, 2); // 页面Trace信息 if (isset($_SERVER['HTTP_HOST'])) { $uri = $_SERVER['SERVER_PROTOCOL'] . ' ' . $_SERVER['REQUEST_METHOD'] . ' : ' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']; } else { $uri = 'cmd:' . implode(' ', $_SERVER['argv']); } $base = ['请求信息' => date('Y-m-d H:i:s', $_SERVER['REQUEST_TIME']) . ' ' . $uri, '运行时间' => number_format($runtime, 6) . 's [ 吞吐率:' . $reqs . 'req/s ] 内存消耗:' . $mem . 'kb 文件加载:' . count(get_included_files()), '查询信息' => Db::$queryTimes . ' queries ' . Db::$executeTimes . ' writes ', '缓存信息' => Cache::$readTimes . ' reads,' . Cache::$writeTimes . ' writes', '配置加载' => count(Config::get())]; if (session_id()) { $base['会话信息'] = 'SESSION_ID=' . session_id(); } $info = Debug::getFile(true); // 页面Trace信息 $trace = []; foreach ($this->config['trace_tabs'] as $name => $title) { $name = strtolower($name); switch ($name) { case 'base': // 基本信息 $trace[$title] = $base; break; case 'file': // 文件信息 $trace[$title] = $info; break; default: // 调试信息 if (strpos($name, '|')) { // 多组信息 $names = explode('|', $name); $result = []; foreach ($names as $name) { $result = array_merge($result, isset($log[$name]) ? $log[$name] : []); } $trace[$title] = $result; } else { $trace[$title] = isset($log[$name]) ? $log[$name] : ''; } } } // 调用Trace页面模板 ob_start(); include $this->config['trace_file']; return ob_get_clean(); }
/** * kindeditor 图片上传 */ public function kindeditor($dir = '') { if (!in_array($dir, ['image', 'file', 'flash', 'media'])) { $return = ['error' => 1, 'message' => '不支持的上传类型']; Response::create($return, 'json')->send(); } $Storage = Loader::model('Storage'); $return = ['error' => 0, 'info' => '上传成功']; switch ($dir) { case 'image': $options['ext'] = ['jpg', 'gif', 'png', 'jpeg']; break; case 'file': $options['ext'] = ['xls', 'xlsx', 'doc', 'docx', 'txt', 'zip', 'rar']; break; case 'flash': $options['ext'] = ['flv', 'swf']; break; case 'media': $options['ext'] = ['mp4', 'avi']; break; } $info = $Storage->upload('imgFile', $options); if (false !== $info) { $return['url'] = $info['path']; } else { $return['error'] = 1; $return['message'] = $Storage->getError(); } Response::create($return, 'json')->send(); }
/** * @covers think\Response::send * @todo Implement testSend(). */ public function testSend() { $dataArr = []; $dataArr["key"] = "value"; $response = Response::create($dataArr, 'json'); $result = $response->getContent(); $this->assertEquals('{"key":"value"}', $result); $request = Request::instance(); $request->get(['callback' => 'callback']); $response = Response::create($dataArr, 'jsonp'); $result = $response->getContent(); $this->assertEquals('callback({"key":"value"});', $result); }
/** * 输出返回数据 * @access protected * @param mixed $data 要返回的数据 * @param String $type 返回类型 JSON XML * @param integer $code HTTP状态码 * @return Response */ protected function response($data, $type = 'json', $code = 200) { return Response::create($data, $type)->code($code); }
/** * 执行应用程序 * @access public * @param \think\Request $request Request对象 * @return \think\Response * @throws Exception */ public static function run($request) { // 初始化应用(公共模块) self::initModule(COMMON_MODULE, Config::get()); // 获取配置参数 $config = Config::get(); // 注册根命名空间 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)) { include_once $file; } } } // 设置系统时区 date_default_timezone_set($config['default_timezone']); // 监听app_init APP_HOOK && Hook::listen('app_init'); // 开启多语言机制 if ($config['lang_switch_on']) { // 获取当前语言 defined('LANG_SET') or define('LANG_SET', Lang::range()); // 加载系统语言包 Lang::load(THINK_PATH . 'lang' . DS . LANG_SET . EXT); if (!APP_MULTI_MODULE) { Lang::load(APP_PATH . 'lang' . DS . LANG_SET . EXT); } } // 获取当前请求的调度信息 $dispatch = $request->dispatch(); if (empty($dispatch)) { // 未指定调度类型 则进行URL路由检测 $dispatch = self::route($request, $config); } // 记录路由信息 APP_DEBUG && Log::record('[ ROUTE ] ' . var_export($dispatch, true), 'info'); // 监听app_begin APP_HOOK && Hook::listen('app_begin', $dispatch); try { switch ($dispatch['type']) { case 'redirect': // 执行重定向跳转 header('Location: ' . $dispatch['url'], true, $dispatch['status']); break; case 'module': // 模块/控制器/操作 $data = self::module($dispatch['module'], $config); break; case 'controller': // 执行控制器操作 $data = Loader::action($dispatch['controller'], $dispatch['params']); break; case 'method': // 执行回调方法 $data = self::invokeMethod($dispatch['method'], $dispatch['params']); break; case 'function': // 规则闭包 $data = self::invokeFunction($dispatch['function'], $dispatch['params']); break; case 'finish': // 已经完成 不再继续执行 break; default: throw new Exception('dispatch type not support', 10008); } } catch (HttpResponseException $exception) { $data = $exception->getResponse(); } // 输出数据到客户端 if (isset($data)) { if ($data instanceof Response) { return $data->send(); } else { // 监听app_end APP_HOOK && Hook::listen('app_end', $data); // 自动响应输出 return Response::instance()->send($data, '', Config::get('response_return')); } } }
/** * 获取\think\response\Redirect对象实例 * @param mixed $url 重定向地址 支持Url::build方法的地址 * @param array|integer $params 额外参数 * @param integer $code 状态码 * @return \think\response\Redirect */ function redirect($url = [], $params = [], $code = 302) { if (is_integer($params)) { $code = $params; $params = []; } return Response::create($url, 'redirect', $code)->params($params); }
/** * 执行应用程序 * @access public * @param Request $request Request对象 * @return Response * @throws Exception */ public static function run(Request $request = null) { is_null($request) && ($request = Request::instance()); if ('ico' == $request->ext()) { throw new HttpException(404, 'ico file not exists'); } $config = self::initCommon(); try { // 开启多语言机制 if ($config['lang_switch_on']) { // 获取当前语言 $request->langset(Lang::detect()); // 加载系统语言包 Lang::load(THINK_PATH . 'lang' . DS . $request->langset() . EXT); if (!$config['app_multi_module']) { Lang::load(APP_PATH . 'lang' . DS . $request->langset() . EXT); } } // 获取应用调度信息 $dispatch = self::$dispatch; if (empty($dispatch)) { // 进行URL路由检测 $dispatch = self::routeCheck($request, $config); } // 记录当前调度信息 $request->dispatch($dispatch); // 记录路由信息 self::$debug && Log::record('[ ROUTE ] ' . var_export($dispatch, true), 'info'); // 监听app_begin Hook::listen('app_begin', $dispatch); 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': // 执行控制器操作 $data = Loader::action($dispatch['controller'], $dispatch['params']); break; case 'method': // 执行回调方法 $data = self::invokeMethod($dispatch['method'], $dispatch['params']); break; case 'function': // 执行闭包 $data = self::invokeFunction($dispatch['function'], $dispatch['params']); break; case 'response': $data = $dispatch['response']; break; default: throw new \InvalidArgumentException('dispatch type not support'); } } catch (HttpResponseException $exception) { $data = $exception->getResponse(); } // 清空类的实例化 Loader::clearInstance(); // 输出数据到客户端 if ($data instanceof Response) { $response = $data; } elseif (!is_null($data)) { // 默认自动识别响应输出类型 $isAjax = $request->isAjax(); $type = $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); // Trace调试注入 if (Config::get('app_trace')) { Debug::inject($response); } return $response; }
/** * 输出异常信息 * @param \Exception $exception * @param Array $vars 异常信息 * @return void */ public static function output($exception, array $vars) { http_response_code($exception instanceof Exception ? $exception->getHttpStatus() : 500); $type = Config::get('default_return_type'); if (IS_API && 'html' != $type) { // 异常信息输出监听 APP_HOOK && Hook::listen('error_output', $data); // 输出异常内容 Response::send($data, $type, Config::get('response_return')); } else { //ob_end_clean(); extract($vars); include Config::get('exception_tmpl'); } }
/** * URL重定向 * @access protected * @param string $url 跳转的URL表达式 * @param array|int $params 其它URL参数或http code * @return void */ public function redirect($url, $params = []) { return Response::redirect($url, $params); }
/** * 返回封装后的API数据到客户端 * @access protected * @param mixed $data 要返回的数据 * @param integer $code 返回的code * @param mixed $msg 提示信息 * @param string $type 返回数据格式 * @return mixed */ protected function result($data, $code = 0, $msg = '', $type = '') { $result = ['code' => $code, 'msg' => $msg, 'time' => $_SERVER['REQUEST_TIME'], 'data' => $data]; $type = $type ?: $this->getResponseType(); return Response::create($result, $type); }
public function __construct($data = '', $code = 302, array $header = [], array $options = []) { parent::__construct($data, $code, $header, $options); $this->cacheControl('no-cache,must-revalidate'); }
/** * 设置当前地址的请求缓存 * @access public * @param string $key 缓存标识,支持变量规则 ,例如 item/:name/:id * @param mixed $expire 缓存有效期 * @return void */ public function cache($key, $expire = null) { if (false !== $key && $this->isGet() && !$this->isCheckCache) { // 标记请求缓存检查 $this->isCheckCache = true; if (false === $expire) { // 关闭当前缓存 return; } if ($key instanceof \Closure) { $key = call_user_func_array($key, [$this]); } elseif (true === $key) { // 自动缓存功能 $key = '__URL__'; } elseif (strpos($key, '|')) { list($key, $fun) = explode('|', $key); } // 特殊规则替换 if (false !== strpos($key, '__')) { $key = str_replace(['__MODULE__', '__CONTROLLER__', '__ACTION__', '__URL__'], [$this->module, $this->controller, $this->action, md5($this->url())], $key); } if (false !== strpos($key, ':')) { $param = $this->param(); foreach ($param as $item => $val) { if (is_string($val) && false !== strpos($key, ':' . $item)) { $key = str_replace(':' . $item, $val, $key); } } } elseif (strpos($key, ']')) { if ('[' . $this->ext() . ']' == $key) { // 缓存某个后缀的请求 $key = md5($this->url()); } else { return; } } if (isset($fun)) { $key = $fun($key); } if (strtotime($this->server('HTTP_IF_MODIFIED_SINCE')) + $expire > $_SERVER['REQUEST_TIME']) { // 读取缓存 $response = Response::create()->code(304); throw new \think\exception\HttpResponseException($response); } elseif (Cache::has($key)) { list($content, $header) = Cache::get($key); $response = Response::create($content)->header($header); throw new \think\exception\HttpResponseException($response); } else { $this->cache = [$key, $expire]; } } }
/** * @param Exception $exception * @return Response */ protected function convertExceptionToResponse(Exception $exception) { // 收集异常数据 if (App::$debug) { // 调试模式,获取详细的错误信息 $data = ['name' => get_class($exception), 'file' => $exception->getFile(), 'line' => $exception->getLine(), 'message' => $this->getMessage($exception), 'trace' => $exception->getTrace(), 'code' => $this->getCode($exception), 'source' => $this->getSourceCode($exception), 'datas' => $this->getExtendData($exception), 'tables' => ['GET Data' => $_GET, 'POST Data' => $_POST, 'Files' => $_FILES, 'Cookies' => $_COOKIE, 'Session' => isset($_SESSION) ? $_SESSION : [], 'Server/Request Data' => $_SERVER, 'Environment Variables' => $_ENV, 'ThinkPHP Constants' => $this->getConst()]]; } else { // 部署模式仅显示 Code 和 Message $data = ['code' => $this->getCode($exception), 'message' => $this->getMessage($exception)]; if (!Config::get('show_error_msg')) { // 不显示详细错误信息 $data['message'] = Config::get('error_message'); } } //保留一层 while (ob_get_level() > 1) { ob_end_clean(); } $data['echo'] = ob_get_clean(); ob_start(); extract($data); include Config::get('exception_tmpl'); // 获取并清空缓存 $content = ob_get_clean(); $response = new Response($content, 'html'); if ($exception instanceof HttpException) { $statusCode = $exception->getStatusCode(); $response->header($exception->getHeaders()); } if (!isset($statusCode)) { $statusCode = 500; } $response->code($statusCode); return $response; }
/** * 执行应用程序 * @access public * @param Request $request Request对象 * @return Response * @throws Exception */ public static function run(Request $request = null) { is_null($request) && ($request = Request::instance()); 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']); if ($config['lang_switch_on']) { // 开启多语言机制 检测当前语言 Lang::detect(); } else { // 读取默认语言 Lang::range($config['default_lang']); } $request->langset(Lang::range()); // 加载系统语言包 Lang::load([THINK_PATH . 'lang' . DS . $request->langset() . EXT, APP_PATH . 'lang' . DS . $request->langset() . EXT]); // 获取应用调度信息 $dispatch = self::$dispatch; if (empty($dispatch)) { // 进行URL路由检测 $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); 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': // 执行控制器操作 $data = Loader::action($dispatch['controller']); break; case 'method': // 执行回调方法 $data = self::invokeMethod($dispatch['method']); break; case 'function': // 执行闭包 $data = self::invokeFunction($dispatch['function']); break; case 'response': $data = $dispatch['response']; break; default: throw new \InvalidArgumentException('dispatch type not support'); } } catch (HttpResponseException $exception) { $data = $exception->getResponse(); } // 清空类的实例化 Loader::clearInstance(); // 输出数据到客户端 if ($data instanceof Response) { $response = $data; } elseif (!is_null($data)) { // 默认自动识别响应输出类型 $isAjax = $request->isAjax(); $type = $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 protected * @param mixed $data 要返回的数据 * @param String $type 返回类型 JSON XML * @param integer $code HTTP状态 * @return void */ protected function response($data, $type = '', $code = 200) { Response::sendHttpStatus($code); return Response::returnData($data, $type, 1); }
/** * @covers think\Response::error * @todo Implement testError(). */ public function testError() { // round 1 $msg = 1001; $data = "data"; Config::set('default_return_type', "json"); $result = Response::error($msg, $data); $this->assertEquals($msg, $result["code"]); $this->assertEquals($data, $result["data"]); $this->assertEquals('javascript:history.back(-1);', $result["url"]); $this->assertEquals("json", Response::type()); $this->assertEquals(3, $result["wait"]); // round 2 $msg = "the msg"; $url = "www.thinkphptesterror.com"; $result = Response::error($msg, $data, $url); $this->assertEquals($msg, $result["msg"]); $this->assertEquals($url, $result["url"]); // round 3 异常在travis-ci中未能重现 // $this->setExpectedException('\think\Exception'); // FIXME 静态方法mock // $oMockView = $this->getMockBuilder('\think\View')->setMethods(array( // 'fetch' // ))->getMock(); // $oMockView->expects($this->any())->method('fetch')->will($this->returnValue('content')); // Config::set('default_return_type', "html"); // $result = Response::error($msg, $data, $url); // FIXME 静态方法mock // $this->assertEquals('content', $result); }
/** * 将$this->vars解析成json输出,并结束程序 * * @stability: 3 * @param string|array|null $name * @param mixed|null $value * @return void */ protected function json($name = null, $value = null) { if (!is_null($name)) { $this->assign($name, $value); } Response::json($this->vars); }
/** * 返回封装后的API数据到客户端 * @access protected * @param mixed $data 要返回的数据 * @param integer $code 返回的code * @param mixed $msg 提示信息 * @param string $type 返回数据格式 * @param array $header 发送的Header信息 * @return void */ protected function result($data, $code = 0, $msg = '', $type = '', array $header = []) { $result = ['code' => $code, 'msg' => $msg, 'time' => $_SERVER['REQUEST_TIME'], 'data' => $data]; $type = $type ?: $this->getResponseType(); $response = Response::create($result, $type)->header($header); throw new HttpResponseException($response); }
/** * 输出返回数据 * @access protected * @param mixed $data 要返回的数据 * @param String $type 返回类型 JSON XML * @param integer $code HTTP状态 * @return void */ protected function response($data, $type = '', $code = 200) { Response::sendHttpStatus($code); Response::returnData($data, strtolower($type)); }
public static function inject(Response $response) { $config = Config::get('trace'); $type = isset($config['type']) ? $config['type'] : 'Html'; $request = Request::instance(); $accept = $request->header('accept'); $contentType = $response->getHeader('Content-Type'); $class = false !== strpos($type, '\\') ? $type : '\\think\\debug\\' . ucwords($type); unset($config['type']); if (class_exists($class)) { $trace = new $class($config); } else { throw new ClassNotFoundException('class not exists:' . $class, $class); } if ($response instanceof Redirect) { //TODO 记录 } else { $output = $trace->output($response, Log::getLog()); if (is_string($output)) { // trace调试信息注入 $content = $response->getContent(); $pos = strripos($content, '</body>'); if (false !== $pos) { $content = substr($content, 0, $pos) . $output . substr($content, $pos); } else { $content = $content . $output; } $response->content($content); } } }
/** * 输出返回数据 * @access protected * @param mixed $data 要返回的数据 * @param String $type 返回类型 JSON XML * @param integer $code HTTP状态 * @return void */ protected function response($data, $type = '', $code = 200) { return Response::instance()->data($data)->type($type)->code($code); }
/** * 输出异常信息 * @param \Exception $exception * @param Array $vars 异常信息 * @return null */ public static function output(\Exception $exception, array $vars) { if ($exception instanceof Exception) { http_response_code($exception->getHttpStatus()); } else { http_response_code(500); } // header('Content-Type: application/json'); // echo json_encode($vars);exit; $type = Config::get('default_return_type'); if (IS_API && 'html' != $type) { // 异常信息输出监听 APP_HOOK && Hook::listen('error_output', $data); // 输出异常内容 Response::send($data, $type, Config::get('response_return')); } else { ob_end_clean(); extract($vars); include Config::get('exception_tmpl'); } }
/** * 获取当前的Response对象实例 * @return \think\Response */ function response() { return Response::instance(); }
private function error($msg = '', $data = '', $url = '', $wait = 3) { echo Response::error($msg, $data, $url, $wait); die; }
/** * @param Exception $exception * @return Response */ protected function convertExceptionToResponse(Exception $exception) { // 收集异常数据 if (APP_DEBUG) { // 调试模式,获取详细的错误信息 $data = ['name' => get_class($exception), 'file' => $exception->getFile(), 'line' => $exception->getLine(), 'message' => $exception->getMessage(), 'trace' => $exception->getTrace(), 'code' => $this->getCode($exception), 'source' => $this->getSourceCode($exception), 'datas' => $this->getExtendData($exception), 'tables' => ['GET Data' => $_GET, 'POST Data' => $_POST, 'Files' => $_FILES, 'Cookies' => $_COOKIE, 'Session' => isset($_SESSION) ? $_SESSION : [], 'Server/Request Data' => $_SERVER, 'Environment Variables' => $_ENV, 'ThinkPHP Constants' => $this->getConst()]]; } else { // 部署模式仅显示 Code 和 Message $data = ['code' => $exception->getCode(), 'message' => $exception->getMessage()]; } if (!APP_DEBUG && !Config::get('show_error_msg')) { // 不显示详细错误信息 $data['message'] = Config::get('error_message'); } ob_start(); ob_implicit_flush(0); extract($data); include Config::get('exception_tmpl'); // 获取并清空缓存 $content = ob_get_clean(); $response = Response::instance()->data($content); if ($exception instanceof HttpException) { $statusCode = $exception->getStatusCode(); //TODO 设置headers 等待response完善 } if (!isset($statusCode)) { $statusCode = 500; } $response->code($statusCode); return $response; }
/** * Ajax方式返回数据到客户端 * @access protected * @param mixed $data 要返回的数据 * @param String $type AJAX返回数据格式 * @return void */ protected function ajaxReturn($data, $type = '') { Response::returnData($data, $type); }
/** * 读取或者设置缓存 * @access public * @param string $key 缓存标识,支持变量规则 ,例如 item/:name/:id * @param mixed $expire 缓存有效期 * @return mixed */ public function cache($key, $expire = null) { if ($this->isGet()) { if (false !== strpos($key, ':')) { $param = $this->param(); foreach ($param as $item => $val) { if (is_string($val) && false !== strpos($key, ':' . $item)) { $key = str_replace(':' . $item, $val, $key); } } } elseif ('__URL__' == $key) { // 当前URL地址作为缓存标识 $key = md5($this->url()); } elseif (strpos($key, ']')) { if ('[' . $this->ext() . ']' == $key) { // 缓存某个后缀的请求 $key = md5($this->url()); } else { return; } } if (strtotime($this->server('HTTP_IF_MODIFIED_SINCE')) + $expire > $_SERVER['REQUEST_TIME']) { // 读取缓存 $response = Response::create()->code(304); throw new \think\exception\HttpResponseException($response); } elseif (Cache::has($key)) { list($content, $header) = Cache::get($key); $response = Response::create($content)->header($header); throw new \think\exception\HttpResponseException($response); } else { $this->cache = [$key, $expire]; } } }
public static function output(Exception $error) { if (APP_DEBUG) { if (IS_AJAX) { Response::json($error->getMessage()); exit; } include Config::get('TMPL_EXCEPTION_FILE'); exit; } else { echo '程序异常,给您带来麻烦,非常抱歉!'; } exit; }
/** * 输出返回数据 * @access protected * @param mixed $data 要返回的数据 * @param String $type 返回类型 JSON XML * @param integer $code HTTP状态 * @return void */ protected function response($data, $type = '', $code = 200) { Response::sendHttpStatus($code); Response::data($data); if ($type) { Response::type($type); } }
/** * 执行应用程序 * @access public * @return void */ public static function run(array $config = []) { if (version_compare(PHP_VERSION, '5.4.0', '<')) { throw new Exception('require PHP > 5.4.0 !'); } // 日志初始化 Log::init($config['log']); // 缓存初始化 Cache::connect($config['cache']); // 加载框架底层语言包 if (is_file(THINK_PATH . 'Lang/' . strtolower($config['default_lang']) . EXT)) { Lang::set(include THINK_PATH . 'Lang/' . strtolower($config['default_lang']) . EXT); } if (is_file(APP_PATH . 'build.php')) { // 自动化创建脚本 Create::build(include APP_PATH . 'build.php'); } // 监听app_init Hook::listen('app_init'); // 初始化公共模块 self::initModule(APP_PATH . $config['common_module'] . '/', $config); // 启动session if ($config['use_session']) { Session::init($config['session']); } // 应用URL调度 self::dispatch($config); // 监听app_run Hook::listen('app_run'); // 执行操作 if (!preg_match('/^[A-Za-z](\\/|\\w)*$/', CONTROLLER_NAME)) { // 安全检测 $instance = false; } elseif ($config['action_bind_class']) { // 操作绑定到类:模块\controller\控制器\操作 if (is_dir(MODULE_PATH . CONTROLLER_LAYER . '/' . CONTROLLER_NAME)) { $namespace = MODULE_NAME . '\\' . CONTROLLER_LAYER . '\\' . CONTROLLER_NAME . '\\'; } else { // 空控制器 $namespace = MODULE_NAME . '\\' . CONTROLLER_LAYER . '\\empty\\'; } $actionName = strtolower(ACTION_NAME); if (class_exists($namespace . $actionName)) { $class = $namespace . $actionName; } elseif (class_exists($namespace . '_empty')) { // 空操作 $class = $namespace . '_empty'; } else { throw new Exception('_ERROR_ACTION_:' . ACTION_NAME); } $instance = new $class(); // 操作绑定到类后 固定执行run入口 $action = 'run'; } else { $instance = Loader::controller(CONTROLLER_NAME, '', $config['empty_controller']); // 获取当前操作名 $action = ACTION_NAME . $config['action_suffix']; } if (!$instance) { throw new Exception('[ ' . MODULE_NAME . '\\' . CONTROLLER_LAYER . '\\' . Loader::parseName(CONTROLLER_NAME, 1) . ' ] not exists'); } try { // 操作方法开始监听 $call = [$instance, $action]; Hook::listen('action_begin', $call); if (!preg_match('/^[A-Za-z](\\w)*$/', $action)) { // 非法操作 throw new \ReflectionException(); } //执行当前操作 $method = new \ReflectionMethod($instance, $action); if ($method->isPublic()) { // URL参数绑定检测 if ($config['url_params_bind'] && $method->getNumberOfParameters() > 0) { switch ($_SERVER['REQUEST_METHOD']) { case 'POST': $vars = array_merge($_GET, $_POST); break; case 'PUT': parse_str(file_get_contents('php://input'), $vars); break; default: $vars = $_GET; } $params = $method->getParameters(); $paramsBindType = $config['url_parmas_bind_type']; foreach ($params as $param) { $name = $param->getName(); if (1 == $paramsBindType && !empty($vars)) { $args[] = array_shift($vars); } if (0 == $paramsBindType && isset($vars[$name])) { $args[] = $vars[$name]; } elseif ($param->isDefaultValueAvailable()) { $args[] = $param->getDefaultValue(); } else { throw new Exception('_PARAM_ERROR_:' . $name); } } array_walk_recursive($args, 'Input::filterExp'); $data = $method->invokeArgs($instance, $args); } else { $data = $method->invoke($instance); } // 操作方法执行完成监听 Hook::listen('action_end', $data); // 返回数据 Response::returnData($data, $config['default_return_type']); } else { // 操作方法不是Public 抛出异常 throw new \ReflectionException(); } } catch (\ReflectionException $e) { // 操作不存在 if (method_exists($instance, '_empty')) { $method = new \ReflectionMethod($instance, '_empty'); $method->invokeArgs($instance, [$action, '']); } else { throw new Exception('[ ' . (new \ReflectionClass($instance))->getName() . ':' . $action . ' ] not exists ', 404); } } return; }