/** * 初始化目录 * * @param string $templateFile 模板文件名 * * @return string */ private function initBaseDir($templateFile) { $baseDir = Cml::getContainer()->make('cml_route')->getAppName(); $baseDir .= '/' . Cml::getApplicationDir('app_view_path_name') . (Config::get('html_theme') != '' ? DIRECTORY_SEPARATOR . Config::get('html_theme') : ''); $layOutRootDir = $baseDir; if ($templateFile === '') { $baseDir .= '/' . Cml::getContainer()->make('cml_route')->getControllerName() . '/'; $file = Cml::getContainer()->make('cml_route')->getActionName(); } else { $templateFile = str_replace('.', '/', $templateFile); $baseDir .= DIRECTORY_SEPARATOR . dirname($templateFile) . DIRECTORY_SEPARATOR; $file = basename($templateFile); } return ['layoutDir' => Cml::getApplicationDir('apps_path') . DIRECTORY_SEPARATOR . $layOutRootDir, 'layoutCacheRootPath' => Cml::getApplicationDir('runtime_cache_path') . DIRECTORY_SEPARATOR . $layOutRootDir . DIRECTORY_SEPARATOR, 'templateDir' => Cml::getApplicationDir('apps_path') . DIRECTORY_SEPARATOR . $baseDir, 'cacheDir' => Cml::getApplicationDir('runtime_cache_path') . DIRECTORY_SEPARATOR . $baseDir, 'file' => $file]; }
/** * 解析一个静态资源的地址 * * @param string $resource 文件地址 */ public static function parseResourceUrl($resource = '') { //简单判断没有.的时候当作是目录不加版本号 $isDir = strpos($resource, '.') === false ? true : false; if (Cml::$debug) { $file = Response::url("cmlframeworkstaticparse/{$resource}", false); if (Config::get('url_model') == 2) { $file = rtrim($file, Config::get('url_html_suffix')); } $isDir || ($file .= (Config::get("url_model") == 3 ? "&v=" : "?v=") . Cml::$nowTime); } else { $file = Config::get("static__path", Cml::getContainer()->make('cml_route')->getSubDirName() . "public/") . $resource; $isDir || ($file .= (Config::get("url_model") == 3 ? "&v=" : "?v=") . Config::get('static_file_version')); } echo $file; }
Cml::getContainer()->singleton('cml_debug', \Cml\Debug::class); //必须绑定。命令行组件 Cml::getContainer()->singleton('cml_console', \Cml\Console\Console::class); //可选,队列服务 内置 \Cml\Queue\Redis::class.(内置的redis服务与缓存挂钩)参考 http://doc.cmlphp.com/devintro/quenue.html //自定义服务实现\Cml\Interfaces\Queue接口即可或继承\Cml\Queue\Base再按需重载 Cml::getContainer()->singleton('cml_queue', \Cml\Queue\Redis::class); //可选,锁服务 内置\Cml\Lock\File::class|\Cml\Lock\Redis::class|\Cml\Lock\Memcache::class三种. //内置的redis锁跟/memcache锁 跟缓存服务挂钩。参考 http://doc.cmlphp.com/devintro/lock.html //自定义服务实现\Cml\Interfaces\Lock接口即可或继承\Cml\Lock\Base再按需重载 Cml::getContainer()->singleton('cml_lock', \Cml\Lock\Redis::class); //可选。绑定要用到视图引擎内置以下5种 以view_为前缀,用的时候不用带前缀如使用view_html视图服务: \Cml\View::getEngine('html'); //\Cml\View::getEngine();不传类型的时候,使用的引擎可在配置文件中配置 'view_render_engine' => 'Html'默认为view_html //自定义服务实现\Cml\Interfaces\View接口即可或继承\Cml\View\Base再按需重载 Cml::getContainer()->singleton('view_html', \Cml\View\Html::class); Cml::getContainer()->singleton('view_json', \Cml\View\Json::class); Cml::getContainer()->singleton('view_blade', \Cml\Service\Blade::class); //blade模板引擎,使用前安装依赖。composer require linhecheng/cmlphp-ext-blade //Cml::getContainer()->singleton('view_excel', \Cml\View\Excel::class); //Cml::getContainer()->singleton('view_xml', \Cml\View\Xml::class); //可选,db 允许多种驱动同时使用。因同种数据库可能同时连多个.这边不使用单例绑定.内置 \Cml\Db\MySql\Pdo::class|\Cml\Db\MongoDB\MongoDB::class 两种数据库支持. //自定义数据库驱动实现\Cml\Interfaces\Db接口即可或继承\Cml\Db\Base再按需重载 Cml::getContainer()->bind('db_mysql', \Cml\Db\MySql\Pdo::class); //Cml::getContainer()->bind('db_mongodb', \Cml\Db\MongoDB\MongoDB::class); //可选,cache 允许多种驱动同时使用。如即使用memcache又使用redis.有使用数据库时至少要启用一种缓存,因同种缓存可能同时连多个.这边不使用单例绑定。 // 内置 \Cml\Cache\Redis::class|\Cml\Cache\File::class | \Cml\Cache\Memcache::class | \Cml\Cache\Apc::class 四种缓存支持. //自定义数据库驱动实现\Cml\Interfaces\Cache接口即可或继承\Cml\Cache\Base再按需重载 Cml::getContainer()->bind('cache_redis', \Cml\Cache\Redis::class); Cml::getContainer()->bind('cache_file', \Cml\Cache\File::class); //Cml::getContainer()->bind('cache_memcache', \Cml\Cache\Memcache::class); //Cml::getContainer()->bind('cache_apc', \Cml\Cache\Memcache::class); });
/** * 检查对应的权限 * * @param object|string $controller 传入控制器实例对象,用来判断当前访问的方法是不是要跳过权限检查。 * 如当前访问的方法为web/User/list则传入new \web\Controller\User()获得的实例。最常用的是在基础控制器的init方法或构造方法里传入$this。 * 传入字符串如web/User/list时会自动 new \web\Controller\User()获取实例用于判断 * * @return int 返回1是通过检查,0是不能通过检查 */ public static function checkAcl($controller) { $authInfo = self::getLoginInfo(); if (!$authInfo) { return false; } //登录超时 //当前登录用户是否为超级管理员 if (self::isSuperUser()) { return true; } $checkUrl = Cml::getContainer()->make('cml_route')->getFullPathNotContainSubDir(); $checkAction = Cml::getContainer()->make('cml_route')->getActionName(); if (is_string($controller)) { $checkUrl = trim($controller, '/\\'); $controller = str_replace('/', '\\', $checkUrl); $actionPosition = strrpos($controller, '\\'); $checkAction = substr($controller, $actionPosition + 1); $offset = $appPosition = 0; for ($i = 0; $i < Config::get('route_app_hierarchy', 1); $i++) { $appPosition = strpos($controller, '\\', $offset); $offset = $appPosition + 1; } $appPosition = $offset - 1; $subString = substr($controller, 0, $appPosition) . '\\' . Cml::getApplicationDir('app_controller_path_name') . substr($controller, $appPosition, $actionPosition - $appPosition); $controller = "\\{$subString}" . Config::get('controller_suffix'); if (class_exists($controller)) { $controller = new $controller(); } else { return false; } } $checkUrl = ltrim(str_replace('\\', '/', $checkUrl), '/'); if (is_object($controller)) { //判断是否有标识 @noacl 不检查权限 $reflection = new \ReflectionClass($controller); $methods = $reflection->getMethods(\ReflectionMethod::IS_PUBLIC); foreach ($methods as $method) { if ($method->name == $checkAction) { $annotation = $method->getDocComment(); if (strpos($annotation, '@noacl') !== false) { return true; } $checkUrlArray = []; if (preg_match('/@acljump([^\\n]+)/i', $annotation, $aclJump)) { if (isset($aclJump[1]) && $aclJump[1]) { $aclJump[1] = explode('|', $aclJump[1]); foreach ($aclJump[1] as $val) { trim($val) && ($checkUrlArray[] = ltrim(str_replace('\\', '/', trim($val)), '/')); } } empty($checkUrlArray) || ($checkUrl = $checkUrlArray); } } } } $acl = Model::getInstance()->db()->columns('m.id')->table(['access' => 'a'])->join(['menus' => 'm'], 'a.menuid=m.id')->lBrackets()->whereIn('a.groupid', $authInfo['groupid'])->_or()->where('a.userid', $authInfo['id'])->rBrackets(); $acl = is_array($checkUrl) ? $acl->whereIn('m.url', $checkUrl) : $acl->where('m.url', $checkUrl); $acl = $acl->select(); return count($acl) > 0; }
/** * URL组装 支持不同URL模式 * eg: \Cml\Http\Response::url('Home/Blog/cate/id/1') * * @param string $url URL表达式 路径/控制器/操作/参数1/参数1值/..... * @param int $echo 是否输出 1输出 0 return * * @return string */ public static function url($url = '', $echo = 1) { $return = ''; // 解析URL if (empty($url)) { throw new \InvalidArgumentException(Lang::get('_NOT_ALLOW_EMPTY_', 'url')); //'U方法参数出错' } // URL组装 $delimiter = Config::get('url_pathinfo_depr'); $url = ltrim($url, '/'); $url = implode($delimiter, explode('/', $url)); if (Config::get('url_model') == 1) { $return = $_SERVER['SCRIPT_NAME'] . '/' . $url; } elseif (Config::get('url_model') == 2) { $return = Cml::getContainer()->make('cml_route')->getSubDirName() . $url; } elseif (Config::get('url_model') == 3) { $return = $_SERVER['SCRIPT_NAME'] . '?' . Config::get('var_pathinfo') . '=/' . $url; } $return .= Config::get('url_model') == 2 ? Config::get('url_html_suffix') : ''; $return = Secure::filterScript($return); if ($echo === 1) { echo $return; } else { return $return; } return ''; }
/** *输出分页 */ public function show() { if ($this->totalRows == 0) { return ''; } $nowCoolPage = ceil($this->nowPage / $this->barShowPage); $delimiter = Config::get('url_pathinfo_depr'); $params = array_merge($this->param, [$this->pageShowVarName => '__PAGE__']); $paramsString = ''; foreach ($params as $key => $val) { $paramsString == '' || ($paramsString .= '/'); $paramsString .= $key . '/' . $val; } if ($this->url) { $url = rtrim(Response::url($this->url . '/' . $paramsString, false), $delimiter); } else { $url = rtrim(Response::url(Cml::getContainer()->make('cml_route')->getFullPathNotContainSubDir() . '/' . $paramsString, false), $delimiter); } $upRow = $this->nowPage - 1; $downRow = $this->nowPage + 1; $upPage = $upRow > 0 ? '<li><a href = "' . str_replace('__PAGE__', $upRow, $url) . '">' . $this->config['prev'] . '</a></li>' : ''; $downPage = $downRow <= $this->totalPages ? '<li><a href="' . str_replace('__PAGE__', $downRow, $url) . '">' . $this->config['next'] . '</a></li>' : ''; // << < > >> if ($nowCoolPage == 1) { $theFirst = $prePage = ''; } else { $preRow = $this->nowPage - $this->barShowPage; $prePage = '<li><a href="' . str_replace('__PAGE__', $preRow, $url) . '">上' . $this->barShowPage . '页</a></li>'; $theFirst = '<li><a href="' . str_replace('__PAGE__', 1, $url) . '">' . $this->config['first'] . '</a></li>'; } if ($nowCoolPage == $this->coolPages) { $nextPage = $theEnd = ''; } else { $nextRow = $this->nowPage + $this->barShowPage; $theEndRow = $this->totalPages; $nextPage = '<li><a href="' . str_replace('__PAGE__', $nextRow, $url) . '">下' . $this->barShowPage . '页</a></li>'; $theEnd = '<li><a href="' . str_replace('__PAGE__', $theEndRow, $url) . '">' . $this->config['last'] . '</a></li>'; } //1 2 3 4 5 $linkPage = ''; for ($i = 1; $i <= $this->barShowPage; $i++) { $page = ($nowCoolPage - 1) * $this->barShowPage + $i; if ($page != $this->nowPage) { if ($page <= $this->totalPages) { $linkPage .= ' <li><a href="' . str_replace('__PAGE__', $page, $url) . '"> ' . $page . ' </a></li>'; } else { break; } } else { if ($this->totalPages != 1) { $linkPage .= ' <li class="active"><a>' . $page . '</a></li>'; } } } $pageStr = str_replace(['%header%', '%nowPage%', '%totalRow%', '%totalPage%', '%upPage%', '%downPage%', '%first%', '%prePage%', '%linkPage%', '%nextPage%', '%end%'], [$this->config['header'], $this->nowPage, $this->totalRows, $this->totalPages, $upPage, $downPage, $theFirst, $prePage, $linkPage, $nextPage, $theEnd], $this->config['theme']); return '<ul>' . $pageStr . '</ul>'; }
/** *SQL语句条件组装 * *@param array $arr; 要组装的数组 *@param string $tableName 当前操作的数据表名 * *@return string */ protected function arrToCondition($arr, $tableName) { empty($tableName) && ($tableName = Cml::getContainer()->make('cml_route')->getControllerName()); /* //这个应该开发人员自己判断。框架不做额外开销 $dbFields = $this->getDbFields($tableName, $tablePrefix); foreach (array_keys($arr) as $key) { if (!isset($dbFields[$key])) unset($arr[$key]); //过滤db表中不存在的字段 } */ $s = $p = ''; $params = []; foreach ($arr as $k => $v) { if (is_array($v)) { //自增或自减 switch (key($v)) { case 'inc': $p = "`{$k}`= `{$k}`+" . abs(intval(current($v))); break; case 'dec': $p = "`{$k}`= `{$k}`-" . abs(intval(current($v))); break; case 'func': $func = strtoupper(key(current($v))); $funcParams = current(current($v)); foreach ($funcParams as $key => $val) { if (!isset($dbFields[$val])) { $funcParams[$key] = '%s'; $params[] = $val; } } $p = "`{$k}`= {$func}(" . implode($funcParams, ',') . ')'; break; default: //计算类型 $conkey = key($v); if (!isset($dbFields[$conkey])) { $conkey = $k; } if (!in_array(key(current($v)), ['+', '-', '*', '/', '%', '^', '&', '|', '<<', '>>', '~'])) { throw new \InvalidArgumentException(Lang::get('_PARSE_UPDATE_SQL_PARAMS_ERROR_')); } $p = "`{$k}`= `{$conkey}`" . key(current($v)) . abs(intval(current(current($v)))); break; } } else { $p = "`{$k}`= %s"; $params[] = $v; } $s .= (empty($s) ? '' : ',') . $p; } $this->bindParams = array_merge($params, $this->bindParams); return $s; }
/** * 获取Logger实例 * * @return Base */ private static function getLogger() { return Cml::getContainer()->make('cml_log'); }
/** * 未找到控制器的时候设置勾子 * */ public static function montFor404Page() { Plugin::mount('cml.before_show_404_page', [function () { $cmdLists = Config::get('cmlframework_system_command'); $cmd = strtolower(trim(Cml::getContainer()->make('cml_route')->getAppName(), '/')); if (isset($cmdLists[$cmd])) { call_user_func($cmdLists[$cmd]); } }]); Plugin::hook('cml.before_show_404_page'); }
/** * 从文件载入Config * * @param string $file * @param bool $global 是否从全局加载 * * @return array */ public static function load($file, $global = true) { if (isset(static::$_content[$file])) { return static::$_content[$file]; } else { $file = ($global ? Cml::getApplicationDir('global_config_path') : Cml::getApplicationDir('apps_path') . '/' . Cml::getContainer()->make('cml_route')->getAppName() . '/' . Cml::getApplicationDir('app_config_path_name')) . '/' . ($global ? self::$isLocal . DIRECTORY_SEPARATOR : '') . $file . '.php'; if (!is_file($file)) { throw new ConfigNotFoundException(Lang::get('_NOT_FOUND_', $file)); } static::$_content[$file] = Cml::requireFile($file); return static::$_content[$file]; } }
/** * 程序执行完毕,打印CmlPHP运行信息 * */ public static function stop() { self::$stopTime = microtime(true); // 记录内存结束使用 function_exists('memory_get_usage') && (self::$stopMemory = memory_get_usage()); Cml::getContainer()->make('cml_debug')->stopAndShowDebugInfo(); CML_OB_START && ob_end_flush(); }
/** * 访问Cml::getContainer()->make('cml_route')中其余方法 * * @param string $name * @param array $arguments * * @return mixed */ public static function __callStatic($name, $arguments) { return call_user_func_array([Cml::getContainer()->make('cml_route'), $name], $arguments); }