/** * 调试输出接口 * @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(); }
/** * 处理数据 * @access protected * @param mixed $data 要处理的数据 * @return mixed */ protected function output($data) { // 返回JSON数据格式到客户端 包含状态信息 [当url_common_param为false时是无法获取到$_GET的数据的,故使用Request来获取<*****@*****.**>] $var_jsonp_handler = Request::instance()->param($this->options['var_jsonp_handler'], ""); $handler = !empty($var_jsonp_handler) ? $var_jsonp_handler : $this->options['default_jsonp_handler']; $data = json_encode($data, $this->options['json_encode_param']); if ($data === false) { throw new \InvalidArgumentException(json_last_error_msg()); } $data = $handler . '(' . $data . ');'; return $data; }
/** * @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); }
/** * 架构函数 * @param Request $request Request对象 * @access public */ public function __construct(Request $request = null) { if (is_null($request)) { $request = Request::instance(); } $this->view = View::instance(Config::get('template'), Config::get('view_replace_str')); $this->request = $request; // 控制器初始化 $this->_initialize(); // 前置操作方法 if ($this->beforeActionList) { foreach ($this->beforeActionList as $method => $options) { is_numeric($method) ? $this->beforeAction($options) : $this->beforeAction($method, $options); } } }
/** * 定义系统常量 */ public function module_init() { $request = \think\Request::instance(); $method = $request->method(); define('IS_GET', $method == 'GET' ? true : false); define('IS_POST', $method == 'POST' ? true : false); define('IS_PUT', $method == 'PUT' ? true : false); define('IS_DELETE', $method == 'DELETE' ? true : false); define('IS_AJAX', $request->isAjax()); define('IS_PJAX', $request->isPjax()); define('NOW_TIME', $request->time()); define('MODULE_NAME', $request->module()); define('CONTROLLER_NAME', $request->controller()); define('ACTION_NAME', $request->action()); define('__SELF__', $request->url(true)); }
public function fetch($template, $data = [], $cache = []) { if (!$template) { $request = Request::instance(); $controller = $request->controller(); $action = $request->action(); $template = $controller . DS . $action; } // 根据模版文件名定位缓存文件 $tpl_cache_file = CACHE_PATH . 'angular_' . md5($template) . '.php'; if (App::$debug || !is_file($tpl_cache_file) || !$this->storage->check($tpl_cache_file, 0)) { // 编译模板内容 $content = $this->template->compiler($template, $data); $this->storage->write($tpl_cache_file, $content); } $this->storage->read($tpl_cache_file, $data); }
/** * 上传文件 * @param string $name input name * @param array $options 扩展配置 * @return array|boolean */ public function upload($name = '', $options = []) { $File = Request::instance()->file($name); // 检查是否有该文件,如果上传过,直接返回文件信息 $info = $this->where('hash', $File->hash())->find(); if ($info) { return ['file_id' => $info->id, 'path' => ltrim($info->path, '.')]; } // 合并扩展选项 $config = Config::get('storage'); if (is_array($options) && !empty($options)) { $config = array_merge($config, $options); } // 校验文件是否允许上传 if (!$File->check($config)) { $this->error = $File->getError(); return false; } else { // 保存的规则 $File->rule(function ($file) { $rule = explode('/', $file->getMime())[0] . '/'; $rule .= date('Y-m/d'); $rule .= '/' . $file->hash(); $rule .= '.' . strtolower(pathinfo($file->getInfo('name'), PATHINFO_EXTENSION)); return $rule; }); // 上传文件 $info = $File->move($config['path'], true, $config['replace']); if ($info) { $data = ['type' => explode('/', $info->getMime())[0], 'name' => rtrim($info->getInfo('name'), '.' . $info->getExtension()), 'ext' => $info->getExtension(), 'hash' => $info->hash(), 'path' => ltrim($info->getPathname(), '.'), 'size' => $info->getSize()]; // 保存文件信息 if ($insert = parent::create($data)) { return ['file_id' => $insert->id, 'path' => ltrim($insert->path, '.')]; } else { $this->error = '数据保存失败'; return false; } } else { $this->error = $File->getError(); return false; } } }
/** * 架构函数 取得模板对象实例 * @access public */ public function __construct() { // 资源类型检测 $request = Request::instance(); $ext = $request->ext(); if ('' == $ext) { // 自动检测资源类型 $this->type = $request->type(); } elseif (!preg_match('/\\(' . $this->restTypeList . '\\)$/i', $ext)) { // 资源类型非法 则用默认资源类型访问 $this->type = $this->restDefaultType; } else { $this->type = $ext; } // 请求方式检测 $method = strtolower($request->method()); if (false === stripos($this->restMethodList, $method)) { // 请求方式非法 则用默认请求方法 $method = $this->restDefaultMethod; } $this->method = $method; }
/** * 获取当前Request对象实例 * @return \think\Request */ function request() { return Request::instance(); }
public function testValidate() { $controller = new Foo(Request::instance()); $result = $controller->test(); $this->assertTrue($result); }
/** * 解析URL地址中的参数Request对象 * @access private * @param string $rule 路由规则 * @param array $var 变量 * @return void */ private static function parseUrlParams($url, &$var = []) { if ($url) { if (Config::get('url_param_type')) { $var += explode('|', $url); } else { preg_replace_callback('/(\\w+)\\|([^\\|]+)/', function ($match) use(&$var) { $var[$match[1]] = strip_tags($match[2]); }, $url); } } // 设置当前请求的参数 Request::instance()->route($var); }
/** * 获取当前的response 输出类型 * @access protected * @return string */ protected function getResponseType() { $isAjax = Request::instance()->isAjax(); return $isAjax ? Config::get('default_ajax_return') : Config::get('default_return_type'); }
public static function root($root) { self::$root = $root; Request::instance()->root($root); }
/** * 初始化应用或模块 * @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 { $path = APP_PATH . $module; // 加载模块配置 $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 (strpos($file, CONF_EXT)) { $filename = $dir . DS . $file; Config::load($filename, pathinfo($file, PATHINFO_FILENAME)); } } } // 加载应用状态配置 if ($config['app_status']) { $config = 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); } // 加载公共文件 if (is_file($path . 'common' . EXT)) { include $path . 'common' . EXT; } // 加载当前模块语言包 if ($module) { Lang::load($path . 'lang' . DS . Request::instance()->langset() . EXT); } } return Config::get(); }
public function testBind() { $request = Request::instance(); Route::bind('index/blog'); Route::get('index/blog/:id', 'index/blog/read'); $result = Route::check($request, '10'); $this->assertEquals(['index', 'blog', 'read'], $result['module']); Route::bind('\\app\\index\\controller', 'namespace'); $this->assertEquals(['type' => 'method', 'method' => ['\\app\\index\\controller\\blog', 'read']], Route::check($request, 'blog/read')); Route::bind('\\app\\index\\controller\\blog', 'class'); $this->assertEquals(['type' => 'method', 'method' => ['\\app\\index\\controller\\blog', 'read']], Route::check($request, 'read')); }
/** * 自动定位模板文件 * @access private * @param string $template 模板文件规则 * @return string */ private function parseTemplate($template) { if (empty($this->config['view_path'])) { $this->config['view_path'] = App::$modulePath . 'view' . DS; } if (strpos($template, '@')) { list($module, $template) = explode('@', $template); $path = APP_PATH . $module . DS . 'view' . DS; } else { $path = $this->config['view_path']; } // 分析模板文件规则 $request = Request::instance(); $controller = Loader::parseName($request->controller()); if ($controller && 0 !== strpos($template, '/')) { $depr = $this->config['view_depr']; $template = str_replace(['/', ':'], $depr, $template); if ('' == $template) { // 如果模板文件名为空 按照默认规则定位 $template = str_replace('.', DS, $controller) . $depr . $request->action(); } elseif (false === strpos($template, $depr)) { $template = str_replace('.', DS, $controller) . $depr . $template; } } return $path . ltrim($template, '/') . '.' . ltrim($this->config['view_suffix'], '.'); }
<?php // +------------------------------------------------+ // |http://www.cjango.com | // +------------------------------------------------+ // | 修复BUG不是一朝一夕的事情,等我喝醉了再说吧! | // +------------------------------------------------+ // | Author: 小陈叔叔 <Jason.Chen> | // +------------------------------------------------+ return ['log' => ['type' => 'file', 'path' => LOG_PATH . 'index/', 'time_format' => ' c ', 'file_size' => 2097152], 'template' => ['tpl_cache' => !APP_DEBUG, 'strip_space' => false, 'taglib_pre_load' => '', 'cache_path' => TEMP_PATH . 'index/'], 'view_replace_str' => ['__SELF__' => \think\Request::instance()->url(true), '__CDN__' => '//cdn.' . ROOT_DOMAIN, '__CSS__' => '//cdn.' . ROOT_DOMAIN . '/index/css', '__JS__' => '//cdn.' . ROOT_DOMAIN . '/index/js', '__IMG__' => '//cdn.' . ROOT_DOMAIN . '/index/images', '__LIB__' => '//cdn.' . ROOT_DOMAIN . '/index/lib']];
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); } } }
function __construct() { $this->request = Request::instance(); $this->init(); }
/** * 记住当前url后跳转 */ public function remember() { Session::set('redirect_url', Request::instance()->url()); }
/** * 发送数据到客户端 * @access public * @return mixed * @throws \InvalidArgumentException */ public function send() { // 处理输出数据 $data = $this->getContent(); // Trace调试注入 if (Env::get('app_trace', Config::get('app_trace'))) { Debug::inject($this, $data); } if (!headers_sent() && !empty($this->header)) { // 发送状态码 http_response_code($this->code); // 发送头部信息 foreach ($this->header as $name => $val) { header($name . ':' . $val); } } if (200 == $this->code) { $cache = Request::instance()->getCache(); if ($cache) { header('Cache-Control: max-age=' . $cache[1] . ',must-revalidate'); header('Last-Modified:' . gmdate('D, d M Y H:i:s') . ' GMT'); header('Expires:' . gmdate('D, d M Y H:i:s', $_SERVER['REQUEST_TIME'] + $cache[1]) . ' GMT'); $header['Content-Type'] = $this->header['Content-Type']; Cache::set($cache[0], [$data, $header], $cache[1]); } } echo $data; if (function_exists('fastcgi_finish_request')) { // 提高页面响应 fastcgi_finish_request(); } // 监听response_end Hook::listen('response_end', $this); }
/** * 初始化应用或模块 * @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; } else { $path = APP_PATH . $module; // 加载模块配置 $config = Config::load(CONF_PATH . $module . 'config' . CONF_EXT); // 加载应用状态配置 if ($config['app_status']) { $config = Config::load(CONF_PATH . $module . $config['app_status'] . CONF_EXT); } // 读取扩展配置文件 if ($config['extra_config_list']) { foreach ($config['extra_config_list'] as $name => $file) { $filename = CONF_PATH . $module . $file . CONF_EXT; Config::load($filename, is_string($name) ? $name : pathinfo($filename, PATHINFO_FILENAME)); } } // 加载别名文件 if (is_file(CONF_PATH . $module . 'alias' . EXT)) { Loader::addClassMap(include CONF_PATH . $module . 'alias' . EXT); } // 加载行为扩展文件 if (is_file(CONF_PATH . $module . 'tags' . EXT)) { Hook::import(include CONF_PATH . $module . 'tags' . EXT); } // 加载公共文件 if (is_file($path . 'common' . EXT)) { include $path . 'common' . EXT; } // 加载当前模块语言包 if ($config['lang_switch_on'] && $module) { Lang::load($path . 'lang' . DS . Request::instance()->langset() . EXT); } } return Config::get(); }
/** * 自动获取当前的path * @return string */ public static function getCurrentPath() { return Request::instance()->baseUrl(); }
/** * action访问控制,在 **登录成功** 后执行的第一项权限检测任务 * * @return boolean|null 返回值必须使用 `===` 进行判断 * * 返回 **false**, 不允许任何人访问(超管除外) * 返回 **true**, 允许任何管理员访问,无需执行节点权限检测 * 返回 **null**, 需要继续执行节点权限检测决定是否允许访问 * @author 朱亚杰 <*****@*****.**> */ protected final function accessControl() { if (IS_ROOT) { return true; //管理员允许访问任何页面 } $allow = Config::get('allow_visit'); $deny = Config::get('deny_visit'); $request = \think\Request::instance(); $check = strtolower($request->controller() . '/' . $request->action()); if (!empty($deny) && $this->in_array_case($check, $deny)) { return false; //非超管禁止访问deny中的方法 } if (!empty($allow) && $this->in_array_case($check, $allow)) { return true; } return null; //需要检测节点权限 }
/** * 验证请求类型 * @access protected * @param mixed $value 字段值 * @param mixed $rule 验证规则 * @return bool */ protected function method($value, $rule) { $method = Request::instance()->method(); return strtoupper($rule) == $method; }
/** * 远程调用模块的操作方法 参数格式 [模块/控制器/]操作 * @param string $url 调用地址 * @param string|array $vars 调用参数 支持字符串和数组 * @param string $layer 要调用的控制层名称 * @param bool $appendSuffix 是否添加类名后缀 * @return mixed */ public static function action($url, $vars = [], $layer = 'controller', $appendSuffix = false) { $info = pathinfo($url); $action = $info['basename']; $module = '.' != $info['dirname'] ? $info['dirname'] : Request::instance()->controller(); $class = self::controller($module, $layer, $appendSuffix); if ($class) { if (is_scalar($vars)) { if (strpos($vars, '=')) { parse_str($vars, $vars); } else { $vars = [$vars]; } } return App::invokeMethod([$class, $action . Config::get('action_suffix')], $vars); } }
/** * 生成表单令牌 * @param string $name 令牌名称 * @param mixed $type 令牌生成方法 * @return string */ function token($name = '__token__', $type = 'md5') { $token = Request::instance()->token($name, $type); return '<input type="hidden" name="' . $name . '" value="' . $token . '" />'; }
public function testCli() { $request = Request::instance(); $this->assertTrue($request->isCli()); }
<?php // +------------------------------------------------+ // |http://www.cjango.com | // +------------------------------------------------+ // | 修复BUG不是一朝一夕的事情,等我喝醉了再说吧! | // +------------------------------------------------+ // | Author: 小陈叔叔 <Jason.Chen> | // +------------------------------------------------+ return ['log' => ['type' => 'file', 'path' => LOG_PATH . 'system/', 'time_format' => ' c ', 'file_size' => 2097152], 'template' => ['tpl_cache' => !APP_DEBUG, 'strip_space' => false, 'taglib_pre_load' => '', 'cache_path' => TEMP_PATH . 'system/'], 'view_replace_str' => ['__SELF__' => \think\Request::instance()->url(true), '__CDN__' => '//cdn.' . ROOT_DOMAIN, '__CSS__' => '//cdn.' . ROOT_DOMAIN . '/system/css', '__JS__' => '//cdn.' . ROOT_DOMAIN . '/system/js', '__IMG__' => '//cdn.' . ROOT_DOMAIN . '/system/img', '__LIB__' => '//cdn.' . ROOT_DOMAIN . '/system/lib'], 'backdata' => ['path' => realpath('../backup/data/') . DS, 'part' => 2097152, 'compress' => true, 'level' => 9]];
private function parseTemplate($template) { $request = Request::instance(); $depr = $this->config['view_depr']; $controller = Loader::parseName($request->controller()); if ($controller && 0 !== strpos($template, '/')) { if ('' == $template) { // 如果模板文件名为空 按照默认规则定位 $template = str_replace('.', DS, $controller) . $depr . $request->action(); } elseif (false === strpos($template, '/')) { $template = str_replace('.', DS, $controller) . $depr . $template; } } return str_replace('/', $depr, $template) . $this->config['view_suffix']; }