From c98ca32ededa0d1d0ccddba3a3abe2c7ec5f4606 Mon Sep 17 00:00:00 2001 From: molong Date: Wed, 29 Jun 2016 15:02:59 +0800 Subject: [PATCH] =?UTF-8?q?=E5=86=85=E6=A0=B8=E6=9B=B4=E6=96=B0=EF=BC=8C?= =?UTF-8?q?=E6=A0=87=E7=AD=BE=E7=9A=84=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 63 +---- addons/devteam/view/index/widget.html | 2 +- core/lang/zh-cn.php | 87 +++---- core/library/think/App.php | 6 +- core/library/think/File.php | 4 +- core/library/think/Lang.php | 2 +- core/library/think/Loader.php | 340 +++++++++++++------------ core/library/think/Route.php | 51 ++-- core/library/think/Template.php | 55 ++-- core/library/think/Url.php | 9 +- core/library/think/controller/Rest.php | 2 +- core/library/think/controller/Yar.php | 2 +- core/library/think/db/Builder.php | 2 - core/library/think/db/Query.php | 24 +- core/library/think/model/Relation.php | 9 +- extend/com/Sent.php | 38 ++- 16 files changed, 354 insertions(+), 342 deletions(-) diff --git a/README.md b/README.md index 7a1baf85..e14c6b3a 100644 --- a/README.md +++ b/README.md @@ -1,67 +1,10 @@ -## SentCMS介绍 -> SentCMS网站管理系统是南昌腾速科技有限公司倾力打造的一款简单易用的网站管理系统,SentCMS网站管理系统(下文简称SentCMS)继承了thinkphp5.0的优秀品质,秉承“大道至简”的设计理念。SnetCMS为网站建设而生,为网站建设减少90%的代码编写,只需前端设计师就可以设计出完美的网站,而如此完美的系统还是完全开源的。 +>[danger] #### SentCMS网站管理系统是南昌腾速科技有限公司倾力打造的一款简单易用的网站管理系统,SentCMS网站管理系统(下文简称SentCMS)继承了thinkphp5.0的优秀品质,秉承“大道至简”的设计理念。SnetCMS为网站建设而生,为网站建设减少90%的代码编写,只需前端设计师就可以设计出完美的网站,而如此完美的系统还是完全开源的。 -## SentCMS特性包括: +SentCMS特性包括: * 全新的路由体系,完美的路由解决方案 * 全新的系统架构,采用thinkphp5.0内核框架 * 完善而健全的会员体系 * 健全的权限系统,权限细化到界面上的按钮和链接 * 漂亮的后台界面,后台界面采用世界领先的前端框架bootstrap,自适应的体验 * 简单易用的标签体系 -* 便捷的文档系统,无需程序即可设计出完美的模型,做出完美的网站 - -下载最新版框架后,解压缩到web目录下面,可以看到初始的目录结构如下: -## 目录结构 -~~~ -├─addons 扩展插件目录 -├─application 项目目录文件 -│ ├─admin 网站后台模型 -│ │ ├─controller -│ │ ├─static -│ │ ├─view -│ │ ├─config.php -│ ├─api API接口模型 -│ │ ├─controller -│ │ ├─static -│ │ ├─view -│ │ ├─config.php -│ ├─common COMMON公共模型,不可访问 -│ │ ├─controller -│ │ ├─static -│ │ ├─view -│ │ ├─config.php -│ ├─index 前台模型 -│ │ ├─controller -│ │ ├─static -│ │ ├─view -│ │ ├─config.php -│ ├─user 用户中心模型 -│ │ ├─controller -│ │ ├─static -│ │ ├─view -│ │ ├─config.php -│ ├─common.php 公共函数库文件 -│ ├─config.php 基础配置文件 -│ ├─database.php 数据库配置文件 -│ ├─route.php 路由配置文件 -│ ├─tags.php 行为扩展配置文件 -│ ├─ueditor.json 编辑配置文件 -├─core thinkphp框架目录 -├─data 缓存以及备份目录 -├─extend 扩展类库目录(后期可能会变更目录) -├─public 公共资源库 -├─uploads 上传文件目录 -├─.htaccess Apache下伪静态文件 -├─favicon.ico ico图标 -├─index.php 入口文件 -├─README.md 系统介绍文件 -~~~ - -## 安装 - -目前暂无安装文件,可按以下方法安装: - -* 第一步、修改数据库配置文件 application/database.php -* 第二步、通过数据库导入工具,比如phpmyadmin导入数据,数据sql文件data/sql.sql - -初始账号:admin,密码:admin888 \ No newline at end of file +* 便捷的文档系统,无需程序即可设计出完美的模型,做出完美的网站 \ No newline at end of file diff --git a/addons/devteam/view/index/widget.html b/addons/devteam/view/index/widget.html index 2fdcf797..94fa6628 100644 --- a/addons/devteam/view/index/widget.html +++ b/addons/devteam/view/index/widget.html @@ -11,7 +11,7 @@ 产品设计及研发团队 - 郭平平 + 郭平平、Colin 界面及用户体验团队 diff --git a/core/lang/zh-cn.php b/core/lang/zh-cn.php index 9a92c17a..be26c53a 100644 --- a/core/lang/zh-cn.php +++ b/core/lang/zh-cn.php @@ -11,49 +11,50 @@ // 核心中文语言包 return [ - // 系统错误提示 - 'Undefined variable' => '未定义变量', - 'Undefined index' => '未定义索引', - 'Parse error' => '语法解析错误', - 'Type error' => '类型错误', - 'Fatal error' => '致命错误', + // 系统错误提示 + 'Undefined variable' => '未定义变量', + 'Undefined index' => '未定义索引', + 'Parse error' => '语法解析错误', + 'Type error' => '类型错误', + 'Fatal error' => '致命错误', // 框架核心错误提示 - 'dispatch type not support' => '不支持的调度类型', - 'method param miss' => '方法参数错误', - 'method not exists' => '方法不存在', - 'module not exists' => '模块不存在', - 'class not exists' => '类不存在', - 'template not exists' => '模板文件不存在', - 'illegal controller name' => '非法的控制器名称', - 'illegal action name' => '非法的操作名称', - 'url suffix deny' => '禁止的URL后缀访问', - 'Route Not Found' => '当前访问路由未定义', - 'Underfined db type' => '未定义数据库类型', - 'variable type error' => '变量类型错误', - 'PSR-4 error' => 'PSR-4 规范错误', - 'not support total' => '简洁模式下不能获取数据总数', - 'not support last' => '简洁模式下不能获取最后一页', - 'error session handler' => '错误的SESSION处理器类', - 'not allow php tag' => '模板不允许使用PHP语法', - 'not support' => '不支持', - 'redisd master' => 'Redisd 主服务器错误', - 'redisd slave' => 'Redisd 从服务器错误', - 'must run at sae' => '必须在SAE运行', - 'memcache init error' => '未开通Memcache服务,请在SAE管理平台初始化Memcache服务', - 'KVDB init error' => '没有初始化KVDB,请在SAE管理平台初始化KVDB服务', - 'fields not exists' => '数据表字段不存在', - 'where express error' => '查询表达式错误', - 'no data to update' => '没有任何数据需要更新', - 'miss data to insert' => '缺少需要写入的数据', - 'miss complex primary data' => '缺少复合主键数据', - 'miss update condition' => '缺少更新条件', - 'model data Not Found' => '模型数据不存在', - 'table data not Found' => '表数据不存在', - 'delete without condition' => '没有条件不会执行删除操作', - 'miss relation data' => '缺少关联表数据', - 'tag attr must' => '模板标签属性必须', - 'tag error' => '模板标签错误', - 'cache write error' => '缓存写入失败', - 'sae mc write error' => 'SAE mc 写入错误', + 'dispatch type not support' => '不支持的调度类型', + 'method param miss' => '方法参数错误', + 'method not exists' => '方法不存在', + 'module not exists' => '模块不存在', + 'controller not exists' => '控制器不存在', + 'class not exists' => '类不存在', + 'template not exists' => '模板文件不存在', + 'illegal controller name' => '非法的控制器名称', + 'illegal action name' => '非法的操作名称', + 'url suffix deny' => '禁止的URL后缀访问', + 'Route Not Found' => '当前访问路由未定义', + 'Underfined db type' => '未定义数据库类型', + 'variable type error' => '变量类型错误', + 'PSR-4 error' => 'PSR-4 规范错误', + 'not support total' => '简洁模式下不能获取数据总数', + 'not support last' => '简洁模式下不能获取最后一页', + 'error session handler' => '错误的SESSION处理器类', + 'not allow php tag' => '模板不允许使用PHP语法', + 'not support' => '不支持', + 'redisd master' => 'Redisd 主服务器错误', + 'redisd slave' => 'Redisd 从服务器错误', + 'must run at sae' => '必须在SAE运行', + 'memcache init error' => '未开通Memcache服务,请在SAE管理平台初始化Memcache服务', + 'KVDB init error' => '没有初始化KVDB,请在SAE管理平台初始化KVDB服务', + 'fields not exists' => '数据表字段不存在', + 'where express error' => '查询表达式错误', + 'no data to update' => '没有任何数据需要更新', + 'miss data to insert' => '缺少需要写入的数据', + 'miss complex primary data' => '缺少复合主键数据', + 'miss update condition' => '缺少更新条件', + 'model data Not Found' => '模型数据不存在', + 'table data not Found' => '表数据不存在', + 'delete without condition' => '没有条件不会执行删除操作', + 'miss relation data' => '缺少关联表数据', + 'tag attr must' => '模板标签属性必须', + 'tag error' => '模板标签错误', + 'cache write error' => '缓存写入失败', + 'sae mc write error' => 'SAE mc 写入错误', ]; diff --git a/core/library/think/App.php b/core/library/think/App.php index 266475f2..99613ac6 100644 --- a/core/library/think/App.php +++ b/core/library/think/App.php @@ -162,7 +162,7 @@ class App * @param array $params 参数 * @return void */ - public static function dispatch($dispath, $type = 'module', $params = []) + public static function dispatch($dispatch, $type = 'module', $params = []) { self::$dispatch = ['type' => $type, $type => $dispatch, 'params' => $params]; } @@ -307,7 +307,9 @@ class App try { $instance = Loader::controller($controller, $config['url_controller_layer'], $config['controller_suffix'], $config['empty_controller']); - + if (is_null($instance)) { + throw new HttpException(404, 'controller not exists:' . $controller); + } // 获取当前操作名 $action = $actionName . $config['action_suffix']; if (!preg_match('/^[A-Za-z](\w)*$/', $action)) { diff --git a/core/library/think/File.php b/core/library/think/File.php index 6701d93d..ef5d69da 100644 --- a/core/library/think/File.php +++ b/core/library/think/File.php @@ -29,9 +29,9 @@ class File extends SplFileObject // 上传文件信息 protected $info; - public function __construct($filename, $mode = 'r', $useIncludePath = false, $context = null) + public function __construct($filename, $mode = 'r') { - parent::__construct($filename, $mode, $useIncludePath, $context); + parent::__construct($filename, $mode); $this->filename = $this->getRealPath(); } diff --git a/core/library/think/Lang.php b/core/library/think/Lang.php index 571921be..35c98f05 100644 --- a/core/library/think/Lang.php +++ b/core/library/think/Lang.php @@ -148,7 +148,7 @@ class Lang /** * 自动侦测设置获取语言选择 - * @return void + * @return string */ public static function detect() { diff --git a/core/library/think/Loader.php b/core/library/think/Loader.php index 00f758dd..00ee74d3 100644 --- a/core/library/think/Loader.php +++ b/core/library/think/Loader.php @@ -11,28 +11,28 @@ namespace think; -use think\App; use think\exception\ClassNotFoundException; -use think\Request; class Loader { protected static $instance = []; // 类名映射 protected static $map = []; - // 加载列表 - protected static $load = []; - // 命名空间 - protected static $namespace = []; + // 命名空间别名 protected static $namespaceAlias = []; + // PSR-4 private static $prefixLengthsPsr4 = []; private static $prefixDirsPsr4 = []; + private static $fallbackDirsPsr4 = []; + // PSR-0 - private static $prefixesPsr0 = []; - // Composer自动加载 - private static $composerLoader = false; + private static $prefixesPsr0 = []; + private static $fallbackDirsPsr0 = []; + + // 自动加载的文件 + private static $autoloadFiles = []; // 自动加载 public static function autoload($class) @@ -48,55 +48,83 @@ class Loader } } - if (!empty(self::$map[$class])) { - // 类库映射 - include self::$map[$class]; - } elseif (self::$composerLoader && $file = self::findFileInComposer($class)) { - // Composer自动加载 - include $file; - } else { - // 命名空间自动加载 - if (!strpos($class, '\\')) { + if ($file = self::findFile($class)) { + + // Win环境严格区分大小写 + if (IS_WIN && pathinfo($file, PATHINFO_FILENAME) != pathinfo(realpath($file), PATHINFO_FILENAME)) { return false; } - $item = explode('\\', $class); - // 解析命名空间所在的路径 - if (count($item) > 2 && isset(self::$namespace[$item[0] . '\\' . $item[1]])) { - // 子命名空间定义(仅支持二级) - list($ns1, $ns2, $class) = explode('\\', $class, 3); - $path = self::$namespace[$ns1 . '\\' . $ns2]; - } elseif (isset(self::$namespace[$item[0]])) { - // 根命名空间定义 - list($name, $class) = explode('\\', $class, 2); - $path = self::$namespace[$name]; - } elseif (is_dir(EXTEND_PATH . $item[0])) { - // 扩展类库命名空间 - list($name, $class) = explode('\\', $class, 2); - $path = EXTEND_PATH . $name . DS; - } else { - return false; - } - // 定位文件 - $match = false; - foreach ((array) $path as $p) { - $filename = $p . str_replace('\\', DS, $class) . EXT; - if (is_file($filename)) { - // Win环境严格区分大小写 - if (IS_WIN && false === strpos(realpath($filename), $class . EXT)) { - continue; - } - $match = true; - break; - } - } - if ($match) { - include $filename; - } else { - return false; + includeFile($file); + return true; + } + } + + /** + * 查找文件 + * @param $class + * @return bool + */ + private static function findFile($class) + { + if (!empty(self::$map[$class])) { + // 类库映射 + return self::$map[$class]; + } + + // 查找 PSR-4 + $logicalPathPsr4 = strtr($class, '\\', DS) . EXT; + + $first = $class[0]; + if (isset(self::$prefixLengthsPsr4[$first])) { + foreach (self::$prefixLengthsPsr4[$first] as $prefix => $length) { + if (0 === strpos($class, $prefix)) { + foreach (self::$prefixDirsPsr4[$prefix] as $dir) { + if (is_file($file = $dir . DS . substr($logicalPathPsr4, $length))) { + return $file; + } + } + } } } - return true; + + // 查找 PSR-4 fallback dirs + foreach (self::$fallbackDirsPsr4 as $dir) { + if (is_file($file = $dir . DS . $logicalPathPsr4)) { + return $file; + } + } + + // 查找 PSR-0 + if (false !== $pos = strrpos($class, '\\')) { + // namespaced class name + $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1) + . strtr(substr($logicalPathPsr4, $pos + 1), '_', DS); + } else { + // PEAR-like class name + $logicalPathPsr0 = strtr($class, '_', DS) . EXT; + } + + if (isset(self::$prefixesPsr0[$first])) { + foreach (self::$prefixesPsr0[$first] as $prefix => $dirs) { + if (0 === strpos($class, $prefix)) { + foreach ($dirs as $dir) { + if (is_file($file = $dir . DS . $logicalPathPsr0)) { + return $file; + } + } + } + } + } + + // 查找 PSR-0 fallback dirs + foreach (self::$fallbackDirsPsr0 as $dir) { + if (is_file($file = $dir . DS . $logicalPathPsr0)) { + return $file; + } + } + + return self::$map[$class] = false; } // 注册classmap @@ -113,12 +141,40 @@ class Loader public static function addNamespace($namespace, $path = '') { if (is_array($namespace)) { - self::$namespace = array_merge(self::$namespace, $namespace); + foreach ($namespace as $prefix => $paths) { + self::setPsr4($prefix . '\\', rtrim($paths, DS)); + } } else { - self::$namespace[$namespace] = $path; + self::setPsr4($namespace . '\\', rtrim($path, DS)); } } + // 注册Psr0空间 + private static function setPsr0($prefix, $paths) + { + if (!$prefix) { + self::$fallbackDirsPsr0 = (array)$paths; + } else { + self::$prefixesPsr0[$prefix[0]][$prefix] = (array)$paths; + } + } + + // 注册Psr4空间 + private static function setPsr4($prefix, $paths) + { + if (!$prefix) { + self::$fallbackDirsPsr4 = (array)$paths; + } else { + $length = strlen($prefix); + if ('\\' !== $prefix[$length - 1]) { + throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); + } + self::$prefixLengthsPsr4[$prefix[0]][$prefix] = $length; + self::$prefixDirsPsr4[$prefix] = (array)$paths; + } + } + + // 注册命名空间别名 public static function addNamespaceAlias($namespace, $original = '') { @@ -133,7 +189,7 @@ class Loader public static function register($autoload = '') { // 注册系统自动加载 - spl_autoload_register($autoload ?: 'think\\Loader::autoload'); + spl_autoload_register($autoload ?: 'think\\Loader::autoload', true, true); // 注册命名空间定义 self::addNamespace([ 'think' => LIB_PATH . 'think' . DS, @@ -141,26 +197,15 @@ class Loader 'traits' => LIB_PATH . 'traits' . DS, ]); // 加载类库映射文件 - self::addClassMap(include THINK_PATH . 'classmap' . EXT); + self::addClassMap(includeFile(THINK_PATH . 'classmap' . EXT)); // Composer自动加载支持 if (is_dir(VENDOR_PATH . 'composer')) { - // 注册Composer自动加载 - self::$composerLoader = true; self::registerComposerLoader(); - } elseif (is_file(VENDOR_PATH . 'think_autoload.php')) { - // 读取Composer自动加载文件 - $autoload = include VENDOR_PATH . 'think_autoload.php'; - if (is_array($autoload)) { - // 命名空间和类库映射注册 - self::addNamespace($autoload['namespace']); - self::addClassMap($autoload['classmap']); - // 载入composer包的文件列表 - foreach ($autoload['files'] as $file) { - include $file; - } - } } + + // 自动加载extend目录 + self::$fallbackDirsPsr4[] = rtrim(EXTEND_PATH, DS); } // 注册composer自动加载 @@ -169,19 +214,14 @@ class Loader if (is_file(VENDOR_PATH . 'composer/autoload_namespaces.php')) { $map = require VENDOR_PATH . 'composer/autoload_namespaces.php'; foreach ($map as $namespace => $path) { - self::$prefixesPsr0[$namespace[0]][$namespace] = (array) $path; + self::setPsr0($namespace, $path); } } if (is_file(VENDOR_PATH . 'composer/autoload_psr4.php')) { $map = require VENDOR_PATH . 'composer/autoload_psr4.php'; foreach ($map as $namespace => $path) { - $length = strlen($namespace); - if ('\\' !== $namespace[$length - 1]) { - throw new \InvalidArgumentException("PSR-4 error: A non-empty PSR-4 prefix must end with a namespace separator."); - } - self::$prefixLengthsPsr4[$namespace[0]][$namespace] = $length; - self::$prefixDirsPsr4[$namespace] = (array) $path; + self::setPsr4($namespace, $path); } } @@ -195,81 +235,34 @@ class Loader if (is_file(VENDOR_PATH . 'composer/autoload_files.php')) { $includeFiles = require VENDOR_PATH . 'composer/autoload_files.php'; foreach ($includeFiles as $fileIdentifier => $file) { - self::composerRequire($fileIdentifier, $file); - } - } - } - - private static function composerRequire($fileIdentifier, $file) - { - if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) { - require $file; - $GLOBALS['__composer_autoload_files'][$fileIdentifier] = true; - } - } - - private static function findFileInComposer($class, $ext = '.php') - { - // PSR-4 lookup - $logicalPathPsr4 = strtr($class, '\\', DS) . $ext; - - $first = $class[0]; - if (isset(self::$prefixLengthsPsr4[$first])) { - foreach (self::$prefixLengthsPsr4[$first] as $prefix => $length) { - if (0 === strpos($class, $prefix)) { - foreach (self::$prefixDirsPsr4[$prefix] as $dir) { - if (file_exists($file = $dir . DS . substr($logicalPathPsr4, $length))) { - return $file; - } - } + if (empty(self::$autoloadFiles[$fileIdentifier])) { + requireFile($file); + self::$autoloadFiles[$fileIdentifier] = true; } } } - // PSR-0 lookup - if (false !== $pos = strrpos($class, '\\')) { - // namespaced class name - $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1) - . strtr(substr($logicalPathPsr4, $pos + 1), '_', DS); - } else { - // PEAR-like class name - $logicalPathPsr0 = strtr($class, '_', DS) . $ext; - } - - if (isset(self::$prefixesPsr0[$first])) { - foreach (self::$prefixesPsr0[$first] as $prefix => $dirs) { - if (0 === strpos($class, $prefix)) { - foreach ($dirs as $dir) { - if (file_exists($file = $dir . DS . $logicalPathPsr0)) { - return $file; - } - } - } - } - } - // Remember that this class does not exist. - return self::$map[$class] = false; } /** * 导入所需的类库 同java的Import 本函数有缓存功能 - * @param string $class 类库命名空间字符串 + * @param string $class 类库命名空间字符串 * @param string $baseUrl 起始路径 - * @param string $ext 导入的文件扩展名 + * @param string $ext 导入的文件扩展名 * @return boolean */ public static function import($class, $baseUrl = '', $ext = EXT) { static $_file = []; - $class = str_replace(['.', '#'], [DS, '.'], $class); + $class = str_replace(['.', '#'], [DS, '.'], $class); if (isset($_file[$class . $baseUrl])) { return true; } if (empty($baseUrl)) { list($name, $class) = explode(DS, $class, 2); - if (isset(self::$namespace[$name])) { + if (isset(self::$prefixDirsPsr4[$name])) { // 注册的命名空间 - $baseUrl = self::$namespace[$name]; + $baseUrl = self::$prefixDirsPsr4[$name]; } elseif ('@' == $name) { //加载当前模块应用类库 $baseUrl = App::$modulePath; @@ -283,13 +276,23 @@ class Loader $baseUrl .= DS; } // 如果类存在 则导入类库文件 - $filename = $baseUrl . $class . $ext; - if (is_file($filename)) { + if (is_array($baseUrl)) { + foreach ($baseUrl as $path) { + $filename = $path . DS . $class . $ext; + if (is_file($filename)) { + break; + } + } + } else { + $filename = $baseUrl . $class . $ext; + } + + if (!empty($filename) && is_file($filename)) { // 开启调试模式Win环境严格区分大小写 - if (IS_WIN && false === strpos(realpath($filename), $class . $ext)) { + if (IS_WIN && pathinfo($filename, PATHINFO_FILENAME) != pathinfo(realpath($filename), PATHINFO_FILENAME)) { return false; } - include $filename; + includeFile($filename); $_file[$class . $baseUrl] = true; return true; } @@ -298,10 +301,10 @@ class Loader /** * 实例化(分层)模型 - * @param string $name Model名称 - * @param string $layer 业务层名称 - * @param bool $appendSuffix 是否添加类名后缀 - * @param string $common 公共模块名 + * @param string $name Model名称 + * @param string $layer 业务层名称 + * @param bool $appendSuffix 是否添加类名后缀 + * @param string $common 公共模块名 * @return Object * @throws ClassNotFoundException */ @@ -332,10 +335,10 @@ class Loader /** * 实例化(分层)控制器 格式:[模块名/]控制器名 - * @param string $name 资源地址 - * @param string $layer 控制层名称 - * @param bool $appendSuffix 是否添加类名后缀 - * @param string $empty 空控制器名称 + * @param string $name 资源地址 + * @param string $layer 控制层名称 + * @param bool $appendSuffix 是否添加类名后缀 + * @param string $empty 空控制器名称 * @return Object|false * @throws ClassNotFoundException */ @@ -351,17 +354,15 @@ class Loader return new $class(Request::instance()); } elseif ($empty && class_exists($emptyClass = self::parseClass($module, $layer, $empty, $appendSuffix))) { return new $emptyClass(Request::instance()); - } else { - throw new ClassNotFoundException('class not exists:' . $class, $class); } } /** * 实例化验证类 格式:[模块名/]验证器名 - * @param string $name 资源地址 - * @param string $layer 验证层名称 - * @param bool $appendSuffix 是否添加类名后缀 - * @param string $common 公共模块名 + * @param string $name 资源地址 + * @param string $layer 验证层名称 + * @param bool $appendSuffix 是否添加类名后缀 + * @param string $common 公共模块名 * @return Object|false * @throws ClassNotFoundException */ @@ -407,10 +408,10 @@ class Loader /** * 远程调用模块的操作方法 参数格式 [模块/控制器/]操作 - * @param string $url 调用地址 - * @param string|array $vars 调用参数 支持字符串和数组 - * @param string $layer 要调用的控制层名称 - * @param bool $appendSuffix 是否添加类名后缀 + * @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) @@ -434,14 +435,16 @@ class Loader /** * 字符串命名风格转换 * type 0 将Java风格转换为C的风格 1 将C风格转换为Java的风格 - * @param string $name 字符串 - * @param integer $type 转换类型 + * @param string $name 字符串 + * @param integer $type 转换类型 * @return string */ public static function parseName($name, $type = 0) { if ($type) { - return ucfirst(preg_replace_callback('/_([a-zA-Z])/', function ($match) {return strtoupper($match[1]);}, $name)); + return ucfirst(preg_replace_callback('/_([a-zA-Z])/', function ($match) { + return strtoupper($match[1]); + }, $name)); } else { return strtolower(trim(preg_replace("/[A-Z]/", "_\\0", $name), "_")); } @@ -450,8 +453,9 @@ class Loader /** * 解析应用类的类名 * @param string $module 模块名 - * @param string $layer 层名 controller model ... - * @param string $name 类名 + * @param string $layer 层名 controller model ... + * @param string $name 类名 + * @param bool $appendSuffix * @return string */ public static function parseClass($module, $layer, $name, $appendSuffix = false) @@ -472,3 +476,19 @@ class Loader self::$instance = []; } } + +/** + * 作用范围隔离 + * + * @param $file + * @return mixed + */ +function includeFile($file) +{ + return include $file; +} + +function requireFile($file) +{ + return require $file; +} \ No newline at end of file diff --git a/core/library/think/Route.php b/core/library/think/Route.php index 088dcdb7..705c7e30 100644 --- a/core/library/think/Route.php +++ b/core/library/think/Route.php @@ -638,7 +638,7 @@ class Route if (isset(self::$map[$url])) { // URL映射(完整静态URL匹配) - return self::parseUrl(self::$map[$url], $depr); + return self::parseModule(self::$map[$url], $depr); } if (strpos($url, '/') && isset(self::$alias[strstr($url, '/', true)])) { @@ -1010,12 +1010,8 @@ class Route // 如果有模块/控制器绑定 $url = self::$bind['module'] . '/' . $url; } - // 分隔符替换 确保路由定义使用统一的分隔符 - if ('/' != $depr) { - $url = str_replace($depr, '/', $url); - } - list($path, $var) = self::parseUrlPath($url); + list($path, $var) = self::parseUrlPath($url, $depr); $route = [null, null, null]; if (isset($path)) { // 解析模块 @@ -1052,10 +1048,15 @@ class Route * 解析URL的pathinfo参数和变量 * @access private * @param string $url URL地址 + * @param string $depr URL分隔符 * @return array */ - private static function parseUrlPath($url) + private static function parseUrlPath($url, $depr = '/') { + // 分隔符替换 确保路由定义使用统一的分隔符 + if ('/' != $depr) { + $url = str_replace($depr, '/', $url); + } $url = trim($url, '/'); $var = []; if (false !== strpos($url, '?')) { @@ -1185,24 +1186,36 @@ class Route $result = ['type' => 'controller', 'controller' => substr($url, 1), 'params' => $matches]; } else { // 路由到模块/控制器/操作 - list($path, $var) = self::parseUrlPath($url); - $action = array_pop($path); - $controller = !empty($path) ? array_pop($path) : null; - $module = Config::get('app_multi_module') && !empty($path) ? array_pop($path) : null; - $method = Request::instance()->method(); - if (Config::get('use_action_prefix') && !empty(self::$methodPrefix[$method])) { - // 操作方法前缀支持 - $action = 0 !== strpos($action, self::$methodPrefix[$method]) ? self::$methodPrefix[$method] . $action : $action; - } - $_GET = array_merge($_GET, $var); - // 路由到模块/控制器/操作 - $result = ['type' => 'module', 'module' => [$module, $controller, $action], 'convert' => false]; + $result = self::parseModule($url); } // 解析额外参数 self::parseUrlParams(empty($paths) ? '' : implode('/', $paths), $matches); return $result; } + /** + * 解析URL地址为 模块/控制器/操作 + * @access private + * @param string $url URL地址 + * @param string $depr URL分隔符 + * @return array + */ + private static function parseModule($url, $depr = '/') + { + list($path, $var) = self::parseUrlPath($url, $depr); + $action = array_pop($path); + $controller = !empty($path) ? array_pop($path) : null; + $module = Config::get('app_multi_module') && !empty($path) ? array_pop($path) : null; + $method = Request::instance()->method(); + if (Config::get('use_action_prefix') && !empty(self::$methodPrefix[$method])) { + // 操作方法前缀支持 + $action = 0 !== strpos($action, self::$methodPrefix[$method]) ? self::$methodPrefix[$method] . $action : $action; + } + $_GET = array_merge($_GET, $var); + // 路由到模块/控制器/操作 + return ['type' => 'module', 'module' => [$module, $controller, $action], 'convert' => false]; + } + /** * 解析URL地址中的参数Request对象 * @access private diff --git a/core/library/think/Template.php b/core/library/think/Template.php index a0f27706..97c01d4e 100644 --- a/core/library/think/Template.php +++ b/core/library/think/Template.php @@ -556,9 +556,15 @@ class Template $children[$parent][] = $name; continue; } + } elseif (!empty($val['parent'])) { + // 如果子标签没有被继承则用原值 + $children[$val['parent']][] = $name; + $blocks[$name] = $val; + } + if (!$val['parent']) { + // 替换模板中的顶级block标签 + $extend = str_replace($val['begin'] . $val['content'] . $val['end'], $replace, $extend); } - // 替换模板中的block标签 - $extend = str_replace($val['begin'] . $val['content'] . $val['end'], $replace, $extend); } } $content = $extend; @@ -735,20 +741,15 @@ class Template $str = trim(substr($str, $pos + 1)); $this->parseVar($str); $first = substr($str, 0, 1); - if (isset($array[1])) { - $this->parseVar($array[2]); - $name .= $array[1] . $array[2]; - if ('=' == $first) { - // {$varname?='xxx'} $varname为真时才输出xxx - $str = ''; - } else { - $str = ''; - } - } elseif (')' == substr($name, -1, 1)) { + if (strpos($name, ')')) { // $name为对象或是自动识别,或者含有函数 + if (isset($array[1])) { + $this->parseVar($array[2]); + $name .= $array[1] . $array[2]; + } switch ($first) { case '?': - $str = ''; + $str = ''; break; case '=': $str = ''; @@ -757,26 +758,32 @@ class Template $str = ''; } } else { + if (isset($array[1])) { + $this->parseVar($array[2]); + $_name = ' && ' . $name . $array[1] . $array[2]; + } else { + $_name = ''; + } // $name为数组 switch ($first) { case '?': // {$varname??'xxx'} $varname有定义则输出$varname,否则输出xxx - $str = ''; + $str = ''; break; case '=': // {$varname?='xxx'} $varname为真时才输出xxx - $str = ''; + $str = ''; break; case ':': // {$varname?:'xxx'} $varname为真时输出$varname,否则输出xxx - $str = ''; + $str = ''; break; default: if (strpos($str, ':')) { // {$varname ? 'a' : 'b'} $varname为真时输出a,否则输出b - $str = ''; + $str = ''; } else { - $str = ''; + $str = ''; } } } @@ -847,6 +854,18 @@ class Template if ('$Think' == $first) { // 所有以Think.打头的以特殊变量对待 无需模板赋值就可以输出 $parseStr = $this->parseThinkVar($vars); + } elseif ('$Request' == $first) { + // 获取Request请求对象参数 + $method = array_shift($vars); + if (!empty($vars)) { + $params = implode('.', $vars); + if ('true' != $params) { + $params = '\'' . $params . '\''; + } + } else { + $params = ''; + } + $parseStr = '\think\Request::instance()->' . $method . '(' . $params . ')'; } else { switch ($this->config['tpl_var_identify']) { case 'array': // 识别为数组 diff --git a/core/library/think/Url.php b/core/library/think/Url.php index 774fc6e5..0d9bd418 100644 --- a/core/library/think/Url.php +++ b/core/library/think/Url.php @@ -243,7 +243,7 @@ class Url } elseif (empty($pattern) && array_intersect_assoc($param, $array) == $param) { $match = true; } - if (!empty($param) && array_intersect_assoc($param, $array) != $param) { + if ($match && !empty($param) && array_intersect_assoc($param, $array) != $param) { $match = false; } if ($match) { @@ -324,10 +324,6 @@ class Url // 分析路由规则中的变量 private static function parseVar($rule) { - // 检测是否设置了参数分隔符 - if ($depr = Config::get('url_params_depr')) { - $rule = str_replace($depr, '/', $rule); - } // 提取路由规则中的变量 $var = []; foreach (explode('/', $rule) as $val) { @@ -344,6 +340,9 @@ class Url } } + if ('$' == substr($val, -1, 1)) { + $val = substr($val, 0, -1); + } if (0 === strpos($val, '[:')) { // 可选参数 $optional = true; diff --git a/core/library/think/controller/Rest.php b/core/library/think/controller/Rest.php index 84ac3ed5..a58743b3 100644 --- a/core/library/think/controller/Rest.php +++ b/core/library/think/controller/Rest.php @@ -70,7 +70,7 @@ abstract class Rest if (method_exists($this, $method . '_' . $this->method . '_' . $this->type)) { // RESTFul方法支持 $fun = $method . '_' . $this->method . '_' . $this->type; - } elseif ($this->_method == $this->restDefaultMethod && method_exists($this, $method . '_' . $this->type)) { + } elseif ($this->method == $this->restDefaultMethod && method_exists($this, $method . '_' . $this->type)) { $fun = $method . '_' . $this->type; } elseif ($this->type == $this->restDefaultType && method_exists($this, $method . '_' . $this->method)) { $fun = $method . '_' . $this->method; diff --git a/core/library/think/controller/Yar.php b/core/library/think/controller/Yar.php index 0a876326..fcf5ced1 100644 --- a/core/library/think/controller/Yar.php +++ b/core/library/think/controller/Yar.php @@ -30,7 +30,7 @@ abstract class Yar //判断扩展是否存在 if (!extension_loaded('yar')) { - throw new Exception('not support yar'); + throw new \Exception('not support yar'); } //实例化Yar_Server diff --git a/core/library/think/db/Builder.php b/core/library/think/db/Builder.php index f07eca0c..ab95753d 100644 --- a/core/library/think/db/Builder.php +++ b/core/library/think/db/Builder.php @@ -138,8 +138,6 @@ abstract class Builder { if (is_string($value)) { $value = strpos($value, ':') === 0 && $this->query->isBind(substr($value, 1)) ? $value : $this->connection->quote($value); - } elseif (is_array($value) && is_string($value[0]) && strtolower($value[0]) == 'exp') { - $value = $value[1]; } elseif (is_array($value)) { $value = array_map([$this, 'parseValue'], $value); } elseif (is_bool($value)) { diff --git a/core/library/think/db/Query.php b/core/library/think/db/Query.php index df66fa07..b6719410 100644 --- a/core/library/think/db/Query.php +++ b/core/library/think/db/Query.php @@ -178,16 +178,15 @@ class Query * @access public * @param string $sql sql指令 * @param array $bind 参数绑定 - * @param boolean $fetch 不执行只是获取SQL * @param boolean $master 是否在主服务器读操作 * @param bool|string $class 指定返回的数据集对象 * @return mixed * @throws BindParamException * @throws PDOException */ - public function query($sql, $bind = [], $fetch = false, $master = false, $class = false) + public function query($sql, $bind = [], $master = false, $class = false) { - return $this->connection->query($sql, $bind, $fetch, $master, $class); + return $this->connection->query($sql, $bind, $master, $class); } /** @@ -195,16 +194,15 @@ class Query * @access public * @param string $sql sql指令 * @param array $bind 参数绑定 - * @param boolean $fetch 不执行只是获取SQL * @param boolean $getLastInsID 是否获取自增ID * @param boolean $sequence 自增序列名 * @return int * @throws BindParamException * @throws PDOException */ - public function execute($sql, $bind = [], $fetch = false, $getLastInsID = false, $sequence = null) + public function execute($sql, $bind = [], $getLastInsID = false, $sequence = null) { - return $this->connection->execute($sql, $bind, $fetch, $getLastInsID, $sequence); + return $this->connection->execute($sql, $bind, $getLastInsID, $sequence); } /** @@ -1466,7 +1464,7 @@ class Query unset($this->options['with_field']); } } - $this->field($field, false, $joinTable, $joinAlias, $joinName . '__'); + $this->field($field, false, $joinTable, $joinAlias, $relation . '__'); $i++; } elseif ($closure) { $with[$key] = $closure; @@ -1873,7 +1871,7 @@ class Query * @throws Exception * @throws PDOException */ - public function selectOrFail($data = []) + public function selectOrFail($data = null) { return $this->failException(true)->select($data); } @@ -1887,7 +1885,7 @@ class Query * @throws Exception * @throws PDOException */ - public function findOrFail($data = []) + public function findOrFail($data = null) { return $this->failException(true)->find($data); } @@ -1950,22 +1948,22 @@ class Query /** * 删除记录 * @access public - * @param array $data 表达式 + * @param mixed $data 表达式 true 表示强制删除 * @return int * @throws Exception * @throws PDOException */ - public function delete($data = []) + public function delete($data = null) { // 分析查询表达式 $options = $this->parseExpress(); - if (!empty($data)) { + if (!is_null($data) && true !== $data) { // AR模式分析主键条件 $this->parsePkWhere($data, $options); } - if (empty($options['where'])) { + if (true !== $data && empty($options['where'])) { // 如果条件为空 不进行删除操作 除非设置 1=1 throw new Exception('delete without condition'); } diff --git a/core/library/think/model/Relation.php b/core/library/think/model/Relation.php index 070f6ea1..a065524c 100644 --- a/core/library/think/model/Relation.php +++ b/core/library/think/model/Relation.php @@ -302,23 +302,22 @@ class Relation */ protected function match($model, $relation, &$result) { - $modelName = Loader::parseName(basename(str_replace('\\', '/', $model))); // 重新组装模型数据 foreach ($result->toArray() as $key => $val) { if (strpos($key, '__')) { list($name, $attr) = explode('__', $key, 2); - if ($name == $modelName) { + if ($name == $relation) { $list[$name][$attr] = $val; unset($result->$key); } } } - if (!isset($list[$modelName])) { + if (!isset($list[$relation])) { // 设置关联模型属性 - $list[$modelName] = []; + $list[$relation] = []; } - $result->setAttr($relation, new $model($list[$modelName])); + $result->setAttr($relation, new $model($list[$relation])); } /** diff --git a/extend/com/Sent.php b/extend/com/Sent.php index e8160906..56d19c44 100644 --- a/extend/com/Sent.php +++ b/extend/com/Sent.php @@ -25,12 +25,13 @@ class Sent extends Taglib{ // 标签定义 protected $tags = array( // 标签定义: attr 属性列表 close 是否闭合(0 或者1 默认1) alias 标签别名 level 嵌套层次 - 'nav' => array('attr' => 'field,name', 'close' => 1), //获取导航 - 'list' => array('attr' => 'table,where,order,limit,id,sql,field,key','level'=>3),//列表 - 'doc' => array('attr' => 'model,field,limit,id,field,key','level'=>3), - 'link' => array('attr' => 'type,limit' , 'close' => 1),//友情链接 - 'prev' => array('attr' => 'id,cate' , 'close' => 1),//上一篇 - 'next' => array('attr' => 'id,cate' , 'close' => 1),//下一篇 + 'nav' => array('attr' => 'field,name', 'close' => 1), //获取导航 + 'list' => array('attr' => 'table,where,order,limit,id,sql,field,key','level'=>3),//列表 + 'doc' => array('attr' => 'model,field,limit,id,field,key','level'=>3), + 'recom' => array('attr' => 'doc_id,id'), + 'link' => array('attr' => 'type,limit' , 'close' => 1),//友情链接 + 'prev' => array('attr' => 'id,cate' , 'close' => 1),//上一篇 + 'next' => array('attr' => 'id,cate' , 'close' => 1),//下一篇 ); public function tagnav($tag, $content){ @@ -62,7 +63,7 @@ class Sent extends Taglib{ $where .= " and model_id = {$model} and status >= 1"; $parse = $parse = 'extend(\''.$model.'\')->list(\''.$where.'\',\''.$field.'\',\''.$limit.'\',\''.$order.'\')->all();'; + $parse .= '$__LIST__ = model(\'Document\')->extend(\''.$model.'\')->where(\''.$where.'\')->field(\''.$field.'\')->limit(\''.$limit.'\')->order(\''.$order.'\')->select();'; $parse .= 'foreach ($__LIST__ as $key => $'.$tag['name'].') {'; $parse .= '?>'; $parse .= $content; @@ -84,7 +85,26 @@ class Sent extends Taglib{ $map = implode(" and ", $where); $parse = $parse = 'list(\''.$map.'\',\''.$field.'\',\''.$limit.'\',\''.$order.'\')->all();'; + $parse .= '$__LIST__ = model(\''.$name.'\')->where(\''.$map.'\')->field(\''.$field.'\')->limit(\''.$limit.'\')->order(\''.$order.'\')->select();'; + $parse .= 'foreach ($__LIST__ as $key => $'.$tag['id'].') {'; + $parse .= '?>'; + $parse .= $content; + $parse .= ''; + return $parse; + } + + public function tagrecom($tag, $content){ + $doc_id = empty($tag['doc_id']) ? '' : $tag['doc_id']; + $field = empty($tag['field']) ? '*' : $tag['field']; + $limit = empty($tag['limit']) ? 20 : $tag['limit']; + $order = empty($tag['order']) ? 'id desc' : $tag['order']; + + if (!$doc_id) { + return array(); + } + + $parse = $parse = 'recom('. $doc_id .',\'' .$field. '\',' .$limit. ',\'' .$order. '\');'; $parse .= 'foreach ($__LIST__ as $key => $'.$tag['id'].') {'; $parse .= '?>'; $parse .= $content; @@ -106,7 +126,7 @@ class Sent extends Taglib{ $map = implode(" and ", $where); $parse = $parse = 'list(\''.$map.'\',\''.$field.'\',\''.$limit.'\',\''.$order.'\')->all();'; + $parse .= '$__LIST__ = model(\'Link\')->where(\''.$map.'\')->field(\''.$field.'\')->limit(\''.$limit.'\')->order(\''.$order.'\')->select();'; $parse .= 'foreach ($__LIST__ as $key => $'.$tag['name'].') {'; $parse .= '?>'; $parse .= $content;