diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..ce2d3bf
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,3 @@
+.idea
+composer.lock
+*.log
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 0000000..0dee600
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,115 @@
+如何贡献我的源代码
+===
+
+此文档介绍了 ThinkPHP 团队的组成以及运转机制,您提交的代码将给 ThinkPHP 项目带来什么好处,以及如何才能加入我们的行列。
+
+## 通过 Github 贡献代码
+
+ThinkPHP 目前使用 Git 来控制程序版本,如果你想为 ThinkPHP 贡献源代码,请先大致了解 Git 的使用方法。我们目前把项目托管在 GitHub 上,任何 GitHub 用户都可以向我们贡献代码。
+
+参与的方式很简单,`fork`一份 ThinkPHP 的代码到你的仓库中,修改后提交,并向我们发起`pull request`申请,我们会及时对代码进行审查并处理你的申请并。审查通过后,你的代码将被`merge`进我们的仓库中,这样你就会自动出现在贡献者名单里了,非常方便。
+
+我们希望你贡献的代码符合:
+
+* ThinkPHP 的编码规范
+* 适当的注释,能让其他人读懂
+* 遵循 Apache2 开源协议
+
+**如果想要了解更多细节或有任何疑问,请继续阅读下面的内容**
+
+### 注意事项
+
+* 本项目代码格式化标准选用 [**PSR-2**](http://www.kancloud.cn/thinkphp/php-fig-psr/3141);
+* 类名和类文件名遵循 [**PSR-4**](http://www.kancloud.cn/thinkphp/php-fig-psr/3144);
+* 对于 Issues 的处理,请使用诸如 `fix #xxx(Issue ID)` 的 commit title 直接关闭 issue。
+* 系统会自动在 PHP 5.4 5.5 5.6 7.0 和 HHVM 上测试修改,其中 HHVM 下的测试容许报错,请确保你的修改符合 PHP 5.4 ~ 5.6 和 PHP 7.0 的语法规范;
+* 管理员不会合并造成 CI faild 的修改,若出现 CI faild 请检查自己的源代码或修改相应的[单元测试文件](thinkphp/tests);
+
+## GitHub Issue
+
+GitHub 提供了 Issue 功能,该功能可以用于:
+
+* 提出 bug
+* 提出功能改进
+* 反馈使用体验
+
+该功能不应该用于:
+
+ * 提出修改意见(涉及代码署名和修订追溯问题)
+ * 不友善的言论
+
+## 快速修改
+
+**GitHub 提供了快速编辑文件的功能**
+
+1. 登录 GitHub 帐号;
+2. 浏览项目文件,找到要进行修改的文件;
+3. 点击右上角铅笔图标进行修改;
+4. 填写 `Commit changes` 相关内容(Title 必填);
+5. 提交修改,等待 CI 验证和管理员合并。
+
+**若您需要一次提交大量修改,请继续阅读下面的内容**
+
+## 完整流程
+
+1. `fork`本项目;
+2. 克隆(`clone`)你 `fork` 的项目到本地;
+3. 新建分支(`branch`)并检出(`checkout`)新分支;
+4. 添加本项目到你的本地 git 仓库作为上游(`upstream`);
+5. 进行修改,若你的修改包含方法或函数的增减,请记得修改[单元测试文件](thinkphp/tests);
+6. 变基(衍合 `rebase`)你的分支到上游 master 分支;
+7. `push` 你的本地仓库到 GitHub;
+8. 提交 ``pull request`s`;
+9. 等待 CI 验证(若不通过则重复 5~7,GitHub 会自动更新你的 ``pull request`s`);
+10. 等待管理员处理,并及时 `rebase` 你的分支到上游 master 分支(若上游 master 分支有修改)。
+
+*若有必要,可以 `git push -f` 强行推送 rebase 后的分支到自己的 GitHub `fork`*
+
+### 注意事项
+
+* 若对上述流程有任何不清楚的地方,请查阅 GIT 教程,如 [这个](http://backlogtool.com/git-guide/cn/);
+* 对于代码**不同方面**的修改,请在自己 `fork` 的项目中**创建不同的分支**(原因参见`完整流程`第9条备注部分);
+* 变基及交互式变基操作参见 [Git 交互式变基](http://pakchoi.me/2015/03/17/git-interactive-rebase/)
+
+## 推荐资源
+
+### 开发环境
+
+* XAMPP for Windows 5.5.x
+* WampServer (for Windows)
+* upupw Apache PHP5.4 ( for Windows)
+
+或自行安装
+
+- Apache / Nginx
+- PHP 5.4 ~ 5.6
+- MySQL / MariaDB
+
+*Windows 用户推荐添加 PHP bin 目录到 PATH,方便使用 composer*
+
+*Linux 用户自行配置环境, Mac 用户推荐使用内嵌 Apache 配合 Homebrew 安装 PHP 和 MariaDB*
+
+### 编辑器
+
+Sublime Text 3 + phpfmt 插件
+
+phpfmt 插件参数
+
+```json
+{
+ "enable_auto_align": true,
+ "indent_with_space": true,
+ "psr1_naming": true,
+ "psr2": true,
+ "version": 1
+}
+```
+
+或其他 编辑器 / IDE 配合 PSR2 自动格式化工具
+
+### Git GUI
+
+* SourceTree
+* GitHub Desktop
+
+或其他 Git 图形界面客户端
diff --git a/LICENSE.txt b/LICENSE.txt
new file mode 100644
index 0000000..574a39c
--- /dev/null
+++ b/LICENSE.txt
@@ -0,0 +1,32 @@
+
+ThinkPHP遵循Apache2开源协议发布,并提供免费使用。
+版权所有Copyright © 2006-2016 by ThinkPHP (http://thinkphp.cn)
+All rights reserved。
+ThinkPHP® 商标和著作权所有者为上海顶想信息科技有限公司。
+
+Apache Licence是著名的非盈利开源组织Apache采用的协议。
+该协议和BSD类似,鼓励代码共享和尊重原作者的著作权,
+允许代码修改,再作为开源或商业软件发布。需要满足
+的条件:
+1. 需要给代码的用户一份Apache Licence ;
+2. 如果你修改了代码,需要在被修改的文件中说明;
+3. 在延伸的代码中(修改和有源代码衍生的代码中)需要
+带有原来代码中的协议,商标,专利声明和其他原来作者规
+定需要包含的说明;
+4. 如果再发布的产品中包含一个Notice文件,则在Notice文
+件中需要带有本协议内容。你可以在Notice中增加自己的
+许可,但不可以表现为对Apache Licence构成更改。
+具体的协议参考:http://www.apache.org/licenses/LICENSE-2.0
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
diff --git a/application/.htaccess b/application/.htaccess
new file mode 100644
index 0000000..3418e55
--- /dev/null
+++ b/application/.htaccess
@@ -0,0 +1 @@
+deny from all
\ No newline at end of file
diff --git a/application/command.php b/application/command.php
new file mode 100644
index 0000000..f93890c
--- /dev/null
+++ b/application/command.php
@@ -0,0 +1,12 @@
+
+// +----------------------------------------------------------------------
+
+return [];
\ No newline at end of file
diff --git a/application/common.php b/application/common.php
new file mode 100644
index 0000000..55d22f2
--- /dev/null
+++ b/application/common.php
@@ -0,0 +1,12 @@
+
+// +----------------------------------------------------------------------
+
+// 应用公共文件
diff --git a/application/config.php b/application/config.php
new file mode 100644
index 0000000..767b325
--- /dev/null
+++ b/application/config.php
@@ -0,0 +1,231 @@
+
+// +----------------------------------------------------------------------
+
+return [
+ // +----------------------------------------------------------------------
+ // | 应用设置
+ // +----------------------------------------------------------------------
+
+ // 应用命名空间
+ 'app_namespace' => 'app',
+ // 应用调试模式
+ 'app_debug' => true,
+ // 应用Trace
+ 'app_trace' => false,
+ // 应用模式状态
+ 'app_status' => '',
+ // 是否支持多模块
+ 'app_multi_module' => true,
+ // 入口自动绑定模块
+ 'auto_bind_module' => false,
+ // 注册的根命名空间
+ 'root_namespace' => [],
+ // 扩展配置文件
+ 'extra_config_list' => ['database', 'validate'],
+ // 扩展函数文件
+ 'extra_file_list' => [THINK_PATH . 'helper' . EXT],
+ // 默认输出类型
+ 'default_return_type' => 'html',
+ // 默认AJAX 数据返回格式,可选json xml ...
+ 'default_ajax_return' => 'json',
+ // 默认JSONP格式返回的处理方法
+ 'default_jsonp_handler' => 'jsonpReturn',
+ // 默认JSONP处理方法
+ 'var_jsonp_handler' => 'callback',
+ // 默认时区
+ 'default_timezone' => 'PRC',
+ // 是否开启多语言
+ 'lang_switch_on' => false,
+ // 默认全局过滤方法 用逗号分隔多个
+ 'default_filter' => '',
+ // 默认语言
+ 'default_lang' => 'zh-cn',
+ // 应用类库后缀
+ 'class_suffix' => false,
+ // 控制器类后缀
+ 'controller_suffix' => false,
+
+ // +----------------------------------------------------------------------
+ // | 模块设置
+ // +----------------------------------------------------------------------
+
+ // 默认模块名
+ 'default_module' => 'index',
+ // 禁止访问模块
+ 'deny_module_list' => ['common'],
+ // 默认控制器名
+ 'default_controller' => 'Index',
+ // 默认操作名
+ 'default_action' => 'index',
+ // 默认验证器
+ 'default_validate' => '',
+ // 默认的空控制器名
+ 'empty_controller' => 'Error',
+ // 操作方法后缀
+ 'action_suffix' => '',
+ // 自动搜索控制器
+ 'controller_auto_search' => false,
+
+ // +----------------------------------------------------------------------
+ // | URL设置
+ // +----------------------------------------------------------------------
+
+ // PATHINFO变量名 用于兼容模式
+ 'var_pathinfo' => 's',
+ // 兼容PATH_INFO获取
+ 'pathinfo_fetch' => ['ORIG_PATH_INFO', 'REDIRECT_PATH_INFO', 'REDIRECT_URL'],
+ // pathinfo分隔符
+ 'pathinfo_depr' => '/',
+ // URL伪静态后缀
+ 'url_html_suffix' => 'html',
+ // URL普通方式参数 用于自动生成
+ 'url_common_param' => false,
+ // URL参数方式 0 按名称成对解析 1 按顺序解析
+ 'url_param_type' => 0,
+ // 是否开启路由
+ 'url_route_on' => true,
+ // 路由配置文件(支持配置多个)
+ 'route_config_file' => ['route'],
+ // 是否强制使用路由
+ 'url_route_must' => false,
+ // 域名部署
+ 'url_domain_deploy' => false,
+ // 域名根,如.thinkphp.cn
+ 'url_domain_root' => '',
+ // 是否自动转换URL中的控制器和操作名
+ 'url_convert' => true,
+ // 默认的访问控制器层
+ 'url_controller_layer' => 'controller',
+ // 表单请求类型伪装变量
+ 'var_method' => '_method',
+
+ // +----------------------------------------------------------------------
+ // | 模板设置
+ // +----------------------------------------------------------------------
+
+ 'template' => [
+ // 模板引擎类型 支持 php think 支持扩展
+ 'type' => 'Think',
+ // 模板路径
+ 'view_path' => '',
+ // 模板后缀
+ 'view_suffix' => 'html',
+ // 模板文件名分隔符
+ 'view_depr' => DS,
+ // 模板引擎普通标签开始标记
+ 'tpl_begin' => '{',
+ // 模板引擎普通标签结束标记
+ 'tpl_end' => '}',
+ // 标签库标签开始标记
+ 'taglib_begin' => '{',
+ // 标签库标签结束标记
+ 'taglib_end' => '}',
+ ],
+
+ // 视图输出字符串内容替换
+ 'view_replace_str' => [],
+ // 默认跳转页面对应的模板文件
+ 'dispatch_success_tmpl' => THINK_PATH . 'tpl' . DS . 'dispatch_jump.tpl',
+ 'dispatch_error_tmpl' => THINK_PATH . 'tpl' . DS . 'dispatch_jump.tpl',
+
+ // +----------------------------------------------------------------------
+ // | 异常及错误设置
+ // +----------------------------------------------------------------------
+
+ // 异常页面的模板文件
+ 'exception_tmpl' => THINK_PATH . 'tpl' . DS . 'think_exception.tpl',
+
+ // 错误显示信息,非调试模式有效
+ 'error_message' => '页面错误!请稍后再试~',
+ // 显示错误信息
+ 'show_error_msg' => false,
+ // 异常处理handle类 留空使用 \think\exception\Handle
+ 'exception_handle' => '',
+
+ // +----------------------------------------------------------------------
+ // | 日志设置
+ // +----------------------------------------------------------------------
+
+ 'log' => [
+ // 日志记录方式,内置 file socket 支持扩展
+ 'type' => 'File',
+ // 日志保存目录
+ 'path' => LOG_PATH,
+ // 日志记录级别
+ 'level' => [],
+ ],
+
+ // +----------------------------------------------------------------------
+ // | Trace设置 开启 app_trace 后 有效
+ // +----------------------------------------------------------------------
+ 'trace' => [
+ // 内置Html Console 支持扩展
+ 'type' => 'Html',
+ ],
+
+ // +----------------------------------------------------------------------
+ // | 缓存设置
+ // +----------------------------------------------------------------------
+
+ 'cache' => [
+ // 驱动方式
+ 'type' => 'File',
+ // 缓存保存目录
+ 'path' => CACHE_PATH,
+ // 缓存前缀
+ 'prefix' => '',
+ // 缓存有效期 0表示永久缓存
+ 'expire' => 0,
+ ],
+
+ // +----------------------------------------------------------------------
+ // | 会话设置
+ // +----------------------------------------------------------------------
+
+ 'session' => [
+ 'id' => '',
+ // SESSION_ID的提交变量,解决flash上传跨域
+ 'var_session_id' => '',
+ // SESSION 前缀
+ 'prefix' => 'think',
+ // 驱动方式 支持redis memcache memcached
+ 'type' => '',
+ // 是否自动开启 SESSION
+ 'auto_start' => true,
+ ],
+
+ // +----------------------------------------------------------------------
+ // | Cookie设置
+ // +----------------------------------------------------------------------
+ 'cookie' => [
+ // cookie 名称前缀
+ 'prefix' => '',
+ // cookie 保存时间
+ 'expire' => 0,
+ // cookie 保存路径
+ 'path' => '/',
+ // cookie 有效域名
+ 'domain' => '',
+ // cookie 启用安全传输
+ 'secure' => false,
+ // httponly设置
+ 'httponly' => '',
+ // 是否使用 setcookie
+ 'setcookie' => true,
+ ],
+
+ //分页配置
+ 'paginate' => [
+ 'type' => 'bootstrap',
+ 'var_page' => 'page',
+ 'list_rows' => 15,
+ ],
+];
diff --git a/application/database.php b/application/database.php
new file mode 100644
index 0000000..0fa377d
--- /dev/null
+++ b/application/database.php
@@ -0,0 +1,51 @@
+
+// +----------------------------------------------------------------------
+
+return [
+ // 数据库类型
+ 'type' => 'mysql',
+ // 服务器地址
+ 'hostname' => '127.0.0.1',
+ // 数据库名
+ 'database' => 'chat',
+ // 用户名
+ 'username' => 'root',
+ // 密码
+ 'password' => 'root',
+ // 端口
+ 'hostport' => '',
+ // 连接dsn
+ 'dsn' => '',
+ // 数据库连接参数
+ 'params' => [],
+ // 数据库编码默认采用utf8
+ 'charset' => 'utf8',
+ // 数据库表前缀
+ 'prefix' => 'chat_',
+ // 数据库调试模式
+ 'debug' => true,
+ // 数据库部署方式:0 集中式(单一服务器),1 分布式(主从服务器)
+ 'deploy' => 0,
+ // 数据库读写是否分离 主从式有效
+ 'rw_separate' => false,
+ // 读写分离后 主服务器数量
+ 'master_num' => 1,
+ // 指定从服务器序号
+ 'slave_no' => '',
+ // 是否严格检查字段是否存在
+ 'fields_strict' => true,
+ // 数据集返回类型 array 数组 collection Collection对象
+ 'resultset_type' => 'array',
+ // 是否自动写入时间戳字段
+ 'auto_timestamp' => false,
+ // 是否需要进行SQL性能分析
+ 'sql_explain' => false,
+];
diff --git a/application/index/common.php b/application/index/common.php
new file mode 100644
index 0000000..b3d9bbc
--- /dev/null
+++ b/application/index/common.php
@@ -0,0 +1 @@
+
+// +----------------------------------------------------------------------
+namespace app\index\controller;
+
+use think\Controller;
+
+class Index extends Controller
+{
+ public function _initialize()
+ {
+ if( empty(session('uid')) ){
+ $this->redirect( url('login/index'), 302 );
+ }
+ }
+
+ public function index()
+ {
+ $mine = db('user')->where('id', session('uid'))->find();
+ $this->assign([
+ 'uinfo' => $mine
+ ]);
+ return $this->fetch();
+ }
+
+ //获取列表
+ public function getList()
+ {
+ //查询自己的信息
+ $mine = db('user')->where('id', session('uid'))->find();
+ $other = db('user')->where('id != ' . session('uid'))->select();
+
+ $online = 1;
+ foreach( $other as $key=>$vo ){
+
+ $list[$key]['username'] = $vo['uname'];
+ $list[$key]['id'] = $vo['id'];
+ $list[$key]['avatar'] = $vo['avatar'];
+ $list[$key]['sign'] = $vo['sign'];
+ if( 'online' == $vo['status'] ){
+ $online++;
+ }
+ }
+
+ unset( $other );
+
+ $return = [
+ 'code' => 0,
+ 'msg'=> '',
+ 'data' => [
+ 'mine' => [
+ 'username' => $mine['uname'],
+ 'id' => $mine['id'],
+ 'status' => $mine['status'],
+ 'sign' => $mine['sign'],
+ 'avatar' => $mine['avatar']
+ ],
+ 'friend' => [
+ [
+ 'groupname' => '阿里在线',
+ 'id' => 1,
+ 'online' => $online,
+ 'list' => $list
+ ]
+ ],
+ ],
+ ];
+ return json( $return );
+
+ }
+
+ //获取组员信息
+ public function getMembers()
+ {
+
+ return ;
+ }
+
+
+
+}
diff --git a/application/index/controller/Login.php b/application/index/controller/Login.php
new file mode 100644
index 0000000..5750cf3
--- /dev/null
+++ b/application/index/controller/Login.php
@@ -0,0 +1,39 @@
+
+// +----------------------------------------------------------------------
+namespace app\index\controller;
+
+use think\Controller;
+
+class Login extends Controller
+{
+ public function index()
+ {
+ return $this->fetch();
+ }
+
+ public function doLogin()
+ {
+ $uname = input('param.uname');
+ $userinfo = db('user')->where('uname', $uname)->find();
+ if( empty($userinfo) ){
+ $this->error("用户不存在");
+ }
+
+ //设置为登录状态
+ db('user')->where('uname', $uname)->setField('status', 'online');
+
+ session( 'uid', $userinfo['id'] );
+ session( 'uname', $userinfo['uname'] );
+
+ $this->redirect(url('index/index'));
+ }
+
+}
diff --git a/application/index/database.php b/application/index/database.php
new file mode 100644
index 0000000..b3d9bbc
--- /dev/null
+++ b/application/index/database.php
@@ -0,0 +1 @@
+
+
+
+
+LayIM测试
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/application/index/view/login/index.html b/application/index/view/login/index.html
new file mode 100644
index 0000000..d09e337
--- /dev/null
+++ b/application/index/view/login/index.html
@@ -0,0 +1,35 @@
+
+
+
+
+
+ layerIM 体验
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/application/route.php b/application/route.php
new file mode 100644
index 0000000..f648d3b
--- /dev/null
+++ b/application/route.php
@@ -0,0 +1,21 @@
+
+// +----------------------------------------------------------------------
+
+return [
+ '__pattern__' => [
+ 'name' => '\w+',
+ ],
+ '[hello]' => [
+ ':id' => ['index/hello', ['method' => 'get'], ['id' => '\d+']],
+ ':name' => ['index/hello', ['method' => 'post']],
+ ],
+
+];
diff --git a/back/chat_user.sql b/back/chat_user.sql
new file mode 100644
index 0000000..207892a
--- /dev/null
+++ b/back/chat_user.sql
@@ -0,0 +1,36 @@
+/*
+Navicat MySQL Data Transfer
+
+Source Server : localhost
+Source Server Version : 50540
+Source Host : localhost:3306
+Source Database : chat
+
+Target Server Type : MYSQL
+Target Server Version : 50540
+File Encoding : 65001
+
+Date: 2016-08-30 14:49:16
+*/
+
+SET FOREIGN_KEY_CHECKS=0;
+
+-- ----------------------------
+-- Table structure for chat_user
+-- ----------------------------
+DROP TABLE IF EXISTS `chat_user`;
+CREATE TABLE `chat_user` (
+ `id` int(11) NOT NULL AUTO_INCREMENT,
+ `uname` varchar(155) DEFAULT NULL,
+ `status` varchar(55) DEFAULT NULL,
+ `sign` varchar(255) DEFAULT NULL,
+ `avatar` varchar(255) DEFAULT NULL,
+ PRIMARY KEY (`id`)
+) ENGINE=MyISAM AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;
+
+-- ----------------------------
+-- Records of chat_user
+-- ----------------------------
+INSERT INTO `chat_user` VALUES ('1', '纸飞机', 'online', '在深邃的编码世界,做一枚轻盈的纸飞机', 'http://cdn.firstlinkapp.com/upload/2016_6/1465575923433_33812.jpg');
+INSERT INTO `chat_user` VALUES ('2', '马云', 'online', '让天下没有难写的代码', 'http://tp4.sinaimg.cn/2145291155/180/5601307179/1');
+INSERT INTO `chat_user` VALUES ('3', '罗玉凤', 'outline', '在自己实力不济的时候,不要去相信什么媒体和记者。他们不是善良的人,有时候候他们的采访对当事人而言就是陷阱', 'http://tp1.sinaimg.cn/1241679004/180/5743814375/0');
diff --git a/build.php b/build.php
new file mode 100644
index 0000000..7838f0a
--- /dev/null
+++ b/build.php
@@ -0,0 +1,25 @@
+
+// +----------------------------------------------------------------------
+
+return [
+ // 生成应用公共文件
+ '__file__' => ['common.php', 'config.php', 'database.php'],
+
+ // 定义index模块
+ 'index' => [
+ '__file__' => ['common.php', 'config.php', 'database.php'],
+ '__dir__' => ['behavior', 'controller', 'model', 'view'],
+ 'controller' => ['Index'],
+ 'model' => [],
+ 'view' => ['index/index'],
+ ],
+ // 其他更多的模块定义
+];
diff --git a/composer.json b/composer.json
new file mode 100644
index 0000000..2ca919f
--- /dev/null
+++ b/composer.json
@@ -0,0 +1,29 @@
+{
+ "name": "topthink/think",
+ "description": "the new thinkphp framework",
+ "type": "project",
+ "keywords": [
+ "framework",
+ "thinkphp",
+ "ORM"
+ ],
+ "homepage": "http://thinkphp.cn/",
+ "license": "Apache-2.0",
+ "authors": [
+ {
+ "name": "liu21st",
+ "email": "liu21st@gmail.com"
+ }
+ ],
+ "require": {
+ "php": ">=5.4.0",
+ "topthink/framework": "*"
+ },
+ "extra": {
+ "think-path": "thinkphp"
+ },
+ "minimum-stability": "dev",
+ "config": {
+ "preferred-install": "dist"
+ }
+}
diff --git a/extend/.gitignore b/extend/.gitignore
new file mode 100644
index 0000000..c96a04f
--- /dev/null
+++ b/extend/.gitignore
@@ -0,0 +1,2 @@
+*
+!.gitignore
\ No newline at end of file
diff --git a/public/.htaccess b/public/.htaccess
new file mode 100644
index 0000000..d9ee23c
--- /dev/null
+++ b/public/.htaccess
@@ -0,0 +1,8 @@
+
+ Options +FollowSymlinks -Multiviews
+ RewriteEngine On
+
+ RewriteCond %{REQUEST_FILENAME} !-d
+ RewriteCond %{REQUEST_FILENAME} !-f
+ RewriteRule ^(.*)$ index.php?/$1 [QSA,PT,L]
+
diff --git a/public/favicon.ico b/public/favicon.ico
new file mode 100644
index 0000000..e71815a
Binary files /dev/null and b/public/favicon.ico differ
diff --git a/public/index.php b/public/index.php
new file mode 100644
index 0000000..1473e24
--- /dev/null
+++ b/public/index.php
@@ -0,0 +1,17 @@
+
+// +----------------------------------------------------------------------
+
+// [ 应用入口文件 ]
+
+// 定义应用目录
+define('APP_PATH', __DIR__ . '/../application/');
+// 加载框架引导文件
+require __DIR__ . '/../thinkphp/start.php';
diff --git a/public/robots.txt b/public/robots.txt
new file mode 100644
index 0000000..eb05362
--- /dev/null
+++ b/public/robots.txt
@@ -0,0 +1,2 @@
+User-agent: *
+Disallow:
diff --git a/public/router.php b/public/router.php
new file mode 100644
index 0000000..6ba1fab
--- /dev/null
+++ b/public/router.php
@@ -0,0 +1,17 @@
+
+// +----------------------------------------------------------------------
+// $Id$
+
+if (is_file($_SERVER["DOCUMENT_ROOT"] . $_SERVER["REQUEST_URI"])) {
+ return false;
+} else {
+ require __DIR__ . "/index.php";
+}
diff --git a/public/static/.gitignore b/public/static/.gitignore
new file mode 100644
index 0000000..c96a04f
--- /dev/null
+++ b/public/static/.gitignore
@@ -0,0 +1,2 @@
+*
+!.gitignore
\ No newline at end of file
diff --git a/runtime/.gitignore b/runtime/.gitignore
new file mode 100644
index 0000000..c96a04f
--- /dev/null
+++ b/runtime/.gitignore
@@ -0,0 +1,2 @@
+*
+!.gitignore
\ No newline at end of file
diff --git a/think b/think
new file mode 100644
index 0000000..5de77e6
--- /dev/null
+++ b/think
@@ -0,0 +1,17 @@
+#!/usr/bin/env php
+
+// +----------------------------------------------------------------------
+
+// 定义项目路径
+define('APP_PATH', './application/');
+
+// 加载框架引导文件
+require './thinkphp/console.php';
\ No newline at end of file
diff --git a/thinkphp/.gitignore b/thinkphp/.gitignore
new file mode 100644
index 0000000..7e31ef5
--- /dev/null
+++ b/thinkphp/.gitignore
@@ -0,0 +1,4 @@
+/composer.lock
+/vendor
+.idea
+.DS_Store
diff --git a/thinkphp/.htaccess b/thinkphp/.htaccess
new file mode 100644
index 0000000..3418e55
--- /dev/null
+++ b/thinkphp/.htaccess
@@ -0,0 +1 @@
+deny from all
\ No newline at end of file
diff --git a/thinkphp/.travis.yml b/thinkphp/.travis.yml
new file mode 100644
index 0000000..96a9dff
--- /dev/null
+++ b/thinkphp/.travis.yml
@@ -0,0 +1,49 @@
+sudo: false
+
+language: php
+
+services:
+ - memcached
+ - mongodb
+ - mysql
+ - postgresql
+ - redis-server
+
+matrix:
+ fast_finish: true
+ include:
+ - php: 5.4
+ - php: 5.5
+ - php: 5.6
+ - php: 7.0
+ - php: hhvm
+ allow_failures:
+ - php: hhvm
+
+cache:
+ directories:
+ - $HOME/.composer/cache
+
+before_install:
+ - composer self-update
+ - mysql -e "create database IF NOT EXISTS test;" -uroot
+ - psql -c 'DROP DATABASE IF EXISTS test;' -U postgres
+ - psql -c 'create database test;' -U postgres
+
+install:
+ - ./tests/script/install.sh
+
+script:
+ ## LINT
+ - find . -path ./vendor -prune -o -type f -name \*.php -exec php -l {} \;
+ ## PHP_CodeSniffer
+ - vendor/bin/phpcs --runtime-set ignore_errors_on_exit 1 --runtime-set ignore_warnings_on_exit 1 --standard=PSR2 --ignore="vendor/*" ./
+ ## PHP Copy/Paste Detector
+ - vendor/bin/phpcpd --verbose --exclude vendor ./ || true
+ ## PHPLOC
+ - vendor/bin/phploc --exclude vendor ./
+ ## PHPUNIT
+ - vendor/bin/phpunit --coverage-clover=coverage.xml --configuration=phpunit.xml
+
+after_success:
+ - bash <(curl -s https://codecov.io/bash)
diff --git a/thinkphp/CONTRIBUTING.md b/thinkphp/CONTRIBUTING.md
new file mode 100644
index 0000000..de0fb5e
--- /dev/null
+++ b/thinkphp/CONTRIBUTING.md
@@ -0,0 +1,115 @@
+如何贡献我的源代码
+===
+
+此文档介绍了 ThinkPHP 团队的组成以及运转机制,您提交的代码将给 ThinkPHP 项目带来什么好处,以及如何才能加入我们的行列。
+
+## 通过 Github 贡献代码
+
+ThinkPHP 目前使用 Git 来控制程序版本,如果你想为 ThinkPHP 贡献源代码,请先大致了解 Git 的使用方法。我们目前把项目托管在 GitHub 上,任何 GitHub 用户都可以向我们贡献代码。
+
+参与的方式很简单,`fork`一份 ThinkPHP 的代码到你的仓库中,修改后提交,并向我们发起`pull request`申请,我们会及时对代码进行审查并处理你的申请并。审查通过后,你的代码将被`merge`进我们的仓库中,这样你就会自动出现在贡献者名单里了,非常方便。
+
+我们希望你贡献的代码符合:
+
+* ThinkPHP 的编码规范
+* 适当的注释,能让其他人读懂
+* 遵循 Apache2 开源协议
+
+**如果想要了解更多细节或有任何疑问,请继续阅读下面的内容**
+
+### 注意事项
+
+* 本项目代码格式化标准选用 [**PSR-2**](http://www.kancloud.cn/thinkphp/php-fig-psr/3141);
+* 类名和类文件名遵循 [**PSR-4**](http://www.kancloud.cn/thinkphp/php-fig-psr/3144);
+* 对于 Issues 的处理,请使用诸如 `fix #xxx(Issue ID)` 的 commit title 直接关闭 issue。
+* 系统会自动在 PHP 5.4 5.5 5.6 7.0 和 HHVM 上测试修改,其中 HHVM 下的测试容许报错,请确保你的修改符合 PHP 5.4 ~ 5.6 和 PHP 7.0 的语法规范;
+* 管理员不会合并造成 CI faild 的修改,若出现 CI faild 请检查自己的源代码或修改相应的[单元测试文件](thinkphp/tests);
+
+## GitHub Issue
+
+GitHub 提供了 Issue 功能,该功能可以用于:
+
+* 提出 bug
+* 提出功能改进
+* 反馈使用体验
+
+该功能不应该用于:
+
+ * 提出修改意见(涉及代码署名和修订追溯问题)
+ * 不友善的言论
+
+## 快速修改
+
+**GitHub 提供了快速编辑文件的功能**
+
+1. 登录 GitHub 帐号;
+2. 浏览项目文件,找到要进行修改的文件;
+3. 点击右上角铅笔图标进行修改;
+4. 填写 `Commit changes` 相关内容(Title 必填);
+5. 提交修改,等待 CI 验证和管理员合并。
+
+**若您需要一次提交大量修改,请继续阅读下面的内容**
+
+## 完整流程
+
+1. `fork`本项目;
+2. 克隆(`clone`)你 `fork` 的项目到本地;
+3. 新建分支(`branch`)并检出(`checkout`)新分支;
+4. 添加本项目到你的本地 git 仓库作为上游(`upstream`);
+5. 进行修改,若你的修改包含方法或函数的增减,请记得修改[单元测试文件](thinkphp/tests);
+6. 变基(衍合 `rebase`)你的分支到上游 master 分支;
+7. `push` 你的本地仓库到 GitHub;
+8. 提交 `pull request`;
+9. 等待 CI 验证(若不通过则重复 5~7,GitHub 会自动更新你的 `pull request`);
+10. 等待管理员处理,并及时 `rebase` 你的分支到上游 master 分支(若上游 master 分支有修改)。
+
+*若有必要,可以 `git push -f` 强行推送 rebase 后的分支到自己的 GitHub `fork`*
+
+### 注意事项
+
+* 若对上述流程有任何不清楚的地方,请查阅 GIT 教程,如 [这个](http://backlogtool.com/git-guide/cn/);
+* 对于代码**不同方面**的修改,请在自己 `fork` 的项目中**创建不同的分支**(原因参见`完整流程`第9条备注部分);
+* 变基及交互式变基操作参见 [Git 交互式变基](http://pakchoi.me/2015/03/17/git-interactive-rebase/)
+
+## 推荐资源
+
+### 开发环境
+
+* XAMPP for Windows 5.5.x
+* WampServer (for Windows)
+* upupw Apache PHP5.4 ( for Windows)
+
+或自行安装
+
+- Apache / Nginx
+- PHP 5.4 ~ 5.6
+- MySQL / MariaDB
+
+*Windows 用户推荐添加 PHP bin 目录到 PATH,方便使用 composer*
+
+*Linux 用户自行配置环境, Mac 用户推荐使用内嵌 Apache 配合 Homebrew 安装 PHP 和 MariaDB*
+
+### 编辑器
+
+Sublime Text 3 + phpfmt 插件
+
+phpfmt 插件参数
+
+```json
+{
+ "enable_auto_align": true,
+ "indent_with_space": true,
+ "psr1_naming": true,
+ "psr2": true,
+ "version": 1
+}
+```
+
+或其他 编辑器 / IDE 配合 PSR2 自动格式化工具
+
+### Git GUI
+
+* SourceTree
+* GitHub Desktop
+
+或其他 Git 图形界面客户端
diff --git a/thinkphp/LICENSE.txt b/thinkphp/LICENSE.txt
new file mode 100644
index 0000000..574a39c
--- /dev/null
+++ b/thinkphp/LICENSE.txt
@@ -0,0 +1,32 @@
+
+ThinkPHP遵循Apache2开源协议发布,并提供免费使用。
+版权所有Copyright © 2006-2016 by ThinkPHP (http://thinkphp.cn)
+All rights reserved。
+ThinkPHP® 商标和著作权所有者为上海顶想信息科技有限公司。
+
+Apache Licence是著名的非盈利开源组织Apache采用的协议。
+该协议和BSD类似,鼓励代码共享和尊重原作者的著作权,
+允许代码修改,再作为开源或商业软件发布。需要满足
+的条件:
+1. 需要给代码的用户一份Apache Licence ;
+2. 如果你修改了代码,需要在被修改的文件中说明;
+3. 在延伸的代码中(修改和有源代码衍生的代码中)需要
+带有原来代码中的协议,商标,专利声明和其他原来作者规
+定需要包含的说明;
+4. 如果再发布的产品中包含一个Notice文件,则在Notice文
+件中需要带有本协议内容。你可以在Notice中增加自己的
+许可,但不可以表现为对Apache Licence构成更改。
+具体的协议参考:http://www.apache.org/licenses/LICENSE-2.0
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
diff --git a/thinkphp/README.md b/thinkphp/README.md
new file mode 100644
index 0000000..ecbb33c
--- /dev/null
+++ b/thinkphp/README.md
@@ -0,0 +1,112 @@
+ThinkPHP 5.0 RC4
+===============
+
+[](https://travis-ci.org/top-think/framework)
+[](https://codecov.io/github/top-think/framework)
+[](https://github.com/top-think/framework/releases)
+[](https://github.com/top-think/framework/releases/latest)
+[](https://github.com/top-think/framework/releases/latest)
+[](https://packagist.org/packages/topthink/framework)
+[](https://packagist.org/packages/topthink/framework)
+
+ThinkPHP5在保持快速开发和大道至简的核心理念不变的同时,PHP版本要求提升到5.4,对已有的CBD模式做了更深的强化,优化核心,减少依赖,基于全新的架构思想和命名空间实现,是ThinkPHP突破原有框架思路的颠覆之作,其主要特性包括:
+
+ + 基于命名空间和众多PHP新特性
+ + 核心功能组件化
+ + 强化路由功能
+ + 更灵活的控制器
+ + 重构的模型和数据库类
+ + 配置文件可分离
+ + 重写的自动验证和完成
+ + 简化扩展机制
+ + API支持完善
+ + 改进的Log类
+ + 命令行访问支持
+ + REST支持
+ + 引导文件支持
+ + 方便的自动生成定义
+ + 真正惰性加载
+ + 分布式环境支持
+ + 更多的社交类库
+
+> ThinkPHP5的运行环境要求PHP5.4以上。
+
+详细开发文档参考 [ThinkPHP5完全开发手册](http://www.kancloud.cn/manual/thinkphp5)
+
+## 目录结构
+
+初始的目录结构如下:
+
+~~~
+www WEB部署目录(或者子目录)
+├─application 应用目录
+│ ├─common 公共模块目录(可以更改)
+│ ├─module_name 模块目录
+│ │ ├─config.php 模块配置文件
+│ │ ├─common.php 模块函数文件
+│ │ ├─controller 控制器目录
+│ │ ├─model 模型目录
+│ │ ├─view 视图目录
+│ │ └─ ... 更多类库目录
+│ │
+│ ├─command.php 命令行工具配置文件
+│ ├─common.php 公共函数文件
+│ ├─config.php 公共配置文件
+│ ├─route.php 路由配置文件
+│ └─database.php 数据库配置文件
+│
+├─public WEB目录(对外访问目录)
+│ ├─index.php 入口文件
+│ ├─router.php 快速测试文件
+│ └─.htaccess 用于apache的重写
+│
+├─thinkphp 框架系统目录
+│ ├─lang 语言文件目录
+│ ├─library 框架类库目录
+│ │ ├─think Think类库包目录
+│ │ └─traits 系统Trait目录
+│ │
+│ ├─tpl 系统模板目录
+│ ├─base.php 基础定义文件
+│ ├─console.php 控制台入口文件
+│ ├─convention.php 框架惯例配置文件
+│ ├─helper.php 助手函数文件
+│ ├─phpunit.xml phpunit配置文件
+│ └─start.php 框架入口文件
+│
+├─extend 扩展类库目录
+├─runtime 应用的运行时目录(可写,可定制)
+├─vendor 第三方类库目录(Composer依赖库)
+├─build.php 自动生成定义文件(参考)
+├─composer.json composer 定义文件
+├─LICENSE.txt 授权说明文件
+├─README.md README 文件
+├─think 命令行入口文件
+~~~
+
+> router.php用于php自带webserver支持,可用于快速测试
+> 切换到public目录后,启动命令:php -S localhost:8888 router.php
+> 上面的目录结构和名称是可以改变的,这取决于你的入口文件和配置参数。
+
+## 命名规范
+
+ThinkPHP5的命名规范遵循PSR-2规范以及PSR-4自动加载规范。
+
+## 参与开发
+注册并登录 Github 帐号, fork 本项目并进行改动。
+
+更多细节参阅 [CONTRIBUTING.md](CONTRIBUTING.md)
+
+## 版权信息
+
+ThinkPHP遵循Apache2开源协议发布,并提供免费使用。
+
+本项目包含的第三方源码和二进制文件之版权信息另行标注。
+
+版权所有Copyright © 2006-2016 by ThinkPHP (http://thinkphp.cn)
+
+All rights reserved。
+
+ThinkPHP® 商标和著作权所有者为上海顶想信息科技有限公司。
+
+更多细节参阅 [LICENSE.txt](LICENSE.txt)
diff --git a/thinkphp/base.php b/thinkphp/base.php
new file mode 100644
index 0000000..018da58
--- /dev/null
+++ b/thinkphp/base.php
@@ -0,0 +1,61 @@
+
+// +----------------------------------------------------------------------
+
+defined('THINK_VERSION') || define('THINK_VERSION', '5.0.0 RC4');
+defined('THINK_START_TIME') || define('THINK_START_TIME', microtime(true));
+defined('THINK_START_MEM') || define('THINK_START_MEM', memory_get_usage());
+defined('EXT') || define('EXT', '.php');
+defined('DS') || define('DS', DIRECTORY_SEPARATOR);
+defined('THINK_PATH') or define('THINK_PATH', __DIR__ . DS);
+defined('LIB_PATH') || define('LIB_PATH', THINK_PATH . 'library' . DS);
+defined('CORE_PATH') || define('CORE_PATH', LIB_PATH . 'think' . DS);
+defined('TRAIT_PATH') || define('TRAIT_PATH', LIB_PATH . 'traits' . DS);
+defined('APP_PATH') or define('APP_PATH', dirname($_SERVER['SCRIPT_FILENAME']) . DS);
+defined('ROOT_PATH') or define('ROOT_PATH', dirname(APP_PATH) . DS);
+defined('EXTEND_PATH') or define('EXTEND_PATH', ROOT_PATH . 'extend' . DS);
+defined('VENDOR_PATH') or define('VENDOR_PATH', ROOT_PATH . 'vendor' . DS);
+defined('RUNTIME_PATH') or define('RUNTIME_PATH', ROOT_PATH . 'runtime' . DS);
+defined('LOG_PATH') or define('LOG_PATH', RUNTIME_PATH . 'log' . DS);
+defined('CACHE_PATH') or define('CACHE_PATH', RUNTIME_PATH . 'cache' . DS);
+defined('TEMP_PATH') or define('TEMP_PATH', RUNTIME_PATH . 'temp' . DS);
+defined('CONF_PATH') or define('CONF_PATH', APP_PATH); // 配置文件目录
+defined('CONF_EXT') or define('CONF_EXT', EXT); // 配置文件后缀
+defined('ENV_PREFIX') or define('ENV_PREFIX', 'PHP_'); // 环境变量的配置前缀
+
+// 环境常量
+defined('IS_CLI') || define('IS_CLI', PHP_SAPI == 'cli' ? true : false);
+defined('IS_WIN') || define('IS_WIN', strpos(PHP_OS, 'WIN') !== false);
+
+// 载入Loader类
+require CORE_PATH . 'Loader.php';
+
+// 加载环境变量配置文件
+if (is_file(ROOT_PATH . 'env' . EXT)) {
+ $env = include ROOT_PATH . 'env' . EXT;
+ foreach ($env as $key => $val) {
+ $name = ENV_PREFIX . strtoupper($key);
+ if (is_bool($val)) {
+ $val = $val ? 1 : 0;
+ } elseif (!is_scalar($val)) {
+ continue;
+ }
+ putenv("$name=$val");
+ }
+}
+
+// 注册自动加载
+\think\Loader::register();
+
+// 注册错误和异常处理机制
+\think\Error::register();
+
+// 加载惯例配置文件
+\think\Config::set(include THINK_PATH . 'convention' . EXT);
diff --git a/thinkphp/codecov.yml b/thinkphp/codecov.yml
new file mode 100644
index 0000000..bef9d64
--- /dev/null
+++ b/thinkphp/codecov.yml
@@ -0,0 +1,12 @@
+comment:
+ layout: header, changes, diff
+coverage:
+ ignore:
+ - base.php
+ - helper.php
+ - convention.php
+ - lang/zh-cn.php
+ - start.php
+ - console.php
+ status:
+ patch: false
diff --git a/thinkphp/composer.json b/thinkphp/composer.json
new file mode 100644
index 0000000..444d688
--- /dev/null
+++ b/thinkphp/composer.json
@@ -0,0 +1,31 @@
+{
+ "name": "topthink/framework",
+ "description": "the new thinkphp framework",
+ "type": "think-framework",
+ "keywords": [
+ "framework",
+ "thinkphp",
+ "ORM"
+ ],
+ "homepage": "http://thinkphp.cn/",
+ "license": "Apache-2.0",
+ "authors": [
+ {
+ "name": "liu21st",
+ "email": "liu21st@gmail.com"
+ }
+ ],
+ "require": {
+ "php": ">=5.4.0",
+ "topthink/think-installer": "~1.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "4.8.*",
+ "johnkary/phpunit-speedtrap": "^1.0",
+ "mikey179/vfsStream": "~1.6",
+ "phploc/phploc": "2.*",
+ "sebastian/phpcpd": "2.*",
+ "squizlabs/php_codesniffer": "2.*",
+ "phpdocumentor/reflection-docblock": "^2.0"
+ }
+}
diff --git a/thinkphp/console.php b/thinkphp/console.php
new file mode 100644
index 0000000..5947d3f
--- /dev/null
+++ b/thinkphp/console.php
@@ -0,0 +1,20 @@
+
+// +----------------------------------------------------------------------
+
+namespace think;
+
+// ThinkPHP 引导文件
+// 加载基础文件
+require __DIR__ . '/base.php';
+
+// 执行应用
+App::initCommon();
+Console::init();
\ No newline at end of file
diff --git a/thinkphp/convention.php b/thinkphp/convention.php
new file mode 100644
index 0000000..6a841a3
--- /dev/null
+++ b/thinkphp/convention.php
@@ -0,0 +1,264 @@
+ 'app',
+ // 应用调试模式
+ 'app_debug' => true,
+ // 应用Trace
+ 'app_trace' => false,
+ // 应用模式状态
+ 'app_status' => '',
+ // 是否支持多模块
+ 'app_multi_module' => true,
+ // 入口自动绑定模块
+ 'auto_bind_module' => false,
+ // 注册的根命名空间
+ 'root_namespace' => [],
+ // 扩展配置文件
+ 'extra_config_list' => ['database', 'validate'],
+ // 扩展函数文件
+ 'extra_file_list' => [THINK_PATH . 'helper' . EXT],
+ // 默认输出类型
+ 'default_return_type' => 'html',
+ // 默认AJAX 数据返回格式,可选json xml ...
+ 'default_ajax_return' => 'json',
+ // 默认JSONP格式返回的处理方法
+ 'default_jsonp_handler' => 'jsonpReturn',
+ // 默认JSONP处理方法
+ 'var_jsonp_handler' => 'callback',
+ // 默认时区
+ 'default_timezone' => 'PRC',
+ // 是否开启多语言
+ 'lang_switch_on' => false,
+ // 默认全局过滤方法 用逗号分隔多个
+ 'default_filter' => '',
+ // 默认语言
+ 'default_lang' => 'zh-cn',
+ // 应用类库后缀
+ 'class_suffix' => false,
+ // 控制器类后缀
+ 'controller_suffix' => false,
+
+ // +----------------------------------------------------------------------
+ // | 模块设置
+ // +----------------------------------------------------------------------
+
+ // 默认模块名
+ 'default_module' => 'index',
+ // 禁止访问模块
+ 'deny_module_list' => ['common'],
+ // 默认控制器名
+ 'default_controller' => 'Index',
+ // 默认操作名
+ 'default_action' => 'index',
+ // 默认验证器
+ 'default_validate' => '',
+ // 默认的空控制器名
+ 'empty_controller' => 'Error',
+ // 操作方法后缀
+ 'action_suffix' => '',
+ // 自动搜索控制器
+ 'controller_auto_search' => false,
+
+ // +----------------------------------------------------------------------
+ // | URL设置
+ // +----------------------------------------------------------------------
+
+ // PATHINFO变量名 用于兼容模式
+ 'var_pathinfo' => 's',
+ // 兼容PATH_INFO获取
+ 'pathinfo_fetch' => ['ORIG_PATH_INFO', 'REDIRECT_PATH_INFO', 'REDIRECT_URL'],
+ // pathinfo分隔符
+ 'pathinfo_depr' => '/',
+ // URL伪静态后缀
+ 'url_html_suffix' => 'html',
+ // URL普通方式参数 用于自动生成
+ 'url_common_param' => false,
+ // URL参数方式 0 按名称成对解析 1 按顺序解析
+ 'url_param_type' => 0,
+ // 是否开启路由
+ 'url_route_on' => true,
+ // 路由配置文件(支持配置多个)
+ 'route_config_file' => ['route'],
+ // 是否强制使用路由
+ 'url_route_must' => false,
+ // 域名部署
+ 'url_domain_deploy' => false,
+ // 域名根,如.thinkphp.cn
+ 'url_domain_root' => '',
+ // 是否自动转换URL中的控制器和操作名
+ 'url_convert' => true,
+ // 默认的访问控制器层
+ 'url_controller_layer' => 'controller',
+ // 表单请求类型伪装变量
+ 'var_method' => '_method',
+
+ // +----------------------------------------------------------------------
+ // | 模板设置
+ // +----------------------------------------------------------------------
+
+ 'template' => [
+ // 模板引擎类型 支持 php think 支持扩展
+ 'type' => 'Think',
+ // 模板路径
+ 'view_path' => '',
+ // 模板后缀
+ 'view_suffix' => 'html',
+ // 模板文件名分隔符
+ 'view_depr' => DS,
+ // 模板引擎普通标签开始标记
+ 'tpl_begin' => '{',
+ // 模板引擎普通标签结束标记
+ 'tpl_end' => '}',
+ // 标签库标签开始标记
+ 'taglib_begin' => '{',
+ // 标签库标签结束标记
+ 'taglib_end' => '}',
+ ],
+
+ // 视图输出字符串内容替换
+ 'view_replace_str' => [],
+ // 默认跳转页面对应的模板文件
+ 'dispatch_success_tmpl' => THINK_PATH . 'tpl' . DS . 'dispatch_jump.tpl',
+ 'dispatch_error_tmpl' => THINK_PATH . 'tpl' . DS . 'dispatch_jump.tpl',
+
+ // +----------------------------------------------------------------------
+ // | 异常及错误设置
+ // +----------------------------------------------------------------------
+
+ // 异常页面的模板文件
+ 'exception_tmpl' => THINK_PATH . 'tpl' . DS . 'think_exception.tpl',
+
+ // 错误显示信息,非调试模式有效
+ 'error_message' => '页面错误!请稍后再试~',
+ // 显示错误信息
+ 'show_error_msg' => false,
+ // 异常处理handle类 留空使用 \think\exception\Handle
+ 'exception_handle' => '',
+
+ // +----------------------------------------------------------------------
+ // | 日志设置
+ // +----------------------------------------------------------------------
+
+ 'log' => [
+ // 日志记录方式,内置 file socket 支持扩展
+ 'type' => 'File',
+ // 日志保存目录
+ 'path' => LOG_PATH,
+ // 日志记录级别
+ 'level' => [],
+ ],
+
+ // +----------------------------------------------------------------------
+ // | Trace设置 开启 app_trace 后 有效
+ // +----------------------------------------------------------------------
+ 'trace' => [
+ // 内置Html Console 支持扩展
+ 'type' => 'Html',
+ ],
+
+ // +----------------------------------------------------------------------
+ // | 缓存设置
+ // +----------------------------------------------------------------------
+
+ 'cache' => [
+ // 驱动方式
+ 'type' => 'File',
+ // 缓存保存目录
+ 'path' => CACHE_PATH,
+ // 缓存前缀
+ 'prefix' => '',
+ // 缓存有效期 0表示永久缓存
+ 'expire' => 0,
+ ],
+
+ // +----------------------------------------------------------------------
+ // | 会话设置
+ // +----------------------------------------------------------------------
+
+ 'session' => [
+ 'id' => '',
+ // SESSION_ID的提交变量,解决flash上传跨域
+ 'var_session_id' => '',
+ // SESSION 前缀
+ 'prefix' => 'think',
+ // 驱动方式 支持redis memcache memcached
+ 'type' => '',
+ // 是否自动开启 SESSION
+ 'auto_start' => true,
+ ],
+
+ // +----------------------------------------------------------------------
+ // | Cookie设置
+ // +----------------------------------------------------------------------
+ 'cookie' => [
+ // cookie 名称前缀
+ 'prefix' => '',
+ // cookie 保存时间
+ 'expire' => 0,
+ // cookie 保存路径
+ 'path' => '/',
+ // cookie 有效域名
+ 'domain' => '',
+ // cookie 启用安全传输
+ 'secure' => false,
+ // httponly设置
+ 'httponly' => '',
+ // 是否使用 setcookie
+ 'setcookie' => true,
+ ],
+
+ // +----------------------------------------------------------------------
+ // | 数据库设置
+ // +----------------------------------------------------------------------
+
+ 'database' => [
+ // 数据库类型
+ 'type' => 'mysql',
+ // 数据库连接DSN配置
+ 'dsn' => '',
+ // 服务器地址
+ 'hostname' => 'localhost',
+ // 数据库名
+ 'database' => '',
+ // 数据库用户名
+ 'username' => 'root',
+ // 数据库密码
+ 'password' => '',
+ // 数据库连接端口
+ 'hostport' => '',
+ // 数据库连接参数
+ 'params' => [],
+ // 数据库编码默认采用utf8
+ 'charset' => 'utf8',
+ // 数据库表前缀
+ 'prefix' => '',
+ // 数据库调试模式
+ 'debug' => false,
+ // 数据库部署方式:0 集中式(单一服务器),1 分布式(主从服务器)
+ 'deploy' => 0,
+ // 数据库读写是否分离 主从式有效
+ 'rw_separate' => false,
+ // 读写分离后 主服务器数量
+ 'master_num' => 1,
+ // 指定从服务器序号
+ 'slave_no' => '',
+ // 是否严格检查字段是否存在
+ 'fields_strict' => true,
+ // 自动写入时间戳字段
+ 'auto_timestamp' => false,
+ ],
+
+ //分页配置
+ 'paginate' => [
+ 'type' => 'bootstrap',
+ 'var_page' => 'page',
+ 'list_rows' => 15,
+ ],
+
+];
diff --git a/thinkphp/helper.php b/thinkphp/helper.php
new file mode 100644
index 0000000..1b8def1
--- /dev/null
+++ b/thinkphp/helper.php
@@ -0,0 +1,538 @@
+
+// +----------------------------------------------------------------------
+
+//------------------------
+// ThinkPHP 助手函数
+//-------------------------
+
+use think\Cache;
+use think\Config;
+use think\Cookie;
+use think\Db;
+use think\Debug;
+use think\Lang;
+use think\Loader;
+use think\Log;
+use think\Request;
+use think\Response;
+use think\Session;
+use think\Url;
+use think\View;
+
+if (!function_exists('load_trait')) {
+ /**
+ * 快速导入Traits PHP5.5以上无需调用
+ * @param string $class trait库
+ * @param string $ext 类库后缀
+ * @return boolean
+ */
+ function load_trait($class, $ext = EXT)
+ {
+ return Loader::import($class, TRAIT_PATH, $ext);
+ }
+}
+
+if (!function_exists('exception')) {
+ /**
+ * 抛出异常处理
+ *
+ * @param string $msg 异常消息
+ * @param integer $code 异常代码 默认为0
+ * @param string $exception 异常类
+ *
+ * @throws Exception
+ */
+ function exception($msg, $code = 0, $exception = '')
+ {
+ $e = $exception ?: '\think\Exception';
+ throw new $e($msg, $code);
+ }
+}
+
+if (!function_exists('debug')) {
+ /**
+ * 记录时间(微秒)和内存使用情况
+ * @param string $start 开始标签
+ * @param string $end 结束标签
+ * @param integer|string $dec 小数位 如果是m 表示统计内存占用
+ * @return mixed
+ */
+ function debug($start, $end = '', $dec = 6)
+ {
+ if ('' == $end) {
+ Debug::remark($start);
+ } else {
+ return 'm' == $dec ? Debug::getRangeMem($start, $end) : Debug::getRangeTime($start, $end, $dec);
+ }
+ }
+}
+
+if (!function_exists('lang')) {
+ /**
+ * 获取语言变量值
+ * @param string $name 语言变量名
+ * @param array $vars 动态变量值
+ * @param string $lang 语言
+ * @return mixed
+ */
+ function lang($name, $vars = [], $lang = '')
+ {
+ return Lang::get($name, $vars, $lang);
+ }
+}
+
+if (!function_exists('config')) {
+ /**
+ * 获取和设置配置参数
+ * @param string|array $name 参数名
+ * @param mixed $value 参数值
+ * @param string $range 作用域
+ * @return mixed
+ */
+ function config($name = '', $value = null, $range = '')
+ {
+ if (is_null($value) && is_string($name)) {
+ return Config::get($name, $range);
+ } else {
+ return Config::set($name, $value, $range);
+ }
+ }
+}
+
+if (!function_exists('input')) {
+ /**
+ * 获取输入数据 支持默认值和过滤
+ * @param string $key 获取的变量名
+ * @param mixed $default 默认值
+ * @param string $filter 过滤方法
+ * @return mixed
+ */
+ function input($key = '', $default = null, $filter = null)
+ {
+ if (0 === strpos($key, '?')) {
+ $key = substr($key, 1);
+ $has = true;
+ }
+ if ($pos = strpos($key, '.')) {
+ // 指定参数来源
+ $method = substr($key, 0, $pos);
+ if (in_array($method, ['get', 'post', 'put', 'patch', 'delete', 'param', 'request', 'session', 'cookie', 'server', 'env', 'path', 'file'])) {
+ $key = substr($key, $pos + 1);
+ } else {
+ $method = 'param';
+ }
+ } else {
+ // 默认为自动判断
+ $method = 'param';
+ }
+ if (isset($has)) {
+ return request()->has($key, $method, $default);
+ } else {
+ return request()->$method($key, $default, $filter);
+ }
+ }
+}
+
+if (!function_exists('widget')) {
+ /**
+ * 渲染输出Widget
+ * @param string $name Widget名称
+ * @param array $data 传人的参数
+ * @return mixed
+ */
+ function widget($name, $data = [])
+ {
+ return Loader::action($name, $data, 'widget');
+ }
+}
+
+if (!function_exists('model')) {
+ /**
+ * 实例化Model
+ * @param string $name Model名称
+ * @param string $layer 业务层名称
+ * @param bool $appendSuffix 是否添加类名后缀
+ * @return \think\Model
+ */
+ function model($name = '', $layer = 'model', $appendSuffix = false)
+ {
+ return Loader::model($name, $layer, $appendSuffix);
+ }
+}
+
+if (!function_exists('validate')) {
+ /**
+ * 实例化验证器
+ * @param string $name 验证器名称
+ * @param string $layer 业务层名称
+ * @param bool $appendSuffix 是否添加类名后缀
+ * @return \think\Validate
+ */
+ function validate($name = '', $layer = 'validate', $appendSuffix = false)
+ {
+ return Loader::validate($name, $layer, $appendSuffix);
+ }
+}
+
+if (!function_exists('db')) {
+ /**
+ * 实例化数据库类
+ * @param string $name 操作的数据表名称(不含前缀)
+ * @param array|string $config 数据库配置参数
+ * @param bool $force 是否强制重新连接
+ * @return \think\db\Query
+ */
+ function db($name = '', $config = [], $force = true)
+ {
+ return Db::connect($config, $force)->name($name);
+ }
+}
+
+if (!function_exists('controller')) {
+ /**
+ * 实例化控制器 格式:[模块/]控制器
+ * @param string $name 资源地址
+ * @param string $layer 控制层名称
+ * @param bool $appendSuffix 是否添加类名后缀
+ * @return \think\Controller
+ */
+ function controller($name, $layer = 'controller', $appendSuffix = false)
+ {
+ return Loader::controller($name, $layer, $appendSuffix);
+ }
+}
+
+if (!function_exists('action')) {
+ /**
+ * 调用模块的操作方法 参数格式 [模块/控制器/]操作
+ * @param string $url 调用地址
+ * @param string|array $vars 调用参数 支持字符串和数组
+ * @param string $layer 要调用的控制层名称
+ * @param bool $appendSuffix 是否添加类名后缀
+ * @return mixed
+ */
+ function action($url, $vars = [], $layer = 'controller', $appendSuffix = false)
+ {
+ return Loader::action($url, $vars, $layer, $appendSuffix);
+ }
+}
+
+if (!function_exists('import')) {
+ /**
+ * 导入所需的类库 同java的Import 本函数有缓存功能
+ * @param string $class 类库命名空间字符串
+ * @param string $baseUrl 起始路径
+ * @param string $ext 导入的文件扩展名
+ * @return boolean
+ */
+ function import($class, $baseUrl = '', $ext = EXT)
+ {
+ return Loader::import($class, $baseUrl, $ext);
+ }
+}
+
+if (!function_exists('vendor')) {
+ /**
+ * 快速导入第三方框架类库 所有第三方框架的类库文件统一放到 系统的Vendor目录下面
+ * @param string $class 类库
+ * @param string $ext 类库后缀
+ * @return boolean
+ */
+ function vendor($class, $ext = EXT)
+ {
+ return Loader::import($class, VENDOR_PATH, $ext);
+ }
+}
+
+if (!function_exists('dump')) {
+ /**
+ * 浏览器友好的变量输出
+ * @param mixed $var 变量
+ * @param boolean $echo 是否输出 默认为true 如果为false 则返回输出字符串
+ * @param string $label 标签 默认为空
+ * @return void|string
+ */
+ function dump($var, $echo = true, $label = null)
+ {
+ return Debug::dump($var, $echo, $label);
+ }
+}
+
+if (!function_exists('url')) {
+ /**
+ * Url生成
+ * @param string $url 路由地址
+ * @param string|array $value 变量
+ * @param bool|string $suffix 前缀
+ * @param bool|string $domain 域名
+ * @return string
+ */
+ function url($url = '', $vars = '', $suffix = true, $domain = false)
+ {
+ return Url::build($url, $vars, $suffix, $domain);
+ }
+}
+
+if (!function_exists('session')) {
+ /**
+ * Session管理
+ * @param string|array $name session名称,如果为数组表示进行session设置
+ * @param mixed $value session值
+ * @param string $prefix 前缀
+ * @return mixed
+ */
+ function session($name, $value = '', $prefix = null)
+ {
+ if (is_array($name)) {
+ // 初始化
+ Session::init($name);
+ } elseif (is_null($name)) {
+ // 清除
+ Session::clear($value);
+ } elseif ('' === $value) {
+ // 判断或获取
+ return 0 === strpos($name, '?') ? Session::has(substr($name, 1), $prefix) : Session::get($name, $prefix);
+ } elseif (is_null($value)) {
+ // 删除
+ return Session::delete($name, $prefix);
+ } else {
+ // 设置
+ return Session::set($name, $value, $prefix);
+ }
+ }
+}
+
+if (!function_exists('cookie')) {
+ /**
+ * Cookie管理
+ * @param string|array $name cookie名称,如果为数组表示进行cookie设置
+ * @param mixed $value cookie值
+ * @param mixed $option 参数
+ * @return mixed
+ */
+ function cookie($name, $value = '', $option = null)
+ {
+ if (is_array($name)) {
+ // 初始化
+ Cookie::init($name);
+ } elseif (is_null($name)) {
+ // 清除
+ Cookie::clear($value);
+ } elseif ('' === $value) {
+ // 获取
+ return 0 === strpos($name, '?') ? Cookie::has(substr($name, 1), $option) : Cookie::get($name);
+ } elseif (is_null($value)) {
+ // 删除
+ return Cookie::delete($name);
+ } else {
+ // 设置
+ return Cookie::set($name, $value, $option);
+ }
+ }
+}
+
+if (!function_exists('cache')) {
+ /**
+ * 缓存管理
+ * @param mixed $name 缓存名称,如果为数组表示进行缓存设置
+ * @param mixed $value 缓存值
+ * @param mixed $options 缓存参数
+ * @return mixed
+ */
+ function cache($name, $value = '', $options = null)
+ {
+ if (is_array($options)) {
+ // 缓存操作的同时初始化
+ Cache::connect($options);
+ } elseif (is_array($name)) {
+ // 缓存初始化
+ return Cache::connect($name);
+ }
+ if ('' === $value) {
+ // 获取缓存
+ return Cache::get($name);
+ } elseif (is_null($value)) {
+ // 删除缓存
+ return Cache::rm($name);
+ } else {
+ // 缓存数据
+ if (is_array($options)) {
+ $expire = isset($options['expire']) ? $options['expire'] : null; //修复查询缓存无法设置过期时间
+ } else {
+ $expire = is_numeric($options) ? $options : null; //默认快捷缓存设置过期时间
+ }
+ return Cache::set($name, $value, $expire);
+ }
+ }
+}
+
+if (!function_exists('trace')) {
+ /**
+ * 记录日志信息
+ * @param mixed $log log信息 支持字符串和数组
+ * @param string $level 日志级别
+ * @return void|array
+ */
+ function trace($log = '[think]', $level = 'log')
+ {
+ if ('[think]' === $log) {
+ return Log::getLog();
+ } else {
+ Log::record($log, $level);
+ }
+ }
+}
+
+if (!function_exists('request')) {
+ /**
+ * 获取当前Request对象实例
+ * @return Request
+ */
+ function request()
+ {
+ return Request::instance();
+ }
+}
+
+if (!function_exists('response')) {
+ /**
+ * 创建普通 Response 对象实例
+ * @param mixed $data 输出数据
+ * @param int|string $code 状态码
+ * @param array $header 头信息
+ * @param string $type
+ * @return Response
+ */
+ function response($data = [], $code = 200, $header = [], $type = 'html')
+ {
+ return Response::create($data, $type, $code, $header);
+ }
+}
+
+if (!function_exists('view')) {
+ /**
+ * 渲染模板输出
+ * @param string $template 模板文件
+ * @param array $vars 模板变量
+ * @param array $replace 模板替换
+ * @param integer $code 状态码
+ * @return \think\response\View
+ */
+ function view($template = '', $vars = [], $replace = [], $code = 200)
+ {
+ return Response::create($template, 'view', $code)->replace($replace)->assign($vars);
+ }
+}
+
+if (!function_exists('json')) {
+ /**
+ * 获取\think\response\Json对象实例
+ * @param mixed $data 返回的数据
+ * @param integer $code 状态码
+ * @param array $header 头部
+ * @param array $options 参数
+ * @return \think\response\Json
+ */
+ function json($data = [], $code = 200, $header = [], $options = [])
+ {
+ return Response::create($data, 'json', $code, $header, $options);
+ }
+}
+
+if (!function_exists('jsonp')) {
+ /**
+ * 获取\think\response\Jsonp对象实例
+ * @param mixed $data 返回的数据
+ * @param integer $code 状态码
+ * @param array $header 头部
+ * @param array $options 参数
+ * @return \think\response\Jsonp
+ */
+ function jsonp($data = [], $code = 200, $header = [], $options = [])
+ {
+ return Response::create($data, 'jsonp', $code, $header, $options);
+ }
+}
+
+if (!function_exists('xml')) {
+ /**
+ * 获取\think\response\Xml对象实例
+ * @param mixed $data 返回的数据
+ * @param integer $code 状态码
+ * @param array $header 头部
+ * @param array $options 参数
+ * @return \think\response\Xml
+ */
+ function xml($data = [], $code = 200, $header = [], $options = [])
+ {
+ return Response::create($data, 'xml', $code, $header, $options);
+ }
+}
+
+if (!function_exists('redirect')) {
+ /**
+ * 获取\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);
+ }
+}
+
+if (!function_exists('abort')) {
+ /**
+ * 抛出HTTP异常
+ * @param integer|Response $code 状态码 或者 Response对象实例
+ * @param string $message 错误信息
+ * @param array $header 参数
+ */
+ function abort($code, $message = null, $header = [])
+ {
+ if ($code instanceof Response) {
+ throw new \think\exception\HttpResponseException($code);
+ } else {
+ throw new \think\exception\HttpException($code, $message, null, $header);
+ }
+ }
+}
+
+if (!function_exists('halt')) {
+ /**
+ * 调试变量并且中断输出
+ * @param mixed $var 调试变量或者信息
+ */
+ function halt($var)
+ {
+ dump($var);
+ throw new \think\exception\HttpResponseException(new Response);
+ }
+}
+
+if (!function_exists('token')) {
+ /**
+ * 生成表单令牌
+ * @param string $name 令牌名称
+ * @param mixed $type 令牌生成方法
+ */
+ function token($name = '__token__', $type = 'md5')
+ {
+ $token = Request::instance()->token($name, $type);
+ return '';
+ }
+}
diff --git a/thinkphp/lang/zh-cn.php b/thinkphp/lang/zh-cn.php
new file mode 100644
index 0000000..778aef4
--- /dev/null
+++ b/thinkphp/lang/zh-cn.php
@@ -0,0 +1,63 @@
+
+// +----------------------------------------------------------------------
+
+// 核心中文语言包
+return [
+ // 系统错误提示
+ 'Undefined variable' => '未定义变量',
+ 'Undefined index' => '未定义索引',
+ 'Parse error' => '语法解析错误',
+ 'Type error' => '类型错误',
+ 'Fatal error' => '致命错误',
+ 'syntax error' => '语法错误',
+
+ // 框架核心错误提示
+ 'dispatch type not support' => '不支持的调度类型',
+ 'method param miss' => '方法参数错误',
+ 'method not exists' => '方法不存在',
+ 'module not exists' => '模块不存在',
+ 'controller not exists' => '控制器不存在',
+ 'class not exists' => '类不存在',
+ 'property 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 写入错误',
+ 'route name not exists' => '路由标识不存在(或参数不够)',
+];
diff --git a/thinkphp/library/think/App.php b/thinkphp/library/think/App.php
new file mode 100644
index 0000000..a9236f6
--- /dev/null
+++ b/thinkphp/library/think/App.php
@@ -0,0 +1,537 @@
+
+// +----------------------------------------------------------------------
+
+namespace think;
+
+use think\Config;
+use think\Exception;
+use think\exception\HttpException;
+use think\exception\HttpResponseException;
+use think\Hook;
+use think\Lang;
+use think\Loader;
+use think\Log;
+use think\Request;
+use think\Response;
+use think\Route;
+
+/**
+ * App 应用管理
+ * @author liu21st
+ */
+class App
+{
+ /**
+ * @var bool 是否初始化过
+ */
+ protected static $init = false;
+
+ /**
+ * @var string 当前模块路径
+ */
+ public static $modulePath;
+
+ /**
+ * @var bool 应用调试模式
+ */
+ public static $debug = true;
+
+ /**
+ * @var string 应用类库命名空间
+ */
+ public static $namespace = 'app';
+
+ /**
+ * @var bool 应用类库后缀
+ */
+ public static $suffix = false;
+
+ /**
+ * @var bool 应用路由检测
+ */
+ protected static $routeCheck;
+
+ /**
+ * @var bool 严格路由检测
+ */
+ protected static $routeMust;
+
+ protected static $dispatch;
+ protected static $file = [];
+
+ /**
+ * 执行应用程序
+ * @access public
+ * @param Request $request Request对象
+ * @return Response
+ * @throws Exception
+ */
+ public static function run(Request $request = null)
+ {
+ is_null($request) && $request = Request::instance();
+
+ $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']);
+ 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);
+
+ // 记录路由和请求信息
+ 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'], $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);
+
+ return $response;
+ }
+
+ /**
+ * 设置当前请求的调度信息
+ * @access public
+ * @param array|string $dispatch 调度信息
+ * @param string $type 调度类型
+ * @param array $params 参数
+ * @return void
+ */
+ public static function dispatch($dispatch, $type = 'module', $params = [])
+ {
+ self::$dispatch = ['type' => $type, $type => $dispatch, 'params' => $params];
+ }
+
+ /**
+ * 执行函数或者闭包方法 支持参数调用
+ * @access public
+ * @param string|array|\Closure $function 函数或者闭包
+ * @param array $vars 变量
+ * @return mixed
+ */
+ public static function invokeFunction($function, $vars = [])
+ {
+ $reflect = new \ReflectionFunction($function);
+ $args = self::bindParams($reflect, $vars);
+ // 记录执行信息
+ self::$debug && Log::record('[ RUN ] ' . $reflect->__toString(), 'info');
+ return $reflect->invokeArgs($args);
+ }
+
+ /**
+ * 调用反射执行类的方法 支持参数绑定
+ * @access public
+ * @param string|array $method 方法
+ * @param array $vars 变量
+ * @return mixed
+ */
+ public static function invokeMethod($method, $vars = [])
+ {
+ if (empty($vars)) {
+ // 自动获取请求变量
+ $vars = Request::instance()->param();
+ }
+ if (is_array($method)) {
+ $class = is_object($method[0]) ? $method[0] : new $method[0];
+ $reflect = new \ReflectionMethod($class, $method[1]);
+ } else {
+ // 静态方法
+ $reflect = new \ReflectionMethod($method);
+ }
+ $args = self::bindParams($reflect, $vars);
+ // 记录执行信息
+ self::$debug && Log::record('[ RUN ] ' . $reflect->__toString(), 'info');
+ return $reflect->invokeArgs(isset($class) ? $class : null, $args);
+ }
+
+ /**
+ * 绑定参数
+ * @access public
+ * @param \ReflectionMethod|\ReflectionFunction $reflect 反射类
+ * @param array $vars 变量
+ * @return array
+ */
+ private static function bindParams($reflect, $vars)
+ {
+ $args = [];
+ // 判断数组类型 数字数组时按顺序绑定参数
+ $type = key($vars) === 0 ? 1 : 0;
+ if ($reflect->getNumberOfParameters() > 0) {
+ $params = $reflect->getParameters();
+ foreach ($params as $param) {
+ $name = $param->getName();
+ $class = $param->getClass();
+ if ($class) {
+ $className = $class->getName();
+ $args[] = method_exists($className, 'instance') ? $className::instance() : new $className();
+ } elseif (1 == $type && !empty($vars)) {
+ $args[] = array_shift($vars);
+ } elseif (0 == $type && isset($vars[$name])) {
+ $args[] = $vars[$name];
+ } elseif ($param->isDefaultValueAvailable()) {
+ $args[] = $param->getDefaultValue();
+ } else {
+ throw new \InvalidArgumentException('method param miss:' . $name);
+ }
+ }
+ // 全局过滤
+ array_walk_recursive($args, [Request::instance(), 'filterExp']);
+ }
+ return $args;
+ }
+
+ /**
+ * 执行模块
+ * @access public
+ * @param array $result 模块/控制器/操作
+ * @param array $config 配置参数
+ * @param bool $convert 是否自动转换控制器和操作名
+ * @return mixed
+ */
+ public static function module($result, $config, $convert = null)
+ {
+ if (is_string($result)) {
+ $result = explode('/', $result);
+ }
+ $request = Request::instance();
+ if ($config['app_multi_module']) {
+ // 多模块部署
+ $module = strip_tags(strtolower($result[0] ?: $config['default_module']));
+ $bind = Route::getBind('module');
+ $available = false;
+ if ($bind) {
+ // 绑定模块
+ list($bindModule) = explode('/', $bind);
+ if (empty($result[0])) {
+ $module = $bindModule;
+ $available = true;
+ } elseif ($module == $bindModule) {
+ $available = true;
+ }
+ } elseif (!in_array($module, $config['deny_module_list']) && is_dir(APP_PATH . $module)) {
+ $available = true;
+ }
+
+ // 模块初始化
+ if ($module && $available) {
+ // 初始化模块
+ $request->module($module);
+ $config = self::init($module);
+ } else {
+ throw new HttpException(404, 'module not exists:' . $module);
+ }
+ } else {
+ // 单一模块部署
+ $module = '';
+ $request->module($module);
+ }
+ // 当前模块路径
+ App::$modulePath = APP_PATH . ($module ? $module . DS : '');
+
+ // 是否自动转换控制器和操作名
+ $convert = is_bool($convert) ? $convert : $config['url_convert'];
+ // 获取控制器名
+ $controller = strip_tags($result[1] ?: $config['default_controller']);
+ $controller = $convert ? strtolower($controller) : $controller;
+
+ // 获取操作名
+ $actionName = strip_tags($result[2] ?: $config['default_action']);
+ $actionName = $convert ? strtolower($actionName) : $actionName;
+
+ // 设置当前请求的控制器、操作
+ $request->controller($controller)->action($actionName);
+
+ // 监听module_init
+ Hook::listen('module_init', $request);
+
+ 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:' . Loader::parseName($controller, 1));
+ }
+ // 获取当前操作名
+ $action = $actionName . $config['action_suffix'];
+ if (!preg_match('/^[A-Za-z](\w)*$/', $action)) {
+ // 非法操作
+ throw new \ReflectionException('illegal action name:' . $actionName);
+ }
+
+ // 执行操作方法
+ $call = [$instance, $action];
+ Hook::listen('action_begin', $call);
+
+ $data = self::invokeMethod($call);
+ } catch (\ReflectionException $e) {
+ // 操作不存在
+ if (method_exists($instance, '_empty')) {
+ $reflect = new \ReflectionMethod($instance, '_empty');
+ $data = $reflect->invokeArgs($instance, [$action]);
+ self::$debug && Log::record('[ RUN ] ' . $reflect->__toString(), 'info');
+ } else {
+ throw new HttpException(404, 'method not exists:' . (new \ReflectionClass($instance))->getName() . '->' . $action);
+ }
+ }
+ return $data;
+ }
+
+ /**
+ * 初始化应用
+ */
+ public static function initCommon()
+ {
+ if (empty(self::$init)) {
+ // 初始化应用
+ $config = self::init();
+ self::$suffix = $config['class_suffix'];
+
+ // 应用调试模式
+ self::$debug = Config::get('app_debug');
+ if (!self::$debug) {
+ ini_set('display_errors', 'Off');
+ } elseif (!IS_CLI) {
+ //重新申请一块比较大的buffer
+ if (ob_get_level() > 0) {
+ $output = ob_get_clean();
+ }
+ ob_start();
+ if (!empty($output)) {
+ echo $output;
+ }
+ }
+
+ // 注册应用命名空间
+ self::$namespace = $config['app_namespace'];
+ Loader::addNamespace($config['app_namespace'], APP_PATH);
+ if (!empty($config['root_namespace'])) {
+ Loader::addNamespace($config['root_namespace']);
+ }
+
+ // 加载额外文件
+ if (!empty($config['extra_file_list'])) {
+ foreach ($config['extra_file_list'] as $file) {
+ $file = strpos($file, '.') ? $file : APP_PATH . $file . EXT;
+ if (is_file($file) && !isset(self::$file[$file])) {
+ include $file;
+ self::$file[$file] = true;
+ }
+ }
+ }
+
+ // 设置系统时区
+ date_default_timezone_set($config['default_timezone']);
+
+ // 监听app_init
+ Hook::listen('app_init');
+
+ self::$init = $config;
+ }
+ return self::$init;
+ }
+
+ /**
+ * 初始化应用或模块
+ * @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);
+
+ // 读取扩展配置文件
+ 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 ($config['app_status']) {
+ $config = Config::load(CONF_PATH . $module . $config['app_status'] . CONF_EXT);
+ }
+
+ // 加载别名文件
+ 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();
+ }
+
+ /**
+ * URL路由检测(根据PATH_INFO)
+ * @access public
+ * @param \think\Request $request
+ * @param array $config
+ * @return array
+ * @throws \think\Exception
+ */
+ public static function routeCheck($request, array $config)
+ {
+ $path = $request->path();
+ $depr = $config['pathinfo_depr'];
+ $result = false;
+ // 路由检测
+ $check = !is_null(self::$routeCheck) ? self::$routeCheck : $config['url_route_on'];
+ if ($check) {
+ // 开启路由
+ if (is_file(RUNTIME_PATH . 'route.php')) {
+ // 读取路由缓存
+ $rules = include RUNTIME_PATH . 'route.php';
+ if (is_array($rules)) {
+ Route::rules($rules);
+ }
+ } else {
+ $files = $config['route_config_file'];
+ foreach ($files as $file) {
+ if (is_file(CONF_PATH . $file . CONF_EXT)) {
+ // 导入路由配置
+ $rules = include CONF_PATH . $file . CONF_EXT;
+ if (is_array($rules)) {
+ Route::import($rules);
+ }
+ }
+ }
+ }
+
+ // 路由检测(根据路由定义返回不同的URL调度)
+ $result = Route::check($request, $path, $depr, $config['url_domain_deploy']);
+ $must = !is_null(self::$routeMust) ? self::$routeMust : $config['url_route_must'];
+ if ($must && false === $result) {
+ // 路由无效
+ throw new HttpException(404, 'Route Not Found');
+ }
+ }
+ if (false === $result) {
+ // 路由无效 解析模块/控制器/操作/参数... 支持控制器自动搜索
+ $result = Route::parseUrl($path, $depr, $config['controller_auto_search']);
+ }
+ return $result;
+ }
+
+ /**
+ * 设置应用的路由检测机制
+ * @access public
+ * @param bool $route 是否需要检测路由
+ * @param bool $must 是否强制检测路由
+ * @return void
+ */
+ public static function route($route, $must = false)
+ {
+ self::$routeCheck = $route;
+ self::$routeMust = $must;
+ }
+}
diff --git a/thinkphp/library/think/Build.php b/thinkphp/library/think/Build.php
new file mode 100644
index 0000000..dd2bd55
--- /dev/null
+++ b/thinkphp/library/think/Build.php
@@ -0,0 +1,204 @@
+
+// +----------------------------------------------------------------------
+
+namespace think;
+
+class Build
+{
+ /**
+ * 根据传入的build资料创建目录和文件
+ * @access protected
+ * @param array $build build列表
+ * @param string $namespace 应用类库命名空间
+ * @param bool $suffix 类库后缀
+ * @return void
+ */
+ public static function run(array $build = [], $namespace = 'app', $suffix = false)
+ {
+ // 锁定
+ $lockfile = APP_PATH . 'build.lock';
+ if (is_writable($lockfile)) {
+ return;
+ } elseif (!touch($lockfile)) {
+ throw new Exception('应用目录[' . APP_PATH . ']不可写,目录无法自动生成!
请手动生成项目目录~', 10006);
+ }
+ foreach ($build as $module => $list) {
+ if ('__dir__' == $module) {
+ // 创建目录列表
+ self::buildDir($list);
+ } elseif ('__file__' == $module) {
+ // 创建文件列表
+ self::buildFile($list);
+ } else {
+ // 创建模块
+ self::module($module, $list, $namespace, $suffix);
+ }
+ }
+ // 解除锁定
+ unlink($lockfile);
+ }
+
+ /**
+ * 创建目录
+ * @access protected
+ * @param array $list 目录列表
+ * @return void
+ */
+ protected static function buildDir($list)
+ {
+ foreach ($list as $dir) {
+ if (!is_dir(APP_PATH . $dir)) {
+ // 创建目录
+ mkdir(APP_PATH . $dir, 0755, true);
+ }
+ }
+ }
+
+ /**
+ * 创建文件
+ * @access protected
+ * @param array $list 文件列表
+ * @return void
+ */
+ protected static function buildFile($list)
+ {
+ foreach ($list as $file) {
+ if (!is_dir(APP_PATH . dirname($file))) {
+ // 创建目录
+ mkdir(APP_PATH . dirname($file), 0755, true);
+ }
+ if (!is_file(APP_PATH . $file)) {
+ file_put_contents(APP_PATH . $file, 'php' == pathinfo($file, PATHINFO_EXTENSION) ? " ['config.php', 'common.php'],
+ '__dir__' => ['controller', 'model', 'view'],
+ ];
+ }
+ // 创建子目录和文件
+ foreach ($list as $path => $file) {
+ $modulePath = APP_PATH . $module . DS;
+ if ('__dir__' == $path) {
+ // 生成子目录
+ foreach ($file as $dir) {
+ if (!is_dir($modulePath . $dir)) {
+ // 创建目录
+ mkdir($modulePath . $dir, 0755, true);
+ }
+ }
+ } elseif ('__file__' == $path) {
+ // 生成(空白)文件
+ foreach ($file as $name) {
+ if (!is_file($modulePath . $name)) {
+ file_put_contents($modulePath . $name, 'php' == pathinfo($name, PATHINFO_EXTENSION) ? "
+// +----------------------------------------------------------------------
+
+namespace think;
+
+use think\App;
+
+class Cache
+{
+ protected static $instance = [];
+ public static $readTimes = 0;
+ public static $writeTimes = 0;
+
+ /**
+ * 操作句柄
+ * @var object
+ * @access protected
+ */
+ protected static $handler;
+
+ /**
+ * 连接缓存
+ * @access public
+ * @param array $options 配置数组
+ * @param bool|string $name 缓存连接标识 true 强制重新连接
+ * @return \think\cache\Driver
+ */
+ public static function connect(array $options = [], $name = false)
+ {
+ $type = !empty($options['type']) ? $options['type'] : 'File';
+ if (false === $name) {
+ $name = $type;
+ }
+
+ if (true === $name || !isset(self::$instance[$name])) {
+ $class = false !== strpos($type, '\\') ? $type : '\\think\\cache\\driver\\' . ucwords($type);
+
+ // 记录初始化信息
+ App::$debug && Log::record('[ CACHE ] INIT ' . $type . ':' . var_export($options, true), 'info');
+ if (true === $name) {
+ return new $class($options);
+ } else {
+ self::$instance[$name] = new $class($options);
+ }
+ }
+ self::$handler = self::$instance[$name];
+ return self::$handler;
+ }
+
+ /**
+ * 自动初始化缓存
+ * @access public
+ * @param array $options 配置数组
+ * @return void
+ */
+ public static function init(array $options = [])
+ {
+ if (is_null(self::$handler)) {
+ // 自动初始化缓存
+ if (!empty($options)) {
+ self::connect($options);
+ } elseif ('complex' == Config::get('cache.type')) {
+ self::connect(Config::get('cache.default'));
+ } else {
+ self::connect(Config::get('cache'));
+ }
+ }
+ }
+
+ /**
+ * 切换缓存类型 需要配置 cache.type 为 complex
+ * @access public
+ * @param string $name 缓存标识
+ * @return \think\cache\Driver
+ */
+ public static function store($name)
+ {
+ if ('complex' == Config::get('cache.type')) {
+ self::connect(Config::get('cache.' . $name), strtolower($name));
+ }
+ return self::$handler;
+ }
+
+ /**
+ * 判断缓存是否存在
+ * @access public
+ * @param string $name 缓存变量名
+ * @return bool
+ */
+ public static function has($name)
+ {
+ self::init();
+ self::$readTimes++;
+ return self::$handler->has($name);
+ }
+
+ /**
+ * 读取缓存
+ * @access public
+ * @param string $name 缓存标识
+ * @param mixed $default 默认值
+ * @return mixed
+ */
+ public static function get($name, $default = false)
+ {
+ self::init();
+ self::$readTimes++;
+ return self::$handler->get($name, $default);
+ }
+
+ /**
+ * 写入缓存
+ * @access public
+ * @param string $name 缓存标识
+ * @param mixed $value 存储数据
+ * @param int|null $expire 有效时间 0为永久
+ * @return boolean
+ */
+ public static function set($name, $value, $expire = null)
+ {
+ self::init();
+ self::$writeTimes++;
+ return self::$handler->set($name, $value, $expire);
+ }
+
+ /**
+ * 自增缓存(针对数值缓存)
+ * @access public
+ * @param string $name 缓存变量名
+ * @param int $step 步长
+ * @return false|int
+ */
+ public static function inc($name, $step = 1)
+ {
+ self::init();
+ self::$writeTimes++;
+ return self::$handler->inc($name, $step);
+ }
+
+ /**
+ * 自减缓存(针对数值缓存)
+ * @access public
+ * @param string $name 缓存变量名
+ * @param int $step 步长
+ * @return false|int
+ */
+ public static function dec($name, $step = 1)
+ {
+ self::init();
+ self::$writeTimes++;
+ return self::$handler->dec($name, $step);
+ }
+
+ /**
+ * 删除缓存
+ * @access public
+ * @param string $name 缓存标识
+ * @return boolean
+ */
+ public static function rm($name)
+ {
+ self::init();
+ self::$writeTimes++;
+ return self::$handler->rm($name);
+ }
+
+ /**
+ * 清除缓存
+ * @access public
+ * @param string $tag 标签名
+ * @return boolean
+ */
+ public static function clear($tag = null)
+ {
+ self::init();
+ self::$writeTimes++;
+ return self::$handler->clear($tag);
+ }
+
+ /**
+ * 缓存标签
+ * @access public
+ * @param string $name 标签名
+ * @param string|array $keys 缓存标识
+ * @param bool $overlay 是否覆盖
+ * @return \think\cache\Driver
+ */
+ public static function tag($name, $keys = null, $overlay = false)
+ {
+ self::init();
+ return self::$handler->tag($name, $keys, $overlay);
+ }
+
+}
diff --git a/thinkphp/library/think/Collection.php b/thinkphp/library/think/Collection.php
new file mode 100644
index 0000000..8315268
--- /dev/null
+++ b/thinkphp/library/think/Collection.php
@@ -0,0 +1,373 @@
+
+// +----------------------------------------------------------------------
+
+namespace think;
+
+use ArrayAccess;
+use ArrayIterator;
+use Countable;
+use IteratorAggregate;
+use JsonSerializable;
+
+class Collection implements ArrayAccess, Countable, IteratorAggregate, JsonSerializable
+{
+ protected $items = [];
+
+ public function __construct($items = [])
+ {
+ $this->items = $this->convertToArray($items);
+ }
+
+ public static function make($items = [])
+ {
+ return new static($items);
+ }
+
+ /**
+ * 是否为空
+ * @return bool
+ */
+ public function isEmpty()
+ {
+ return empty($this->items);
+ }
+
+ public function toArray()
+ {
+ return array_map(function ($value) {
+ return ($value instanceof Model || $value instanceof self) ? $value->toArray() : $value;
+ }, $this->items);
+ }
+
+ public function all()
+ {
+ return $this->items;
+ }
+
+ /**
+ * 合并数组
+ *
+ * @param mixed $items
+ * @return static
+ */
+ public function merge($items)
+ {
+ return new static(array_merge($this->items, $this->convertToArray($items)));
+ }
+
+ /**
+ * 比较数组,返回差集
+ *
+ * @param mixed $items
+ * @return static
+ */
+ public function diff($items)
+ {
+ return new static(array_diff($this->items, $this->convertToArray($items)));
+ }
+
+ /**
+ * 交换数组中的键和值
+ *
+ * @return static
+ */
+ public function flip()
+ {
+ return new static(array_flip($this->items));
+ }
+
+ /**
+ * 比较数组,返回交集
+ *
+ * @param mixed $items
+ * @return static
+ */
+ public function intersect($items)
+ {
+ return new static(array_intersect($this->items, $this->convertToArray($items)));
+ }
+
+ /**
+ * 返回数组中所有的键名
+ *
+ * @return static
+ */
+ public function keys()
+ {
+ return new static(array_keys($this->items));
+ }
+
+ /**
+ * 删除数组的最后一个元素(出栈)
+ *
+ * @return mixed
+ */
+ public function pop()
+ {
+ return array_pop($this->items);
+ }
+
+ /**
+ * 通过使用用户自定义函数,以字符串返回数组
+ *
+ * @param callable $callback
+ * @param mixed $initial
+ * @return mixed
+ */
+ public function reduce(callable $callback, $initial = null)
+ {
+ return array_reduce($this->items, $callback, $initial);
+ }
+
+ /**
+ * 以相反的顺序返回数组。
+ *
+ * @return static
+ */
+ public function reverse()
+ {
+ return new static(array_reverse($this->items));
+ }
+
+ /**
+ * 删除数组中首个元素,并返回被删除元素的值
+ *
+ * @return mixed
+ */
+ public function shift()
+ {
+ return array_shift($this->items);
+ }
+
+ /**
+ * 把一个数组分割为新的数组块.
+ *
+ * @param int $size
+ * @param bool $preserveKeys
+ * @return static
+ */
+ public function chunk($size, $preserveKeys = false)
+ {
+ $chunks = [];
+
+ foreach (array_chunk($this->items, $size, $preserveKeys) as $chunk) {
+ $chunks[] = new static($chunk);
+ }
+
+ return new static($chunks);
+ }
+
+ /**
+ * 在数组开头插入一个元素
+ * @param mixed $value
+ * @param null $key
+ * @return int
+ */
+ public function unshift($value, $key = null)
+ {
+ if (is_null($key)) {
+ array_unshift($this->items, $value);
+ } else {
+ $this->items = [$key => $value] + $this->items;
+ }
+ }
+
+ /**
+ * 给每个元素执行个回调
+ *
+ * @param callable $callback
+ * @return $this
+ */
+ public function each(callable $callback)
+ {
+ foreach ($this->items as $key => $item) {
+ if ($callback($item, $key) === false) {
+ break;
+ }
+ }
+
+ return $this;
+ }
+
+ /**
+ * 用回调函数过滤数组中的元素
+ * @param callable|null $callback
+ * @return static
+ */
+ public function filter(callable $callback = null)
+ {
+ if ($callback) {
+ return new static(array_filter($this->items, $callback));
+ }
+
+ return new static(array_filter($this->items));
+ }
+
+ /**
+ * 返回数组中指定的一列
+ * @param $column_key
+ * @param null $index_key
+ * @return array
+ */
+ public function column($column_key, $index_key = null)
+ {
+ if (function_exists('array_column')) {
+ return array_column($this->items, $column_key, $index_key);
+ }
+
+ $result = [];
+ foreach ($this->items as $row) {
+ $key = $value = null;
+ $keySet = $valueSet = false;
+ if (null !== $index_key && array_key_exists($index_key, $row)) {
+ $keySet = true;
+ $key = (string)$row[$index_key];
+ }
+ if (null === $column_key) {
+ $valueSet = true;
+ $value = $row;
+ } elseif (is_array($row) && array_key_exists($column_key, $row)) {
+ $valueSet = true;
+ $value = $row[$column_key];
+ }
+ if ($valueSet) {
+ if ($keySet) {
+ $result[$key] = $value;
+ } else {
+ $result[] = $value;
+ }
+ }
+ }
+ return $result;
+ }
+
+ /**
+ * 对数组排序
+ *
+ * @param callable|null $callback
+ * @return static
+ */
+ public function sort(callable $callback = null)
+ {
+ $items = $this->items;
+
+ $callback ? uasort($items, $callback) : uasort($items, function ($a, $b) {
+
+ if ($a == $b) {
+ return 0;
+ }
+
+ return ($a < $b) ? -1 : 1;
+ });
+
+ return new static($items);
+ }
+
+ /**
+ * 将数组打乱
+ *
+ * @return static
+ */
+ public function shuffle()
+ {
+ $items = $this->items;
+
+ shuffle($items);
+
+ return new static($items);
+ }
+
+ /**
+ * 截取数组
+ *
+ * @param int $offset
+ * @param int $length
+ * @param bool $preserveKeys
+ * @return static
+ */
+ public function slice($offset, $length = null, $preserveKeys = false)
+ {
+ return new static(array_slice($this->items, $offset, $length, $preserveKeys));
+ }
+
+ // ArrayAccess
+ public function offsetExists($offset)
+ {
+ return array_key_exists($offset, $this->items);
+ }
+
+ public function offsetGet($offset)
+ {
+ return $this->items[$offset];
+ }
+
+ public function offsetSet($offset, $value)
+ {
+ if (is_null($offset)) {
+ $this->items[] = $value;
+ } else {
+ $this->items[$offset] = $value;
+ }
+ }
+
+ public function offsetUnset($offset)
+ {
+ unset($this->items[$offset]);
+ }
+
+ //Countable
+ public function count()
+ {
+ return count($this->items);
+ }
+
+ //IteratorAggregate
+ public function getIterator()
+ {
+ return new ArrayIterator($this->items);
+ }
+
+ //JsonSerializable
+ public function jsonSerialize()
+ {
+ return $this->toArray();
+ }
+
+ /**
+ * 转换当前数据集为JSON字符串
+ * @access public
+ * @param integer $options json参数
+ * @return string
+ */
+ public function toJson($options = JSON_UNESCAPED_UNICODE)
+ {
+ return json_encode($this->toArray(), $options);
+ }
+
+ public function __toString()
+ {
+ return $this->toJson();
+ }
+
+ /**
+ * 转换成数组
+ *
+ * @param mixed $items
+ * @return array
+ */
+ protected function convertToArray($items)
+ {
+ if ($items instanceof self) {
+ return $items->all();
+ }
+ return (array)$items;
+ }
+}
diff --git a/thinkphp/library/think/Config.php b/thinkphp/library/think/Config.php
new file mode 100644
index 0000000..7256e0e
--- /dev/null
+++ b/thinkphp/library/think/Config.php
@@ -0,0 +1,186 @@
+
+// +----------------------------------------------------------------------
+
+namespace think;
+
+class Config
+{
+ // 配置参数
+ private static $config = [];
+ // 参数作用域
+ private static $range = '_sys_';
+
+ // 设定配置参数的作用域
+ public static function range($range)
+ {
+ self::$range = $range;
+ if (!isset(self::$config[$range])) {
+ self::$config[$range] = [];
+ }
+ }
+
+ /**
+ * 解析配置文件或内容
+ * @param string $config 配置文件路径或内容
+ * @param string $type 配置解析类型
+ * @param string $name 配置名(如设置即表示二级配置)
+ * @param string $range 作用域
+ * @return mixed
+ */
+ public static function parse($config, $type = '', $name = '', $range = '')
+ {
+ $range = $range ?: self::$range;
+ if (empty($type)) {
+ $type = pathinfo($config, PATHINFO_EXTENSION);
+ }
+ $class = false !== strpos($type, '\\') ? $type : '\\think\\config\\driver\\' . ucwords($type);
+ return self::set((new $class())->parse($config), $name, $range);
+ }
+
+ /**
+ * 加载配置文件(PHP格式)
+ * @param string $file 配置文件名
+ * @param string $name 配置名(如设置即表示二级配置)
+ * @param string $range 作用域
+ * @return mixed
+ */
+ public static function load($file, $name = '', $range = '')
+ {
+ $range = $range ?: self::$range;
+ if (!isset(self::$config[$range])) {
+ self::$config[$range] = [];
+ }
+ if (is_file($file)) {
+ $type = pathinfo($file, PATHINFO_EXTENSION);
+ if ('php' != $type) {
+ return self::parse($file, $type, $name, $range);
+ } else {
+ return self::set(include $file, $name, $range);
+ }
+ } else {
+ return self::$config[$range];
+ }
+ }
+
+ /**
+ * 检测配置是否存在
+ * @param string $name 配置参数名(支持二级配置 .号分割)
+ * @param string $range 作用域
+ * @return bool
+ */
+ public static function has($name, $range = '')
+ {
+ $range = $range ?: self::$range;
+
+ if (!strpos($name, '.')) {
+ // 判断环境变量
+ $result = getenv(ENV_PREFIX . strtoupper($name));
+ if (false !== $result) {
+ return $result;
+ }
+ return isset(self::$config[$range][strtolower($name)]);
+ } else {
+ // 二维数组设置和获取支持
+ $name = explode('.', $name);
+ $result = getenv(ENV_PREFIX . strtoupper($name[0] . '_' . $name[1]));
+ // 判断环境变量
+ if (false !== $result) {
+ return $result;
+ }
+ return isset(self::$config[$range][strtolower($name[0])][$name[1]]);
+ }
+ }
+
+ /**
+ * 获取配置参数 为空则获取所有配置
+ * @param string $name 配置参数名(支持二级配置 .号分割)
+ * @param string $range 作用域
+ * @return mixed
+ */
+ public static function get($name = null, $range = '')
+ {
+ $range = $range ?: self::$range;
+ // 无参数时获取所有
+ if (empty($name) && isset(self::$config[$range])) {
+ return self::$config[$range];
+ }
+
+ if (!strpos($name, '.')) {
+ $result = getenv(ENV_PREFIX . strtoupper($name));
+ if (false !== $result) {
+ return $result;
+ }
+ $name = strtolower($name);
+ return isset(self::$config[$range][$name]) ? self::$config[$range][$name] : null;
+ } else {
+ // 二维数组设置和获取支持
+ $name = explode('.', $name);
+ $result = getenv(ENV_PREFIX . strtoupper($name[0] . '_' . $name[1]));
+ // 判断环境变量
+ if (false !== $result) {
+ return $result;
+ }
+ $name[0] = strtolower($name[0]);
+ return isset(self::$config[$range][$name[0]][$name[1]]) ? self::$config[$range][$name[0]][$name[1]] : null;
+ }
+ }
+
+ /**
+ * 设置配置参数 name为数组则为批量设置
+ * @param string|array $name 配置参数名(支持二级配置 .号分割)
+ * @param mixed $value 配置值
+ * @param string $range 作用域
+ * @return mixed
+ */
+ public static function set($name, $value = null, $range = '')
+ {
+ $range = $range ?: self::$range;
+ if (!isset(self::$config[$range])) {
+ self::$config[$range] = [];
+ }
+ if (is_string($name)) {
+ if (!strpos($name, '.')) {
+ self::$config[$range][strtolower($name)] = $value;
+ } else {
+ // 二维数组设置和获取支持
+ $name = explode('.', $name);
+ self::$config[$range][strtolower($name[0])][$name[1]] = $value;
+ }
+ return;
+ } elseif (is_array($name)) {
+ // 批量设置
+ if (!empty($value)) {
+ self::$config[$range][$value] = isset(self::$config[$range][$value]) ?
+ array_merge(self::$config[$range][$value], $name) :
+ self::$config[$range][$value] = $name;
+ return self::$config[$range][$value];
+ } else {
+ return self::$config[$range] = array_merge(self::$config[$range], array_change_key_case($name));
+ }
+ } else {
+ // 为空直接返回 已有配置
+ return self::$config[$range];
+ }
+ }
+
+ /**
+ * 重置配置参数
+ */
+ public static function reset($range = '')
+ {
+ $range = $range ?: self::$range;
+ if (true === $range) {
+ self::$config = [];
+ } else {
+ self::$config[$range] = [];
+ }
+ }
+}
diff --git a/thinkphp/library/think/Console.php b/thinkphp/library/think/Console.php
new file mode 100644
index 0000000..70defad
--- /dev/null
+++ b/thinkphp/library/think/Console.php
@@ -0,0 +1,717 @@
+
+// +----------------------------------------------------------------------
+
+namespace think;
+
+use think\console\Command;
+use think\console\command\Help as HelpCommand;
+use think\console\Input;
+use think\console\input\Argument as InputArgument;
+use think\console\input\Definition as InputDefinition;
+use think\console\input\Option as InputOption;
+use think\console\Output;
+use think\console\output\driver\Buffer;
+
+class Console
+{
+
+ private $name;
+ private $version;
+
+ /** @var Command[] */
+ private $commands = [];
+
+ private $wantHelps = false;
+
+ private $catchExceptions = true;
+ private $autoExit = true;
+ private $definition;
+ private $defaultCommand;
+
+ private static $defaultCommands = [
+ "think\\console\\command\\Help",
+ "think\\console\\command\\Lists",
+ "think\\console\\command\\Build",
+ "think\\console\\command\\Clear",
+ "think\\console\\command\\make\\Controller",
+ "think\\console\\command\\make\\Model",
+ "think\\console\\command\\optimize\\Autoload",
+ "think\\console\\command\\optimize\\Config",
+ "think\\console\\command\\optimize\\Route",
+ ];
+
+ public function __construct($name = 'UNKNOWN', $version = 'UNKNOWN')
+ {
+ $this->name = $name;
+ $this->version = $version;
+
+ $this->defaultCommand = 'list';
+ $this->definition = $this->getDefaultInputDefinition();
+
+ foreach ($this->getDefaultCommands() as $command) {
+ $this->add($command);
+ }
+ }
+
+ public static function init($run = true)
+ {
+ static $console;
+ if (!$console) {
+ // 实例化console
+ $console = new self('Think Console', '0.1');
+ // 读取指令集
+ if (is_file(CONF_PATH . 'command' . EXT)) {
+ $commands = include CONF_PATH . 'command' . EXT;
+ if (is_array($commands)) {
+ foreach ($commands as $command) {
+ if (class_exists($command) && is_subclass_of($command, "\\think\\console\\Command")) {
+ // 注册指令
+ $console->add(new $command());
+ }
+ }
+ }
+ }
+ }
+ if ($run) {
+ // 运行
+ return $console->run();
+ } else {
+ return $console;
+ }
+ }
+
+ /**
+ * @param $command
+ * @param array $parameters
+ * @return Output|Buffer
+ */
+ public static function call($command, array $parameters = [])
+ {
+ $console = self::init(false);
+
+ array_unshift($parameters, $command);
+
+ $input = new Input($parameters);
+ $output = new Output('buffer');
+
+ $console->setCatchExceptions(false);
+ $console->find($command)->run($input, $output);
+
+ return $output;
+ }
+
+ /**
+ * 执行当前的指令
+ * @return int
+ * @throws \Exception
+ * @api
+ */
+ public function run()
+ {
+ $input = new Input();
+ $output = new Output();
+
+ $this->configureIO($input, $output);
+
+ try {
+ $exitCode = $this->doRun($input, $output);
+ } catch (\Exception $e) {
+ if (!$this->catchExceptions) {
+ throw $e;
+ }
+
+ $output->renderException($e);
+
+ $exitCode = $e->getCode();
+ if (is_numeric($exitCode)) {
+ $exitCode = (int)$exitCode;
+ if (0 === $exitCode) {
+ $exitCode = 1;
+ }
+ } else {
+ $exitCode = 1;
+ }
+ }
+
+ if ($this->autoExit) {
+ if ($exitCode > 255) {
+ $exitCode = 255;
+ }
+
+ exit($exitCode);
+ }
+
+ return $exitCode;
+ }
+
+ /**
+ * 执行指令
+ * @param Input $input
+ * @param Output $output
+ * @return int
+ */
+ public function doRun(Input $input, Output $output)
+ {
+ if (true === $input->hasParameterOption(['--version', '-V'])) {
+ $output->writeln($this->getLongVersion());
+
+ return 0;
+ }
+
+ $name = $this->getCommandName($input);
+
+ if (true === $input->hasParameterOption(['--help', '-h'])) {
+ if (!$name) {
+ $name = 'help';
+ $input = new Input(['help']);
+ } else {
+ $this->wantHelps = true;
+ }
+ }
+
+ if (!$name) {
+ $name = $this->defaultCommand;
+ $input = new Input([$this->defaultCommand]);
+ }
+
+ $command = $this->find($name);
+
+ $exitCode = $this->doRunCommand($command, $input, $output);
+
+ return $exitCode;
+ }
+
+ /**
+ * 设置输入参数定义
+ * @param InputDefinition $definition
+ */
+ public function setDefinition(InputDefinition $definition)
+ {
+ $this->definition = $definition;
+ }
+
+ /**
+ * 获取输入参数定义
+ * @return InputDefinition The InputDefinition instance
+ */
+ public function getDefinition()
+ {
+ return $this->definition;
+ }
+
+ /**
+ * Gets the help message.
+ * @return string A help message.
+ */
+ public function getHelp()
+ {
+ return $this->getLongVersion();
+ }
+
+ /**
+ * 是否捕获异常
+ * @param bool $boolean
+ * @api
+ */
+ public function setCatchExceptions($boolean)
+ {
+ $this->catchExceptions = (bool)$boolean;
+ }
+
+ /**
+ * 是否自动退出
+ * @param bool $boolean
+ * @api
+ */
+ public function setAutoExit($boolean)
+ {
+ $this->autoExit = (bool)$boolean;
+ }
+
+ /**
+ * 获取名称
+ * @return string
+ */
+ public function getName()
+ {
+ return $this->name;
+ }
+
+ /**
+ * 设置名称
+ * @param string $name
+ */
+ public function setName($name)
+ {
+ $this->name = $name;
+ }
+
+ /**
+ * 获取版本
+ * @return string
+ * @api
+ */
+ public function getVersion()
+ {
+ return $this->version;
+ }
+
+ /**
+ * 设置版本
+ * @param string $version
+ */
+ public function setVersion($version)
+ {
+ $this->version = $version;
+ }
+
+ /**
+ * 获取完整的版本号
+ * @return string
+ */
+ public function getLongVersion()
+ {
+ if ('UNKNOWN' !== $this->getName() && 'UNKNOWN' !== $this->getVersion()) {
+ return sprintf('%s version %s', $this->getName(), $this->getVersion());
+ }
+
+ return 'Console Tool';
+ }
+
+ /**
+ * 注册一个指令
+ * @param string $name
+ * @return Command
+ */
+ public function register($name)
+ {
+ return $this->add(new Command($name));
+ }
+
+ /**
+ * 添加指令
+ * @param Command[] $commands
+ */
+ public function addCommands(array $commands)
+ {
+ foreach ($commands as $command) {
+ $this->add($command);
+ }
+ }
+
+ /**
+ * 添加一个指令
+ * @param Command $command
+ * @return Command
+ */
+ public function add(Command $command)
+ {
+ $command->setConsole($this);
+
+ if (!$command->isEnabled()) {
+ $command->setConsole(null);
+ return null;
+ }
+
+ if (null === $command->getDefinition()) {
+ throw new \LogicException(sprintf('Command class "%s" is not correctly initialized. You probably forgot to call the parent constructor.', get_class($command)));
+ }
+
+ $this->commands[$command->getName()] = $command;
+
+ foreach ($command->getAliases() as $alias) {
+ $this->commands[$alias] = $command;
+ }
+
+ return $command;
+ }
+
+ /**
+ * 获取指令
+ * @param string $name 指令名称
+ * @return Command
+ * @throws \InvalidArgumentException
+ */
+ public function get($name)
+ {
+ if (!isset($this->commands[$name])) {
+ throw new \InvalidArgumentException(sprintf('The command "%s" does not exist.', $name));
+ }
+
+ $command = $this->commands[$name];
+
+ if ($this->wantHelps) {
+ $this->wantHelps = false;
+
+ /** @var HelpCommand $helpCommand */
+ $helpCommand = $this->get('help');
+ $helpCommand->setCommand($command);
+
+ return $helpCommand;
+ }
+
+ return $command;
+ }
+
+ /**
+ * 某个指令是否存在
+ * @param string $name 指令名称
+ * @return bool
+ */
+ public function has($name)
+ {
+ return isset($this->commands[$name]);
+ }
+
+ /**
+ * 获取所有的命名空间
+ * @return array
+ */
+ public function getNamespaces()
+ {
+ $namespaces = [];
+ foreach ($this->commands as $command) {
+ $namespaces = array_merge($namespaces, $this->extractAllNamespaces($command->getName()));
+
+ foreach ($command->getAliases() as $alias) {
+ $namespaces = array_merge($namespaces, $this->extractAllNamespaces($alias));
+ }
+ }
+
+ return array_values(array_unique(array_filter($namespaces)));
+ }
+
+ /**
+ * 查找注册命名空间中的名称或缩写。
+ * @param string $namespace
+ * @return string
+ * @throws \InvalidArgumentException
+ */
+ public function findNamespace($namespace)
+ {
+ $allNamespaces = $this->getNamespaces();
+ $expr = preg_replace_callback('{([^:]+|)}', function ($matches) {
+ return preg_quote($matches[1]) . '[^:]*';
+ }, $namespace);
+ $namespaces = preg_grep('{^' . $expr . '}', $allNamespaces);
+
+ if (empty($namespaces)) {
+ $message = sprintf('There are no commands defined in the "%s" namespace.', $namespace);
+
+ if ($alternatives = $this->findAlternatives($namespace, $allNamespaces)) {
+ if (1 == count($alternatives)) {
+ $message .= "\n\nDid you mean this?\n ";
+ } else {
+ $message .= "\n\nDid you mean one of these?\n ";
+ }
+
+ $message .= implode("\n ", $alternatives);
+ }
+
+ throw new \InvalidArgumentException($message);
+ }
+
+ $exact = in_array($namespace, $namespaces, true);
+ if (count($namespaces) > 1 && !$exact) {
+ throw new \InvalidArgumentException(sprintf('The namespace "%s" is ambiguous (%s).', $namespace, $this->getAbbreviationSuggestions(array_values($namespaces))));
+ }
+
+ return $exact ? $namespace : reset($namespaces);
+ }
+
+ /**
+ * 查找指令
+ * @param string $name 名称或者别名
+ * @return Command
+ * @throws \InvalidArgumentException
+ */
+ public function find($name)
+ {
+ $allCommands = array_keys($this->commands);
+ $expr = preg_replace_callback('{([^:]+|)}', function ($matches) {
+ return preg_quote($matches[1]) . '[^:]*';
+ }, $name);
+ $commands = preg_grep('{^' . $expr . '}', $allCommands);
+
+ if (empty($commands) || count(preg_grep('{^' . $expr . '$}', $commands)) < 1) {
+ if (false !== $pos = strrpos($name, ':')) {
+ $this->findNamespace(substr($name, 0, $pos));
+ }
+
+ $message = sprintf('Command "%s" is not defined.', $name);
+
+ if ($alternatives = $this->findAlternatives($name, $allCommands)) {
+ if (1 == count($alternatives)) {
+ $message .= "\n\nDid you mean this?\n ";
+ } else {
+ $message .= "\n\nDid you mean one of these?\n ";
+ }
+ $message .= implode("\n ", $alternatives);
+ }
+
+ throw new \InvalidArgumentException($message);
+ }
+
+ if (count($commands) > 1) {
+ $commandList = $this->commands;
+ $commands = array_filter($commands, function ($nameOrAlias) use ($commandList, $commands) {
+ $commandName = $commandList[$nameOrAlias]->getName();
+
+ return $commandName === $nameOrAlias || !in_array($commandName, $commands);
+ });
+ }
+
+ $exact = in_array($name, $commands, true);
+ if (count($commands) > 1 && !$exact) {
+ $suggestions = $this->getAbbreviationSuggestions(array_values($commands));
+
+ throw new \InvalidArgumentException(sprintf('Command "%s" is ambiguous (%s).', $name, $suggestions));
+ }
+
+ return $this->get($exact ? $name : reset($commands));
+ }
+
+ /**
+ * 获取所有的指令
+ * @param string $namespace 命名空间
+ * @return Command[]
+ * @api
+ */
+ public function all($namespace = null)
+ {
+ if (null === $namespace) {
+ return $this->commands;
+ }
+
+ $commands = [];
+ foreach ($this->commands as $name => $command) {
+ if ($this->extractNamespace($name, substr_count($namespace, ':') + 1) === $namespace) {
+ $commands[$name] = $command;
+ }
+ }
+
+ return $commands;
+ }
+
+ /**
+ * 获取可能的指令名
+ * @param array $names
+ * @return array
+ */
+ public static function getAbbreviations($names)
+ {
+ $abbrevs = [];
+ foreach ($names as $name) {
+ for ($len = strlen($name); $len > 0; --$len) {
+ $abbrev = substr($name, 0, $len);
+ $abbrevs[$abbrev][] = $name;
+ }
+ }
+
+ return $abbrevs;
+ }
+
+ /**
+ * 配置基于用户的参数和选项的输入和输出实例。
+ * @param Input $input 输入实例
+ * @param Output $output 输出实例
+ */
+ protected function configureIO(Input $input, Output $output)
+ {
+ if (true === $input->hasParameterOption(['--ansi'])) {
+ $output->setDecorated(true);
+ } elseif (true === $input->hasParameterOption(['--no-ansi'])) {
+ $output->setDecorated(false);
+ }
+
+ if (true === $input->hasParameterOption(['--no-interaction', '-n'])) {
+ $input->setInteractive(false);
+ }
+
+ if (true === $input->hasParameterOption(['--quiet', '-q'])) {
+ $output->setVerbosity(Output::VERBOSITY_QUIET);
+ } else {
+ if ($input->hasParameterOption('-vvv') || $input->hasParameterOption('--verbose=3') || $input->getParameterOption('--verbose') === 3) {
+ $output->setVerbosity(Output::VERBOSITY_DEBUG);
+ } elseif ($input->hasParameterOption('-vv') || $input->hasParameterOption('--verbose=2') || $input->getParameterOption('--verbose') === 2) {
+ $output->setVerbosity(Output::VERBOSITY_VERY_VERBOSE);
+ } elseif ($input->hasParameterOption('-v') || $input->hasParameterOption('--verbose=1') || $input->hasParameterOption('--verbose') || $input->getParameterOption('--verbose')) {
+ $output->setVerbosity(Output::VERBOSITY_VERBOSE);
+ }
+ }
+ }
+
+ /**
+ * 执行指令
+ * @param Command $command 指令实例
+ * @param Input $input 输入实例
+ * @param Output $output 输出实例
+ * @return int
+ * @throws \Exception
+ */
+ protected function doRunCommand(Command $command, Input $input, Output $output)
+ {
+ return $command->run($input, $output);
+ }
+
+ /**
+ * 获取指令的基础名称
+ * @param Input $input
+ * @return string
+ */
+ protected function getCommandName(Input $input)
+ {
+ return $input->getFirstArgument();
+ }
+
+ /**
+ * 获取默认输入定义
+ * @return InputDefinition
+ */
+ protected function getDefaultInputDefinition()
+ {
+ return new InputDefinition([
+ new InputArgument('command', InputArgument::REQUIRED, 'The command to execute'),
+ new InputOption('--help', '-h', InputOption::VALUE_NONE, 'Display this help message'),
+ new InputOption('--version', '-V', InputOption::VALUE_NONE, 'Display this console version'),
+ new InputOption('--quiet', '-q', InputOption::VALUE_NONE, 'Do not output any message'),
+ new InputOption('--verbose', '-v|vv|vvv', InputOption::VALUE_NONE, 'Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug'),
+ new InputOption('--ansi', '', InputOption::VALUE_NONE, 'Force ANSI output'),
+ new InputOption('--no-ansi', '', InputOption::VALUE_NONE, 'Disable ANSI output'),
+ new InputOption('--no-interaction', '-n', InputOption::VALUE_NONE, 'Do not ask any interactive question'),
+ ]);
+ }
+
+ /**
+ * 设置默认命令
+ * @return Command[] An array of default Command instances
+ */
+ protected function getDefaultCommands()
+ {
+ $defaultCommands = [];
+
+ foreach (self::$defaultCommands as $classname) {
+ if (class_exists($classname) && is_subclass_of($classname, "think\\console\\Command")) {
+ $defaultCommands[] = new $classname();
+ }
+ }
+
+ return $defaultCommands;
+ }
+
+ public static function addDefaultCommands(array $classnames)
+ {
+ self::$defaultCommands = array_merge(self::$defaultCommands, $classnames);
+ }
+
+ /**
+ * 获取可能的建议
+ * @param array $abbrevs
+ * @return string
+ */
+ private function getAbbreviationSuggestions($abbrevs)
+ {
+ return sprintf('%s, %s%s', $abbrevs[0], $abbrevs[1], count($abbrevs) > 2 ? sprintf(' and %d more', count($abbrevs) - 2) : '');
+ }
+
+ /**
+ * 返回命名空间部分
+ * @param string $name 指令
+ * @param string $limit 部分的命名空间的最大数量
+ * @return string
+ */
+ public function extractNamespace($name, $limit = null)
+ {
+ $parts = explode(':', $name);
+ array_pop($parts);
+
+ return implode(':', null === $limit ? $parts : array_slice($parts, 0, $limit));
+ }
+
+ /**
+ * 查找可替代的建议
+ * @param string $name
+ * @param array|\Traversable $collection
+ * @return array
+ */
+ private function findAlternatives($name, $collection)
+ {
+ $threshold = 1e3;
+ $alternatives = [];
+
+ $collectionParts = [];
+ foreach ($collection as $item) {
+ $collectionParts[$item] = explode(':', $item);
+ }
+
+ foreach (explode(':', $name) as $i => $subname) {
+ foreach ($collectionParts as $collectionName => $parts) {
+ $exists = isset($alternatives[$collectionName]);
+ if (!isset($parts[$i]) && $exists) {
+ $alternatives[$collectionName] += $threshold;
+ continue;
+ } elseif (!isset($parts[$i])) {
+ continue;
+ }
+
+ $lev = levenshtein($subname, $parts[$i]);
+ if ($lev <= strlen($subname) / 3 || '' !== $subname && false !== strpos($parts[$i], $subname)) {
+ $alternatives[$collectionName] = $exists ? $alternatives[$collectionName] + $lev : $lev;
+ } elseif ($exists) {
+ $alternatives[$collectionName] += $threshold;
+ }
+ }
+ }
+
+ foreach ($collection as $item) {
+ $lev = levenshtein($name, $item);
+ if ($lev <= strlen($name) / 3 || false !== strpos($item, $name)) {
+ $alternatives[$item] = isset($alternatives[$item]) ? $alternatives[$item] - $lev : $lev;
+ }
+ }
+
+ $alternatives = array_filter($alternatives, function ($lev) use ($threshold) {
+ return $lev < 2 * $threshold;
+ });
+ asort($alternatives);
+
+ return array_keys($alternatives);
+ }
+
+ /**
+ * 设置默认的指令
+ * @param string $commandName The Command name
+ */
+ public function setDefaultCommand($commandName)
+ {
+ $this->defaultCommand = $commandName;
+ }
+
+ /**
+ * 返回所有的命名空间
+ * @param string $name
+ * @return array
+ */
+ private function extractAllNamespaces($name)
+ {
+ $parts = explode(':', $name, -1);
+ $namespaces = [];
+
+ foreach ($parts as $part) {
+ if (count($namespaces)) {
+ $namespaces[] = end($namespaces) . ':' . $part;
+ } else {
+ $namespaces[] = $part;
+ }
+ }
+
+ return $namespaces;
+ }
+
+}
diff --git a/thinkphp/library/think/Controller.php b/thinkphp/library/think/Controller.php
new file mode 100644
index 0000000..941ffd1
--- /dev/null
+++ b/thinkphp/library/think/Controller.php
@@ -0,0 +1,211 @@
+
+// +----------------------------------------------------------------------
+
+namespace think;
+
+\think\Loader::import('controller/Jump', TRAIT_PATH, EXT);
+
+use think\Exception;
+use think\exception\ValidateException;
+
+class Controller
+{
+ use \traits\controller\Jump;
+
+ // 视图类实例
+ protected $view;
+ // Request实例
+ protected $request;
+ // 验证失败是否抛出异常
+ protected $failException = false;
+ // 是否批量验证
+ protected $batchValidate = false;
+
+ /**
+ * 前置操作方法列表
+ * @var array $beforeActionList
+ * @access protected
+ */
+ protected $beforeActionList = [];
+
+ /**
+ * 架构函数
+ * @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);
+ }
+ }
+ }
+
+ // 初始化
+ protected function _initialize()
+ {
+ }
+
+ /**
+ * 前置操作
+ * @access protected
+ * @param string $method 前置操作方法名
+ * @param array $options 调用参数 ['only'=>[...]] 或者['except'=>[...]]
+ */
+ protected function beforeAction($method, $options = [])
+ {
+ if (isset($options['only'])) {
+ if (is_string($options['only'])) {
+ $options['only'] = explode(',', $options['only']);
+ }
+ if (!in_array($this->request->action(), $options['only'])) {
+ return;
+ }
+ } elseif (isset($options['except'])) {
+ if (is_string($options['except'])) {
+ $options['except'] = explode(',', $options['except']);
+ }
+ if (in_array($this->request->action(), $options['except'])) {
+ return;
+ }
+ }
+
+ if (method_exists($this, $method)) {
+ call_user_func([$this, $method]);
+ }
+ }
+
+ /**
+ * 加载模板输出
+ * @access protected
+ * @param string $template 模板文件名
+ * @param array $vars 模板输出变量
+ * @param array $replace 模板替换
+ * @param array $config 模板参数
+ * @return mixed
+ */
+ protected function fetch($template = '', $vars = [], $replace = [], $config = [])
+ {
+ return $this->view->fetch($template, $vars, $replace, $config);
+ }
+
+ /**
+ * 渲染内容输出
+ * @access protected
+ * @param string $content 模板内容
+ * @param array $vars 模板输出变量
+ * @param array $replace 替换内容
+ * @param array $config 模板参数
+ * @return mixed
+ */
+ protected function display($content = '', $vars = [], $replace = [], $config = [])
+ {
+ return $this->view->display($content, $vars, $replace, $config);
+ }
+
+ /**
+ * 模板变量赋值
+ * @access protected
+ * @param mixed $name 要显示的模板变量
+ * @param mixed $value 变量的值
+ * @return void
+ */
+ protected function assign($name, $value = '')
+ {
+ $this->view->assign($name, $value);
+ }
+
+ /**
+ * 初始化模板引擎
+ * @access protected
+ * @param array|string $engine 引擎参数
+ * @return void
+ */
+ protected function engine($engine)
+ {
+ $this->view->engine($engine);
+ }
+
+ /**
+ * 设置验证失败后是否抛出异常
+ * @access protected
+ * @param bool $fail 是否抛出异常
+ * @return $this
+ */
+ protected function validateFailException($fail = true)
+ {
+ $this->failException = $fail;
+ return $this;
+ }
+
+ /**
+ * 验证数据
+ * @access protected
+ * @param array $data 数据
+ * @param string|array $validate 验证器名或者验证规则数组
+ * @param array $message 提示信息
+ * @param bool $batch 是否批量验证
+ * @param mixed $callback 回调方法(闭包)
+ * @return array|string|true
+ * @throws ValidateException
+ */
+ protected function validate($data, $validate, $message = [], $batch = false, $callback = null)
+ {
+ if (is_array($validate)) {
+ $v = Loader::validate();
+ $v->rule($validate);
+ } else {
+ if (strpos($validate, '.')) {
+ // 支持场景
+ list($validate, $scene) = explode('.', $validate);
+ }
+ $v = Loader::validate($validate);
+ if (!empty($scene)) {
+ $v->scene($scene);
+ }
+ }
+ // 是否批量验证
+ if ($batch || $this->batchValidate) {
+ $v->batch(true);
+ }
+
+ if (is_array($message)) {
+ $v->message($message);
+ }
+
+ if ($callback && is_callable($callback)) {
+ call_user_func_array($callback, [$v, &$data]);
+ }
+
+ if (!$v->check($data)) {
+ if ($this->failException) {
+ throw new ValidateException($v->getError());
+ } else {
+ return $v->getError();
+ }
+ } else {
+ return true;
+ }
+ }
+}
diff --git a/thinkphp/library/think/Cookie.php b/thinkphp/library/think/Cookie.php
new file mode 100644
index 0000000..648b2c6
--- /dev/null
+++ b/thinkphp/library/think/Cookie.php
@@ -0,0 +1,195 @@
+
+// +----------------------------------------------------------------------
+
+namespace think;
+
+class Cookie
+{
+ protected static $config = [
+ // cookie 名称前缀
+ 'prefix' => '',
+ // cookie 保存时间
+ 'expire' => 0,
+ // cookie 保存路径
+ 'path' => '/',
+ // cookie 有效域名
+ 'domain' => '',
+ // cookie 启用安全传输
+ 'secure' => false,
+ // httponly设置
+ 'httponly' => '',
+ // 是否使用 setcookie
+ 'setcookie' => true,
+ ];
+
+ protected static $init;
+
+ /**
+ * Cookie初始化
+ * @param array $config
+ * @return void
+ */
+ public static function init(array $config = [])
+ {
+ if (empty($config)) {
+ $config = Config::get('cookie');
+ }
+ self::$config = array_merge(self::$config, array_change_key_case($config));
+ if (!empty(self::$config['httponly'])) {
+ ini_set('session.cookie_httponly', 1);
+ }
+ self::$init = true;
+ }
+
+ /**
+ * 设置或者获取cookie作用域(前缀)
+ * @param string $prefix
+ * @return string|void
+ */
+ public static function prefix($prefix = '')
+ {
+ if (empty($prefix)) {
+ return self::$config['prefix'];
+ }
+ self::$config['prefix'] = $prefix;
+ }
+
+ /**
+ * Cookie 设置、获取、删除
+ *
+ * @param string $name cookie名称
+ * @param mixed $value cookie值
+ * @param mixed $option 可选参数 可能会是 null|integer|string
+ *
+ * @return mixed
+ * @internal param mixed $options cookie参数
+ */
+ public static function set($name, $value = '', $option = null)
+ {
+ !isset(self::$init) && self::init();
+ // 参数设置(会覆盖黙认设置)
+ if (!is_null($option)) {
+ if (is_numeric($option)) {
+ $option = ['expire' => $option];
+ } elseif (is_string($option)) {
+ parse_str($option, $option);
+ }
+ $config = array_merge(self::$config, array_change_key_case($option));
+ } else {
+ $config = self::$config;
+ }
+ $name = $config['prefix'] . $name;
+ // 设置cookie
+ if (is_array($value)) {
+ array_walk_recursive($value, 'self::jsonFormatProtect', 'encode');
+ $value = 'think:' . json_encode($value);
+ }
+ $expire = !empty($config['expire']) ? $_SERVER['REQUEST_TIME'] + intval($config['expire']) : 0;
+ if ($config['setcookie']) {
+ setcookie($name, $value, $expire, $config['path'], $config['domain'], $config['secure'], $config['httponly']);
+ }
+ $_COOKIE[$name] = $value;
+ }
+
+ /**
+ * 判断Cookie数据
+ * @param string $name cookie名称
+ * @param string|null $prefix cookie前缀
+ * @return bool
+ */
+ public static function has($name, $prefix = null)
+ {
+ !isset(self::$init) && self::init();
+ $prefix = !is_null($prefix) ? $prefix : self::$config['prefix'];
+ $name = $prefix . $name;
+ return isset($_COOKIE[$name]);
+ }
+
+ /**
+ * Cookie获取
+ * @param string $name cookie名称
+ * @param string|null $prefix cookie前缀
+ * @return mixed
+ */
+ public static function get($name, $prefix = null)
+ {
+ !isset(self::$init) && self::init();
+ $prefix = !is_null($prefix) ? $prefix : self::$config['prefix'];
+ $name = $prefix . $name;
+ if (isset($_COOKIE[$name])) {
+ $value = $_COOKIE[$name];
+ if (0 === strpos($value, 'think:')) {
+ $value = substr($value, 6);
+ $value = json_decode($value, true);
+ array_walk_recursive($value, 'self::jsonFormatProtect', 'decode');
+ }
+ return $value;
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Cookie删除
+ * @param string $name cookie名称
+ * @param string|null $prefix cookie前缀
+ * @return mixed
+ */
+ public static function delete($name, $prefix = null)
+ {
+ !isset(self::$init) && self::init();
+ $config = self::$config;
+ $prefix = !is_null($prefix) ? $prefix : $config['prefix'];
+ $name = $prefix . $name;
+ if ($config['setcookie']) {
+ setcookie($name, '', $_SERVER['REQUEST_TIME'] - 3600, $config['path'], $config['domain'], $config['secure'], $config['httponly']);
+ }
+ // 删除指定cookie
+ unset($_COOKIE[$name]);
+ }
+
+ /**
+ * Cookie清空
+ * @param string|null $prefix cookie前缀
+ * @return mixed
+ */
+ public static function clear($prefix = null)
+ {
+ // 清除指定前缀的所有cookie
+ if (empty($_COOKIE)) {
+ return;
+ }
+ !isset(self::$init) && self::init();
+ // 要删除的cookie前缀,不指定则删除config设置的指定前缀
+ $config = self::$config;
+ $prefix = !is_null($prefix) ? $prefix : $config['prefix'];
+ if ($prefix) {
+ // 如果前缀为空字符串将不作处理直接返回
+ foreach ($_COOKIE as $key => $val) {
+ if (0 === strpos($key, $prefix)) {
+ if ($config['setcookie']) {
+ setcookie($key, '', $_SERVER['REQUEST_TIME'] - 3600, $config['path'], $config['domain'], $config['secure'], $config['httponly']);
+ }
+ unset($_COOKIE[$key]);
+ }
+ }
+ }
+ return;
+ }
+
+ private static function jsonFormatProtect(&$val, $key, $type = 'encode')
+ {
+ if (!empty($val) && true !== $val) {
+ $val = 'decode' == $type ? urldecode($val) : urlencode($val);
+ }
+ }
+
+}
diff --git a/thinkphp/library/think/Db.php b/thinkphp/library/think/Db.php
new file mode 100644
index 0000000..9aefbe3
--- /dev/null
+++ b/thinkphp/library/think/Db.php
@@ -0,0 +1,148 @@
+
+// +----------------------------------------------------------------------
+
+namespace think;
+
+use think\App;
+use think\Collection;
+use think\db\Query;
+use think\paginator\Collection as PaginatorCollection;
+
+/**
+ * Class Db
+ * @package think
+ * @method Query table(string $table) static 指定数据表(含前缀)
+ * @method Query name(string $name) static 指定数据表(不含前缀)
+ * @method Query where(mixed $field, string $op = null, mixed $condition = null) static 查询条件
+ * @method Query join(mixed $join, mixed $condition = null, string $type = 'INNER') static JOIN查询
+ * @method Query union(mixed $union, boolean $all = false) static UNION查询
+ * @method Query limit(mixed $offset, integer $length = null) static 查询LIMIT
+ * @method Query order(mixed $field, string $order = null) static 查询ORDER
+ * @method Query cache(mixed $key = true , integer $expire = null) static 设置查询缓存
+ * @method mixed value(string $field) static 获取某个字段的值
+ * @method array column(string $field, string $key = '') static 获取某个列的值
+ * @method Query view(mixed $join, mixed $field = null, mixed $on = null, string $type = 'INNER') static 视图查询
+ * @method mixed find(mixed $data = []) static 查询单个记录
+ * @method mixed select(mixed $data = []) static 查询多个记录
+ * @method integer insert(array $data, boolean $replace = false, boolean $getLastInsID = false, string $sequence = null) static 插入一条记录
+ * @method integer insertGetId(array $data, boolean $replace = false, string $sequence = null) static 插入一条记录并返回自增ID
+ * @method integer insertAll(array $dataSet) static 插入多条记录
+ * @method integer update(array $data) static 更新记录
+ * @method integer delete(mixed $data = []) static 删除记录
+ * @method boolean chunk(integer $count, callable $callback, string $column = null) static 分块获取数据
+ * @method mixed query(string $sql, array $bind = [], boolean $fetch = false, boolean $master = false, mixed $class = false) static SQL查询
+ * @method integer execute(string $sql, array $bind = [], boolean $fetch = false, boolean $getLastInsID = false, string $sequence = null) static SQL执行
+ * @method PaginatorCollection paginate(integer $listRows = 15, boolean $simple = false, array $config = []) static 分页查询
+ * @method mixed transaction(callable $callback) static 执行数据库事务
+ * @method boolean batchQuery(array $sqlArray) static 批处理执行SQL语句
+ */
+class Db
+{
+ // 数据库连接实例
+ private static $instance = [];
+ // 查询次数
+ public static $queryTimes = 0;
+ // 执行次数
+ public static $executeTimes = 0;
+
+ /**
+ * 数据库初始化 并取得数据库类实例
+ * @static
+ * @access public
+ * @param mixed $config 连接配置
+ * @param bool|string $name 连接标识 true 强制重新连接
+ * @return \think\db\Connection
+ * @throws Exception
+ */
+ public static function connect($config = [], $name = false)
+ {
+ if (false === $name) {
+ $name = md5(serialize($config));
+ }
+ if (true === $name || !isset(self::$instance[$name])) {
+ // 解析连接参数 支持数组和字符串
+ $options = self::parseConfig($config);
+ if (empty($options['type'])) {
+ throw new \InvalidArgumentException('Underfined db type');
+ }
+ $class = false !== strpos($options['type'], '\\') ? $options['type'] : '\\think\\db\\connector\\' . ucwords($options['type']);
+ // 记录初始化信息
+ App::$debug && Log::record('[ DB ] INIT ' . $options['type'] . ':' . var_export($options, true), 'info');
+ if (true === $name) {
+ return new $class($options);
+ } else {
+ self::$instance[$name] = new $class($options);
+ }
+ }
+ return self::$instance[$name];
+ }
+
+ /**
+ * 数据库连接参数解析
+ * @static
+ * @access private
+ * @param mixed $config
+ * @return array
+ */
+ private static function parseConfig($config)
+ {
+ if (empty($config)) {
+ $config = Config::get('database');
+ } elseif (is_string($config) && false === strpos($config, '/')) {
+ // 支持读取配置参数
+ $config = Config::get($config);
+ }
+ if (is_string($config)) {
+ return self::parseDsn($config);
+ } else {
+ return $config;
+ }
+ }
+
+ /**
+ * DSN解析
+ * 格式: mysql://username:passwd@localhost:3306/DbName?param1=val1¶m2=val2#utf8
+ * @static
+ * @access private
+ * @param string $dsnStr
+ * @return array
+ */
+ private static function parseDsn($dsnStr)
+ {
+ $info = parse_url($dsnStr);
+ if (!$info) {
+ return [];
+ }
+ $dsn = [
+ 'type' => $info['scheme'],
+ 'username' => isset($info['user']) ? $info['user'] : '',
+ 'password' => isset($info['pass']) ? $info['pass'] : '',
+ 'hostname' => isset($info['host']) ? $info['host'] : '',
+ 'hostport' => isset($info['port']) ? $info['port'] : '',
+ 'database' => !empty($info['path']) ? ltrim($info['path'], '/') : '',
+ 'charset' => isset($info['fragment']) ? $info['fragment'] : 'utf8',
+ ];
+
+ if (isset($info['query'])) {
+ parse_str($info['query'], $dsn['params']);
+ } else {
+ $dsn['params'] = [];
+ }
+ return $dsn;
+ }
+
+ // 调用驱动类的方法
+ public static function __callStatic($method, $params)
+ {
+ // 自动初始化数据库
+ return call_user_func_array([self::connect(), $method], $params);
+ }
+}
diff --git a/thinkphp/library/think/Debug.php b/thinkphp/library/think/Debug.php
new file mode 100644
index 0000000..e36a764
--- /dev/null
+++ b/thinkphp/library/think/Debug.php
@@ -0,0 +1,216 @@
+
+// +----------------------------------------------------------------------
+
+namespace think;
+
+use think\Config;
+use think\exception\ClassNotFoundException;
+use think\Log;
+use think\Request;
+use think\Response;
+use think\response\Redirect;
+
+class Debug
+{
+ // 区间时间信息
+ protected static $info = [];
+ // 区间内存信息
+ protected static $mem = [];
+
+ /**
+ * 记录时间(微秒)和内存使用情况
+ * @param string $name 标记位置
+ * @param mixed $value 标记值 留空则取当前 time 表示仅记录时间 否则同时记录时间和内存
+ * @return mixed
+ */
+ public static function remark($name, $value = '')
+ {
+ // 记录时间和内存使用
+ self::$info[$name] = is_float($value) ? $value : microtime(true);
+ if ('time' != $value) {
+ self::$mem['mem'][$name] = is_float($value) ? $value : memory_get_usage();
+ self::$mem['peak'][$name] = memory_get_peak_usage();
+ }
+ }
+
+ /**
+ * 统计某个区间的时间(微秒)使用情况
+ * @param string $start 开始标签
+ * @param string $end 结束标签
+ * @param integer|string $dec 小数位
+ * @return integer
+ */
+ public static function getRangeTime($start, $end, $dec = 6)
+ {
+ if (!isset(self::$info[$end])) {
+ self::$info[$end] = microtime(true);
+ }
+ return number_format((self::$info[$end] - self::$info[$start]), $dec);
+ }
+
+ /**
+ * 统计从开始到统计时的时间(微秒)使用情况
+ * @param integer|string $dec 小数位
+ * @return integer
+ */
+ public static function getUseTime($dec = 6)
+ {
+ return number_format((microtime(true) - THINK_START_TIME), $dec);
+ }
+
+ /**
+ * 获取当前访问的吞吐率情况
+ * @return string
+ */
+ public static function getThroughputRate()
+ {
+ return number_format(1 / self::getUseTime(), 2) . 'req/s';
+ }
+
+ /**
+ * 记录区间的内存使用情况
+ * @param string $start 开始标签
+ * @param string $end 结束标签
+ * @param integer|string $dec 小数位
+ * @return string
+ */
+ public static function getRangeMem($start, $end, $dec = 2)
+ {
+ if (!isset(self::$mem['mem'][$end])) {
+ self::$mem['mem'][$end] = memory_get_usage();
+ }
+ $size = self::$mem['mem'][$end] - self::$mem['mem'][$start];
+ $a = ['B', 'KB', 'MB', 'GB', 'TB'];
+ $pos = 0;
+ while ($size >= 1024) {
+ $size /= 1024;
+ $pos++;
+ }
+ return round($size, $dec) . " " . $a[$pos];
+ }
+
+ /**
+ * 统计从开始到统计时的内存使用情况
+ * @param integer|string $dec 小数位
+ * @return string
+ */
+ public static function getUseMem($dec = 2)
+ {
+ $size = memory_get_usage() - THINK_START_MEM;
+ $a = ['B', 'KB', 'MB', 'GB', 'TB'];
+ $pos = 0;
+ while ($size >= 1024) {
+ $size /= 1024;
+ $pos++;
+ }
+ return round($size, $dec) . " " . $a[$pos];
+ }
+
+ /**
+ * 统计区间的内存峰值情况
+ * @param string $start 开始标签
+ * @param string $end 结束标签
+ * @param integer|string $dec 小数位
+ * @return mixed
+ */
+ public static function getMemPeak($start, $end, $dec = 2)
+ {
+ if (!isset(self::$mem['peak'][$end])) {
+ self::$mem['peak'][$end] = memory_get_peak_usage();
+ }
+ $size = self::$mem['peak'][$end] - self::$mem['peak'][$start];
+ $a = ['B', 'KB', 'MB', 'GB', 'TB'];
+ $pos = 0;
+ while ($size >= 1024) {
+ $size /= 1024;
+ $pos++;
+ }
+ return round($size, $dec) . " " . $a[$pos];
+ }
+
+ /**
+ * 获取文件加载信息
+ * @param bool $detail 是否显示详细
+ * @return integer|array
+ */
+ public static function getFile($detail = false)
+ {
+ if ($detail) {
+ $files = get_included_files();
+ $info = [];
+ foreach ($files as $key => $file) {
+ $info[] = $file . ' ( ' . number_format(filesize($file) / 1024, 2) . ' KB )';
+ }
+ return $info;
+ }
+ return count(get_included_files());
+ }
+
+ /**
+ * 浏览器友好的变量输出
+ * @param mixed $var 变量
+ * @param boolean $echo 是否输出 默认为true 如果为false 则返回输出字符串
+ * @param string $label 标签 默认为空
+ * @param integer $flags htmlspecialchars flags
+ * @return void|string
+ */
+ public static function dump($var, $echo = true, $label = null, $flags = ENT_SUBSTITUTE)
+ {
+ $label = (null === $label) ? '' : rtrim($label) . ':';
+ ob_start();
+ var_dump($var);
+ $output = ob_get_clean();
+ $output = preg_replace('/\]\=\>\n(\s+)/m', '] => ', $output);
+ if (IS_CLI) {
+ $output = PHP_EOL . $label . $output . PHP_EOL;
+ } else {
+ if (!extension_loaded('xdebug')) {
+ $output = htmlspecialchars($output, $flags);
+ }
+ $output = '' . $label . $output . '
';
+ }
+ if ($echo) {
+ echo ($output);
+ return null;
+ } else {
+ return $output;
+ }
+ }
+
+ public static function inject(Response $response, &$content)
+ {
+ $config = Config::get('trace');
+ $type = isset($config['type']) ? $config['type'] : 'Html';
+ $request = Request::instance();
+ $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调试信息注入
+ $pos = strripos($content, '