正在显示
23 个修改的文件
包含
4807 行增加
和
2 行删除
thinkphp/.gitignore
0 → 100644
thinkphp/.htaccess
0 → 100644
1 | +deny from all |
thinkphp/.travis.yml
0 → 100644
1 | +sudo: false | ||
2 | + | ||
3 | +language: php | ||
4 | + | ||
5 | +services: | ||
6 | + - memcached | ||
7 | + - mongodb | ||
8 | + - mysql | ||
9 | + - postgresql | ||
10 | + - redis-server | ||
11 | + | ||
12 | +matrix: | ||
13 | + fast_finish: true | ||
14 | + include: | ||
15 | + - php: 5.4 | ||
16 | + - php: 5.5 | ||
17 | + - php: 5.6 | ||
18 | + - php: 7.0 | ||
19 | + - php: hhvm | ||
20 | + allow_failures: | ||
21 | + - php: hhvm | ||
22 | + | ||
23 | +cache: | ||
24 | + directories: | ||
25 | + - $HOME/.composer/cache | ||
26 | + | ||
27 | +before_install: | ||
28 | + - composer self-update | ||
29 | + - mysql -e "create database IF NOT EXISTS test;" -uroot | ||
30 | + - psql -c 'DROP DATABASE IF EXISTS test;' -U postgres | ||
31 | + - psql -c 'create database test;' -U postgres | ||
32 | + | ||
33 | +install: | ||
34 | + - ./tests/script/install.sh | ||
35 | + | ||
36 | +script: | ||
37 | + ## LINT | ||
38 | + - find . -path ./vendor -prune -o -type f -name \*.php -exec php -l {} \; | ||
39 | + ## PHP Copy/Paste Detector | ||
40 | + - vendor/bin/phpcpd --verbose --exclude vendor ./ || true | ||
41 | + ## PHPLOC | ||
42 | + - vendor/bin/phploc --exclude vendor ./ | ||
43 | + ## PHPUNIT | ||
44 | + - vendor/bin/phpunit --coverage-clover=coverage.xml --configuration=phpunit.xml | ||
45 | + | ||
46 | +after_success: | ||
47 | + - bash <(curl -s https://codecov.io/bash) |
thinkphp/CONTRIBUTING.md
0 → 100644
1 | +如何贡献我的源代码 | ||
2 | +=== | ||
3 | + | ||
4 | +此文档介绍了 ThinkPHP 团队的组成以及运转机制,您提交的代码将给 ThinkPHP 项目带来什么好处,以及如何才能加入我们的行列。 | ||
5 | + | ||
6 | +## 通过 Github 贡献代码 | ||
7 | + | ||
8 | +ThinkPHP 目前使用 Git 来控制程序版本,如果你想为 ThinkPHP 贡献源代码,请先大致了解 Git 的使用方法。我们目前把项目托管在 GitHub 上,任何 GitHub 用户都可以向我们贡献代码。 | ||
9 | + | ||
10 | +参与的方式很简单,`fork`一份 ThinkPHP 的代码到你的仓库中,修改后提交,并向我们发起`pull request`申请,我们会及时对代码进行审查并处理你的申请。审查通过后,你的代码将被`merge`进我们的仓库中,这样你就会自动出现在贡献者名单里了,非常方便。 | ||
11 | + | ||
12 | +我们希望你贡献的代码符合: | ||
13 | + | ||
14 | +* ThinkPHP 的编码规范 | ||
15 | +* 适当的注释,能让其他人读懂 | ||
16 | +* 遵循 Apache2 开源协议 | ||
17 | + | ||
18 | +**如果想要了解更多细节或有任何疑问,请继续阅读下面的内容** | ||
19 | + | ||
20 | +### 注意事项 | ||
21 | + | ||
22 | +* 本项目代码格式化标准选用 [**PSR-2**](http://www.kancloud.cn/thinkphp/php-fig-psr/3141); | ||
23 | +* 类名和类文件名遵循 [**PSR-4**](http://www.kancloud.cn/thinkphp/php-fig-psr/3144); | ||
24 | +* 对于 Issues 的处理,请使用诸如 `fix #xxx(Issue ID)` 的 commit title 直接关闭 issue。 | ||
25 | +* 系统会自动在 PHP 5.4 5.5 5.6 7.0 和 HHVM 上测试修改,其中 HHVM 下的测试容许报错,请确保你的修改符合 PHP 5.4 ~ 5.6 和 PHP 7.0 的语法规范; | ||
26 | +* 管理员不会合并造成 CI faild 的修改,若出现 CI faild 请检查自己的源代码或修改相应的[单元测试文件](tests); | ||
27 | + | ||
28 | +## GitHub Issue | ||
29 | + | ||
30 | +GitHub 提供了 Issue 功能,该功能可以用于: | ||
31 | + | ||
32 | +* 提出 bug | ||
33 | +* 提出功能改进 | ||
34 | +* 反馈使用体验 | ||
35 | + | ||
36 | +该功能不应该用于: | ||
37 | + | ||
38 | + * 提出修改意见(涉及代码署名和修订追溯问题) | ||
39 | + * 不友善的言论 | ||
40 | + | ||
41 | +## 快速修改 | ||
42 | + | ||
43 | +**GitHub 提供了快速编辑文件的功能** | ||
44 | + | ||
45 | +1. 登录 GitHub 帐号; | ||
46 | +2. 浏览项目文件,找到要进行修改的文件; | ||
47 | +3. 点击右上角铅笔图标进行修改; | ||
48 | +4. 填写 `Commit changes` 相关内容(Title 必填); | ||
49 | +5. 提交修改,等待 CI 验证和管理员合并。 | ||
50 | + | ||
51 | +**若您需要一次提交大量修改,请继续阅读下面的内容** | ||
52 | + | ||
53 | +## 完整流程 | ||
54 | + | ||
55 | +1. `fork`本项目; | ||
56 | +2. 克隆(`clone`)你 `fork` 的项目到本地; | ||
57 | +3. 新建分支(`branch`)并检出(`checkout`)新分支; | ||
58 | +4. 添加本项目到你的本地 git 仓库作为上游(`upstream`); | ||
59 | +5. 进行修改,若你的修改包含方法或函数的增减,请记得修改[单元测试文件](tests); | ||
60 | +6. 变基(衍合 `rebase`)你的分支到上游 master 分支; | ||
61 | +7. `push` 你的本地仓库到 GitHub; | ||
62 | +8. 提交 `pull request`; | ||
63 | +9. 等待 CI 验证(若不通过则重复 5~7,不需要重新提交 `pull request`,GitHub 会自动更新你的 `pull request`); | ||
64 | +10. 等待管理员处理,并及时 `rebase` 你的分支到上游 master 分支(若上游 master 分支有修改)。 | ||
65 | + | ||
66 | +*若有必要,可以 `git push -f` 强行推送 rebase 后的分支到自己的 `fork`* | ||
67 | + | ||
68 | +*绝对不可以使用 `git push -f` 强行推送修改到上游* | ||
69 | + | ||
70 | +### 注意事项 | ||
71 | + | ||
72 | +* 若对上述流程有任何不清楚的地方,请查阅 GIT 教程,如 [这个](http://backlogtool.com/git-guide/cn/); | ||
73 | +* 对于代码**不同方面**的修改,请在自己 `fork` 的项目中**创建不同的分支**(原因参见`完整流程`第9条备注部分); | ||
74 | +* 变基及交互式变基操作参见 [Git 交互式变基](http://pakchoi.me/2015/03/17/git-interactive-rebase/) | ||
75 | + | ||
76 | +## 推荐资源 | ||
77 | + | ||
78 | +### 开发环境 | ||
79 | + | ||
80 | +* XAMPP for Windows 5.5.x | ||
81 | +* WampServer (for Windows) | ||
82 | +* upupw Apache PHP5.4 ( for Windows) | ||
83 | + | ||
84 | +或自行安装 | ||
85 | + | ||
86 | +- Apache / Nginx | ||
87 | +- PHP 5.4 ~ 5.6 | ||
88 | +- MySQL / MariaDB | ||
89 | + | ||
90 | +*Windows 用户推荐添加 PHP bin 目录到 PATH,方便使用 composer* | ||
91 | + | ||
92 | +*Linux 用户自行配置环境, Mac 用户推荐使用内置 Apache 配合 Homebrew 安装 PHP 和 MariaDB* | ||
93 | + | ||
94 | +### 编辑器 | ||
95 | + | ||
96 | +Sublime Text 3 + phpfmt 插件 | ||
97 | + | ||
98 | +phpfmt 插件参数 | ||
99 | + | ||
100 | +```json | ||
101 | +{ | ||
102 | + "autocomplete": true, | ||
103 | + "enable_auto_align": true, | ||
104 | + "format_on_save": true, | ||
105 | + "indent_with_space": true, | ||
106 | + "psr1_naming": false, | ||
107 | + "psr2": true, | ||
108 | + "version": 4 | ||
109 | +} | ||
110 | +``` | ||
111 | + | ||
112 | +或其他 编辑器 / IDE 配合 PSR2 自动格式化工具 | ||
113 | + | ||
114 | +### Git GUI | ||
115 | + | ||
116 | +* SourceTree | ||
117 | +* GitHub Desktop | ||
118 | + | ||
119 | +或其他 Git 图形界面客户端 |
thinkphp/LICENSE.txt
0 → 100644
1 | + | ||
2 | +ThinkPHP遵循Apache2开源协议发布,并提供免费使用。 | ||
3 | +版权所有Copyright © 2006-2017 by ThinkPHP (http://thinkphp.cn) | ||
4 | +All rights reserved。 | ||
5 | +ThinkPHP® 商标和著作权所有者为上海顶想信息科技有限公司。 | ||
6 | + | ||
7 | +Apache Licence是著名的非盈利开源组织Apache采用的协议。 | ||
8 | +该协议和BSD类似,鼓励代码共享和尊重原作者的著作权, | ||
9 | +允许代码修改,再作为开源或商业软件发布。需要满足 | ||
10 | +的条件: | ||
11 | +1. 需要给代码的用户一份Apache Licence ; | ||
12 | +2. 如果你修改了代码,需要在被修改的文件中说明; | ||
13 | +3. 在延伸的代码中(修改和有源代码衍生的代码中)需要 | ||
14 | +带有原来代码中的协议,商标,专利声明和其他原来作者规 | ||
15 | +定需要包含的说明; | ||
16 | +4. 如果再发布的产品中包含一个Notice文件,则在Notice文 | ||
17 | +件中需要带有本协议内容。你可以在Notice中增加自己的 | ||
18 | +许可,但不可以表现为对Apache Licence构成更改。 | ||
19 | +具体的协议参考:http://www.apache.org/licenses/LICENSE-2.0 | ||
20 | + | ||
21 | +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
22 | +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
23 | +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | ||
24 | +FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | ||
25 | +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | ||
26 | +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | ||
27 | +BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
28 | +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | ||
29 | +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | ||
30 | +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN | ||
31 | +ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
32 | +POSSIBILITY OF SUCH DAMAGE. |
thinkphp/README.md
0 → 100644
1 | +# ThinkPHP 5.0(FastAdmin 团队长期维护) | ||
2 | + | ||
3 | +## 维护原因 | ||
4 | + | ||
5 | +FastAdmin 致力于服务开发者,为开发者节省时间,为了 FastAdmin 开源项目持续发展下去。 | ||
6 | + | ||
7 | +## 参与开源 | ||
8 | + | ||
9 | +[贡献代码](https://doc.fastadmin.net/doc/contributing.html) | ||
10 | + | ||
11 | + | ||
12 | +## 使用方法 | ||
13 | + | ||
14 | +- 本框架已经应用在 FastAdmin 后台框架中,在 FastAdmin 项目中使用 `composer update topthink/framework -vvv` 命令即可更新。 | ||
15 | + | ||
16 | +- 非 FastAdmin 的 ThinkPHP5.0 项目使用此仓库,请修改 `composer.json` 添加以下配置,在执行`composer update topthink/framework -vvv` 命令,具体可以参考 FastAdmin 项目目录下的 `composer.json` 文件内容。 | ||
17 | + ``` | ||
18 | + "repositories": [ | ||
19 | + { | ||
20 | + "type": "git", | ||
21 | + "url": "https://gitee.com/fastadminnet/framework.git" | ||
22 | + } | ||
23 | + ] | ||
24 | + ``` | ||
25 | + | ||
26 | +## 环境要求 | ||
27 | + | ||
28 | +php 7.1+ | ||
29 | + | ||
30 | + | ||
31 | + | ||
32 | +## ThinkPHP 介绍 | ||
33 | + | ||
34 | +ThinkPHP5 在保持快速开发和大道至简的核心理念不变的同时,优化核心,减少依赖,基于全新的架构思想和命名空间实现,是 ThinkPHP 突破原有框架思路的颠覆之作,其主要特性包括: | ||
35 | + | ||
36 | + + 基于命名空间和众多PHP新特性 | ||
37 | + + 核心功能组件化 | ||
38 | + + 强化路由功能 | ||
39 | + + 更灵活的控制器 | ||
40 | + + 重构的模型和数据库类 | ||
41 | + + 配置文件可分离 | ||
42 | + + 重写的自动验证和完成 | ||
43 | + + 简化扩展机制 | ||
44 | + + API支持完善 | ||
45 | + + 改进的Log类 | ||
46 | + + 命令行访问支持 | ||
47 | + + REST支持 | ||
48 | + + 引导文件支持 | ||
49 | + + 方便的自动生成定义 | ||
50 | + + 真正惰性加载 | ||
51 | + + 分布式环境支持 | ||
52 | + + 支持Composer | ||
53 | + + 支持MongoDb | ||
54 | + | ||
55 | +详细开发文档参考 [ThinkPHP5完全开发手册](http://www.kancloud.cn/manual/thinkphp5) 以及[ThinkPHP5入门系列教程](http://www.kancloud.cn/special/thinkphp5_quickstart) | ||
56 | + | ||
57 | +## 版权信息 | ||
58 | + | ||
59 | +ThinkPHP遵循Apache2开源协议发布,并提供免费使用。 | ||
60 | + | ||
61 | +本项目包含的第三方源码和二进制文件之版权信息另行标注。 | ||
62 | + | ||
63 | +版权所有Copyright © 2006-2022 by ThinkPHP (http://thinkphp.cn) | ||
64 | + | ||
65 | +All rights reserved。 | ||
66 | + | ||
67 | +ThinkPHP® 商标和著作权所有者为上海顶想信息科技有限公司。 | ||
68 | + | ||
69 | +更多细节参阅 [LICENSE.txt](LICENSE.txt) |
thinkphp/base.php
0 → 100644
1 | +<?php | ||
2 | +// +---------------------------------------------------------------------- | ||
3 | +// | ThinkPHP [ WE CAN DO IT JUST THINK ] | ||
4 | +// +---------------------------------------------------------------------- | ||
5 | +// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. | ||
6 | +// +---------------------------------------------------------------------- | ||
7 | +// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) | ||
8 | +// +---------------------------------------------------------------------- | ||
9 | +// | Author: liu21st <liu21st@gmail.com> | ||
10 | +// +---------------------------------------------------------------------- | ||
11 | + | ||
12 | +define('THINK_VERSION', '5.0.25'); | ||
13 | +define('THINK_START_TIME', microtime(true)); | ||
14 | +define('THINK_START_MEM', memory_get_usage()); | ||
15 | +define('EXT', '.php'); | ||
16 | +define('DS', DIRECTORY_SEPARATOR); | ||
17 | +defined('THINK_PATH') or define('THINK_PATH', __DIR__ . DS); | ||
18 | +define('LIB_PATH', THINK_PATH . 'library' . DS); | ||
19 | +define('CORE_PATH', LIB_PATH . 'think' . DS); | ||
20 | +define('TRAIT_PATH', LIB_PATH . 'traits' . DS); | ||
21 | +defined('APP_PATH') or define('APP_PATH', dirname($_SERVER['SCRIPT_FILENAME']) . DS); | ||
22 | +defined('ROOT_PATH') or define('ROOT_PATH', dirname(realpath(APP_PATH)) . DS); | ||
23 | +defined('EXTEND_PATH') or define('EXTEND_PATH', ROOT_PATH . 'extend' . DS); | ||
24 | +defined('VENDOR_PATH') or define('VENDOR_PATH', ROOT_PATH . 'vendor' . DS); | ||
25 | +defined('RUNTIME_PATH') or define('RUNTIME_PATH', ROOT_PATH . 'runtime' . DS); | ||
26 | +defined('LOG_PATH') or define('LOG_PATH', RUNTIME_PATH . 'log' . DS); | ||
27 | +defined('CACHE_PATH') or define('CACHE_PATH', RUNTIME_PATH . 'cache' . DS); | ||
28 | +defined('TEMP_PATH') or define('TEMP_PATH', RUNTIME_PATH . 'temp' . DS); | ||
29 | +defined('CONF_PATH') or define('CONF_PATH', APP_PATH); // 配置文件目录 | ||
30 | +defined('CONF_EXT') or define('CONF_EXT', EXT); // 配置文件后缀 | ||
31 | +defined('ENV_PREFIX') or define('ENV_PREFIX', 'PHP_'); // 环境变量的配置前缀 | ||
32 | + | ||
33 | +// 环境常量 | ||
34 | +define('IS_CLI', PHP_SAPI == 'cli' ? true : false); | ||
35 | +define('IS_WIN', strpos(PHP_OS, 'WIN') !== false); | ||
36 | + | ||
37 | +// 载入Loader类 | ||
38 | +require CORE_PATH . 'Loader.php'; | ||
39 | + | ||
40 | +// 加载环境变量配置文件 | ||
41 | +if (is_file(ROOT_PATH . '.env')) { | ||
42 | + $env = parse_ini_file(ROOT_PATH . '.env', true); | ||
43 | + | ||
44 | + foreach ($env as $key => $val) { | ||
45 | + $name = ENV_PREFIX . strtoupper($key); | ||
46 | + | ||
47 | + if (is_array($val)) { | ||
48 | + foreach ($val as $k => $v) { | ||
49 | + $item = $name . '_' . strtoupper($k); | ||
50 | + putenv("$item=$v"); | ||
51 | + } | ||
52 | + } else { | ||
53 | + putenv("$name=$val"); | ||
54 | + } | ||
55 | + } | ||
56 | +} | ||
57 | + | ||
58 | +// 注册自动加载 | ||
59 | +\think\Loader::register(); | ||
60 | + | ||
61 | +// 注册错误和异常处理机制 | ||
62 | +\think\Error::register(); | ||
63 | + | ||
64 | +// 加载惯例配置文件 | ||
65 | +\think\Config::set(include THINK_PATH . 'convention' . EXT); |
thinkphp/codecov.yml
0 → 100644
thinkphp/composer.json
0 → 100644
1 | +{ | ||
2 | + "name": "topthink/framework", | ||
3 | + "description": "the new thinkphp framework", | ||
4 | + "type": "think-framework", | ||
5 | + "keywords": [ | ||
6 | + "framework", | ||
7 | + "thinkphp", | ||
8 | + "ORM" | ||
9 | + ], | ||
10 | + "homepage": "http://thinkphp.cn/", | ||
11 | + "license": "Apache-2.0", | ||
12 | + "authors": [ | ||
13 | + { | ||
14 | + "name": "liu21st", | ||
15 | + "email": "liu21st@gmail.com" | ||
16 | + } | ||
17 | + ], | ||
18 | + "require": { | ||
19 | + "php": ">=7.1.0", | ||
20 | + "topthink/think-installer": "~1.0" | ||
21 | + }, | ||
22 | + "require-dev": { | ||
23 | + "phpunit/phpunit": "4.8.*", | ||
24 | + "johnkary/phpunit-speedtrap": "^1.0", | ||
25 | + "mikey179/vfsstream": "~1.6", | ||
26 | + "phploc/phploc": "2.*", | ||
27 | + "sebastian/phpcpd": "2.*", | ||
28 | + "phpdocumentor/reflection-docblock": "^2.0" | ||
29 | + }, | ||
30 | + "autoload": { | ||
31 | + "psr-4": { | ||
32 | + "think\\": "library/think" | ||
33 | + } | ||
34 | + } | ||
35 | +} |
thinkphp/console.php
0 → 100644
1 | +<?php | ||
2 | +// +---------------------------------------------------------------------- | ||
3 | +// | ThinkPHP [ WE CAN DO IT JUST THINK IT ] | ||
4 | +// +---------------------------------------------------------------------- | ||
5 | +// | Copyright (c) 2006-2017 http://thinkphp.cn All rights reserved. | ||
6 | +// +---------------------------------------------------------------------- | ||
7 | +// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) | ||
8 | +// +---------------------------------------------------------------------- | ||
9 | +// | Author: yunwuxin <448901948@qq.com> | ||
10 | +// +---------------------------------------------------------------------- | ||
11 | + | ||
12 | +namespace think; | ||
13 | + | ||
14 | +// ThinkPHP 引导文件 | ||
15 | +// 加载基础文件 | ||
16 | +require __DIR__ . '/base.php'; | ||
17 | + | ||
18 | +// 执行应用 | ||
19 | +App::initCommon(); | ||
20 | +Console::init(); |
thinkphp/convention.php
0 → 100644
1 | +<?php | ||
2 | + | ||
3 | +return [ | ||
4 | + // +---------------------------------------------------------------------- | ||
5 | + // | 应用设置 | ||
6 | + // +---------------------------------------------------------------------- | ||
7 | + // 默认Host地址 | ||
8 | + 'app_host' => '', | ||
9 | + // 应用调试模式 | ||
10 | + 'app_debug' => false, | ||
11 | + // 应用Trace | ||
12 | + 'app_trace' => false, | ||
13 | + // 应用模式状态 | ||
14 | + 'app_status' => '', | ||
15 | + // 是否支持多模块 | ||
16 | + 'app_multi_module' => true, | ||
17 | + // 入口自动绑定模块 | ||
18 | + 'auto_bind_module' => false, | ||
19 | + // 注册的根命名空间 | ||
20 | + 'root_namespace' => [], | ||
21 | + // 扩展函数文件 | ||
22 | + 'extra_file_list' => [THINK_PATH . 'helper' . EXT], | ||
23 | + // 默认输出类型 | ||
24 | + 'default_return_type' => 'html', | ||
25 | + // 默认AJAX 数据返回格式,可选json xml ... | ||
26 | + 'default_ajax_return' => 'json', | ||
27 | + // 默认JSONP格式返回的处理方法 | ||
28 | + 'default_jsonp_handler' => 'jsonpReturn', | ||
29 | + // 默认JSONP处理方法 | ||
30 | + 'var_jsonp_handler' => 'callback', | ||
31 | + // 默认时区 | ||
32 | + 'default_timezone' => 'PRC', | ||
33 | + // 是否开启多语言 | ||
34 | + 'lang_switch_on' => false, | ||
35 | + // 默认全局过滤方法 用逗号分隔多个 | ||
36 | + 'default_filter' => '', | ||
37 | + // 默认语言 | ||
38 | + 'default_lang' => 'zh-cn', | ||
39 | + // 应用类库后缀 | ||
40 | + 'class_suffix' => false, | ||
41 | + // 控制器类后缀 | ||
42 | + 'controller_suffix' => false, | ||
43 | + | ||
44 | + // +---------------------------------------------------------------------- | ||
45 | + // | 模块设置 | ||
46 | + // +---------------------------------------------------------------------- | ||
47 | + | ||
48 | + // 默认模块名 | ||
49 | + 'default_module' => 'index', | ||
50 | + // 禁止访问模块 | ||
51 | + 'deny_module_list' => ['common'], | ||
52 | + // 默认控制器名 | ||
53 | + 'default_controller' => 'Index', | ||
54 | + // 默认操作名 | ||
55 | + 'default_action' => 'index', | ||
56 | + // 默认验证器 | ||
57 | + 'default_validate' => '', | ||
58 | + // 默认的空控制器名 | ||
59 | + 'empty_controller' => 'Error', | ||
60 | + // 操作方法前缀 | ||
61 | + 'use_action_prefix' => false, | ||
62 | + // 操作方法后缀 | ||
63 | + 'action_suffix' => '', | ||
64 | + // 自动搜索控制器 | ||
65 | + 'controller_auto_search' => false, | ||
66 | + | ||
67 | + // +---------------------------------------------------------------------- | ||
68 | + // | URL设置 | ||
69 | + // +---------------------------------------------------------------------- | ||
70 | + | ||
71 | + // PATHINFO变量名 用于兼容模式 | ||
72 | + 'var_pathinfo' => 's', | ||
73 | + // 兼容PATH_INFO获取 | ||
74 | + 'pathinfo_fetch' => ['ORIG_PATH_INFO', 'REDIRECT_PATH_INFO', 'REDIRECT_URL'], | ||
75 | + // pathinfo分隔符 | ||
76 | + 'pathinfo_depr' => '/', | ||
77 | + // HTTPS代理标识 | ||
78 | + 'https_agent_name' => '', | ||
79 | + // URL伪静态后缀 | ||
80 | + 'url_html_suffix' => 'html', | ||
81 | + // URL普通方式参数 用于自动生成 | ||
82 | + 'url_common_param' => false, | ||
83 | + // URL参数方式 0 按名称成对解析 1 按顺序解析 | ||
84 | + 'url_param_type' => 0, | ||
85 | + // 是否开启路由 | ||
86 | + 'url_route_on' => true, | ||
87 | + // 路由配置文件(支持配置多个) | ||
88 | + 'route_config_file' => ['route'], | ||
89 | + // 路由使用完整匹配 | ||
90 | + 'route_complete_match' => false, | ||
91 | + // 是否强制使用路由 | ||
92 | + 'url_route_must' => false, | ||
93 | + // 域名部署 | ||
94 | + 'url_domain_deploy' => false, | ||
95 | + // 域名根,如thinkphp.cn | ||
96 | + 'url_domain_root' => '', | ||
97 | + // 是否自动转换URL中的控制器和操作名 | ||
98 | + 'url_convert' => true, | ||
99 | + // 默认的访问控制器层 | ||
100 | + 'url_controller_layer' => 'controller', | ||
101 | + // 表单请求类型伪装变量 | ||
102 | + 'var_method' => '_method', | ||
103 | + // 表单ajax伪装变量 | ||
104 | + 'var_ajax' => '_ajax', | ||
105 | + // 表单pjax伪装变量 | ||
106 | + 'var_pjax' => '_pjax', | ||
107 | + // 是否开启请求缓存 true自动缓存 支持设置请求缓存规则 | ||
108 | + 'request_cache' => false, | ||
109 | + // 请求缓存有效期 | ||
110 | + 'request_cache_expire' => null, | ||
111 | + // 全局请求缓存排除规则 | ||
112 | + 'request_cache_except' => [], | ||
113 | + | ||
114 | + // +---------------------------------------------------------------------- | ||
115 | + // | 模板设置 | ||
116 | + // +---------------------------------------------------------------------- | ||
117 | + | ||
118 | + 'template' => [ | ||
119 | + // 默认模板渲染规则 1 解析为小写+下划线 2 全部转换小写 | ||
120 | + 'auto_rule' => 1, | ||
121 | + // 模板引擎类型 支持 php think 支持扩展 | ||
122 | + 'type' => 'Think', | ||
123 | + // 视图基础目录,配置目录为所有模块的视图起始目录 | ||
124 | + 'view_base' => '', | ||
125 | + // 当前模板的视图目录 留空为自动获取 | ||
126 | + 'view_path' => '', | ||
127 | + // 模板后缀 | ||
128 | + 'view_suffix' => 'html', | ||
129 | + // 模板文件名分隔符 | ||
130 | + 'view_depr' => DS, | ||
131 | + // 模板引擎普通标签开始标记 | ||
132 | + 'tpl_begin' => '{', | ||
133 | + // 模板引擎普通标签结束标记 | ||
134 | + 'tpl_end' => '}', | ||
135 | + // 标签库标签开始标记 | ||
136 | + 'taglib_begin' => '{', | ||
137 | + // 标签库标签结束标记 | ||
138 | + 'taglib_end' => '}', | ||
139 | + ], | ||
140 | + | ||
141 | + // 视图输出字符串内容替换 | ||
142 | + 'view_replace_str' => [], | ||
143 | + // 默认跳转页面对应的模板文件 | ||
144 | + 'dispatch_success_tmpl' => THINK_PATH . 'tpl' . DS . 'dispatch_jump.tpl', | ||
145 | + 'dispatch_error_tmpl' => THINK_PATH . 'tpl' . DS . 'dispatch_jump.tpl', | ||
146 | + | ||
147 | + // +---------------------------------------------------------------------- | ||
148 | + // | 异常及错误设置 | ||
149 | + // +---------------------------------------------------------------------- | ||
150 | + | ||
151 | + // 异常页面的模板文件 | ||
152 | + 'exception_tmpl' => THINK_PATH . 'tpl' . DS . 'think_exception.tpl', | ||
153 | + | ||
154 | + // 错误显示信息,非调试模式有效 | ||
155 | + 'error_message' => '页面错误!请稍后再试~', | ||
156 | + // 显示错误信息 | ||
157 | + 'show_error_msg' => false, | ||
158 | + // 异常处理handle类 留空使用 \think\exception\Handle | ||
159 | + 'exception_handle' => '', | ||
160 | + // 是否记录trace信息到日志 | ||
161 | + 'record_trace' => false, | ||
162 | + | ||
163 | + // +---------------------------------------------------------------------- | ||
164 | + // | 日志设置 | ||
165 | + // +---------------------------------------------------------------------- | ||
166 | + | ||
167 | + 'log' => [ | ||
168 | + // 日志记录方式,内置 file socket 支持扩展 | ||
169 | + 'type' => 'File', | ||
170 | + // 日志保存目录 | ||
171 | + 'path' => LOG_PATH, | ||
172 | + // 日志记录级别 | ||
173 | + 'level' => [], | ||
174 | + ], | ||
175 | + | ||
176 | + // +---------------------------------------------------------------------- | ||
177 | + // | Trace设置 开启 app_trace 后 有效 | ||
178 | + // +---------------------------------------------------------------------- | ||
179 | + 'trace' => [ | ||
180 | + // 内置Html Console 支持扩展 | ||
181 | + 'type' => 'Html', | ||
182 | + ], | ||
183 | + | ||
184 | + // +---------------------------------------------------------------------- | ||
185 | + // | 缓存设置 | ||
186 | + // +---------------------------------------------------------------------- | ||
187 | + | ||
188 | + 'cache' => [ | ||
189 | + // 驱动方式 | ||
190 | + 'type' => 'File', | ||
191 | + // 缓存保存目录 | ||
192 | + 'path' => CACHE_PATH, | ||
193 | + // 缓存前缀 | ||
194 | + 'prefix' => '', | ||
195 | + // 缓存有效期 0表示永久缓存 | ||
196 | + 'expire' => 0, | ||
197 | + ], | ||
198 | + | ||
199 | + // +---------------------------------------------------------------------- | ||
200 | + // | 会话设置 | ||
201 | + // +---------------------------------------------------------------------- | ||
202 | + | ||
203 | + 'session' => [ | ||
204 | + 'id' => '', | ||
205 | + // SESSION_ID的提交变量,解决flash上传跨域 | ||
206 | + 'var_session_id' => '', | ||
207 | + // SESSION 前缀 | ||
208 | + 'prefix' => 'think', | ||
209 | + // 驱动方式 支持redis memcache memcached | ||
210 | + 'type' => '', | ||
211 | + // 是否自动开启 SESSION | ||
212 | + 'auto_start' => true, | ||
213 | + 'httponly' => true, | ||
214 | + 'secure' => false, | ||
215 | + ], | ||
216 | + | ||
217 | + // +---------------------------------------------------------------------- | ||
218 | + // | Cookie设置 | ||
219 | + // +---------------------------------------------------------------------- | ||
220 | + 'cookie' => [ | ||
221 | + // cookie 名称前缀 | ||
222 | + 'prefix' => '', | ||
223 | + // cookie 保存时间 | ||
224 | + 'expire' => 0, | ||
225 | + // cookie 保存路径 | ||
226 | + 'path' => '/', | ||
227 | + // cookie 有效域名 | ||
228 | + 'domain' => '', | ||
229 | + // cookie 启用安全传输 | ||
230 | + 'secure' => false, | ||
231 | + // httponly设置 | ||
232 | + 'httponly' => '', | ||
233 | + // 是否使用 setcookie | ||
234 | + 'setcookie' => true, | ||
235 | + ], | ||
236 | + | ||
237 | + // +---------------------------------------------------------------------- | ||
238 | + // | 数据库设置 | ||
239 | + // +---------------------------------------------------------------------- | ||
240 | + | ||
241 | + 'database' => [ | ||
242 | + // 数据库类型 | ||
243 | + 'type' => 'mysql', | ||
244 | + // 数据库连接DSN配置 | ||
245 | + 'dsn' => '', | ||
246 | + // 服务器地址 | ||
247 | + 'hostname' => '127.0.0.1', | ||
248 | + // 数据库名 | ||
249 | + 'database' => '', | ||
250 | + // 数据库用户名 | ||
251 | + 'username' => 'root', | ||
252 | + // 数据库密码 | ||
253 | + 'password' => '', | ||
254 | + // 数据库连接端口 | ||
255 | + 'hostport' => '', | ||
256 | + // 数据库连接参数 | ||
257 | + 'params' => [], | ||
258 | + // 数据库编码默认采用utf8 | ||
259 | + 'charset' => 'utf8', | ||
260 | + // 数据库表前缀 | ||
261 | + 'prefix' => '', | ||
262 | + // 数据库调试模式 | ||
263 | + 'debug' => false, | ||
264 | + // 数据库部署方式:0 集中式(单一服务器),1 分布式(主从服务器) | ||
265 | + 'deploy' => 0, | ||
266 | + // 数据库读写是否分离 主从式有效 | ||
267 | + 'rw_separate' => false, | ||
268 | + // 读写分离后 主服务器数量 | ||
269 | + 'master_num' => 1, | ||
270 | + // 指定从服务器序号 | ||
271 | + 'slave_no' => '', | ||
272 | + // 是否严格检查字段是否存在 | ||
273 | + 'fields_strict' => true, | ||
274 | + // 数据集返回类型 | ||
275 | + 'resultset_type' => 'array', | ||
276 | + // 自动写入时间戳字段 | ||
277 | + 'auto_timestamp' => false, | ||
278 | + // 时间字段取出后的默认时间格式 | ||
279 | + 'datetime_format' => 'Y-m-d H:i:s', | ||
280 | + // 是否需要进行SQL性能分析 | ||
281 | + 'sql_explain' => false, | ||
282 | + ], | ||
283 | + | ||
284 | + //分页配置 | ||
285 | + 'paginate' => [ | ||
286 | + 'type' => 'bootstrap', | ||
287 | + 'var_page' => 'page', | ||
288 | + 'list_rows' => 15, | ||
289 | + ], | ||
290 | + | ||
291 | + //控制台配置 | ||
292 | + 'console' => [ | ||
293 | + 'name' => 'Think Console', | ||
294 | + 'version' => '0.1', | ||
295 | + 'user' => null, | ||
296 | + ], | ||
297 | + | ||
298 | +]; |
thinkphp/helper.php
0 → 100644
1 | +<?php | ||
2 | +// +---------------------------------------------------------------------- | ||
3 | +// | ThinkPHP [ WE CAN DO IT JUST THINK ] | ||
4 | +// +---------------------------------------------------------------------- | ||
5 | +// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. | ||
6 | +// +---------------------------------------------------------------------- | ||
7 | +// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) | ||
8 | +// +---------------------------------------------------------------------- | ||
9 | +// | Author: liu21st <liu21st@gmail.com> | ||
10 | +// +---------------------------------------------------------------------- | ||
11 | + | ||
12 | +//------------------------ | ||
13 | +// ThinkPHP 助手函数 | ||
14 | +//------------------------- | ||
15 | + | ||
16 | +use think\Cache; | ||
17 | +use think\Config; | ||
18 | +use think\Cookie; | ||
19 | +use think\Db; | ||
20 | +use think\Debug; | ||
21 | +use think\exception\HttpException; | ||
22 | +use think\exception\HttpResponseException; | ||
23 | +use think\Lang; | ||
24 | +use think\Loader; | ||
25 | +use think\Log; | ||
26 | +use think\Model; | ||
27 | +use think\Request; | ||
28 | +use think\Response; | ||
29 | +use think\Session; | ||
30 | +use think\Url; | ||
31 | +use think\View; | ||
32 | + | ||
33 | +if (!function_exists('load_trait')) { | ||
34 | + /** | ||
35 | + * 快速导入Traits PHP5.5以上无需调用 | ||
36 | + * @param string $class trait库 | ||
37 | + * @param string $ext 类库后缀 | ||
38 | + * @return boolean | ||
39 | + */ | ||
40 | + function load_trait($class, $ext = EXT) | ||
41 | + { | ||
42 | + return Loader::import($class, TRAIT_PATH, $ext); | ||
43 | + } | ||
44 | +} | ||
45 | + | ||
46 | +if (!function_exists('exception')) { | ||
47 | + /** | ||
48 | + * 抛出异常处理 | ||
49 | + * | ||
50 | + * @param string $msg 异常消息 | ||
51 | + * @param integer $code 异常代码 默认为0 | ||
52 | + * @param string $exception 异常类 | ||
53 | + * | ||
54 | + * @throws Exception | ||
55 | + */ | ||
56 | + function exception($msg, $code = 0, $exception = '') | ||
57 | + { | ||
58 | + $e = $exception ?: '\think\Exception'; | ||
59 | + throw new $e($msg, $code); | ||
60 | + } | ||
61 | +} | ||
62 | + | ||
63 | +if (!function_exists('debug')) { | ||
64 | + /** | ||
65 | + * 记录时间(微秒)和内存使用情况 | ||
66 | + * @param string $start 开始标签 | ||
67 | + * @param string $end 结束标签 | ||
68 | + * @param integer|string $dec 小数位 如果是m 表示统计内存占用 | ||
69 | + * @return mixed | ||
70 | + */ | ||
71 | + function debug($start, $end = '', $dec = 6) | ||
72 | + { | ||
73 | + if ('' == $end) { | ||
74 | + Debug::remark($start); | ||
75 | + } else { | ||
76 | + return 'm' == $dec ? Debug::getRangeMem($start, $end) : Debug::getRangeTime($start, $end, $dec); | ||
77 | + } | ||
78 | + } | ||
79 | +} | ||
80 | + | ||
81 | +if (!function_exists('lang')) { | ||
82 | + /** | ||
83 | + * 获取语言变量值 | ||
84 | + * @param string $name 语言变量名 | ||
85 | + * @param array $vars 动态变量值 | ||
86 | + * @param string $lang 语言 | ||
87 | + * @return mixed | ||
88 | + */ | ||
89 | + function lang($name, $vars = [], $lang = '') | ||
90 | + { | ||
91 | + return Lang::get($name, $vars, $lang); | ||
92 | + } | ||
93 | +} | ||
94 | + | ||
95 | +if (!function_exists('config')) { | ||
96 | + /** | ||
97 | + * 获取和设置配置参数 | ||
98 | + * @param string|array $name 参数名 | ||
99 | + * @param mixed $value 参数值 | ||
100 | + * @param string $range 作用域 | ||
101 | + * @return mixed | ||
102 | + */ | ||
103 | + function config($name = '', $value = null, $range = '') | ||
104 | + { | ||
105 | + if (is_null($value) && is_string($name)) { | ||
106 | + return 0 === strpos($name, '?') ? Config::has(substr($name, 1), $range) : Config::get($name, $range); | ||
107 | + } else { | ||
108 | + return Config::set($name, $value, $range); | ||
109 | + } | ||
110 | + } | ||
111 | +} | ||
112 | + | ||
113 | +if (!function_exists('input')) { | ||
114 | + /** | ||
115 | + * 获取输入数据 支持默认值和过滤 | ||
116 | + * @param string $key 获取的变量名 | ||
117 | + * @param mixed $default 默认值 | ||
118 | + * @param string $filter 过滤方法 | ||
119 | + * @return mixed | ||
120 | + */ | ||
121 | + function input($key = '', $default = null, $filter = '') | ||
122 | + { | ||
123 | + if (0 === strpos($key, '?')) { | ||
124 | + $key = substr($key, 1); | ||
125 | + $has = true; | ||
126 | + } | ||
127 | + if ($pos = strpos($key, '.')) { | ||
128 | + // 指定参数来源 | ||
129 | + list($method, $key) = explode('.', $key, 2); | ||
130 | + if (!in_array($method, ['get', 'post', 'put', 'patch', 'delete', 'route', 'param', 'request', 'session', 'cookie', 'server', 'env', 'path', 'file'])) { | ||
131 | + $key = $method . '.' . $key; | ||
132 | + $method = 'param'; | ||
133 | + } | ||
134 | + } else { | ||
135 | + // 默认为自动判断 | ||
136 | + $method = 'param'; | ||
137 | + } | ||
138 | + if (isset($has)) { | ||
139 | + return request()->has($key, $method, $default); | ||
140 | + } else { | ||
141 | + return request()->$method($key, $default, $filter); | ||
142 | + } | ||
143 | + } | ||
144 | +} | ||
145 | + | ||
146 | +if (!function_exists('widget')) { | ||
147 | + /** | ||
148 | + * 渲染输出Widget | ||
149 | + * @param string $name Widget名称 | ||
150 | + * @param array $data 传入的参数 | ||
151 | + * @return mixed | ||
152 | + */ | ||
153 | + function widget($name, $data = []) | ||
154 | + { | ||
155 | + return Loader::action($name, $data, 'widget'); | ||
156 | + } | ||
157 | +} | ||
158 | + | ||
159 | +if (!function_exists('model')) { | ||
160 | + /** | ||
161 | + * 实例化Model | ||
162 | + * @param string $name Model名称 | ||
163 | + * @param string $layer 业务层名称 | ||
164 | + * @param bool $appendSuffix 是否添加类名后缀 | ||
165 | + * @return \think\Model | ||
166 | + */ | ||
167 | + function model($name = '', $layer = 'model', $appendSuffix = false) | ||
168 | + { | ||
169 | + return Loader::model($name, $layer, $appendSuffix); | ||
170 | + } | ||
171 | +} | ||
172 | + | ||
173 | +if (!function_exists('validate')) { | ||
174 | + /** | ||
175 | + * 实例化验证器 | ||
176 | + * @param string $name 验证器名称 | ||
177 | + * @param string $layer 业务层名称 | ||
178 | + * @param bool $appendSuffix 是否添加类名后缀 | ||
179 | + * @return \think\Validate | ||
180 | + */ | ||
181 | + function validate($name = '', $layer = 'validate', $appendSuffix = false) | ||
182 | + { | ||
183 | + return Loader::validate($name, $layer, $appendSuffix); | ||
184 | + } | ||
185 | +} | ||
186 | + | ||
187 | +if (!function_exists('db')) { | ||
188 | + /** | ||
189 | + * 实例化数据库类 | ||
190 | + * @param string $name 操作的数据表名称(不含前缀) | ||
191 | + * @param array|string $config 数据库配置参数 | ||
192 | + * @param bool $force 是否强制重新连接 | ||
193 | + * @return \think\db\Query | ||
194 | + */ | ||
195 | + function db($name = '', $config = [], $force = false) | ||
196 | + { | ||
197 | + return Db::connect($config, $force)->name($name); | ||
198 | + } | ||
199 | +} | ||
200 | + | ||
201 | +if (!function_exists('controller')) { | ||
202 | + /** | ||
203 | + * 实例化控制器 格式:[模块/]控制器 | ||
204 | + * @param string $name 资源地址 | ||
205 | + * @param string $layer 控制层名称 | ||
206 | + * @param bool $appendSuffix 是否添加类名后缀 | ||
207 | + * @return \think\Controller | ||
208 | + */ | ||
209 | + function controller($name, $layer = 'controller', $appendSuffix = false) | ||
210 | + { | ||
211 | + return Loader::controller($name, $layer, $appendSuffix); | ||
212 | + } | ||
213 | +} | ||
214 | + | ||
215 | +if (!function_exists('action')) { | ||
216 | + /** | ||
217 | + * 调用模块的操作方法 参数格式 [模块/控制器/]操作 | ||
218 | + * @param string $url 调用地址 | ||
219 | + * @param string|array $vars 调用参数 支持字符串和数组 | ||
220 | + * @param string $layer 要调用的控制层名称 | ||
221 | + * @param bool $appendSuffix 是否添加类名后缀 | ||
222 | + * @return mixed | ||
223 | + */ | ||
224 | + function action($url, $vars = [], $layer = 'controller', $appendSuffix = false) | ||
225 | + { | ||
226 | + return Loader::action($url, $vars, $layer, $appendSuffix); | ||
227 | + } | ||
228 | +} | ||
229 | + | ||
230 | +if (!function_exists('import')) { | ||
231 | + /** | ||
232 | + * 导入所需的类库 同java的Import 本函数有缓存功能 | ||
233 | + * @param string $class 类库命名空间字符串 | ||
234 | + * @param string $baseUrl 起始路径 | ||
235 | + * @param string $ext 导入的文件扩展名 | ||
236 | + * @return boolean | ||
237 | + */ | ||
238 | + function import($class, $baseUrl = '', $ext = EXT) | ||
239 | + { | ||
240 | + return Loader::import($class, $baseUrl, $ext); | ||
241 | + } | ||
242 | +} | ||
243 | + | ||
244 | +if (!function_exists('vendor')) { | ||
245 | + /** | ||
246 | + * 快速导入第三方框架类库 所有第三方框架的类库文件统一放到 系统的Vendor目录下面 | ||
247 | + * @param string $class 类库 | ||
248 | + * @param string $ext 类库后缀 | ||
249 | + * @return boolean | ||
250 | + */ | ||
251 | + function vendor($class, $ext = EXT) | ||
252 | + { | ||
253 | + return Loader::import($class, VENDOR_PATH, $ext); | ||
254 | + } | ||
255 | +} | ||
256 | + | ||
257 | +if (!function_exists('dump')) { | ||
258 | + /** | ||
259 | + * 浏览器友好的变量输出 | ||
260 | + * @param mixed $var 变量 | ||
261 | + * @param boolean $echo 是否输出 默认为true 如果为false 则返回输出字符串 | ||
262 | + * @param string $label 标签 默认为空 | ||
263 | + * @return void|string | ||
264 | + */ | ||
265 | + function dump($var, $echo = true, $label = null) | ||
266 | + { | ||
267 | + return Debug::dump($var, $echo, $label); | ||
268 | + } | ||
269 | +} | ||
270 | + | ||
271 | +if (!function_exists('url')) { | ||
272 | + /** | ||
273 | + * Url生成 | ||
274 | + * @param string $url 路由地址 | ||
275 | + * @param string|array $vars 变量 | ||
276 | + * @param bool|string $suffix 生成的URL后缀 | ||
277 | + * @param bool|string $domain 域名 | ||
278 | + * @return string | ||
279 | + */ | ||
280 | + function url($url = '', $vars = '', $suffix = true, $domain = false) | ||
281 | + { | ||
282 | + return Url::build($url, $vars, $suffix, $domain); | ||
283 | + } | ||
284 | +} | ||
285 | + | ||
286 | +if (!function_exists('session')) { | ||
287 | + /** | ||
288 | + * Session管理 | ||
289 | + * @param string|array $name session名称,如果为数组表示进行session设置 | ||
290 | + * @param mixed $value session值 | ||
291 | + * @param string $prefix 前缀 | ||
292 | + * @return mixed | ||
293 | + */ | ||
294 | + function session($name, $value = '', $prefix = null) | ||
295 | + { | ||
296 | + if (is_array($name)) { | ||
297 | + // 初始化 | ||
298 | + Session::init($name); | ||
299 | + } elseif (is_null($name)) { | ||
300 | + // 清除 | ||
301 | + Session::clear('' === $value ? null : $value); | ||
302 | + } elseif ('' === $value) { | ||
303 | + // 判断或获取 | ||
304 | + return 0 === strpos($name, '?') ? Session::has(substr($name, 1), $prefix) : Session::get($name, $prefix); | ||
305 | + } elseif (is_null($value)) { | ||
306 | + // 删除 | ||
307 | + return Session::delete($name, $prefix); | ||
308 | + } else { | ||
309 | + // 设置 | ||
310 | + return Session::set($name, $value, $prefix); | ||
311 | + } | ||
312 | + } | ||
313 | +} | ||
314 | + | ||
315 | +if (!function_exists('cookie')) { | ||
316 | + /** | ||
317 | + * Cookie管理 | ||
318 | + * @param string|array $name cookie名称,如果为数组表示进行cookie设置 | ||
319 | + * @param mixed $value cookie值 | ||
320 | + * @param mixed $option 参数 | ||
321 | + * @return mixed | ||
322 | + */ | ||
323 | + function cookie($name, $value = '', $option = null) | ||
324 | + { | ||
325 | + if (is_array($name)) { | ||
326 | + // 初始化 | ||
327 | + Cookie::init($name); | ||
328 | + } elseif (is_null($name)) { | ||
329 | + // 清除 | ||
330 | + Cookie::clear($value); | ||
331 | + } elseif ('' === $value) { | ||
332 | + // 获取 | ||
333 | + return 0 === strpos($name, '?') ? Cookie::has(substr($name, 1), $option) : Cookie::get($name, $option); | ||
334 | + } elseif (is_null($value)) { | ||
335 | + // 删除 | ||
336 | + return Cookie::delete($name); | ||
337 | + } else { | ||
338 | + // 设置 | ||
339 | + return Cookie::set($name, $value, $option); | ||
340 | + } | ||
341 | + } | ||
342 | +} | ||
343 | + | ||
344 | +if (!function_exists('cache')) { | ||
345 | + /** | ||
346 | + * 缓存管理 | ||
347 | + * @param mixed $name 缓存名称,如果为数组表示进行缓存设置 | ||
348 | + * @param mixed $value 缓存值 | ||
349 | + * @param mixed $options 缓存参数 | ||
350 | + * @param string $tag 缓存标签 | ||
351 | + * @return mixed | ||
352 | + */ | ||
353 | + function cache($name, $value = '', $options = null, $tag = null) | ||
354 | + { | ||
355 | + if (is_array($options)) { | ||
356 | + // 缓存操作的同时初始化 | ||
357 | + $cache = Cache::connect($options); | ||
358 | + } elseif (is_array($name)) { | ||
359 | + // 缓存初始化 | ||
360 | + return Cache::connect($name); | ||
361 | + } else { | ||
362 | + $cache = Cache::init(); | ||
363 | + } | ||
364 | + | ||
365 | + if (is_null($name)) { | ||
366 | + return $cache->clear($value); | ||
367 | + } elseif ('' === $value) { | ||
368 | + // 获取缓存 | ||
369 | + return 0 === strpos($name, '?') ? $cache->has(substr($name, 1)) : $cache->get($name); | ||
370 | + } elseif (is_null($value)) { | ||
371 | + // 删除缓存 | ||
372 | + return $cache->rm($name); | ||
373 | + } elseif (0 === strpos($name, '?') && '' !== $value) { | ||
374 | + $expire = is_numeric($options) ? $options : null; | ||
375 | + return $cache->remember(substr($name, 1), $value, $expire); | ||
376 | + } else { | ||
377 | + // 缓存数据 | ||
378 | + if (is_array($options)) { | ||
379 | + $expire = isset($options['expire']) ? $options['expire'] : null; //修复查询缓存无法设置过期时间 | ||
380 | + } else { | ||
381 | + $expire = is_numeric($options) ? $options : null; //默认快捷缓存设置过期时间 | ||
382 | + } | ||
383 | + if (is_null($tag)) { | ||
384 | + return $cache->set($name, $value, $expire); | ||
385 | + } else { | ||
386 | + return $cache->tag($tag)->set($name, $value, $expire); | ||
387 | + } | ||
388 | + } | ||
389 | + } | ||
390 | +} | ||
391 | + | ||
392 | +if (!function_exists('trace')) { | ||
393 | + /** | ||
394 | + * 记录日志信息 | ||
395 | + * @param mixed $log log信息 支持字符串和数组 | ||
396 | + * @param string $level 日志级别 | ||
397 | + * @return void|array | ||
398 | + */ | ||
399 | + function trace($log = '[think]', $level = 'log') | ||
400 | + { | ||
401 | + if ('[think]' === $log) { | ||
402 | + return Log::getLog(); | ||
403 | + } else { | ||
404 | + Log::record($log, $level); | ||
405 | + } | ||
406 | + } | ||
407 | +} | ||
408 | + | ||
409 | +if (!function_exists('request')) { | ||
410 | + /** | ||
411 | + * 获取当前Request对象实例 | ||
412 | + * @return Request | ||
413 | + */ | ||
414 | + function request() | ||
415 | + { | ||
416 | + return Request::instance(); | ||
417 | + } | ||
418 | +} | ||
419 | + | ||
420 | +if (!function_exists('response')) { | ||
421 | + /** | ||
422 | + * 创建普通 Response 对象实例 | ||
423 | + * @param mixed $data 输出数据 | ||
424 | + * @param int|string $code 状态码 | ||
425 | + * @param array $header 头信息 | ||
426 | + * @param string $type | ||
427 | + * @return Response | ||
428 | + */ | ||
429 | + function response($data = [], $code = 200, $header = [], $type = 'html') | ||
430 | + { | ||
431 | + return Response::create($data, $type, $code, $header); | ||
432 | + } | ||
433 | +} | ||
434 | + | ||
435 | +if (!function_exists('view')) { | ||
436 | + /** | ||
437 | + * 渲染模板输出 | ||
438 | + * @param string $template 模板文件 | ||
439 | + * @param array $vars 模板变量 | ||
440 | + * @param array $replace 模板替换 | ||
441 | + * @param integer $code 状态码 | ||
442 | + * @return \think\response\View | ||
443 | + */ | ||
444 | + function view($template = '', $vars = [], $replace = [], $code = 200) | ||
445 | + { | ||
446 | + return Response::create($template, 'view', $code)->replace($replace)->assign($vars); | ||
447 | + } | ||
448 | +} | ||
449 | + | ||
450 | +if (!function_exists('json')) { | ||
451 | + /** | ||
452 | + * 获取\think\response\Json对象实例 | ||
453 | + * @param mixed $data 返回的数据 | ||
454 | + * @param integer $code 状态码 | ||
455 | + * @param array $header 头部 | ||
456 | + * @param array $options 参数 | ||
457 | + * @return \think\response\Json | ||
458 | + */ | ||
459 | + function json($data = [], $code = 200, $header = [], $options = []) | ||
460 | + { | ||
461 | + return Response::create($data, 'json', $code, $header, $options); | ||
462 | + } | ||
463 | +} | ||
464 | + | ||
465 | +if (!function_exists('jsonp')) { | ||
466 | + /** | ||
467 | + * 获取\think\response\Jsonp对象实例 | ||
468 | + * @param mixed $data 返回的数据 | ||
469 | + * @param integer $code 状态码 | ||
470 | + * @param array $header 头部 | ||
471 | + * @param array $options 参数 | ||
472 | + * @return \think\response\Jsonp | ||
473 | + */ | ||
474 | + function jsonp($data = [], $code = 200, $header = [], $options = []) | ||
475 | + { | ||
476 | + return Response::create($data, 'jsonp', $code, $header, $options); | ||
477 | + } | ||
478 | +} | ||
479 | + | ||
480 | +if (!function_exists('xml')) { | ||
481 | + /** | ||
482 | + * 获取\think\response\Xml对象实例 | ||
483 | + * @param mixed $data 返回的数据 | ||
484 | + * @param integer $code 状态码 | ||
485 | + * @param array $header 头部 | ||
486 | + * @param array $options 参数 | ||
487 | + * @return \think\response\Xml | ||
488 | + */ | ||
489 | + function xml($data = [], $code = 200, $header = [], $options = []) | ||
490 | + { | ||
491 | + return Response::create($data, 'xml', $code, $header, $options); | ||
492 | + } | ||
493 | +} | ||
494 | + | ||
495 | +if (!function_exists('redirect')) { | ||
496 | + /** | ||
497 | + * 获取\think\response\Redirect对象实例 | ||
498 | + * @param mixed $url 重定向地址 支持Url::build方法的地址 | ||
499 | + * @param array|integer $params 额外参数 | ||
500 | + * @param integer $code 状态码 | ||
501 | + * @param array $with 隐式传参 | ||
502 | + * @return \think\response\Redirect | ||
503 | + */ | ||
504 | + function redirect($url = [], $params = [], $code = 302, $with = []) | ||
505 | + { | ||
506 | + if (is_integer($params)) { | ||
507 | + $code = $params; | ||
508 | + $params = []; | ||
509 | + } | ||
510 | + return Response::create($url, 'redirect', $code)->params($params)->with($with); | ||
511 | + } | ||
512 | +} | ||
513 | + | ||
514 | +if (!function_exists('abort')) { | ||
515 | + /** | ||
516 | + * 抛出HTTP异常 | ||
517 | + * @param integer|Response $code 状态码 或者 Response对象实例 | ||
518 | + * @param string $message 错误信息 | ||
519 | + * @param array $header 参数 | ||
520 | + */ | ||
521 | + function abort($code, $message = null, $header = []) | ||
522 | + { | ||
523 | + if ($code instanceof Response) { | ||
524 | + throw new HttpResponseException($code); | ||
525 | + } else { | ||
526 | + throw new HttpException($code, $message, null, $header); | ||
527 | + } | ||
528 | + } | ||
529 | +} | ||
530 | + | ||
531 | +if (!function_exists('halt')) { | ||
532 | + /** | ||
533 | + * 调试变量并且中断输出 | ||
534 | + * @param mixed $var 调试变量或者信息 | ||
535 | + */ | ||
536 | + function halt($var) | ||
537 | + { | ||
538 | + dump($var); | ||
539 | + throw new HttpResponseException(new Response); | ||
540 | + } | ||
541 | +} | ||
542 | + | ||
543 | +if (!function_exists('token')) { | ||
544 | + /** | ||
545 | + * 生成表单令牌 | ||
546 | + * @param string $name 令牌名称 | ||
547 | + * @param mixed $type 令牌生成方法 | ||
548 | + * @return string | ||
549 | + */ | ||
550 | + function token($name = '__token__', $type = 'md5') | ||
551 | + { | ||
552 | + $token = Request::instance()->token($name, $type); | ||
553 | + return '<input type="hidden" name="' . $name . '" value="' . $token . '" />'; | ||
554 | + } | ||
555 | +} | ||
556 | + | ||
557 | +if (!function_exists('load_relation')) { | ||
558 | + /** | ||
559 | + * 延迟预载入关联查询 | ||
560 | + * @param mixed $resultSet 数据集 | ||
561 | + * @param mixed $relation 关联 | ||
562 | + * @return array | ||
563 | + */ | ||
564 | + function load_relation($resultSet, $relation) | ||
565 | + { | ||
566 | + $item = current($resultSet); | ||
567 | + if ($item instanceof Model) { | ||
568 | + $item->eagerlyResultSet($resultSet, $relation); | ||
569 | + } | ||
570 | + return $resultSet; | ||
571 | + } | ||
572 | +} | ||
573 | + | ||
574 | +if (!function_exists('collection')) { | ||
575 | + /** | ||
576 | + * 数组转换为数据集对象 | ||
577 | + * @param array $resultSet 数据集数组 | ||
578 | + * @return \think\model\Collection|\think\Collection | ||
579 | + */ | ||
580 | + function collection($resultSet) | ||
581 | + { | ||
582 | + $item = current($resultSet); | ||
583 | + if ($item instanceof Model) { | ||
584 | + return \think\model\Collection::make($resultSet); | ||
585 | + } else { | ||
586 | + return \think\Collection::make($resultSet); | ||
587 | + } | ||
588 | + } | ||
589 | +} |
thinkphp/lang/zh-cn.php
0 → 100644
1 | +<?php | ||
2 | +// +---------------------------------------------------------------------- | ||
3 | +// | ThinkPHP [ WE CAN DO IT JUST THINK ] | ||
4 | +// +---------------------------------------------------------------------- | ||
5 | +// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. | ||
6 | +// +---------------------------------------------------------------------- | ||
7 | +// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) | ||
8 | +// +---------------------------------------------------------------------- | ||
9 | +// | Author: liu21st <liu21st@gmail.com> | ||
10 | +// +---------------------------------------------------------------------- | ||
11 | + | ||
12 | +// 核心中文语言包 | ||
13 | +return [ | ||
14 | + // 系统错误提示 | ||
15 | + 'Undefined variable' => '未定义变量', | ||
16 | + 'Undefined index' => '未定义数组索引', | ||
17 | + 'Undefined offset' => '未定义数组下标', | ||
18 | + 'Parse error' => '语法解析错误', | ||
19 | + 'Type error' => '类型错误', | ||
20 | + 'Fatal error' => '致命错误', | ||
21 | + 'syntax error' => '语法错误', | ||
22 | + | ||
23 | + // 框架核心错误提示 | ||
24 | + 'dispatch type not support' => '不支持的调度类型', | ||
25 | + 'method param miss' => '方法参数错误', | ||
26 | + 'method not exists' => '方法不存在', | ||
27 | + 'module not exists' => '模块不存在', | ||
28 | + 'controller not exists' => '控制器不存在', | ||
29 | + 'class not exists' => '类不存在', | ||
30 | + 'property not exists' => '类的属性不存在', | ||
31 | + 'template not exists' => '模板文件不存在', | ||
32 | + 'illegal controller name' => '非法的控制器名称', | ||
33 | + 'illegal action name' => '非法的操作名称', | ||
34 | + 'url suffix deny' => '禁止的URL后缀访问', | ||
35 | + 'Route Not Found' => '当前访问路由未定义', | ||
36 | + 'Undefined db type' => '未定义数据库类型', | ||
37 | + 'variable type error' => '变量类型错误', | ||
38 | + 'PSR-4 error' => 'PSR-4 规范错误', | ||
39 | + 'not support total' => '简洁模式下不能获取数据总数', | ||
40 | + 'not support last' => '简洁模式下不能获取最后一页', | ||
41 | + 'error session handler' => '错误的SESSION处理器类', | ||
42 | + 'not allow php tag' => '模板不允许使用PHP语法', | ||
43 | + 'not support' => '不支持', | ||
44 | + 'redisd master' => 'Redisd 主服务器错误', | ||
45 | + 'redisd slave' => 'Redisd 从服务器错误', | ||
46 | + 'must run at sae' => '必须在SAE运行', | ||
47 | + 'memcache init error' => '未开通Memcache服务,请在SAE管理平台初始化Memcache服务', | ||
48 | + 'KVDB init error' => '没有初始化KVDB,请在SAE管理平台初始化KVDB服务', | ||
49 | + 'fields not exists' => '数据表字段不存在', | ||
50 | + 'where express error' => '查询表达式错误', | ||
51 | + 'not support data' => '不支持的数据表达式', | ||
52 | + 'no data to update' => '没有任何数据需要更新', | ||
53 | + 'miss data to insert' => '缺少需要写入的数据', | ||
54 | + 'miss complex primary data' => '缺少复合主键数据', | ||
55 | + 'miss update condition' => '缺少更新条件', | ||
56 | + 'model data Not Found' => '模型数据不存在', | ||
57 | + 'table data not Found' => '表数据不存在', | ||
58 | + 'delete without condition' => '没有条件不会执行删除操作', | ||
59 | + 'miss relation data' => '缺少关联表数据', | ||
60 | + 'tag attr must' => '模板标签属性必须', | ||
61 | + 'tag error' => '模板标签错误', | ||
62 | + 'cache write error' => '缓存写入失败', | ||
63 | + 'sae mc write error' => 'SAE mc 写入错误', | ||
64 | + 'route name not exists' => '路由标识不存在(或参数不够)', | ||
65 | + 'invalid request' => '非法请求', | ||
66 | + 'bind attr has exists' => '模型的属性已经存在', | ||
67 | + 'relation data not exists' => '关联数据不存在', | ||
68 | + 'relation not support' => '关联不支持', | ||
69 | + 'chunk not support order' => 'Chunk不支持调用order方法', | ||
70 | + 'closure not support cache(true)' => '使用闭包查询不支持cache(true),请指定缓存Key', | ||
71 | + | ||
72 | + // 上传错误信息 | ||
73 | + 'unknown upload error' => '未知上传错误!', | ||
74 | + 'file write error' => '文件写入失败!', | ||
75 | + 'upload temp dir not found' => '找不到临时文件夹!', | ||
76 | + 'no file to uploaded' => '没有文件被上传!', | ||
77 | + 'only the portion of file is uploaded' => '文件只有部分被上传!', | ||
78 | + 'upload File size exceeds the maximum value' => '上传文件大小超过了最大值!', | ||
79 | + 'upload write error' => '文件上传保存错误!', | ||
80 | + 'has the same filename: {:filename}' => '存在同名文件:{:filename}', | ||
81 | + 'upload illegal files' => '非法上传文件', | ||
82 | + 'illegal image files' => '非法图片文件', | ||
83 | + 'extensions to upload is not allowed' => '上传文件后缀不允许', | ||
84 | + 'mimetype to upload is not allowed' => '上传文件MIME类型不允许!', | ||
85 | + 'filesize not match' => '上传文件大小不符!', | ||
86 | + 'directory {:path} creation failed' => '目录 {:path} 创建失败!', | ||
87 | + | ||
88 | + // Validate Error Message | ||
89 | + ':attribute require' => ':attribute不能为空', | ||
90 | + ':attribute must be numeric' => ':attribute必须是数字', | ||
91 | + ':attribute must be integer' => ':attribute必须是整数', | ||
92 | + ':attribute must be float' => ':attribute必须是浮点数', | ||
93 | + ':attribute must be bool' => ':attribute必须是布尔值', | ||
94 | + ':attribute not a valid email address' => ':attribute格式不符', | ||
95 | + ':attribute not a valid mobile' => ':attribute格式不符', | ||
96 | + ':attribute must be a array' => ':attribute必须是数组', | ||
97 | + ':attribute must be yes,on or 1' => ':attribute必须是yes、on或者1', | ||
98 | + ':attribute not a valid datetime' => ':attribute不是一个有效的日期或时间格式', | ||
99 | + ':attribute not a valid file' => ':attribute不是有效的上传文件', | ||
100 | + ':attribute not a valid image' => ':attribute不是有效的图像文件', | ||
101 | + ':attribute must be alpha' => ':attribute只能是字母', | ||
102 | + ':attribute must be alpha-numeric' => ':attribute只能是字母和数字', | ||
103 | + ':attribute must be alpha-numeric, dash, underscore' => ':attribute只能是字母、数字和下划线_及破折号-', | ||
104 | + ':attribute not a valid domain or ip' => ':attribute不是有效的域名或者IP', | ||
105 | + ':attribute must be chinese' => ':attribute只能是汉字', | ||
106 | + ':attribute must be chinese or alpha' => ':attribute只能是汉字、字母', | ||
107 | + ':attribute must be chinese,alpha-numeric' => ':attribute只能是汉字、字母和数字', | ||
108 | + ':attribute must be chinese,alpha-numeric,underscore, dash' => ':attribute只能是汉字、字母、数字和下划线_及破折号-', | ||
109 | + ':attribute not a valid url' => ':attribute不是有效的URL地址', | ||
110 | + ':attribute not a valid ip' => ':attribute不是有效的IP地址', | ||
111 | + ':attribute must be dateFormat of :rule' => ':attribute必须使用日期格式 :rule', | ||
112 | + ':attribute must be in :rule' => ':attribute必须在 :rule 范围内', | ||
113 | + ':attribute be notin :rule' => ':attribute不能在 :rule 范围内', | ||
114 | + ':attribute must between :1 - :2' => ':attribute只能在 :1 - :2 之间', | ||
115 | + ':attribute not between :1 - :2' => ':attribute不能在 :1 - :2 之间', | ||
116 | + 'size of :attribute must be :rule' => ':attribute长度不符合要求 :rule', | ||
117 | + 'max size of :attribute must be :rule' => ':attribute长度不能超过 :rule', | ||
118 | + 'min size of :attribute must be :rule' => ':attribute长度不能小于 :rule', | ||
119 | + ':attribute cannot be less than :rule' => ':attribute日期不能小于 :rule', | ||
120 | + ':attribute cannot exceed :rule' => ':attribute日期不能超过 :rule', | ||
121 | + ':attribute not within :rule' => '不在有效期内 :rule', | ||
122 | + 'access IP is not allowed' => '不允许的IP访问', | ||
123 | + 'access IP denied' => '禁止的IP访问', | ||
124 | + ':attribute out of accord with :2' => ':attribute和确认字段:2不一致', | ||
125 | + ':attribute cannot be same with :2' => ':attribute和比较字段:2不能相同', | ||
126 | + ':attribute must greater than or equal :rule' => ':attribute必须大于等于 :rule', | ||
127 | + ':attribute must greater than :rule' => ':attribute必须大于 :rule', | ||
128 | + ':attribute must less than or equal :rule' => ':attribute必须小于等于 :rule', | ||
129 | + ':attribute must less than :rule' => ':attribute必须小于 :rule', | ||
130 | + ':attribute must equal :rule' => ':attribute必须等于 :rule', | ||
131 | + ':attribute has exists' => ':attribute已存在', | ||
132 | + ':attribute not conform to the rules' => ':attribute不符合指定规则', | ||
133 | + 'invalid Request method' => '无效的请求类型', | ||
134 | + 'invalid token' => '令牌数据无效', | ||
135 | + 'not conform to the rules' => '规则错误', | ||
136 | +]; |
thinkphp/library/think/App.php
0 → 100644
1 | +<?php | ||
2 | +// +---------------------------------------------------------------------- | ||
3 | +// | ThinkPHP [ WE CAN DO IT JUST THINK ] | ||
4 | +// +---------------------------------------------------------------------- | ||
5 | +// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. | ||
6 | +// +---------------------------------------------------------------------- | ||
7 | +// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) | ||
8 | +// +---------------------------------------------------------------------- | ||
9 | +// | Author: liu21st <liu21st@gmail.com> | ||
10 | +// +---------------------------------------------------------------------- | ||
11 | + | ||
12 | +namespace think; | ||
13 | + | ||
14 | +use think\exception\ClassNotFoundException; | ||
15 | +use think\exception\HttpException; | ||
16 | +use think\exception\HttpResponseException; | ||
17 | +use think\exception\RouteNotFoundException; | ||
18 | + | ||
19 | +/** | ||
20 | + * App 应用管理 | ||
21 | + * @author liu21st <liu21st@gmail.com> | ||
22 | + */ | ||
23 | +class App | ||
24 | +{ | ||
25 | + /** | ||
26 | + * @var bool 是否初始化过 | ||
27 | + */ | ||
28 | + protected static $init = false; | ||
29 | + | ||
30 | + /** | ||
31 | + * @var string 当前模块路径 | ||
32 | + */ | ||
33 | + public static $modulePath; | ||
34 | + | ||
35 | + /** | ||
36 | + * @var bool 应用调试模式 | ||
37 | + */ | ||
38 | + public static $debug = true; | ||
39 | + | ||
40 | + /** | ||
41 | + * @var string 应用类库命名空间 | ||
42 | + */ | ||
43 | + public static $namespace = 'app'; | ||
44 | + | ||
45 | + /** | ||
46 | + * @var bool 应用类库后缀 | ||
47 | + */ | ||
48 | + public static $suffix = false; | ||
49 | + | ||
50 | + /** | ||
51 | + * @var bool 应用路由检测 | ||
52 | + */ | ||
53 | + protected static $routeCheck; | ||
54 | + | ||
55 | + /** | ||
56 | + * @var bool 严格路由检测 | ||
57 | + */ | ||
58 | + protected static $routeMust; | ||
59 | + | ||
60 | + /** | ||
61 | + * @var array 请求调度分发 | ||
62 | + */ | ||
63 | + protected static $dispatch; | ||
64 | + | ||
65 | + /** | ||
66 | + * @var array 额外加载文件 | ||
67 | + */ | ||
68 | + protected static $file = []; | ||
69 | + | ||
70 | + /** | ||
71 | + * 执行应用程序 | ||
72 | + * @access public | ||
73 | + * @param Request $request 请求对象 | ||
74 | + * @return Response | ||
75 | + * @throws Exception | ||
76 | + */ | ||
77 | + public static function run(Request $request = null) | ||
78 | + { | ||
79 | + $request = is_null($request) ? Request::instance() : $request; | ||
80 | + | ||
81 | + try { | ||
82 | + $config = self::initCommon(); | ||
83 | + | ||
84 | + // 模块/控制器绑定 | ||
85 | + if (defined('BIND_MODULE')) { | ||
86 | + BIND_MODULE && Route::bind(BIND_MODULE); | ||
87 | + } elseif ($config['auto_bind_module']) { | ||
88 | + // 入口自动绑定 | ||
89 | + $name = pathinfo($request->baseFile(), PATHINFO_FILENAME); | ||
90 | + if ($name && 'index' != $name && is_dir(APP_PATH . $name)) { | ||
91 | + Route::bind($name); | ||
92 | + } | ||
93 | + } | ||
94 | + | ||
95 | + $request->filter($config['default_filter']); | ||
96 | + | ||
97 | + // 默认语言 | ||
98 | + Lang::range($config['default_lang']); | ||
99 | + // 开启多语言机制 检测当前语言 | ||
100 | + $config['lang_switch_on'] && Lang::detect(); | ||
101 | + $request->langset(Lang::range()); | ||
102 | + | ||
103 | + // 加载系统语言包 | ||
104 | + Lang::load([ | ||
105 | + THINK_PATH . 'lang' . DS . $request->langset() . EXT, | ||
106 | + APP_PATH . 'lang' . DS . $request->langset() . EXT, | ||
107 | + ]); | ||
108 | + | ||
109 | + // 监听 app_dispatch | ||
110 | + Hook::listen('app_dispatch', self::$dispatch); | ||
111 | + // 获取应用调度信息 | ||
112 | + $dispatch = self::$dispatch; | ||
113 | + | ||
114 | + // 未设置调度信息则进行 URL 路由检测 | ||
115 | + if (empty($dispatch)) { | ||
116 | + $dispatch = self::routeCheck($request, $config); | ||
117 | + } | ||
118 | + | ||
119 | + // 记录当前调度信息 | ||
120 | + $request->dispatch($dispatch); | ||
121 | + | ||
122 | + // 记录路由和请求信息 | ||
123 | + if (self::$debug) { | ||
124 | + Log::record('[ ROUTE ] ' . var_export($dispatch, true), 'info'); | ||
125 | + Log::record('[ HEADER ] ' . var_export($request->header(), true), 'info'); | ||
126 | + Log::record('[ PARAM ] ' . var_export($request->param(), true), 'info'); | ||
127 | + } | ||
128 | + | ||
129 | + // 监听 app_begin | ||
130 | + Hook::listen('app_begin', $dispatch); | ||
131 | + | ||
132 | + // 请求缓存检查 | ||
133 | + $request->cache( | ||
134 | + $config['request_cache'], | ||
135 | + $config['request_cache_expire'], | ||
136 | + $config['request_cache_except'] | ||
137 | + ); | ||
138 | + | ||
139 | + $data = self::exec($dispatch, $config); | ||
140 | + } catch (HttpResponseException $exception) { | ||
141 | + $data = $exception->getResponse(); | ||
142 | + } | ||
143 | + | ||
144 | + // 清空类的实例化 | ||
145 | + Loader::clearInstance(); | ||
146 | + | ||
147 | + // 输出数据到客户端 | ||
148 | + if ($data instanceof Response) { | ||
149 | + $response = $data; | ||
150 | + } elseif (!is_null($data)) { | ||
151 | + // 默认自动识别响应输出类型 | ||
152 | + $type = $request->isAjax() ? | ||
153 | + Config::get('default_ajax_return') : | ||
154 | + Config::get('default_return_type'); | ||
155 | + | ||
156 | + $response = Response::create($data, $type); | ||
157 | + } else { | ||
158 | + $response = Response::create(); | ||
159 | + } | ||
160 | + | ||
161 | + // 监听 app_end | ||
162 | + Hook::listen('app_end', $response); | ||
163 | + | ||
164 | + return $response; | ||
165 | + } | ||
166 | + | ||
167 | + /** | ||
168 | + * 初始化应用,并返回配置信息 | ||
169 | + * @access public | ||
170 | + * @return array | ||
171 | + */ | ||
172 | + public static function initCommon() | ||
173 | + { | ||
174 | + if (empty(self::$init)) { | ||
175 | + if (defined('APP_NAMESPACE')) { | ||
176 | + self::$namespace = APP_NAMESPACE; | ||
177 | + } | ||
178 | + | ||
179 | + Loader::addNamespace(self::$namespace, APP_PATH); | ||
180 | + | ||
181 | + // 初始化应用 | ||
182 | + $config = self::init(); | ||
183 | + self::$suffix = $config['class_suffix']; | ||
184 | + | ||
185 | + // 应用调试模式 | ||
186 | + self::$debug = Env::get('app_debug', Config::get('app_debug')); | ||
187 | + | ||
188 | + if (!self::$debug) { | ||
189 | + ini_set('display_errors', 'Off'); | ||
190 | + } elseif (!IS_CLI) { | ||
191 | + // 重新申请一块比较大的 buffer | ||
192 | + if (ob_get_level() > 0) { | ||
193 | + $output = ob_get_clean(); | ||
194 | + } | ||
195 | + | ||
196 | + ob_start(); | ||
197 | + | ||
198 | + if (!empty($output)) { | ||
199 | + echo $output; | ||
200 | + } | ||
201 | + | ||
202 | + } | ||
203 | + | ||
204 | + if (!empty($config['root_namespace'])) { | ||
205 | + Loader::addNamespace($config['root_namespace']); | ||
206 | + } | ||
207 | + | ||
208 | + // 加载额外文件 | ||
209 | + if (!empty($config['extra_file_list'])) { | ||
210 | + foreach ($config['extra_file_list'] as $file) { | ||
211 | + $file = strpos($file, '.') ? $file : APP_PATH . $file . EXT; | ||
212 | + if (is_file($file) && !isset(self::$file[$file])) { | ||
213 | + include $file; | ||
214 | + self::$file[$file] = true; | ||
215 | + } | ||
216 | + } | ||
217 | + } | ||
218 | + | ||
219 | + // 设置系统时区 | ||
220 | + date_default_timezone_set($config['default_timezone']); | ||
221 | + | ||
222 | + // 监听 app_init | ||
223 | + Hook::listen('app_init'); | ||
224 | + | ||
225 | + self::$init = true; | ||
226 | + } | ||
227 | + | ||
228 | + return Config::get(); | ||
229 | + } | ||
230 | + | ||
231 | + /** | ||
232 | + * 初始化应用或模块 | ||
233 | + * @access public | ||
234 | + * @param string $module 模块名 | ||
235 | + * @return array | ||
236 | + */ | ||
237 | + private static function init($module = '') | ||
238 | + { | ||
239 | + // 定位模块目录 | ||
240 | + $module = $module ? $module . DS : ''; | ||
241 | + | ||
242 | + // 加载初始化文件 | ||
243 | + if (is_file(APP_PATH . $module . 'init' . EXT)) { | ||
244 | + include APP_PATH . $module . 'init' . EXT; | ||
245 | + } elseif (is_file(RUNTIME_PATH . $module . 'init' . EXT)) { | ||
246 | + include RUNTIME_PATH . $module . 'init' . EXT; | ||
247 | + } else { | ||
248 | + // 加载模块配置 | ||
249 | + $config = Config::load(CONF_PATH . $module . 'config' . CONF_EXT); | ||
250 | + | ||
251 | + // 读取数据库配置文件 | ||
252 | + $filename = CONF_PATH . $module . 'database' . CONF_EXT; | ||
253 | + Config::load($filename, 'database'); | ||
254 | + | ||
255 | + // 读取扩展配置文件 | ||
256 | + if (is_dir(CONF_PATH . $module . 'extra')) { | ||
257 | + $dir = CONF_PATH . $module . 'extra'; | ||
258 | + $files = scandir($dir); | ||
259 | + foreach ($files as $file) { | ||
260 | + if ('.' . pathinfo($file, PATHINFO_EXTENSION) === CONF_EXT) { | ||
261 | + $filename = $dir . DS . $file; | ||
262 | + Config::load($filename, pathinfo($file, PATHINFO_FILENAME)); | ||
263 | + } | ||
264 | + } | ||
265 | + } | ||
266 | + | ||
267 | + // 加载应用状态配置 | ||
268 | + if ($config['app_status']) { | ||
269 | + Config::load(CONF_PATH . $module . $config['app_status'] . CONF_EXT); | ||
270 | + } | ||
271 | + | ||
272 | + // 加载行为扩展文件 | ||
273 | + if (is_file(CONF_PATH . $module . 'tags' . EXT)) { | ||
274 | + Hook::import(include CONF_PATH . $module . 'tags' . EXT); | ||
275 | + } | ||
276 | + | ||
277 | + // 加载公共文件 | ||
278 | + $path = APP_PATH . $module; | ||
279 | + if (is_file($path . 'common' . EXT)) { | ||
280 | + include $path . 'common' . EXT; | ||
281 | + } | ||
282 | + | ||
283 | + // 加载当前模块语言包 | ||
284 | + if ($module) { | ||
285 | + Lang::load($path . 'lang' . DS . Request::instance()->langset() . EXT); | ||
286 | + } | ||
287 | + } | ||
288 | + | ||
289 | + return Config::get(); | ||
290 | + } | ||
291 | + | ||
292 | + /** | ||
293 | + * 设置当前请求的调度信息 | ||
294 | + * @access public | ||
295 | + * @param array|string $dispatch 调度信息 | ||
296 | + * @param string $type 调度类型 | ||
297 | + * @return void | ||
298 | + */ | ||
299 | + public static function dispatch($dispatch, $type = 'module') | ||
300 | + { | ||
301 | + self::$dispatch = ['type' => $type, $type => $dispatch]; | ||
302 | + } | ||
303 | + | ||
304 | + /** | ||
305 | + * 执行函数或者闭包方法 支持参数调用 | ||
306 | + * @access public | ||
307 | + * @param string|array|\Closure $function 函数或者闭包 | ||
308 | + * @param array $vars 变量 | ||
309 | + * @return mixed | ||
310 | + */ | ||
311 | + public static function invokeFunction($function, $vars = []) | ||
312 | + { | ||
313 | + $reflect = new \ReflectionFunction($function); | ||
314 | + $args = self::bindParams($reflect, $vars); | ||
315 | + | ||
316 | + // 记录执行信息 | ||
317 | + self::$debug && Log::record('[ RUN ] ' . $reflect->__toString(), 'info'); | ||
318 | + | ||
319 | + return $reflect->invokeArgs($args); | ||
320 | + } | ||
321 | + | ||
322 | + /** | ||
323 | + * 调用反射执行类的方法 支持参数绑定 | ||
324 | + * @access public | ||
325 | + * @param string|array $method 方法 | ||
326 | + * @param array $vars 变量 | ||
327 | + * @return mixed | ||
328 | + */ | ||
329 | + public static function invokeMethod($method, $vars = []) | ||
330 | + { | ||
331 | + if (is_array($method)) { | ||
332 | + $class = is_object($method[0]) ? $method[0] : self::invokeClass($method[0]); | ||
333 | + $reflect = new \ReflectionMethod($class, $method[1]); | ||
334 | + } else { | ||
335 | + // 静态方法 | ||
336 | + $reflect = new \ReflectionMethod($method); | ||
337 | + } | ||
338 | + | ||
339 | + $args = self::bindParams($reflect, $vars); | ||
340 | + | ||
341 | + self::$debug && Log::record('[ RUN ] ' . $reflect->class . '->' . $reflect->name . '[ ' . $reflect->getFileName() . ' ]', 'info'); | ||
342 | + | ||
343 | + return $reflect->invokeArgs(isset($class) ? $class : null, $args); | ||
344 | + } | ||
345 | + | ||
346 | + /** | ||
347 | + * 调用反射执行类的实例化 支持依赖注入 | ||
348 | + * @access public | ||
349 | + * @param string $class 类名 | ||
350 | + * @param array $vars 变量 | ||
351 | + * @return mixed | ||
352 | + */ | ||
353 | + public static function invokeClass($class, $vars = []) | ||
354 | + { | ||
355 | + $reflect = new \ReflectionClass($class); | ||
356 | + $constructor = $reflect->getConstructor(); | ||
357 | + $args = $constructor ? self::bindParams($constructor, $vars) : []; | ||
358 | + | ||
359 | + return $reflect->newInstanceArgs($args); | ||
360 | + } | ||
361 | + | ||
362 | + /** | ||
363 | + * 绑定参数 | ||
364 | + * @access private | ||
365 | + * @param \ReflectionMethod|\ReflectionFunction $reflect 反射类 | ||
366 | + * @param array $vars 变量 | ||
367 | + * @return array | ||
368 | + */ | ||
369 | + private static function bindParams($reflect, $vars = []) | ||
370 | + { | ||
371 | + // 自动获取请求变量 | ||
372 | + if (empty($vars)) { | ||
373 | + $vars = Config::get('url_param_type') ? | ||
374 | + Request::instance()->route() : | ||
375 | + Request::instance()->param(); | ||
376 | + } | ||
377 | + | ||
378 | + $args = []; | ||
379 | + if ($reflect->getNumberOfParameters() > 0) { | ||
380 | + // 判断数组类型 数字数组时按顺序绑定参数 | ||
381 | + reset($vars); | ||
382 | + $type = key($vars) === 0 ? 1 : 0; | ||
383 | + | ||
384 | + foreach ($reflect->getParameters() as $param) { | ||
385 | + $args[] = self::getParamValue($param, $vars, $type); | ||
386 | + } | ||
387 | + } | ||
388 | + | ||
389 | + return $args; | ||
390 | + } | ||
391 | + | ||
392 | + /** | ||
393 | + * 获取参数值 | ||
394 | + * @access private | ||
395 | + * @param \ReflectionParameter $param 参数 | ||
396 | + * @param array $vars 变量 | ||
397 | + * @param string $type 类别 | ||
398 | + * @return array | ||
399 | + */ | ||
400 | + private static function getParamValue($param, &$vars, $type) | ||
401 | + { | ||
402 | + $name = $param->getName(); | ||
403 | + $reflectionType = $param->getType(); | ||
404 | + | ||
405 | + if ($reflectionType && $reflectionType->isBuiltin() === false) { | ||
406 | + $className = $reflectionType->getName(); | ||
407 | + $bind = Request::instance()->$name; | ||
408 | + | ||
409 | + if ($bind instanceof $className) { | ||
410 | + $result = $bind; | ||
411 | + } else { | ||
412 | + if (method_exists($className, 'invoke')) { | ||
413 | + $method = new \ReflectionMethod($className, 'invoke'); | ||
414 | + | ||
415 | + if ($method->isPublic() && $method->isStatic()) { | ||
416 | + return $className::invoke(Request::instance()); | ||
417 | + } | ||
418 | + } | ||
419 | + | ||
420 | + $result = method_exists($className, 'instance') ? | ||
421 | + $className::instance() : | ||
422 | + new $className; | ||
423 | + } | ||
424 | + } elseif (1 == $type && !empty($vars)) { | ||
425 | + $result = array_shift($vars); | ||
426 | + } elseif (0 == $type && isset($vars[$name])) { | ||
427 | + $result = $vars[$name]; | ||
428 | + } elseif ($param->isDefaultValueAvailable()) { | ||
429 | + $result = $param->getDefaultValue(); | ||
430 | + } else { | ||
431 | + throw new \InvalidArgumentException('method param miss:' . $name); | ||
432 | + } | ||
433 | + | ||
434 | + return $result; | ||
435 | + } | ||
436 | + | ||
437 | + /** | ||
438 | + * 执行调用分发 | ||
439 | + * @access protected | ||
440 | + * @param array $dispatch 调用信息 | ||
441 | + * @param array $config 配置信息 | ||
442 | + * @return Response|mixed | ||
443 | + * @throws \InvalidArgumentException | ||
444 | + */ | ||
445 | + protected static function exec($dispatch, $config) | ||
446 | + { | ||
447 | + switch ($dispatch['type']) { | ||
448 | + case 'redirect': // 重定向跳转 | ||
449 | + $data = Response::create($dispatch['url'], 'redirect') | ||
450 | + ->code($dispatch['status']); | ||
451 | + break; | ||
452 | + case 'module': // 模块/控制器/操作 | ||
453 | + $data = self::module( | ||
454 | + $dispatch['module'], | ||
455 | + $config, | ||
456 | + isset($dispatch['convert']) ? $dispatch['convert'] : null | ||
457 | + ); | ||
458 | + break; | ||
459 | + case 'controller': // 执行控制器操作 | ||
460 | + $vars = array_merge(Request::instance()->param(), $dispatch['var']); | ||
461 | + $data = Loader::action( | ||
462 | + $dispatch['controller'], | ||
463 | + $vars, | ||
464 | + $config['url_controller_layer'], | ||
465 | + $config['controller_suffix'] | ||
466 | + ); | ||
467 | + break; | ||
468 | + case 'method': // 回调方法 | ||
469 | + $vars = array_merge(Request::instance()->param(), $dispatch['var']); | ||
470 | + $data = self::invokeMethod($dispatch['method'], $vars); | ||
471 | + break; | ||
472 | + case 'function': // 闭包 | ||
473 | + $data = self::invokeFunction($dispatch['function']); | ||
474 | + break; | ||
475 | + case 'response': // Response 实例 | ||
476 | + $data = $dispatch['response']; | ||
477 | + break; | ||
478 | + default: | ||
479 | + throw new \InvalidArgumentException('dispatch type not support'); | ||
480 | + } | ||
481 | + | ||
482 | + return $data; | ||
483 | + } | ||
484 | + | ||
485 | + /** | ||
486 | + * 执行模块 | ||
487 | + * @access public | ||
488 | + * @param array $result 模块/控制器/操作 | ||
489 | + * @param array $config 配置参数 | ||
490 | + * @param bool $convert 是否自动转换控制器和操作名 | ||
491 | + * @return mixed | ||
492 | + * @throws HttpException | ||
493 | + */ | ||
494 | + public static function module($result, $config, $convert = null) | ||
495 | + { | ||
496 | + if (is_string($result)) { | ||
497 | + $result = explode('/', $result); | ||
498 | + } | ||
499 | + | ||
500 | + $request = Request::instance(); | ||
501 | + | ||
502 | + if ($config['app_multi_module']) { | ||
503 | + // 多模块部署 | ||
504 | + $module = strip_tags(strtolower($result[0] ?: $config['default_module'])); | ||
505 | + $bind = Route::getBind('module'); | ||
506 | + $available = false; | ||
507 | + | ||
508 | + if ($bind) { | ||
509 | + // 绑定模块 | ||
510 | + list($bindModule) = explode('/', $bind); | ||
511 | + | ||
512 | + if (empty($result[0])) { | ||
513 | + $module = $bindModule; | ||
514 | + $available = true; | ||
515 | + } elseif ($module == $bindModule) { | ||
516 | + $available = true; | ||
517 | + } | ||
518 | + } elseif (!in_array($module, $config['deny_module_list']) && is_dir(APP_PATH . $module)) { | ||
519 | + $available = true; | ||
520 | + } | ||
521 | + | ||
522 | + // 模块初始化 | ||
523 | + if ($module && $available) { | ||
524 | + // 初始化模块 | ||
525 | + $request->module($module); | ||
526 | + $config = self::init($module); | ||
527 | + | ||
528 | + // 模块请求缓存检查 | ||
529 | + $request->cache( | ||
530 | + $config['request_cache'], | ||
531 | + $config['request_cache_expire'], | ||
532 | + $config['request_cache_except'] | ||
533 | + ); | ||
534 | + } else { | ||
535 | + throw new HttpException(404, 'module not exists:' . $module); | ||
536 | + } | ||
537 | + } else { | ||
538 | + // 单一模块部署 | ||
539 | + $module = ''; | ||
540 | + $request->module($module); | ||
541 | + } | ||
542 | + | ||
543 | + // 设置默认过滤机制 | ||
544 | + $request->filter($config['default_filter']); | ||
545 | + | ||
546 | + // 当前模块路径 | ||
547 | + App::$modulePath = APP_PATH . ($module ? $module . DS : ''); | ||
548 | + | ||
549 | + // 是否自动转换控制器和操作名 | ||
550 | + $convert = is_bool($convert) ? $convert : $config['url_convert']; | ||
551 | + | ||
552 | + // 获取控制器名 | ||
553 | + $controller = strip_tags($result[1] ?: $config['default_controller']); | ||
554 | + | ||
555 | + if (!preg_match('/^[A-Za-z](\w|\.)*$/', $controller)) { | ||
556 | + throw new HttpException(404, 'controller not exists:' . $controller); | ||
557 | + } | ||
558 | + | ||
559 | + $controller = $convert ? strtolower($controller) : $controller; | ||
560 | + | ||
561 | + // 获取操作名 | ||
562 | + $actionName = strip_tags($result[2] ?: $config['default_action']); | ||
563 | + if (!empty($config['action_convert'])) { | ||
564 | + $actionName = Loader::parseName($actionName, 1); | ||
565 | + } else { | ||
566 | + $actionName = $convert ? strtolower($actionName) : $actionName; | ||
567 | + } | ||
568 | + | ||
569 | + // 设置当前请求的控制器、操作 | ||
570 | + $request->controller(Loader::parseName($controller, 1))->action($actionName); | ||
571 | + | ||
572 | + // 监听module_init | ||
573 | + Hook::listen('module_init', $request); | ||
574 | + | ||
575 | + try { | ||
576 | + $instance = Loader::controller( | ||
577 | + $controller, | ||
578 | + $config['url_controller_layer'], | ||
579 | + $config['controller_suffix'], | ||
580 | + $config['empty_controller'] | ||
581 | + ); | ||
582 | + } catch (ClassNotFoundException $e) { | ||
583 | + throw new HttpException(404, 'controller not exists:' . $e->getClass()); | ||
584 | + } | ||
585 | + | ||
586 | + // 获取当前操作名 | ||
587 | + $action = $actionName . $config['action_suffix']; | ||
588 | + | ||
589 | + $vars = []; | ||
590 | + if (is_callable([$instance, $action])) { | ||
591 | + // 执行操作方法 | ||
592 | + $call = [$instance, $action]; | ||
593 | + // 严格获取当前操作方法名 | ||
594 | + $reflect = new \ReflectionMethod($instance, $action); | ||
595 | + $methodName = $reflect->getName(); | ||
596 | + $suffix = $config['action_suffix']; | ||
597 | + $actionName = $suffix ? substr($methodName, 0, -strlen($suffix)) : $methodName; | ||
598 | + $request->action($actionName); | ||
599 | + | ||
600 | + } elseif (is_callable([$instance, '_empty'])) { | ||
601 | + // 空操作 | ||
602 | + $call = [$instance, '_empty']; | ||
603 | + $vars = [$actionName]; | ||
604 | + } else { | ||
605 | + // 操作不存在 | ||
606 | + throw new HttpException(404, 'method not exists:' . get_class($instance) . '->' . $action . '()'); | ||
607 | + } | ||
608 | + | ||
609 | + Hook::listen('action_begin', $call); | ||
610 | + | ||
611 | + return self::invokeMethod($call, $vars); | ||
612 | + } | ||
613 | + | ||
614 | + /** | ||
615 | + * URL路由检测(根据PATH_INFO) | ||
616 | + * @access public | ||
617 | + * @param \think\Request $request 请求实例 | ||
618 | + * @param array $config 配置信息 | ||
619 | + * @return array | ||
620 | + * @throws \think\Exception | ||
621 | + */ | ||
622 | + public static function routeCheck($request, array $config) | ||
623 | + { | ||
624 | + $path = $request->path(); | ||
625 | + $depr = $config['pathinfo_depr']; | ||
626 | + $result = false; | ||
627 | + | ||
628 | + // 路由检测 | ||
629 | + $check = !is_null(self::$routeCheck) ? self::$routeCheck : $config['url_route_on']; | ||
630 | + if ($check) { | ||
631 | + // 开启路由 | ||
632 | + if (is_file(RUNTIME_PATH . 'route.php')) { | ||
633 | + // 读取路由缓存 | ||
634 | + $rules = include RUNTIME_PATH . 'route.php'; | ||
635 | + is_array($rules) && Route::rules($rules); | ||
636 | + } else { | ||
637 | + $files = $config['route_config_file']; | ||
638 | + foreach ($files as $file) { | ||
639 | + if (is_file(CONF_PATH . $file . CONF_EXT)) { | ||
640 | + // 导入路由配置 | ||
641 | + $rules = include CONF_PATH . $file . CONF_EXT; | ||
642 | + is_array($rules) && Route::import($rules); | ||
643 | + } | ||
644 | + } | ||
645 | + } | ||
646 | + | ||
647 | + // 路由检测(根据路由定义返回不同的URL调度) | ||
648 | + $result = Route::check($request, $path, $depr, $config['url_domain_deploy']); | ||
649 | + $must = !is_null(self::$routeMust) ? self::$routeMust : $config['url_route_must']; | ||
650 | + | ||
651 | + if ($must && false === $result) { | ||
652 | + // 路由无效 | ||
653 | + throw new RouteNotFoundException(); | ||
654 | + } | ||
655 | + } | ||
656 | + | ||
657 | + // 路由无效 解析模块/控制器/操作/参数... 支持控制器自动搜索 | ||
658 | + if (false === $result) { | ||
659 | + $result = Route::parseUrl($path, $depr, $config['controller_auto_search']); | ||
660 | + } | ||
661 | + | ||
662 | + return $result; | ||
663 | + } | ||
664 | + | ||
665 | + /** | ||
666 | + * 设置应用的路由检测机制 | ||
667 | + * @access public | ||
668 | + * @param bool $route 是否需要检测路由 | ||
669 | + * @param bool $must 是否强制检测路由 | ||
670 | + * @return void | ||
671 | + */ | ||
672 | + public static function route($route, $must = false) | ||
673 | + { | ||
674 | + self::$routeCheck = $route; | ||
675 | + self::$routeMust = $must; | ||
676 | + } | ||
677 | +} |
thinkphp/library/think/Build.php
0 → 100644
1 | +<?php | ||
2 | +// +---------------------------------------------------------------------- | ||
3 | +// | ThinkPHP [ WE CAN DO IT JUST THINK ] | ||
4 | +// +---------------------------------------------------------------------- | ||
5 | +// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. | ||
6 | +// +---------------------------------------------------------------------- | ||
7 | +// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) | ||
8 | +// +---------------------------------------------------------------------- | ||
9 | +// | Author: liu21st <liu21st@gmail.com> | ||
10 | +// +---------------------------------------------------------------------- | ||
11 | + | ||
12 | +namespace think; | ||
13 | + | ||
14 | +class Build | ||
15 | +{ | ||
16 | + /** | ||
17 | + * 根据传入的 build 资料创建目录和文件 | ||
18 | + * @access public | ||
19 | + * @param array $build build 列表 | ||
20 | + * @param string $namespace 应用类库命名空间 | ||
21 | + * @param bool $suffix 类库后缀 | ||
22 | + * @return void | ||
23 | + * @throws Exception | ||
24 | + */ | ||
25 | + public static function run(array $build = [], $namespace = 'app', $suffix = false) | ||
26 | + { | ||
27 | + // 锁定 | ||
28 | + $lock = APP_PATH . 'build.lock'; | ||
29 | + | ||
30 | + // 如果锁定文件不可写(不存在)则进行处理,否则表示已经有程序在处理了 | ||
31 | + if (!is_writable($lock)) { | ||
32 | + if (!touch($lock)) { | ||
33 | + throw new Exception( | ||
34 | + '应用目录[' . APP_PATH . ']不可写,目录无法自动生成!<BR>请手动生成项目目录~', | ||
35 | + 10006 | ||
36 | + ); | ||
37 | + } | ||
38 | + | ||
39 | + foreach ($build as $module => $list) { | ||
40 | + if ('__dir__' == $module) { | ||
41 | + // 创建目录列表 | ||
42 | + self::buildDir($list); | ||
43 | + } elseif ('__file__' == $module) { | ||
44 | + // 创建文件列表 | ||
45 | + self::buildFile($list); | ||
46 | + } else { | ||
47 | + // 创建模块 | ||
48 | + self::module($module, $list, $namespace, $suffix); | ||
49 | + } | ||
50 | + } | ||
51 | + | ||
52 | + // 解除锁定 | ||
53 | + unlink($lock); | ||
54 | + } | ||
55 | + } | ||
56 | + | ||
57 | + /** | ||
58 | + * 创建目录 | ||
59 | + * @access protected | ||
60 | + * @param array $list 目录列表 | ||
61 | + * @return void | ||
62 | + */ | ||
63 | + protected static function buildDir($list) | ||
64 | + { | ||
65 | + foreach ($list as $dir) { | ||
66 | + // 目录不存在则创建目录 | ||
67 | + !is_dir(APP_PATH . $dir) && mkdir(APP_PATH . $dir, 0755, true); | ||
68 | + } | ||
69 | + } | ||
70 | + | ||
71 | + /** | ||
72 | + * 创建文件 | ||
73 | + * @access protected | ||
74 | + * @param array $list 文件列表 | ||
75 | + * @return void | ||
76 | + */ | ||
77 | + protected static function buildFile($list) | ||
78 | + { | ||
79 | + foreach ($list as $file) { | ||
80 | + // 先创建目录 | ||
81 | + if (!is_dir(APP_PATH . dirname($file))) { | ||
82 | + mkdir(APP_PATH . dirname($file), 0755, true); | ||
83 | + } | ||
84 | + | ||
85 | + // 再创建文件 | ||
86 | + if (!is_file(APP_PATH . $file)) { | ||
87 | + file_put_contents( | ||
88 | + APP_PATH . $file, | ||
89 | + 'php' == pathinfo($file, PATHINFO_EXTENSION) ? "<?php\n" : '' | ||
90 | + ); | ||
91 | + } | ||
92 | + } | ||
93 | + } | ||
94 | + | ||
95 | + /** | ||
96 | + * 创建模块 | ||
97 | + * @access public | ||
98 | + * @param string $module 模块名 | ||
99 | + * @param array $list build 列表 | ||
100 | + * @param string $namespace 应用类库命名空间 | ||
101 | + * @param bool $suffix 类库后缀 | ||
102 | + * @return void | ||
103 | + */ | ||
104 | + public static function module($module = '', $list = [], $namespace = 'app', $suffix = false) | ||
105 | + { | ||
106 | + $module = $module ?: ''; | ||
107 | + | ||
108 | + // 创建模块目录 | ||
109 | + !is_dir(APP_PATH . $module) && mkdir(APP_PATH . $module); | ||
110 | + | ||
111 | + // 如果不是 runtime 目录则需要创建配置文件和公共文件、创建模块的默认页面 | ||
112 | + if (basename(RUNTIME_PATH) != $module) { | ||
113 | + self::buildCommon($module); | ||
114 | + self::buildHello($module, $namespace, $suffix); | ||
115 | + } | ||
116 | + | ||
117 | + // 未指定文件和目录,则创建默认的模块目录和文件 | ||
118 | + if (empty($list)) { | ||
119 | + $list = [ | ||
120 | + '__file__' => ['config.php', 'common.php'], | ||
121 | + '__dir__' => ['controller', 'model', 'view'], | ||
122 | + ]; | ||
123 | + } | ||
124 | + | ||
125 | + // 创建子目录和文件 | ||
126 | + foreach ($list as $path => $file) { | ||
127 | + $modulePath = APP_PATH . $module . DS; | ||
128 | + | ||
129 | + if ('__dir__' == $path) { | ||
130 | + // 生成子目录 | ||
131 | + foreach ($file as $dir) { | ||
132 | + self::checkDirBuild($modulePath . $dir); | ||
133 | + } | ||
134 | + } elseif ('__file__' == $path) { | ||
135 | + // 生成(空白)文件 | ||
136 | + foreach ($file as $name) { | ||
137 | + if (!is_file($modulePath . $name)) { | ||
138 | + file_put_contents( | ||
139 | + $modulePath . $name, | ||
140 | + 'php' == pathinfo($name, PATHINFO_EXTENSION) ? "<?php\n" : '' | ||
141 | + ); | ||
142 | + } | ||
143 | + } | ||
144 | + } else { | ||
145 | + // 生成相关 MVC 文件 | ||
146 | + foreach ($file as $val) { | ||
147 | + $val = trim($val); | ||
148 | + $filename = $modulePath . $path . DS . $val . ($suffix ? ucfirst($path) : '') . EXT; | ||
149 | + $space = $namespace . '\\' . ($module ? $module . '\\' : '') . $path; | ||
150 | + $class = $val . ($suffix ? ucfirst($path) : ''); | ||
151 | + | ||
152 | + switch ($path) { | ||
153 | + case 'controller': // 控制器 | ||
154 | + $content = "<?php\nnamespace {$space};\n\nclass {$class}\n{\n\n}"; | ||
155 | + break; | ||
156 | + case 'model': // 模型 | ||
157 | + $content = "<?php\nnamespace {$space};\n\nuse think\Model;\n\nclass {$class} extends Model\n{\n\n}"; | ||
158 | + break; | ||
159 | + case 'view': // 视图 | ||
160 | + $filename = $modulePath . $path . DS . $val . '.html'; | ||
161 | + self::checkDirBuild(dirname($filename)); | ||
162 | + $content = ''; | ||
163 | + break; | ||
164 | + default: | ||
165 | + // 其他文件 | ||
166 | + $content = "<?php\nnamespace {$space};\n\nclass {$class}\n{\n\n}"; | ||
167 | + } | ||
168 | + | ||
169 | + if (!is_file($filename)) { | ||
170 | + file_put_contents($filename, $content); | ||
171 | + } | ||
172 | + } | ||
173 | + } | ||
174 | + } | ||
175 | + } | ||
176 | + | ||
177 | + /** | ||
178 | + * 创建模块的欢迎页面 | ||
179 | + * @access protected | ||
180 | + * @param string $module 模块名 | ||
181 | + * @param string $namespace 应用类库命名空间 | ||
182 | + * @param bool $suffix 类库后缀 | ||
183 | + * @return void | ||
184 | + */ | ||
185 | + protected static function buildHello($module, $namespace, $suffix = false) | ||
186 | + { | ||
187 | + $filename = APP_PATH . ($module ? $module . DS : '') . | ||
188 | + 'controller' . DS . 'Index' . | ||
189 | + ($suffix ? 'Controller' : '') . EXT; | ||
190 | + | ||
191 | + if (!is_file($filename)) { | ||
192 | + $module = $module ? $module . '\\' : ''; | ||
193 | + $suffix = $suffix ? 'Controller' : ''; | ||
194 | + $content = str_replace( | ||
195 | + ['{$app}', '{$module}', '{layer}', '{$suffix}'], | ||
196 | + [$namespace, $module, 'controller', $suffix], | ||
197 | + file_get_contents(THINK_PATH . 'tpl' . DS . 'default_index.tpl') | ||
198 | + ); | ||
199 | + | ||
200 | + self::checkDirBuild(dirname($filename)); | ||
201 | + file_put_contents($filename, $content); | ||
202 | + } | ||
203 | + } | ||
204 | + | ||
205 | + /** | ||
206 | + * 创建模块的公共文件 | ||
207 | + * @access protected | ||
208 | + * @param string $module 模块名 | ||
209 | + * @return void | ||
210 | + */ | ||
211 | + protected static function buildCommon($module) | ||
212 | + { | ||
213 | + $config = CONF_PATH . ($module ? $module . DS : '') . 'config.php'; | ||
214 | + | ||
215 | + self::checkDirBuild(dirname($config)); | ||
216 | + | ||
217 | + if (!is_file($config)) { | ||
218 | + file_put_contents($config, "<?php\n//配置文件\nreturn [\n\n];"); | ||
219 | + } | ||
220 | + | ||
221 | + $common = APP_PATH . ($module ? $module . DS : '') . 'common.php'; | ||
222 | + if (!is_file($common)) file_put_contents($common, "<?php\n"); | ||
223 | + } | ||
224 | + | ||
225 | + /** | ||
226 | + * 创建目录 | ||
227 | + * @access protected | ||
228 | + * @param string $dirname 目录名称 | ||
229 | + * @return void | ||
230 | + */ | ||
231 | + protected static function checkDirBuild($dirname) | ||
232 | + { | ||
233 | + !is_dir($dirname) && mkdir($dirname, 0755, true); | ||
234 | + } | ||
235 | +} |
thinkphp/library/think/Cache.php
0 → 100644
1 | +<?php | ||
2 | +// +---------------------------------------------------------------------- | ||
3 | +// | ThinkPHP [ WE CAN DO IT JUST THINK ] | ||
4 | +// +---------------------------------------------------------------------- | ||
5 | +// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. | ||
6 | +// +---------------------------------------------------------------------- | ||
7 | +// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) | ||
8 | +// +---------------------------------------------------------------------- | ||
9 | +// | Author: liu21st <liu21st@gmail.com> | ||
10 | +// +---------------------------------------------------------------------- | ||
11 | + | ||
12 | +namespace think; | ||
13 | + | ||
14 | +use think\cache\Driver; | ||
15 | + | ||
16 | +class Cache | ||
17 | +{ | ||
18 | + /** | ||
19 | + * @var array 缓存的实例 | ||
20 | + */ | ||
21 | + public static $instance = []; | ||
22 | + | ||
23 | + /** | ||
24 | + * @var int 缓存读取次数 | ||
25 | + */ | ||
26 | + public static $readTimes = 0; | ||
27 | + | ||
28 | + /** | ||
29 | + * @var int 缓存写入次数 | ||
30 | + */ | ||
31 | + public static $writeTimes = 0; | ||
32 | + | ||
33 | + /** | ||
34 | + * @var object 操作句柄 | ||
35 | + */ | ||
36 | + public static $handler; | ||
37 | + | ||
38 | + /** | ||
39 | + * 连接缓存驱动 | ||
40 | + * @access public | ||
41 | + * @param array $options 配置数组 | ||
42 | + * @param bool|string $name 缓存连接标识 true 强制重新连接 | ||
43 | + * @return Driver | ||
44 | + */ | ||
45 | + public static function connect(array $options = [], $name = false) | ||
46 | + { | ||
47 | + $type = !empty($options['type']) ? $options['type'] : 'File'; | ||
48 | + | ||
49 | + if (false === $name) { | ||
50 | + $name = md5(serialize($options)); | ||
51 | + } | ||
52 | + | ||
53 | + if (true === $name || !isset(self::$instance[$name])) { | ||
54 | + $class = false === strpos($type, '\\') ? | ||
55 | + '\\think\\cache\\driver\\' . ucwords($type) : | ||
56 | + $type; | ||
57 | + | ||
58 | + // 记录初始化信息 | ||
59 | + App::$debug && Log::record('[ CACHE ] INIT ' . $type, 'info'); | ||
60 | + | ||
61 | + if (true === $name) { | ||
62 | + return new $class($options); | ||
63 | + } | ||
64 | + | ||
65 | + self::$instance[$name] = new $class($options); | ||
66 | + } | ||
67 | + | ||
68 | + return self::$instance[$name]; | ||
69 | + } | ||
70 | + | ||
71 | + /** | ||
72 | + * 自动初始化缓存 | ||
73 | + * @access public | ||
74 | + * @param array $options 配置数组 | ||
75 | + * @return Driver | ||
76 | + */ | ||
77 | + public static function init(array $options = []) | ||
78 | + { | ||
79 | + if (is_null(self::$handler)) { | ||
80 | + if (empty($options) && 'complex' == Config::get('cache.type')) { | ||
81 | + $default = Config::get('cache.default'); | ||
82 | + // 获取默认缓存配置,并连接 | ||
83 | + $options = Config::get('cache.' . $default['type']) ?: $default; | ||
84 | + } elseif (empty($options)) { | ||
85 | + $options = Config::get('cache'); | ||
86 | + } | ||
87 | + | ||
88 | + self::$handler = self::connect($options); | ||
89 | + } | ||
90 | + | ||
91 | + return self::$handler; | ||
92 | + } | ||
93 | + | ||
94 | + /** | ||
95 | + * 切换缓存类型 需要配置 cache.type 为 complex | ||
96 | + * @access public | ||
97 | + * @param string $name 缓存标识 | ||
98 | + * @return Driver | ||
99 | + */ | ||
100 | + public static function store($name = '') | ||
101 | + { | ||
102 | + if ('' !== $name && 'complex' == Config::get('cache.type')) { | ||
103 | + return self::connect(Config::get('cache.' . $name), strtolower($name)); | ||
104 | + } | ||
105 | + | ||
106 | + return self::init(); | ||
107 | + } | ||
108 | + | ||
109 | + /** | ||
110 | + * 判断缓存是否存在 | ||
111 | + * @access public | ||
112 | + * @param string $name 缓存变量名 | ||
113 | + * @return bool | ||
114 | + */ | ||
115 | + public static function has($name) | ||
116 | + { | ||
117 | + self::$readTimes++; | ||
118 | + | ||
119 | + return self::init()->has($name); | ||
120 | + } | ||
121 | + | ||
122 | + /** | ||
123 | + * 读取缓存 | ||
124 | + * @access public | ||
125 | + * @param string $name 缓存标识 | ||
126 | + * @param mixed $default 默认值 | ||
127 | + * @return mixed | ||
128 | + */ | ||
129 | + public static function get($name, $default = false) | ||
130 | + { | ||
131 | + self::$readTimes++; | ||
132 | + | ||
133 | + return self::init()->get($name, $default); | ||
134 | + } | ||
135 | + | ||
136 | + /** | ||
137 | + * 写入缓存 | ||
138 | + * @access public | ||
139 | + * @param string $name 缓存标识 | ||
140 | + * @param mixed $value 存储数据 | ||
141 | + * @param int|null $expire 有效时间 0为永久 | ||
142 | + * @return boolean | ||
143 | + */ | ||
144 | + public static function set($name, $value, $expire = null) | ||
145 | + { | ||
146 | + self::$writeTimes++; | ||
147 | + | ||
148 | + return self::init()->set($name, $value, $expire); | ||
149 | + } | ||
150 | + | ||
151 | + /** | ||
152 | + * 自增缓存(针对数值缓存) | ||
153 | + * @access public | ||
154 | + * @param string $name 缓存变量名 | ||
155 | + * @param int $step 步长 | ||
156 | + * @return false|int | ||
157 | + */ | ||
158 | + public static function inc($name, $step = 1) | ||
159 | + { | ||
160 | + self::$writeTimes++; | ||
161 | + | ||
162 | + return self::init()->inc($name, $step); | ||
163 | + } | ||
164 | + | ||
165 | + /** | ||
166 | + * 自减缓存(针对数值缓存) | ||
167 | + * @access public | ||
168 | + * @param string $name 缓存变量名 | ||
169 | + * @param int $step 步长 | ||
170 | + * @return false|int | ||
171 | + */ | ||
172 | + public static function dec($name, $step = 1) | ||
173 | + { | ||
174 | + self::$writeTimes++; | ||
175 | + | ||
176 | + return self::init()->dec($name, $step); | ||
177 | + } | ||
178 | + | ||
179 | + /** | ||
180 | + * 删除缓存 | ||
181 | + * @access public | ||
182 | + * @param string $name 缓存标识 | ||
183 | + * @return boolean | ||
184 | + */ | ||
185 | + public static function rm($name) | ||
186 | + { | ||
187 | + self::$writeTimes++; | ||
188 | + | ||
189 | + return self::init()->rm($name); | ||
190 | + } | ||
191 | + | ||
192 | + /** | ||
193 | + * 清除缓存 | ||
194 | + * @access public | ||
195 | + * @param string $tag 标签名 | ||
196 | + * @return boolean | ||
197 | + */ | ||
198 | + public static function clear($tag = null) | ||
199 | + { | ||
200 | + self::$writeTimes++; | ||
201 | + | ||
202 | + return self::init()->clear($tag); | ||
203 | + } | ||
204 | + | ||
205 | + /** | ||
206 | + * 读取缓存并删除 | ||
207 | + * @access public | ||
208 | + * @param string $name 缓存变量名 | ||
209 | + * @return mixed | ||
210 | + */ | ||
211 | + public static function pull($name) | ||
212 | + { | ||
213 | + self::$readTimes++; | ||
214 | + self::$writeTimes++; | ||
215 | + | ||
216 | + return self::init()->pull($name); | ||
217 | + } | ||
218 | + | ||
219 | + /** | ||
220 | + * 如果不存在则写入缓存 | ||
221 | + * @access public | ||
222 | + * @param string $name 缓存变量名 | ||
223 | + * @param mixed $value 存储数据 | ||
224 | + * @param int $expire 有效时间 0为永久 | ||
225 | + * @return mixed | ||
226 | + */ | ||
227 | + public static function remember($name, $value, $expire = null) | ||
228 | + { | ||
229 | + self::$readTimes++; | ||
230 | + | ||
231 | + return self::init()->remember($name, $value, $expire); | ||
232 | + } | ||
233 | + | ||
234 | + /** | ||
235 | + * 缓存标签 | ||
236 | + * @access public | ||
237 | + * @param string $name 标签名 | ||
238 | + * @param string|array $keys 缓存标识 | ||
239 | + * @param bool $overlay 是否覆盖 | ||
240 | + * @return Driver | ||
241 | + */ | ||
242 | + public static function tag($name, $keys = null, $overlay = false) | ||
243 | + { | ||
244 | + return self::init()->tag($name, $keys, $overlay); | ||
245 | + } | ||
246 | + | ||
247 | +} |
thinkphp/library/think/Collection.php
0 → 100644
1 | +<?php | ||
2 | +// +---------------------------------------------------------------------- | ||
3 | +// | ThinkPHP [ WE CAN DO IT JUST THINK ] | ||
4 | +// +---------------------------------------------------------------------- | ||
5 | +// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. | ||
6 | +// +---------------------------------------------------------------------- | ||
7 | +// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) | ||
8 | +// +---------------------------------------------------------------------- | ||
9 | +// | Author: zhangyajun <448901948@qq.com> | ||
10 | +// +---------------------------------------------------------------------- | ||
11 | + | ||
12 | +namespace think; | ||
13 | + | ||
14 | +use ArrayAccess; | ||
15 | +use ArrayIterator; | ||
16 | +use Countable; | ||
17 | +use IteratorAggregate; | ||
18 | +use JsonSerializable; | ||
19 | + | ||
20 | +class Collection implements ArrayAccess, Countable, IteratorAggregate, JsonSerializable | ||
21 | +{ | ||
22 | + /** | ||
23 | + * @var array 数据 | ||
24 | + */ | ||
25 | + protected $items = []; | ||
26 | + | ||
27 | + /** | ||
28 | + * Collection constructor. | ||
29 | + * @access public | ||
30 | + * @param array $items 数据 | ||
31 | + */ | ||
32 | + public function __construct($items = []) | ||
33 | + { | ||
34 | + $this->items = $this->convertToArray($items); | ||
35 | + } | ||
36 | + | ||
37 | + /** | ||
38 | + * 创建 Collection 实例 | ||
39 | + * @access public | ||
40 | + * @param array $items 数据 | ||
41 | + * @return static | ||
42 | + */ | ||
43 | + public static function make($items = []) | ||
44 | + { | ||
45 | + return new static($items); | ||
46 | + } | ||
47 | + | ||
48 | + /** | ||
49 | + * 判断数据是否为空 | ||
50 | + * @access public | ||
51 | + * @return bool | ||
52 | + */ | ||
53 | + public function isEmpty() | ||
54 | + { | ||
55 | + return empty($this->items); | ||
56 | + } | ||
57 | + | ||
58 | + /** | ||
59 | + * 将数据转成数组 | ||
60 | + * @access public | ||
61 | + * @return array | ||
62 | + */ | ||
63 | + public function toArray() | ||
64 | + { | ||
65 | + return array_map(function ($value) { | ||
66 | + return ($value instanceof Model || $value instanceof self) ? | ||
67 | + $value->toArray() : | ||
68 | + $value; | ||
69 | + }, $this->items); | ||
70 | + } | ||
71 | + | ||
72 | + /** | ||
73 | + * 获取全部的数据 | ||
74 | + * @access public | ||
75 | + * @return array | ||
76 | + */ | ||
77 | + public function all() | ||
78 | + { | ||
79 | + return $this->items; | ||
80 | + } | ||
81 | + | ||
82 | + /** | ||
83 | + * 交换数组中的键和值 | ||
84 | + * @access public | ||
85 | + * @return static | ||
86 | + */ | ||
87 | + public function flip() | ||
88 | + { | ||
89 | + return new static(array_flip($this->items)); | ||
90 | + } | ||
91 | + | ||
92 | + /** | ||
93 | + * 返回数组中所有的键名组成的新 Collection 实例 | ||
94 | + * @access public | ||
95 | + * @return static | ||
96 | + */ | ||
97 | + public function keys() | ||
98 | + { | ||
99 | + return new static(array_keys($this->items)); | ||
100 | + } | ||
101 | + | ||
102 | + /** | ||
103 | + * 返回数组中所有的值组成的新 Collection 实例 | ||
104 | + * @access public | ||
105 | + * @return static | ||
106 | + */ | ||
107 | + public function values() | ||
108 | + { | ||
109 | + return new static(array_values($this->items)); | ||
110 | + } | ||
111 | + | ||
112 | + /** | ||
113 | + * 合并数组并返回一个新的 Collection 实例 | ||
114 | + * @access public | ||
115 | + * @param mixed $items 新的数据 | ||
116 | + * @return static | ||
117 | + */ | ||
118 | + public function merge($items) | ||
119 | + { | ||
120 | + return new static(array_merge($this->items, $this->convertToArray($items))); | ||
121 | + } | ||
122 | + | ||
123 | + /** | ||
124 | + * 比较数组,返回差集生成的新 Collection 实例 | ||
125 | + * @access public | ||
126 | + * @param mixed $items 做比较的数据 | ||
127 | + * @return static | ||
128 | + */ | ||
129 | + public function diff($items) | ||
130 | + { | ||
131 | + return new static(array_diff($this->items, $this->convertToArray($items))); | ||
132 | + } | ||
133 | + | ||
134 | + /** | ||
135 | + * 比较数组,返回交集组成的 Collection 新实例 | ||
136 | + * @access public | ||
137 | + * @param mixed $items 比较数据 | ||
138 | + * @return static | ||
139 | + */ | ||
140 | + public function intersect($items) | ||
141 | + { | ||
142 | + return new static(array_intersect($this->items, $this->convertToArray($items))); | ||
143 | + } | ||
144 | + | ||
145 | + /** | ||
146 | + * 返回并删除数据中的的最后一个元素(出栈) | ||
147 | + * @access public | ||
148 | + * @return mixed | ||
149 | + */ | ||
150 | + public function pop() | ||
151 | + { | ||
152 | + return array_pop($this->items); | ||
153 | + } | ||
154 | + | ||
155 | + /** | ||
156 | + * 返回并删除数据中首个元素 | ||
157 | + * @access public | ||
158 | + * @return mixed | ||
159 | + */ | ||
160 | + public function shift() | ||
161 | + { | ||
162 | + return array_shift($this->items); | ||
163 | + } | ||
164 | + | ||
165 | + /** | ||
166 | + * 在数组开头插入一个元素 | ||
167 | + * @access public | ||
168 | + * @param mixed $value 值 | ||
169 | + * @param mixed $key 键名 | ||
170 | + * @return void | ||
171 | + */ | ||
172 | + public function unshift($value, $key = null) | ||
173 | + { | ||
174 | + if (is_null($key)) { | ||
175 | + array_unshift($this->items, $value); | ||
176 | + } else { | ||
177 | + $this->items = [$key => $value] + $this->items; | ||
178 | + } | ||
179 | + } | ||
180 | + | ||
181 | + /** | ||
182 | + * 在数组结尾插入一个元素 | ||
183 | + * @access public | ||
184 | + * @param mixed $value 值 | ||
185 | + * @param mixed $key 键名 | ||
186 | + * @return void | ||
187 | + */ | ||
188 | + public function push($value, $key = null) | ||
189 | + { | ||
190 | + if (is_null($key)) { | ||
191 | + $this->items[] = $value; | ||
192 | + } else { | ||
193 | + $this->items[$key] = $value; | ||
194 | + } | ||
195 | + } | ||
196 | + | ||
197 | + /** | ||
198 | + * 通过使用用户自定义函数,以字符串返回数组 | ||
199 | + * @access public | ||
200 | + * @param callable $callback 回调函数 | ||
201 | + * @param mixed $initial 初始值 | ||
202 | + * @return mixed | ||
203 | + */ | ||
204 | + public function reduce(callable $callback, $initial = null) | ||
205 | + { | ||
206 | + return array_reduce($this->items, $callback, $initial); | ||
207 | + } | ||
208 | + | ||
209 | + /** | ||
210 | + * 以相反的顺序创建一个新的 Collection 实例 | ||
211 | + * @access public | ||
212 | + * @return static | ||
213 | + */ | ||
214 | + public function reverse() | ||
215 | + { | ||
216 | + return new static(array_reverse($this->items)); | ||
217 | + } | ||
218 | + | ||
219 | + /** | ||
220 | + * 把数据分割为新的数组块 | ||
221 | + * @access public | ||
222 | + * @param int $size 分隔长度 | ||
223 | + * @param bool $preserveKeys 是否保持原数据索引 | ||
224 | + * @return static | ||
225 | + */ | ||
226 | + public function chunk($size, $preserveKeys = false) | ||
227 | + { | ||
228 | + $chunks = []; | ||
229 | + | ||
230 | + foreach (array_chunk($this->items, $size, $preserveKeys) as $chunk) { | ||
231 | + $chunks[] = new static($chunk); | ||
232 | + } | ||
233 | + | ||
234 | + return new static($chunks); | ||
235 | + } | ||
236 | + | ||
237 | + /** | ||
238 | + * 给数据中的每个元素执行回调 | ||
239 | + * @access public | ||
240 | + * @param callable $callback 回调函数 | ||
241 | + * @return $this | ||
242 | + */ | ||
243 | + public function each(callable $callback) | ||
244 | + { | ||
245 | + foreach ($this->items as $key => $item) { | ||
246 | + $result = $callback($item, $key); | ||
247 | + | ||
248 | + if (false === $result) { | ||
249 | + break; | ||
250 | + } | ||
251 | + | ||
252 | + if (!is_object($item)) { | ||
253 | + $this->items[$key] = $result; | ||
254 | + } | ||
255 | + } | ||
256 | + | ||
257 | + return $this; | ||
258 | + } | ||
259 | + | ||
260 | + /** | ||
261 | + * 用回调函数过滤数据中的元素 | ||
262 | + * @access public | ||
263 | + * @param callable|null $callback 回调函数 | ||
264 | + * @return static | ||
265 | + */ | ||
266 | + public function filter(callable $callback = null) | ||
267 | + { | ||
268 | + return new static(array_filter($this->items, $callback ?: null)); | ||
269 | + } | ||
270 | + | ||
271 | + /** | ||
272 | + * 返回数据中指定的一列 | ||
273 | + * @access public | ||
274 | + * @param mixed $columnKey 键名 | ||
275 | + * @param null $indexKey 作为索引值的列 | ||
276 | + * @return array | ||
277 | + */ | ||
278 | + public function column($columnKey, $indexKey = null) | ||
279 | + { | ||
280 | + if (function_exists('array_column')) { | ||
281 | + return array_column($this->items, $columnKey, $indexKey); | ||
282 | + } | ||
283 | + | ||
284 | + $result = []; | ||
285 | + foreach ($this->items as $row) { | ||
286 | + $key = $value = null; | ||
287 | + $keySet = $valueSet = false; | ||
288 | + | ||
289 | + if (null !== $indexKey && array_key_exists($indexKey, $row)) { | ||
290 | + $key = (string) $row[$indexKey]; | ||
291 | + $keySet = true; | ||
292 | + } | ||
293 | + | ||
294 | + if (null === $columnKey) { | ||
295 | + $valueSet = true; | ||
296 | + $value = $row; | ||
297 | + } elseif (is_array($row) && array_key_exists($columnKey, $row)) { | ||
298 | + $valueSet = true; | ||
299 | + $value = $row[$columnKey]; | ||
300 | + } | ||
301 | + | ||
302 | + if ($valueSet) { | ||
303 | + if ($keySet) { | ||
304 | + $result[$key] = $value; | ||
305 | + } else { | ||
306 | + $result[] = $value; | ||
307 | + } | ||
308 | + } | ||
309 | + } | ||
310 | + | ||
311 | + return $result; | ||
312 | + } | ||
313 | + | ||
314 | + /** | ||
315 | + * 对数据排序,并返回排序后的数据组成的新 Collection 实例 | ||
316 | + * @access public | ||
317 | + * @param callable|null $callback 回调函数 | ||
318 | + * @return static | ||
319 | + */ | ||
320 | + public function sort(callable $callback = null) | ||
321 | + { | ||
322 | + $items = $this->items; | ||
323 | + $callback = $callback ?: function ($a, $b) { | ||
324 | + return $a == $b ? 0 : (($a < $b) ? -1 : 1); | ||
325 | + }; | ||
326 | + | ||
327 | + uasort($items, $callback); | ||
328 | + return new static($items); | ||
329 | + } | ||
330 | + | ||
331 | + /** | ||
332 | + * 将数据打乱后组成新的 Collection 实例 | ||
333 | + * @access public | ||
334 | + * @return static | ||
335 | + */ | ||
336 | + public function shuffle() | ||
337 | + { | ||
338 | + $items = $this->items; | ||
339 | + | ||
340 | + shuffle($items); | ||
341 | + return new static($items); | ||
342 | + } | ||
343 | + | ||
344 | + /** | ||
345 | + * 截取数据并返回新的 Collection 实例 | ||
346 | + * @access public | ||
347 | + * @param int $offset 起始位置 | ||
348 | + * @param int $length 截取长度 | ||
349 | + * @param bool $preserveKeys 是否保持原先的键名 | ||
350 | + * @return static | ||
351 | + */ | ||
352 | + public function slice($offset, $length = null, $preserveKeys = false) | ||
353 | + { | ||
354 | + return new static(array_slice($this->items, $offset, $length, $preserveKeys)); | ||
355 | + } | ||
356 | + | ||
357 | + /** | ||
358 | + * 指定的键是否存在 | ||
359 | + * @access public | ||
360 | + * @param mixed $offset 键名 | ||
361 | + * @return bool | ||
362 | + */ | ||
363 | + public function offsetExists($offset) | ||
364 | + { | ||
365 | + return array_key_exists($offset, $this->items); | ||
366 | + } | ||
367 | + | ||
368 | + /** | ||
369 | + * 获取指定键对应的值 | ||
370 | + * @access public | ||
371 | + * @param mixed $offset 键名 | ||
372 | + * @return mixed | ||
373 | + */ | ||
374 | + public function offsetGet($offset) | ||
375 | + { | ||
376 | + return $this->items[$offset]; | ||
377 | + } | ||
378 | + | ||
379 | + /** | ||
380 | + * 设置键值 | ||
381 | + * @access public | ||
382 | + * @param mixed $offset 键名 | ||
383 | + * @param mixed $value 值 | ||
384 | + * @return void | ||
385 | + */ | ||
386 | + public function offsetSet($offset, $value) | ||
387 | + { | ||
388 | + if (is_null($offset)) { | ||
389 | + $this->items[] = $value; | ||
390 | + } else { | ||
391 | + $this->items[$offset] = $value; | ||
392 | + } | ||
393 | + } | ||
394 | + | ||
395 | + /** | ||
396 | + * 删除指定键值 | ||
397 | + * @access public | ||
398 | + * @param mixed $offset 键名 | ||
399 | + * @return void | ||
400 | + */ | ||
401 | + public function offsetUnset($offset) | ||
402 | + { | ||
403 | + unset($this->items[$offset]); | ||
404 | + } | ||
405 | + | ||
406 | + /** | ||
407 | + * 统计数据的个数 | ||
408 | + * @access public | ||
409 | + * @return int | ||
410 | + */ | ||
411 | + public function count() | ||
412 | + { | ||
413 | + return count($this->items); | ||
414 | + } | ||
415 | + | ||
416 | + /** | ||
417 | + * 获取数据的迭代器 | ||
418 | + * @access public | ||
419 | + * @return ArrayIterator | ||
420 | + */ | ||
421 | + public function getIterator() | ||
422 | + { | ||
423 | + return new ArrayIterator($this->items); | ||
424 | + } | ||
425 | + | ||
426 | + /** | ||
427 | + * 将数据反序列化成数组 | ||
428 | + * @access public | ||
429 | + * @return array | ||
430 | + */ | ||
431 | + public function jsonSerialize() | ||
432 | + { | ||
433 | + return $this->toArray(); | ||
434 | + } | ||
435 | + | ||
436 | + /** | ||
437 | + * 转换当前数据集为 JSON 字符串 | ||
438 | + * @access public | ||
439 | + * @param integer $options json 参数 | ||
440 | + * @return string | ||
441 | + */ | ||
442 | + public function toJson($options = JSON_UNESCAPED_UNICODE) | ||
443 | + { | ||
444 | + return json_encode($this->toArray(), $options); | ||
445 | + } | ||
446 | + | ||
447 | + /** | ||
448 | + * 将数据转换成字符串 | ||
449 | + * @access public | ||
450 | + * @return string | ||
451 | + */ | ||
452 | + public function __toString() | ||
453 | + { | ||
454 | + return $this->toJson(); | ||
455 | + } | ||
456 | + | ||
457 | + /** | ||
458 | + * 将数据转换成数组 | ||
459 | + * @access protected | ||
460 | + * @param mixed $items 数据 | ||
461 | + * @return array | ||
462 | + */ | ||
463 | + protected function convertToArray($items) | ||
464 | + { | ||
465 | + return $items instanceof self ? $items->all() : (array) $items; | ||
466 | + } | ||
467 | +} |
thinkphp/library/think/Config.php
0 → 100644
1 | +<?php | ||
2 | +// +---------------------------------------------------------------------- | ||
3 | +// | ThinkPHP [ WE CAN DO IT JUST THINK ] | ||
4 | +// +---------------------------------------------------------------------- | ||
5 | +// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. | ||
6 | +// +---------------------------------------------------------------------- | ||
7 | +// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) | ||
8 | +// +---------------------------------------------------------------------- | ||
9 | +// | Author: liu21st <liu21st@gmail.com> | ||
10 | +// +---------------------------------------------------------------------- | ||
11 | + | ||
12 | +namespace think; | ||
13 | + | ||
14 | +class Config | ||
15 | +{ | ||
16 | + /** | ||
17 | + * @var array 配置参数 | ||
18 | + */ | ||
19 | + private static $config = []; | ||
20 | + | ||
21 | + /** | ||
22 | + * @var string 参数作用域 | ||
23 | + */ | ||
24 | + private static $range = '_sys_'; | ||
25 | + | ||
26 | + /** | ||
27 | + * 设定配置参数的作用域 | ||
28 | + * @access public | ||
29 | + * @param string $range 作用域 | ||
30 | + * @return void | ||
31 | + */ | ||
32 | + public static function range($range) | ||
33 | + { | ||
34 | + self::$range = $range; | ||
35 | + | ||
36 | + if (!isset(self::$config[$range])) self::$config[$range] = []; | ||
37 | + } | ||
38 | + | ||
39 | + /** | ||
40 | + * 解析配置文件或内容 | ||
41 | + * @access public | ||
42 | + * @param string $config 配置文件路径或内容 | ||
43 | + * @param string $type 配置解析类型 | ||
44 | + * @param string $name 配置名(如设置即表示二级配置) | ||
45 | + * @param string $range 作用域 | ||
46 | + * @return mixed | ||
47 | + */ | ||
48 | + public static function parse($config, $type = '', $name = '', $range = '') | ||
49 | + { | ||
50 | + $range = $range ?: self::$range; | ||
51 | + | ||
52 | + if (empty($type)) $type = pathinfo($config, PATHINFO_EXTENSION); | ||
53 | + | ||
54 | + $class = false !== strpos($type, '\\') ? | ||
55 | + $type : | ||
56 | + '\\think\\config\\driver\\' . ucwords($type); | ||
57 | + | ||
58 | + return self::set((new $class())->parse($config), $name, $range); | ||
59 | + } | ||
60 | + | ||
61 | + /** | ||
62 | + * 加载配置文件(PHP格式) | ||
63 | + * @access public | ||
64 | + * @param string $file 配置文件名 | ||
65 | + * @param string $name 配置名(如设置即表示二级配置) | ||
66 | + * @param string $range 作用域 | ||
67 | + * @return mixed | ||
68 | + */ | ||
69 | + public static function load($file, $name = '', $range = '') | ||
70 | + { | ||
71 | + $range = $range ?: self::$range; | ||
72 | + | ||
73 | + if (!isset(self::$config[$range])) self::$config[$range] = []; | ||
74 | + | ||
75 | + if (is_file($file)) { | ||
76 | + $name = strtolower($name); | ||
77 | + $type = pathinfo($file, PATHINFO_EXTENSION); | ||
78 | + | ||
79 | + if ('php' == $type) { | ||
80 | + return self::set(include $file, $name, $range); | ||
81 | + } | ||
82 | + | ||
83 | + if ('yaml' == $type && function_exists('yaml_parse_file')) { | ||
84 | + return self::set(yaml_parse_file($file), $name, $range); | ||
85 | + } | ||
86 | + | ||
87 | + return self::parse($file, $type, $name, $range); | ||
88 | + } | ||
89 | + | ||
90 | + return self::$config[$range]; | ||
91 | + } | ||
92 | + | ||
93 | + /** | ||
94 | + * 检测配置是否存在 | ||
95 | + * @access public | ||
96 | + * @param string $name 配置参数名(支持二级配置 . 号分割) | ||
97 | + * @param string $range 作用域 | ||
98 | + * @return bool | ||
99 | + */ | ||
100 | + public static function has($name, $range = '') | ||
101 | + { | ||
102 | + $range = $range ?: self::$range; | ||
103 | + | ||
104 | + if (!strpos($name, '.')) { | ||
105 | + return isset(self::$config[$range][strtolower($name)]); | ||
106 | + } | ||
107 | + | ||
108 | + // 二维数组设置和获取支持 | ||
109 | + $name = explode('.', $name, 2); | ||
110 | + return isset(self::$config[$range][strtolower($name[0])][$name[1]]); | ||
111 | + } | ||
112 | + | ||
113 | + /** | ||
114 | + * 获取配置参数 为空则获取所有配置 | ||
115 | + * @access public | ||
116 | + * @param string $name 配置参数名(支持二级配置 . 号分割) | ||
117 | + * @param string $range 作用域 | ||
118 | + * @return mixed | ||
119 | + */ | ||
120 | + public static function get($name = null, $range = '') | ||
121 | + { | ||
122 | + $range = $range ?: self::$range; | ||
123 | + | ||
124 | + // 无参数时获取所有 | ||
125 | + if (empty($name) && isset(self::$config[$range])) { | ||
126 | + return self::$config[$range]; | ||
127 | + } | ||
128 | + | ||
129 | + // 非二级配置时直接返回 | ||
130 | + if (!strpos($name, '.')) { | ||
131 | + $name = strtolower($name); | ||
132 | + return isset(self::$config[$range][$name]) ? self::$config[$range][$name] : null; | ||
133 | + } | ||
134 | + | ||
135 | + // 二维数组设置和获取支持 | ||
136 | + $name = explode('.', $name, 2); | ||
137 | + $name[0] = strtolower($name[0]); | ||
138 | + | ||
139 | + if (!isset(self::$config[$range][$name[0]])) { | ||
140 | + // 动态载入额外配置 | ||
141 | + $module = Request::instance()->module(); | ||
142 | + $file = CONF_PATH . ($module ? $module . DS : '') . 'extra' . DS . $name[0] . CONF_EXT; | ||
143 | + | ||
144 | + is_file($file) && self::load($file, $name[0]); | ||
145 | + } | ||
146 | + | ||
147 | + return isset(self::$config[$range][$name[0]][$name[1]]) ? | ||
148 | + self::$config[$range][$name[0]][$name[1]] : | ||
149 | + null; | ||
150 | + } | ||
151 | + | ||
152 | + /** | ||
153 | + * 设置配置参数 name 为数组则为批量设置 | ||
154 | + * @access public | ||
155 | + * @param string|array $name 配置参数名(支持二级配置 . 号分割) | ||
156 | + * @param mixed $value 配置值 | ||
157 | + * @param string $range 作用域 | ||
158 | + * @return mixed | ||
159 | + */ | ||
160 | + public static function set($name, $value = null, $range = '') | ||
161 | + { | ||
162 | + $range = $range ?: self::$range; | ||
163 | + | ||
164 | + if (!isset(self::$config[$range])) self::$config[$range] = []; | ||
165 | + | ||
166 | + // 字符串则表示单个配置设置 | ||
167 | + if (is_string($name)) { | ||
168 | + if (!strpos($name, '.')) { | ||
169 | + self::$config[$range][strtolower($name)] = $value; | ||
170 | + } else { | ||
171 | + // 二维数组 | ||
172 | + $name = explode('.', $name, 2); | ||
173 | + self::$config[$range][strtolower($name[0])][$name[1]] = $value; | ||
174 | + } | ||
175 | + | ||
176 | + return $value; | ||
177 | + } | ||
178 | + | ||
179 | + // 数组则表示批量设置 | ||
180 | + if (is_array($name)) { | ||
181 | + if (!empty($value)) { | ||
182 | + self::$config[$range][$value] = isset(self::$config[$range][$value]) ? | ||
183 | + array_merge(self::$config[$range][$value], $name) : | ||
184 | + $name; | ||
185 | + | ||
186 | + return self::$config[$range][$value]; | ||
187 | + } | ||
188 | + | ||
189 | + return self::$config[$range] = array_merge( | ||
190 | + self::$config[$range], array_change_key_case($name) | ||
191 | + ); | ||
192 | + } | ||
193 | + | ||
194 | + // 为空直接返回已有配置 | ||
195 | + return self::$config[$range]; | ||
196 | + } | ||
197 | + | ||
198 | + /** | ||
199 | + * 重置配置参数 | ||
200 | + * @access public | ||
201 | + * @param string $range 作用域 | ||
202 | + * @return void | ||
203 | + */ | ||
204 | + public static function reset($range = '') | ||
205 | + { | ||
206 | + $range = $range ?: self::$range; | ||
207 | + | ||
208 | + if (true === $range) { | ||
209 | + self::$config = []; | ||
210 | + } else { | ||
211 | + self::$config[$range] = []; | ||
212 | + } | ||
213 | + } | ||
214 | +} |
thinkphp/library/think/Console.php
0 → 100644
1 | +<?php | ||
2 | +// +---------------------------------------------------------------------- | ||
3 | +// | TopThink [ WE CAN DO IT JUST THINK IT ] | ||
4 | +// +---------------------------------------------------------------------- | ||
5 | +// | Copyright (c) 2015 http://www.topthink.com All rights reserved. | ||
6 | +// +---------------------------------------------------------------------- | ||
7 | +// | Author: zhangyajun <448901948@qq.com> | ||
8 | +// +---------------------------------------------------------------------- | ||
9 | + | ||
10 | +namespace think; | ||
11 | + | ||
12 | +use think\console\Command; | ||
13 | +use think\console\command\Help as HelpCommand; | ||
14 | +use think\console\Input; | ||
15 | +use think\console\input\Argument as InputArgument; | ||
16 | +use think\console\input\Definition as InputDefinition; | ||
17 | +use think\console\input\Option as InputOption; | ||
18 | +use think\console\Output; | ||
19 | +use think\console\output\driver\Buffer; | ||
20 | + | ||
21 | +class Console | ||
22 | +{ | ||
23 | + /** | ||
24 | + * @var string 命令名称 | ||
25 | + */ | ||
26 | + private $name; | ||
27 | + | ||
28 | + /** | ||
29 | + * @var string 命令版本 | ||
30 | + */ | ||
31 | + private $version; | ||
32 | + | ||
33 | + /** | ||
34 | + * @var Command[] 命令 | ||
35 | + */ | ||
36 | + private $commands = []; | ||
37 | + | ||
38 | + /** | ||
39 | + * @var bool 是否需要帮助信息 | ||
40 | + */ | ||
41 | + private $wantHelps = false; | ||
42 | + | ||
43 | + /** | ||
44 | + * @var bool 是否捕获异常 | ||
45 | + */ | ||
46 | + private $catchExceptions = true; | ||
47 | + | ||
48 | + /** | ||
49 | + * @var bool 是否自动退出执行 | ||
50 | + */ | ||
51 | + private $autoExit = true; | ||
52 | + | ||
53 | + /** | ||
54 | + * @var InputDefinition 输入定义 | ||
55 | + */ | ||
56 | + private $definition; | ||
57 | + | ||
58 | + /** | ||
59 | + * @var string 默认执行的命令 | ||
60 | + */ | ||
61 | + private $defaultCommand; | ||
62 | + | ||
63 | + /** | ||
64 | + * @var array 默认提供的命令 | ||
65 | + */ | ||
66 | + private static $defaultCommands = [ | ||
67 | + "think\\console\\command\\Help", | ||
68 | + "think\\console\\command\\Lists", | ||
69 | + "think\\console\\command\\Build", | ||
70 | + "think\\console\\command\\Clear", | ||
71 | + "think\\console\\command\\make\\Controller", | ||
72 | + "think\\console\\command\\make\\Model", | ||
73 | + "think\\console\\command\\optimize\\Autoload", | ||
74 | + "think\\console\\command\\optimize\\Config", | ||
75 | + "think\\console\\command\\optimize\\Route", | ||
76 | + "think\\console\\command\\optimize\\Schema", | ||
77 | + ]; | ||
78 | + | ||
79 | + /** | ||
80 | + * Console constructor. | ||
81 | + * @access public | ||
82 | + * @param string $name 名称 | ||
83 | + * @param string $version 版本 | ||
84 | + * @param null|string $user 执行用户 | ||
85 | + */ | ||
86 | + public function __construct($name = 'UNKNOWN', $version = 'UNKNOWN', $user = null) | ||
87 | + { | ||
88 | + $this->name = $name; | ||
89 | + $this->version = $version; | ||
90 | + | ||
91 | + if ($user) { | ||
92 | + $this->setUser($user); | ||
93 | + } | ||
94 | + | ||
95 | + $this->defaultCommand = 'list'; | ||
96 | + $this->definition = $this->getDefaultInputDefinition(); | ||
97 | + | ||
98 | + foreach ($this->getDefaultCommands() as $command) { | ||
99 | + $this->add($command); | ||
100 | + } | ||
101 | + } | ||
102 | + | ||
103 | + /** | ||
104 | + * 设置执行用户 | ||
105 | + * @param $user | ||
106 | + */ | ||
107 | + public function setUser($user) | ||
108 | + { | ||
109 | + $user = posix_getpwnam($user); | ||
110 | + if ($user) { | ||
111 | + posix_setuid($user['uid']); | ||
112 | + posix_setgid($user['gid']); | ||
113 | + } | ||
114 | + } | ||
115 | + | ||
116 | + /** | ||
117 | + * 初始化 Console | ||
118 | + * @access public | ||
119 | + * @param bool $run 是否运行 Console | ||
120 | + * @return int|Console | ||
121 | + */ | ||
122 | + public static function init($run = true) | ||
123 | + { | ||
124 | + static $console; | ||
125 | + | ||
126 | + if (!$console) { | ||
127 | + $config = Config::get('console'); | ||
128 | + // 实例化 console | ||
129 | + $console = new self($config['name'], $config['version'], $config['user']); | ||
130 | + | ||
131 | + // 读取指令集 | ||
132 | + if (is_file(CONF_PATH . 'command' . EXT)) { | ||
133 | + $commands = include CONF_PATH . 'command' . EXT; | ||
134 | + | ||
135 | + if (is_array($commands)) { | ||
136 | + foreach ($commands as $command) { | ||
137 | + class_exists($command) && | ||
138 | + is_subclass_of($command, "\\think\\console\\Command") && | ||
139 | + $console->add(new $command()); // 注册指令 | ||
140 | + } | ||
141 | + } | ||
142 | + } | ||
143 | + } | ||
144 | + | ||
145 | + return $run ? $console->run() : $console; | ||
146 | + } | ||
147 | + | ||
148 | + /** | ||
149 | + * 调用命令 | ||
150 | + * @access public | ||
151 | + * @param string $command | ||
152 | + * @param array $parameters | ||
153 | + * @param string $driver | ||
154 | + * @return Output | ||
155 | + */ | ||
156 | + public static function call($command, array $parameters = [], $driver = 'buffer') | ||
157 | + { | ||
158 | + $console = self::init(false); | ||
159 | + | ||
160 | + array_unshift($parameters, $command); | ||
161 | + | ||
162 | + $input = new Input($parameters); | ||
163 | + $output = new Output($driver); | ||
164 | + | ||
165 | + $console->setCatchExceptions(false); | ||
166 | + $console->find($command)->run($input, $output); | ||
167 | + | ||
168 | + return $output; | ||
169 | + } | ||
170 | + | ||
171 | + /** | ||
172 | + * 执行当前的指令 | ||
173 | + * @access public | ||
174 | + * @return int | ||
175 | + * @throws \Exception | ||
176 | + */ | ||
177 | + public function run() | ||
178 | + { | ||
179 | + $input = new Input(); | ||
180 | + $output = new Output(); | ||
181 | + | ||
182 | + $this->configureIO($input, $output); | ||
183 | + | ||
184 | + try { | ||
185 | + $exitCode = $this->doRun($input, $output); | ||
186 | + } catch (\Exception $e) { | ||
187 | + if (!$this->catchExceptions) throw $e; | ||
188 | + | ||
189 | + $output->renderException($e); | ||
190 | + | ||
191 | + $exitCode = $e->getCode(); | ||
192 | + | ||
193 | + if (is_numeric($exitCode)) { | ||
194 | + $exitCode = ((int) $exitCode) ?: 1; | ||
195 | + } else { | ||
196 | + $exitCode = 1; | ||
197 | + } | ||
198 | + } | ||
199 | + | ||
200 | + if ($this->autoExit) { | ||
201 | + if ($exitCode > 255) $exitCode = 255; | ||
202 | + | ||
203 | + exit($exitCode); | ||
204 | + } | ||
205 | + | ||
206 | + return $exitCode; | ||
207 | + } | ||
208 | + | ||
209 | + /** | ||
210 | + * 执行指令 | ||
211 | + * @access public | ||
212 | + * @param Input $input 输入 | ||
213 | + * @param Output $output 输出 | ||
214 | + * @return int | ||
215 | + */ | ||
216 | + public function doRun(Input $input, Output $output) | ||
217 | + { | ||
218 | + // 获取版本信息 | ||
219 | + if (true === $input->hasParameterOption(['--version', '-V'])) { | ||
220 | + $output->writeln($this->getLongVersion()); | ||
221 | + | ||
222 | + return 0; | ||
223 | + } | ||
224 | + | ||
225 | + $name = $this->getCommandName($input); | ||
226 | + | ||
227 | + // 获取帮助信息 | ||
228 | + if (true === $input->hasParameterOption(['--help', '-h'])) { | ||
229 | + if (!$name) { | ||
230 | + $name = 'help'; | ||
231 | + $input = new Input(['help']); | ||
232 | + } else { | ||
233 | + $this->wantHelps = true; | ||
234 | + } | ||
235 | + } | ||
236 | + | ||
237 | + if (!$name) { | ||
238 | + $name = $this->defaultCommand; | ||
239 | + $input = new Input([$this->defaultCommand]); | ||
240 | + } | ||
241 | + | ||
242 | + return $this->doRunCommand($this->find($name), $input, $output); | ||
243 | + } | ||
244 | + | ||
245 | + /** | ||
246 | + * 设置输入参数定义 | ||
247 | + * @access public | ||
248 | + * @param InputDefinition $definition 输入定义 | ||
249 | + * @return $this; | ||
250 | + */ | ||
251 | + public function setDefinition(InputDefinition $definition) | ||
252 | + { | ||
253 | + $this->definition = $definition; | ||
254 | + | ||
255 | + return $this; | ||
256 | + } | ||
257 | + | ||
258 | + /** | ||
259 | + * 获取输入参数定义 | ||
260 | + * @access public | ||
261 | + * @return InputDefinition | ||
262 | + */ | ||
263 | + public function getDefinition() | ||
264 | + { | ||
265 | + return $this->definition; | ||
266 | + } | ||
267 | + | ||
268 | + /** | ||
269 | + * 获取帮助信息 | ||
270 | + * @access public | ||
271 | + * @return string | ||
272 | + */ | ||
273 | + public function getHelp() | ||
274 | + { | ||
275 | + return $this->getLongVersion(); | ||
276 | + } | ||
277 | + | ||
278 | + /** | ||
279 | + * 设置是否捕获异常 | ||
280 | + * @access public | ||
281 | + * @param bool $boolean 是否捕获 | ||
282 | + * @return $this | ||
283 | + */ | ||
284 | + public function setCatchExceptions($boolean) | ||
285 | + { | ||
286 | + $this->catchExceptions = (bool) $boolean; | ||
287 | + | ||
288 | + return $this; | ||
289 | + } | ||
290 | + | ||
291 | + /** | ||
292 | + * 设置是否自动退出 | ||
293 | + * @access public | ||
294 | + * @param bool $boolean 是否自动退出 | ||
295 | + * @return $this | ||
296 | + */ | ||
297 | + public function setAutoExit($boolean) | ||
298 | + { | ||
299 | + $this->autoExit = (bool) $boolean; | ||
300 | + | ||
301 | + return $this; | ||
302 | + } | ||
303 | + | ||
304 | + /** | ||
305 | + * 获取名称 | ||
306 | + * @access public | ||
307 | + * @return string | ||
308 | + */ | ||
309 | + public function getName() | ||
310 | + { | ||
311 | + return $this->name; | ||
312 | + } | ||
313 | + | ||
314 | + /** | ||
315 | + * 设置名称 | ||
316 | + * @access public | ||
317 | + * @param string $name 名称 | ||
318 | + * @return $this | ||
319 | + */ | ||
320 | + public function setName($name) | ||
321 | + { | ||
322 | + $this->name = $name; | ||
323 | + | ||
324 | + return $this; | ||
325 | + } | ||
326 | + | ||
327 | + /** | ||
328 | + * 获取版本 | ||
329 | + * @access public | ||
330 | + * @return string | ||
331 | + */ | ||
332 | + public function getVersion() | ||
333 | + { | ||
334 | + return $this->version; | ||
335 | + } | ||
336 | + | ||
337 | + /** | ||
338 | + * 设置版本 | ||
339 | + * @access public | ||
340 | + * @param string $version 版本信息 | ||
341 | + * @return $this | ||
342 | + */ | ||
343 | + public function setVersion($version) | ||
344 | + { | ||
345 | + $this->version = $version; | ||
346 | + | ||
347 | + return $this; | ||
348 | + } | ||
349 | + | ||
350 | + /** | ||
351 | + * 获取完整的版本号 | ||
352 | + * @access public | ||
353 | + * @return string | ||
354 | + */ | ||
355 | + public function getLongVersion() | ||
356 | + { | ||
357 | + if ('UNKNOWN' !== $this->getName() && 'UNKNOWN' !== $this->getVersion()) { | ||
358 | + return sprintf( | ||
359 | + '<info>%s</info> version <comment>%s</comment>', | ||
360 | + $this->getName(), | ||
361 | + $this->getVersion() | ||
362 | + ); | ||
363 | + } | ||
364 | + | ||
365 | + return '<info>Console Tool</info>'; | ||
366 | + } | ||
367 | + | ||
368 | + /** | ||
369 | + * 注册一个指令 | ||
370 | + * @access public | ||
371 | + * @param string $name 指令名称 | ||
372 | + * @return Command | ||
373 | + */ | ||
374 | + public function register($name) | ||
375 | + { | ||
376 | + return $this->add(new Command($name)); | ||
377 | + } | ||
378 | + | ||
379 | + /** | ||
380 | + * 批量添加指令 | ||
381 | + * @access public | ||
382 | + * @param Command[] $commands 指令实例 | ||
383 | + * @return $this | ||
384 | + */ | ||
385 | + public function addCommands(array $commands) | ||
386 | + { | ||
387 | + foreach ($commands as $command) $this->add($command); | ||
388 | + | ||
389 | + return $this; | ||
390 | + } | ||
391 | + | ||
392 | + /** | ||
393 | + * 添加一个指令 | ||
394 | + * @access public | ||
395 | + * @param Command $command 命令实例 | ||
396 | + * @return Command|bool | ||
397 | + */ | ||
398 | + public function add(Command $command) | ||
399 | + { | ||
400 | + if (!$command->isEnabled()) { | ||
401 | + $command->setConsole(null); | ||
402 | + return false; | ||
403 | + } | ||
404 | + | ||
405 | + $command->setConsole($this); | ||
406 | + | ||
407 | + if (null === $command->getDefinition()) { | ||
408 | + throw new \LogicException( | ||
409 | + sprintf('Command class "%s" is not correctly initialized. You probably forgot to call the parent constructor.', get_class($command)) | ||
410 | + ); | ||
411 | + } | ||
412 | + | ||
413 | + $this->commands[$command->getName()] = $command; | ||
414 | + | ||
415 | + foreach ($command->getAliases() as $alias) { | ||
416 | + $this->commands[$alias] = $command; | ||
417 | + } | ||
418 | + | ||
419 | + return $command; | ||
420 | + } | ||
421 | + | ||
422 | + /** | ||
423 | + * 获取指令 | ||
424 | + * @access public | ||
425 | + * @param string $name 指令名称 | ||
426 | + * @return Command | ||
427 | + * @throws \InvalidArgumentException | ||
428 | + */ | ||
429 | + public function get($name) | ||
430 | + { | ||
431 | + if (!isset($this->commands[$name])) { | ||
432 | + throw new \InvalidArgumentException( | ||
433 | + sprintf('The command "%s" does not exist.', $name) | ||
434 | + ); | ||
435 | + } | ||
436 | + | ||
437 | + $command = $this->commands[$name]; | ||
438 | + | ||
439 | + if ($this->wantHelps) { | ||
440 | + $this->wantHelps = false; | ||
441 | + | ||
442 | + /** @var HelpCommand $helpCommand */ | ||
443 | + $helpCommand = $this->get('help'); | ||
444 | + $helpCommand->setCommand($command); | ||
445 | + | ||
446 | + return $helpCommand; | ||
447 | + } | ||
448 | + | ||
449 | + return $command; | ||
450 | + } | ||
451 | + | ||
452 | + /** | ||
453 | + * 某个指令是否存在 | ||
454 | + * @access public | ||
455 | + * @param string $name 指令名称 | ||
456 | + * @return bool | ||
457 | + */ | ||
458 | + public function has($name) | ||
459 | + { | ||
460 | + return isset($this->commands[$name]); | ||
461 | + } | ||
462 | + | ||
463 | + /** | ||
464 | + * 获取所有的命名空间 | ||
465 | + * @access public | ||
466 | + * @return array | ||
467 | + */ | ||
468 | + public function getNamespaces() | ||
469 | + { | ||
470 | + $namespaces = []; | ||
471 | + | ||
472 | + foreach ($this->commands as $command) { | ||
473 | + $namespaces = array_merge( | ||
474 | + $namespaces, $this->extractAllNamespaces($command->getName()) | ||
475 | + ); | ||
476 | + | ||
477 | + foreach ($command->getAliases() as $alias) { | ||
478 | + $namespaces = array_merge( | ||
479 | + $namespaces, $this->extractAllNamespaces($alias) | ||
480 | + ); | ||
481 | + } | ||
482 | + } | ||
483 | + | ||
484 | + return array_values(array_unique(array_filter($namespaces))); | ||
485 | + } | ||
486 | + | ||
487 | + /** | ||
488 | + * 查找注册命名空间中的名称或缩写 | ||
489 | + * @access public | ||
490 | + * @param string $namespace | ||
491 | + * @return string | ||
492 | + * @throws \InvalidArgumentException | ||
493 | + */ | ||
494 | + public function findNamespace($namespace) | ||
495 | + { | ||
496 | + $expr = preg_replace_callback('{([^:]+|)}', function ($matches) { | ||
497 | + return preg_quote($matches[1]) . '[^:]*'; | ||
498 | + }, $namespace); | ||
499 | + | ||
500 | + $allNamespaces = $this->getNamespaces(); | ||
501 | + $namespaces = preg_grep('{^' . $expr . '}', $allNamespaces); | ||
502 | + | ||
503 | + if (empty($namespaces)) { | ||
504 | + $message = sprintf( | ||
505 | + 'There are no commands defined in the "%s" namespace.', $namespace | ||
506 | + ); | ||
507 | + | ||
508 | + if ($alternatives = $this->findAlternatives($namespace, $allNamespaces)) { | ||
509 | + if (1 == count($alternatives)) { | ||
510 | + $message .= "\n\nDid you mean this?\n "; | ||
511 | + } else { | ||
512 | + $message .= "\n\nDid you mean one of these?\n "; | ||
513 | + } | ||
514 | + | ||
515 | + $message .= implode("\n ", $alternatives); | ||
516 | + } | ||
517 | + | ||
518 | + throw new \InvalidArgumentException($message); | ||
519 | + } | ||
520 | + | ||
521 | + $exact = in_array($namespace, $namespaces, true); | ||
522 | + | ||
523 | + if (count($namespaces) > 1 && !$exact) { | ||
524 | + throw new \InvalidArgumentException( | ||
525 | + sprintf( | ||
526 | + 'The namespace "%s" is ambiguous (%s).', | ||
527 | + $namespace, | ||
528 | + $this->getAbbreviationSuggestions(array_values($namespaces))) | ||
529 | + ); | ||
530 | + } | ||
531 | + | ||
532 | + return $exact ? $namespace : reset($namespaces); | ||
533 | + } | ||
534 | + | ||
535 | + /** | ||
536 | + * 查找指令 | ||
537 | + * @access public | ||
538 | + * @param string $name 名称或者别名 | ||
539 | + * @return Command | ||
540 | + * @throws \InvalidArgumentException | ||
541 | + */ | ||
542 | + public function find($name) | ||
543 | + { | ||
544 | + $expr = preg_replace_callback('{([^:]+|)}', function ($matches) { | ||
545 | + return preg_quote($matches[1]) . '[^:]*'; | ||
546 | + }, $name); | ||
547 | + | ||
548 | + $allCommands = array_keys($this->commands); | ||
549 | + $commands = preg_grep('{^' . $expr . '}', $allCommands); | ||
550 | + | ||
551 | + if (empty($commands) || count(preg_grep('{^' . $expr . '$}', $commands)) < 1) { | ||
552 | + if (false !== ($pos = strrpos($name, ':'))) { | ||
553 | + $this->findNamespace(substr($name, 0, $pos)); | ||
554 | + } | ||
555 | + | ||
556 | + $message = sprintf('Command "%s" is not defined.', $name); | ||
557 | + | ||
558 | + if ($alternatives = $this->findAlternatives($name, $allCommands)) { | ||
559 | + if (1 == count($alternatives)) { | ||
560 | + $message .= "\n\nDid you mean this?\n "; | ||
561 | + } else { | ||
562 | + $message .= "\n\nDid you mean one of these?\n "; | ||
563 | + } | ||
564 | + $message .= implode("\n ", $alternatives); | ||
565 | + } | ||
566 | + | ||
567 | + throw new \InvalidArgumentException($message); | ||
568 | + } | ||
569 | + | ||
570 | + if (count($commands) > 1) { | ||
571 | + $commandList = $this->commands; | ||
572 | + $commands = array_filter($commands, function ($nameOrAlias) use ($commandList, $commands) { | ||
573 | + $commandName = $commandList[$nameOrAlias]->getName(); | ||
574 | + | ||
575 | + return $commandName === $nameOrAlias || !in_array($commandName, $commands); | ||
576 | + }); | ||
577 | + } | ||
578 | + | ||
579 | + $exact = in_array($name, $commands, true); | ||
580 | + if (count($commands) > 1 && !$exact) { | ||
581 | + $suggestions = $this->getAbbreviationSuggestions(array_values($commands)); | ||
582 | + | ||
583 | + throw new \InvalidArgumentException( | ||
584 | + sprintf('Command "%s" is ambiguous (%s).', $name, $suggestions) | ||
585 | + ); | ||
586 | + } | ||
587 | + | ||
588 | + return $this->get($exact ? $name : reset($commands)); | ||
589 | + } | ||
590 | + | ||
591 | + /** | ||
592 | + * 获取所有的指令 | ||
593 | + * @access public | ||
594 | + * @param string $namespace 命名空间 | ||
595 | + * @return Command[] | ||
596 | + */ | ||
597 | + public function all($namespace = null) | ||
598 | + { | ||
599 | + if (null === $namespace) return $this->commands; | ||
600 | + | ||
601 | + $commands = []; | ||
602 | + | ||
603 | + foreach ($this->commands as $name => $command) { | ||
604 | + $ext = $this->extractNamespace($name, substr_count($namespace, ':') + 1); | ||
605 | + | ||
606 | + if ($ext === $namespace) $commands[$name] = $command; | ||
607 | + } | ||
608 | + | ||
609 | + return $commands; | ||
610 | + } | ||
611 | + | ||
612 | + /** | ||
613 | + * 获取可能的指令名 | ||
614 | + * @access public | ||
615 | + * @param array $names 指令名 | ||
616 | + * @return array | ||
617 | + */ | ||
618 | + public static function getAbbreviations($names) | ||
619 | + { | ||
620 | + $abbrevs = []; | ||
621 | + foreach ($names as $name) { | ||
622 | + for ($len = strlen($name); $len > 0; --$len) { | ||
623 | + $abbrev = substr($name, 0, $len); | ||
624 | + $abbrevs[$abbrev][] = $name; | ||
625 | + } | ||
626 | + } | ||
627 | + | ||
628 | + return $abbrevs; | ||
629 | + } | ||
630 | + | ||
631 | + /** | ||
632 | + * 配置基于用户的参数和选项的输入和输出实例 | ||
633 | + * @access protected | ||
634 | + * @param Input $input 输入实例 | ||
635 | + * @param Output $output 输出实例 | ||
636 | + * @return void | ||
637 | + */ | ||
638 | + protected function configureIO(Input $input, Output $output) | ||
639 | + { | ||
640 | + if (true === $input->hasParameterOption(['--ansi'])) { | ||
641 | + $output->setDecorated(true); | ||
642 | + } elseif (true === $input->hasParameterOption(['--no-ansi'])) { | ||
643 | + $output->setDecorated(false); | ||
644 | + } | ||
645 | + | ||
646 | + if (true === $input->hasParameterOption(['--no-interaction', '-n'])) { | ||
647 | + $input->setInteractive(false); | ||
648 | + } | ||
649 | + | ||
650 | + if (true === $input->hasParameterOption(['--quiet', '-q'])) { | ||
651 | + $output->setVerbosity(Output::VERBOSITY_QUIET); | ||
652 | + } else { | ||
653 | + if ($input->hasParameterOption('-vvv') || $input->hasParameterOption('--verbose=3') || $input->getParameterOption('--verbose') === 3) { | ||
654 | + $output->setVerbosity(Output::VERBOSITY_DEBUG); | ||
655 | + } elseif ($input->hasParameterOption('-vv') || $input->hasParameterOption('--verbose=2') || $input->getParameterOption('--verbose') === 2) { | ||
656 | + $output->setVerbosity(Output::VERBOSITY_VERY_VERBOSE); | ||
657 | + } elseif ($input->hasParameterOption('-v') || $input->hasParameterOption('--verbose=1') || $input->hasParameterOption('--verbose') || $input->getParameterOption('--verbose')) { | ||
658 | + $output->setVerbosity(Output::VERBOSITY_VERBOSE); | ||
659 | + } | ||
660 | + } | ||
661 | + } | ||
662 | + | ||
663 | + /** | ||
664 | + * 执行指令 | ||
665 | + * @access protected | ||
666 | + * @param Command $command 指令实例 | ||
667 | + * @param Input $input 输入实例 | ||
668 | + * @param Output $output 输出实例 | ||
669 | + * @return int | ||
670 | + * @throws \Exception | ||
671 | + */ | ||
672 | + protected function doRunCommand(Command $command, Input $input, Output $output) | ||
673 | + { | ||
674 | + return $command->run($input, $output); | ||
675 | + } | ||
676 | + | ||
677 | + /** | ||
678 | + * 获取指令的名称 | ||
679 | + * @access protected | ||
680 | + * @param Input $input 输入实例 | ||
681 | + * @return string | ||
682 | + */ | ||
683 | + protected function getCommandName(Input $input) | ||
684 | + { | ||
685 | + return $input->getFirstArgument(); | ||
686 | + } | ||
687 | + | ||
688 | + /** | ||
689 | + * 获取默认输入定义 | ||
690 | + * @access protected | ||
691 | + * @return InputDefinition | ||
692 | + */ | ||
693 | + protected function getDefaultInputDefinition() | ||
694 | + { | ||
695 | + return new InputDefinition([ | ||
696 | + new InputArgument('command', InputArgument::REQUIRED, 'The command to execute'), | ||
697 | + new InputOption('--help', '-h', InputOption::VALUE_NONE, 'Display this help message'), | ||
698 | + new InputOption('--version', '-V', InputOption::VALUE_NONE, 'Display this console version'), | ||
699 | + new InputOption('--quiet', '-q', InputOption::VALUE_NONE, 'Do not output any message'), | ||
700 | + 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'), | ||
701 | + new InputOption('--ansi', '', InputOption::VALUE_NONE, 'Force ANSI output'), | ||
702 | + new InputOption('--no-ansi', '', InputOption::VALUE_NONE, 'Disable ANSI output'), | ||
703 | + new InputOption('--no-interaction', '-n', InputOption::VALUE_NONE, 'Do not ask any interactive question'), | ||
704 | + ]); | ||
705 | + } | ||
706 | + | ||
707 | + /** | ||
708 | + * 获取默认命令 | ||
709 | + * @access protected | ||
710 | + * @return Command[] | ||
711 | + */ | ||
712 | + protected function getDefaultCommands() | ||
713 | + { | ||
714 | + $defaultCommands = []; | ||
715 | + | ||
716 | + foreach (self::$defaultCommands as $class) { | ||
717 | + if (class_exists($class) && is_subclass_of($class, "think\\console\\Command")) { | ||
718 | + $defaultCommands[] = new $class(); | ||
719 | + } | ||
720 | + } | ||
721 | + | ||
722 | + return $defaultCommands; | ||
723 | + } | ||
724 | + | ||
725 | + /** | ||
726 | + * 添加默认指令 | ||
727 | + * @access public | ||
728 | + * @param array $classes 指令 | ||
729 | + * @return void | ||
730 | + */ | ||
731 | + public static function addDefaultCommands(array $classes) | ||
732 | + { | ||
733 | + self::$defaultCommands = array_merge(self::$defaultCommands, $classes); | ||
734 | + } | ||
735 | + | ||
736 | + /** | ||
737 | + * 获取可能的建议 | ||
738 | + * @access private | ||
739 | + * @param array $abbrevs | ||
740 | + * @return string | ||
741 | + */ | ||
742 | + private function getAbbreviationSuggestions($abbrevs) | ||
743 | + { | ||
744 | + return sprintf( | ||
745 | + '%s, %s%s', | ||
746 | + $abbrevs[0], | ||
747 | + $abbrevs[1], | ||
748 | + count($abbrevs) > 2 ? sprintf(' and %d more', count($abbrevs) - 2) : '' | ||
749 | + ); | ||
750 | + } | ||
751 | + | ||
752 | + /** | ||
753 | + * 返回指令的命名空间部分 | ||
754 | + * @access public | ||
755 | + * @param string $name 指令名称 | ||
756 | + * @param string $limit 部分的命名空间的最大数量 | ||
757 | + * @return string | ||
758 | + */ | ||
759 | + public function extractNamespace($name, $limit = null) | ||
760 | + { | ||
761 | + $parts = explode(':', $name); | ||
762 | + array_pop($parts); | ||
763 | + | ||
764 | + return implode(':', null === $limit ? $parts : array_slice($parts, 0, $limit)); | ||
765 | + } | ||
766 | + | ||
767 | + /** | ||
768 | + * 查找可替代的建议 | ||
769 | + * @access private | ||
770 | + * @param string $name 指令名称 | ||
771 | + * @param array|\Traversable $collection 建议集合 | ||
772 | + * @return array | ||
773 | + */ | ||
774 | + private function findAlternatives($name, $collection) | ||
775 | + { | ||
776 | + $threshold = 1e3; | ||
777 | + $alternatives = []; | ||
778 | + $collectionParts = []; | ||
779 | + | ||
780 | + foreach ($collection as $item) { | ||
781 | + $collectionParts[$item] = explode(':', $item); | ||
782 | + } | ||
783 | + | ||
784 | + foreach (explode(':', $name) as $i => $subname) { | ||
785 | + foreach ($collectionParts as $collectionName => $parts) { | ||
786 | + $exists = isset($alternatives[$collectionName]); | ||
787 | + | ||
788 | + if (!isset($parts[$i]) && $exists) { | ||
789 | + $alternatives[$collectionName] += $threshold; | ||
790 | + continue; | ||
791 | + } elseif (!isset($parts[$i])) { | ||
792 | + continue; | ||
793 | + } | ||
794 | + | ||
795 | + $lev = levenshtein($subname, $parts[$i]); | ||
796 | + | ||
797 | + if ($lev <= strlen($subname) / 3 || | ||
798 | + '' !== $subname && | ||
799 | + false !== strpos($parts[$i], $subname) | ||
800 | + ) { | ||
801 | + $alternatives[$collectionName] = $exists ? | ||
802 | + $alternatives[$collectionName] + $lev : | ||
803 | + $lev; | ||
804 | + } elseif ($exists) { | ||
805 | + $alternatives[$collectionName] += $threshold; | ||
806 | + } | ||
807 | + } | ||
808 | + } | ||
809 | + | ||
810 | + foreach ($collection as $item) { | ||
811 | + $lev = levenshtein($name, $item); | ||
812 | + | ||
813 | + if ($lev <= strlen($name) / 3 || false !== strpos($item, $name)) { | ||
814 | + $alternatives[$item] = isset($alternatives[$item]) ? | ||
815 | + $alternatives[$item] - $lev : | ||
816 | + $lev; | ||
817 | + } | ||
818 | + } | ||
819 | + | ||
820 | + $alternatives = array_filter($alternatives, function ($lev) use ($threshold) { | ||
821 | + return $lev < 2 * $threshold; | ||
822 | + }); | ||
823 | + | ||
824 | + asort($alternatives); | ||
825 | + | ||
826 | + return array_keys($alternatives); | ||
827 | + } | ||
828 | + | ||
829 | + /** | ||
830 | + * 设置默认的指令 | ||
831 | + * @access public | ||
832 | + * @param string $commandName 指令名称 | ||
833 | + * @return $this | ||
834 | + */ | ||
835 | + public function setDefaultCommand($commandName) | ||
836 | + { | ||
837 | + $this->defaultCommand = $commandName; | ||
838 | + | ||
839 | + return $this; | ||
840 | + } | ||
841 | + | ||
842 | + /** | ||
843 | + * 返回所有的命名空间 | ||
844 | + * @access private | ||
845 | + * @param string $name 指令名称 | ||
846 | + * @return array | ||
847 | + */ | ||
848 | + private function extractAllNamespaces($name) | ||
849 | + { | ||
850 | + $namespaces = []; | ||
851 | + | ||
852 | + foreach (explode(':', $name, -1) as $part) { | ||
853 | + if (count($namespaces)) { | ||
854 | + $namespaces[] = end($namespaces) . ':' . $part; | ||
855 | + } else { | ||
856 | + $namespaces[] = $part; | ||
857 | + } | ||
858 | + } | ||
859 | + | ||
860 | + return $namespaces; | ||
861 | + } | ||
862 | + | ||
863 | +} |
thinkphp/library/think/Controller.php
0 → 100644
1 | +<?php | ||
2 | +// +---------------------------------------------------------------------- | ||
3 | +// | ThinkPHP [ WE CAN DO IT JUST THINK ] | ||
4 | +// +---------------------------------------------------------------------- | ||
5 | +// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. | ||
6 | +// +---------------------------------------------------------------------- | ||
7 | +// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) | ||
8 | +// +---------------------------------------------------------------------- | ||
9 | +// | Author: liu21st <liu21st@gmail.com> | ||
10 | +// +---------------------------------------------------------------------- | ||
11 | + | ||
12 | +namespace think; | ||
13 | + | ||
14 | +use think\exception\ValidateException; | ||
15 | +use traits\controller\Jump; | ||
16 | + | ||
17 | +Loader::import('controller/Jump', TRAIT_PATH, EXT); | ||
18 | + | ||
19 | +class Controller | ||
20 | +{ | ||
21 | + use Jump; | ||
22 | + | ||
23 | + /** | ||
24 | + * @var \think\View 视图类实例 | ||
25 | + */ | ||
26 | + protected $view; | ||
27 | + | ||
28 | + /** | ||
29 | + * @var \think\Request Request 实例 | ||
30 | + */ | ||
31 | + protected $request; | ||
32 | + | ||
33 | + /** | ||
34 | + * @var bool 验证失败是否抛出异常 | ||
35 | + */ | ||
36 | + protected $failException = false; | ||
37 | + | ||
38 | + /** | ||
39 | + * @var bool 是否批量验证 | ||
40 | + */ | ||
41 | + protected $batchValidate = false; | ||
42 | + | ||
43 | + /** | ||
44 | + * @var array 前置操作方法列表 | ||
45 | + */ | ||
46 | + protected $beforeActionList = []; | ||
47 | + | ||
48 | + /** | ||
49 | + * 构造方法 | ||
50 | + * @access public | ||
51 | + * @param Request $request Request 对象 | ||
52 | + */ | ||
53 | + public function __construct(Request $request = null) | ||
54 | + { | ||
55 | + $this->view = View::instance(Config::get('template'), Config::get('view_replace_str')); | ||
56 | + $this->request = is_null($request) ? Request::instance() : $request; | ||
57 | + | ||
58 | + // 控制器初始化 | ||
59 | + $this->_initialize(); | ||
60 | + | ||
61 | + // 前置操作方法 | ||
62 | + if ($this->beforeActionList) { | ||
63 | + foreach ($this->beforeActionList as $method => $options) { | ||
64 | + is_numeric($method) ? | ||
65 | + $this->beforeAction($options) : | ||
66 | + $this->beforeAction($method, $options); | ||
67 | + } | ||
68 | + } | ||
69 | + } | ||
70 | + | ||
71 | + /** | ||
72 | + * 初始化操作 | ||
73 | + * @access protected | ||
74 | + */ | ||
75 | + protected function _initialize() | ||
76 | + { | ||
77 | + } | ||
78 | + | ||
79 | + /** | ||
80 | + * 前置操作 | ||
81 | + * @access protected | ||
82 | + * @param string $method 前置操作方法名 | ||
83 | + * @param array $options 调用参数 ['only'=>[...]] 或者 ['except'=>[...]] | ||
84 | + * @return void | ||
85 | + */ | ||
86 | + protected function beforeAction($method, $options = []) | ||
87 | + { | ||
88 | + if (isset($options['only'])) { | ||
89 | + if (is_string($options['only'])) { | ||
90 | + $options['only'] = explode(',', $options['only']); | ||
91 | + } | ||
92 | + | ||
93 | + if (!in_array($this->request->action(), $options['only'])) { | ||
94 | + return; | ||
95 | + } | ||
96 | + } elseif (isset($options['except'])) { | ||
97 | + if (is_string($options['except'])) { | ||
98 | + $options['except'] = explode(',', $options['except']); | ||
99 | + } | ||
100 | + | ||
101 | + if (in_array($this->request->action(), $options['except'])) { | ||
102 | + return; | ||
103 | + } | ||
104 | + } | ||
105 | + | ||
106 | + call_user_func([$this, $method]); | ||
107 | + } | ||
108 | + | ||
109 | + /** | ||
110 | + * 加载模板输出 | ||
111 | + * @access protected | ||
112 | + * @param string $template 模板文件名 | ||
113 | + * @param array $vars 模板输出变量 | ||
114 | + * @param array $replace 模板替换 | ||
115 | + * @param array $config 模板参数 | ||
116 | + * @return mixed | ||
117 | + */ | ||
118 | + protected function fetch($template = '', $vars = [], $replace = [], $config = []) | ||
119 | + { | ||
120 | + return $this->view->fetch($template, $vars, $replace, $config); | ||
121 | + } | ||
122 | + | ||
123 | + /** | ||
124 | + * 渲染内容输出 | ||
125 | + * @access protected | ||
126 | + * @param string $content 模板内容 | ||
127 | + * @param array $vars 模板输出变量 | ||
128 | + * @param array $replace 替换内容 | ||
129 | + * @param array $config 模板参数 | ||
130 | + * @return mixed | ||
131 | + */ | ||
132 | + protected function display($content = '', $vars = [], $replace = [], $config = []) | ||
133 | + { | ||
134 | + return $this->view->display($content, $vars, $replace, $config); | ||
135 | + } | ||
136 | + | ||
137 | + /** | ||
138 | + * 模板变量赋值 | ||
139 | + * @access protected | ||
140 | + * @param mixed $name 要显示的模板变量 | ||
141 | + * @param mixed $value 变量的值 | ||
142 | + * @return $this | ||
143 | + */ | ||
144 | + protected function assign($name, $value = '') | ||
145 | + { | ||
146 | + $this->view->assign($name, $value); | ||
147 | + | ||
148 | + return $this; | ||
149 | + } | ||
150 | + | ||
151 | + /** | ||
152 | + * 初始化模板引擎 | ||
153 | + * @access protected | ||
154 | + * @param array|string $engine 引擎参数 | ||
155 | + * @return $this | ||
156 | + */ | ||
157 | + protected function engine($engine) | ||
158 | + { | ||
159 | + $this->view->engine($engine); | ||
160 | + | ||
161 | + return $this; | ||
162 | + } | ||
163 | + | ||
164 | + /** | ||
165 | + * 设置验证失败后是否抛出异常 | ||
166 | + * @access protected | ||
167 | + * @param bool $fail 是否抛出异常 | ||
168 | + * @return $this | ||
169 | + */ | ||
170 | + protected function validateFailException($fail = true) | ||
171 | + { | ||
172 | + $this->failException = $fail; | ||
173 | + | ||
174 | + return $this; | ||
175 | + } | ||
176 | + | ||
177 | + /** | ||
178 | + * 验证数据 | ||
179 | + * @access protected | ||
180 | + * @param array $data 数据 | ||
181 | + * @param string|array $validate 验证器名或者验证规则数组 | ||
182 | + * @param array $message 提示信息 | ||
183 | + * @param bool $batch 是否批量验证 | ||
184 | + * @param mixed $callback 回调方法(闭包) | ||
185 | + * @return array|string|true | ||
186 | + * @throws ValidateException | ||
187 | + */ | ||
188 | + protected function validate($data, $validate, $message = [], $batch = false, $callback = null) | ||
189 | + { | ||
190 | + if (is_array($validate)) { | ||
191 | + $v = Loader::validate(); | ||
192 | + $v->rule($validate); | ||
193 | + } else { | ||
194 | + // 支持场景 | ||
195 | + if (strpos($validate, '.')) { | ||
196 | + list($validate, $scene) = explode('.', $validate); | ||
197 | + } | ||
198 | + | ||
199 | + $v = Loader::validate($validate); | ||
200 | + | ||
201 | + !empty($scene) && $v->scene($scene); | ||
202 | + } | ||
203 | + | ||
204 | + // 批量验证 | ||
205 | + if ($batch || $this->batchValidate) { | ||
206 | + $v->batch(true); | ||
207 | + } | ||
208 | + | ||
209 | + // 设置错误信息 | ||
210 | + if (is_array($message)) { | ||
211 | + $v->message($message); | ||
212 | + } | ||
213 | + | ||
214 | + // 使用回调验证 | ||
215 | + if ($callback && is_callable($callback)) { | ||
216 | + call_user_func_array($callback, [$v, &$data]); | ||
217 | + } | ||
218 | + | ||
219 | + if (!$v->check($data)) { | ||
220 | + if ($this->failException) { | ||
221 | + throw new ValidateException($v->getError()); | ||
222 | + } | ||
223 | + | ||
224 | + return $v->getError(); | ||
225 | + } | ||
226 | + | ||
227 | + return true; | ||
228 | + } | ||
229 | +} |
thinkphp/library/think/Cookie.php
0 → 100644
1 | +<?php | ||
2 | +// +---------------------------------------------------------------------- | ||
3 | +// | ThinkPHP [ WE CAN DO IT JUST THINK ] | ||
4 | +// +---------------------------------------------------------------------- | ||
5 | +// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. | ||
6 | +// +---------------------------------------------------------------------- | ||
7 | +// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) | ||
8 | +// +---------------------------------------------------------------------- | ||
9 | +// | Author: liu21st <liu21st@gmail.com> | ||
10 | +// +---------------------------------------------------------------------- | ||
11 | + | ||
12 | +namespace think; | ||
13 | + | ||
14 | +class Cookie | ||
15 | +{ | ||
16 | + /** | ||
17 | + * @var array cookie 设置参数 | ||
18 | + */ | ||
19 | + protected static $config = [ | ||
20 | + 'prefix' => '', // cookie 名称前缀 | ||
21 | + 'expire' => 0, // cookie 保存时间 | ||
22 | + 'path' => '/', // cookie 保存路径 | ||
23 | + 'domain' => '', // cookie 有效域名 | ||
24 | + 'secure' => false, // cookie 启用安全传输 | ||
25 | + 'httponly' => false, // httponly 设置 | ||
26 | + 'setcookie' => true, // 是否使用 setcookie | ||
27 | + ]; | ||
28 | + | ||
29 | + /** | ||
30 | + * @var bool 是否完成初始化了 | ||
31 | + */ | ||
32 | + protected static $init; | ||
33 | + | ||
34 | + /** | ||
35 | + * Cookie初始化 | ||
36 | + * @access public | ||
37 | + * @param array $config 配置参数 | ||
38 | + * @return void | ||
39 | + */ | ||
40 | + public static function init(array $config = []) | ||
41 | + { | ||
42 | + if (empty($config)) { | ||
43 | + $config = Config::get('cookie'); | ||
44 | + } | ||
45 | + | ||
46 | + self::$config = array_merge(self::$config, array_change_key_case($config)); | ||
47 | + | ||
48 | + if (!empty(self::$config['httponly'])) { | ||
49 | + ini_set('session.cookie_httponly', 1); | ||
50 | + } | ||
51 | + | ||
52 | + self::$init = true; | ||
53 | + } | ||
54 | + | ||
55 | + /** | ||
56 | + * 设置或者获取 cookie 作用域(前缀) | ||
57 | + * @access public | ||
58 | + * @param string $prefix 前缀 | ||
59 | + * @return string| | ||
60 | + */ | ||
61 | + public static function prefix($prefix = '') | ||
62 | + { | ||
63 | + if (empty($prefix)) { | ||
64 | + return self::$config['prefix']; | ||
65 | + } | ||
66 | + | ||
67 | + return self::$config['prefix'] = $prefix; | ||
68 | + } | ||
69 | + | ||
70 | + /** | ||
71 | + * Cookie 设置、获取、删除 | ||
72 | + * @access public | ||
73 | + * @param string $name cookie 名称 | ||
74 | + * @param mixed $value cookie 值 | ||
75 | + * @param mixed $option 可选参数 可能会是 null|integer|string | ||
76 | + * @return void | ||
77 | + */ | ||
78 | + public static function set($name, $value = '', $option = null) | ||
79 | + { | ||
80 | + !isset(self::$init) && self::init(); | ||
81 | + | ||
82 | + // 参数设置(会覆盖黙认设置) | ||
83 | + if (!is_null($option)) { | ||
84 | + if (is_numeric($option)) { | ||
85 | + $option = ['expire' => $option]; | ||
86 | + } elseif (is_string($option)) { | ||
87 | + parse_str($option, $option); | ||
88 | + } | ||
89 | + | ||
90 | + $config = array_merge(self::$config, array_change_key_case($option)); | ||
91 | + } else { | ||
92 | + $config = self::$config; | ||
93 | + } | ||
94 | + | ||
95 | + $name = $config['prefix'] . $name; | ||
96 | + | ||
97 | + // 设置 cookie | ||
98 | + if (is_array($value)) { | ||
99 | + array_walk_recursive($value, 'self::jsonFormatProtect', 'encode'); | ||
100 | + $value = 'think:' . json_encode($value); | ||
101 | + } | ||
102 | + | ||
103 | + $expire = !empty($config['expire']) ? | ||
104 | + $_SERVER['REQUEST_TIME'] + intval($config['expire']) : | ||
105 | + 0; | ||
106 | + | ||
107 | + if ($config['setcookie']) { | ||
108 | + setcookie( | ||
109 | + $name, $value, $expire, $config['path'], $config['domain'], | ||
110 | + $config['secure'], $config['httponly'] | ||
111 | + ); | ||
112 | + } | ||
113 | + | ||
114 | + $_COOKIE[$name] = $value; | ||
115 | + } | ||
116 | + | ||
117 | + /** | ||
118 | + * 永久保存 Cookie 数据 | ||
119 | + * @access public | ||
120 | + * @param string $name cookie 名称 | ||
121 | + * @param mixed $value cookie 值 | ||
122 | + * @param mixed $option 可选参数 可能会是 null|integer|string | ||
123 | + * @return void | ||
124 | + */ | ||
125 | + public static function forever($name, $value = '', $option = null) | ||
126 | + { | ||
127 | + if (is_null($option) || is_numeric($option)) { | ||
128 | + $option = []; | ||
129 | + } | ||
130 | + | ||
131 | + $option['expire'] = 315360000; | ||
132 | + | ||
133 | + self::set($name, $value, $option); | ||
134 | + } | ||
135 | + | ||
136 | + /** | ||
137 | + * 判断是否有 Cookie 数据 | ||
138 | + * @access public | ||
139 | + * @param string $name cookie 名称 | ||
140 | + * @param string|null $prefix cookie 前缀 | ||
141 | + * @return bool | ||
142 | + */ | ||
143 | + public static function has($name, $prefix = null) | ||
144 | + { | ||
145 | + !isset(self::$init) && self::init(); | ||
146 | + | ||
147 | + $prefix = !is_null($prefix) ? $prefix : self::$config['prefix']; | ||
148 | + | ||
149 | + return isset($_COOKIE[$prefix . $name]); | ||
150 | + } | ||
151 | + | ||
152 | + /** | ||
153 | + * 获取 Cookie 的值 | ||
154 | + * @access public | ||
155 | + * @param string $name cookie 名称 | ||
156 | + * @param string|null $prefix cookie 前缀 | ||
157 | + * @return mixed | ||
158 | + */ | ||
159 | + public static function get($name = '', $prefix = null) | ||
160 | + { | ||
161 | + !isset(self::$init) && self::init(); | ||
162 | + | ||
163 | + $prefix = !is_null($prefix) ? $prefix : self::$config['prefix']; | ||
164 | + $key = $prefix . $name; | ||
165 | + | ||
166 | + if ('' == $name) { | ||
167 | + // 获取全部 | ||
168 | + if ($prefix) { | ||
169 | + $value = []; | ||
170 | + | ||
171 | + foreach ($_COOKIE as $k => $val) { | ||
172 | + if (0 === strpos($k, $prefix)) { | ||
173 | + $value[$k] = $val; | ||
174 | + } | ||
175 | + | ||
176 | + } | ||
177 | + } else { | ||
178 | + $value = $_COOKIE; | ||
179 | + } | ||
180 | + } elseif (isset($_COOKIE[$key])) { | ||
181 | + $value = $_COOKIE[$key]; | ||
182 | + | ||
183 | + if (0 === strpos($value, 'think:')) { | ||
184 | + $value = json_decode(substr($value, 6), true); | ||
185 | + array_walk_recursive($value, 'self::jsonFormatProtect', 'decode'); | ||
186 | + } | ||
187 | + } else { | ||
188 | + $value = null; | ||
189 | + } | ||
190 | + | ||
191 | + return $value; | ||
192 | + } | ||
193 | + | ||
194 | + /** | ||
195 | + * 删除 Cookie | ||
196 | + * @access public | ||
197 | + * @param string $name cookie 名称 | ||
198 | + * @param string|null $prefix cookie 前缀 | ||
199 | + * @return void | ||
200 | + */ | ||
201 | + public static function delete($name, $prefix = null) | ||
202 | + { | ||
203 | + !isset(self::$init) && self::init(); | ||
204 | + | ||
205 | + $config = self::$config; | ||
206 | + $prefix = !is_null($prefix) ? $prefix : $config['prefix']; | ||
207 | + $name = $prefix . $name; | ||
208 | + | ||
209 | + if ($config['setcookie']) { | ||
210 | + setcookie( | ||
211 | + $name, '', $_SERVER['REQUEST_TIME'] - 3600, $config['path'], | ||
212 | + $config['domain'], $config['secure'], $config['httponly'] | ||
213 | + ); | ||
214 | + } | ||
215 | + | ||
216 | + // 删除指定 cookie | ||
217 | + unset($_COOKIE[$name]); | ||
218 | + } | ||
219 | + | ||
220 | + /** | ||
221 | + * 清除指定前缀的所有 cookie | ||
222 | + * @access public | ||
223 | + * @param string|null $prefix cookie 前缀 | ||
224 | + * @return void | ||
225 | + */ | ||
226 | + public static function clear($prefix = null) | ||
227 | + { | ||
228 | + if (empty($_COOKIE)) { | ||
229 | + return; | ||
230 | + } | ||
231 | + | ||
232 | + !isset(self::$init) && self::init(); | ||
233 | + | ||
234 | + // 要删除的 cookie 前缀,不指定则删除 config 设置的指定前缀 | ||
235 | + $config = self::$config; | ||
236 | + $prefix = !is_null($prefix) ? $prefix : $config['prefix']; | ||
237 | + | ||
238 | + if ($prefix) { | ||
239 | + foreach ($_COOKIE as $key => $val) { | ||
240 | + if (0 === strpos($key, $prefix)) { | ||
241 | + if ($config['setcookie']) { | ||
242 | + setcookie( | ||
243 | + $key, '', $_SERVER['REQUEST_TIME'] - 3600, $config['path'], | ||
244 | + $config['domain'], $config['secure'], $config['httponly'] | ||
245 | + ); | ||
246 | + } | ||
247 | + | ||
248 | + unset($_COOKIE[$key]); | ||
249 | + } | ||
250 | + } | ||
251 | + } | ||
252 | + } | ||
253 | + | ||
254 | + /** | ||
255 | + * json 转换时的格式保护 | ||
256 | + * @access protected | ||
257 | + * @param mixed $val 要转换的值 | ||
258 | + * @param string $key 键名 | ||
259 | + * @param string $type 转换类别 | ||
260 | + * @return void | ||
261 | + */ | ||
262 | + protected static function jsonFormatProtect(&$val, $key, $type = 'encode') | ||
263 | + { | ||
264 | + if (!empty($val) && true !== $val) { | ||
265 | + $val = 'decode' == $type ? urldecode($val) : urlencode($val); | ||
266 | + } | ||
267 | + } | ||
268 | +} |
thinkphp/library/think/Db.php
0 → 100644
1 | +<?php | ||
2 | +// +---------------------------------------------------------------------- | ||
3 | +// | ThinkPHP [ WE CAN DO IT JUST THINK ] | ||
4 | +// +---------------------------------------------------------------------- | ||
5 | +// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. | ||
6 | +// +---------------------------------------------------------------------- | ||
7 | +// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) | ||
8 | +// +---------------------------------------------------------------------- | ||
9 | +// | Author: liu21st <liu21st@gmail.com> | ||
10 | +// +---------------------------------------------------------------------- | ||
11 | + | ||
12 | +namespace think; | ||
13 | + | ||
14 | +use think\db\Connection; | ||
15 | +use think\db\Query; | ||
16 | + | ||
17 | +/** | ||
18 | + * Class Db | ||
19 | + * @package think | ||
20 | + * @method static Query table(string $table) 指定数据表(含前缀) | ||
21 | + * @method static Query name(string $name) 指定数据表(不含前缀) | ||
22 | + * @method static Query where(mixed $field, string $op = null, mixed $condition = null) 查询条件 | ||
23 | + * @method static Query join(mixed $join, mixed $condition = null, string $type = 'INNER') JOIN查询 | ||
24 | + * @method static Query union(mixed $union, boolean $all = false) UNION查询 | ||
25 | + * @method static Query limit(mixed $offset, integer $length = null) 查询LIMIT | ||
26 | + * @method static Query order(mixed $field, string $order = null) 查询ORDER | ||
27 | + * @method static Query cache(mixed $key = null , integer $expire = null) 设置查询缓存 | ||
28 | + * @method static mixed value(string $field) 获取某个字段的值 | ||
29 | + * @method static array column(string $field, string $key = '') 获取某个列的值 | ||
30 | + * @method static Query view(mixed $join, mixed $field = null, mixed $on = null, string $type = 'INNER') 视图查询 | ||
31 | + * @method static mixed find(mixed $data = null) 查询单个记录 | ||
32 | + * @method static mixed select(mixed $data = null) 查询多个记录 | ||
33 | + * @method static integer insert(array $data, boolean $replace = false, boolean $getLastInsID = false, string $sequence = null) 插入一条记录 | ||
34 | + * @method static integer insertGetId(array $data, boolean $replace = false, string $sequence = null) 插入一条记录并返回自增ID | ||
35 | + * @method static integer insertAll(array $dataSet) 插入多条记录 | ||
36 | + * @method static integer update(array $data) 更新记录 | ||
37 | + * @method static integer delete(mixed $data = null) 删除记录 | ||
38 | + * @method static boolean chunk(integer $count, callable $callback, string $column = null) 分块获取数据 | ||
39 | + * @method static mixed query(string $sql, array $bind = [], boolean $master = false, bool $pdo = false) SQL查询 | ||
40 | + * @method static integer execute(string $sql, array $bind = [], boolean $fetch = false, boolean $getLastInsID = false, string $sequence = null) SQL执行 | ||
41 | + * @method static Paginator paginate(integer $listRows = 15, mixed $simple = null, array $config = []) 分页查询 | ||
42 | + * @method static mixed transaction(callable $callback) 执行数据库事务 | ||
43 | + * @method static void startTrans() 启动事务 | ||
44 | + * @method static void commit() 用于非自动提交状态下面的查询提交 | ||
45 | + * @method static void rollback() 事务回滚 | ||
46 | + * @method static boolean batchQuery(array $sqlArray) 批处理执行SQL语句 | ||
47 | + * @method static string quote(string $str) SQL指令安全过滤 | ||
48 | + * @method static string getLastInsID($sequence = null) 获取最近插入的ID | ||
49 | + */ | ||
50 | +class Db | ||
51 | +{ | ||
52 | + /** | ||
53 | + * @var Connection[] 数据库连接实例 | ||
54 | + */ | ||
55 | + private static $instance = []; | ||
56 | + | ||
57 | + /** | ||
58 | + * @var int 查询次数 | ||
59 | + */ | ||
60 | + public static $queryTimes = 0; | ||
61 | + | ||
62 | + /** | ||
63 | + * @var int 执行次数 | ||
64 | + */ | ||
65 | + public static $executeTimes = 0; | ||
66 | + | ||
67 | + /** | ||
68 | + * 数据库初始化,并取得数据库类实例 | ||
69 | + * @access public | ||
70 | + * @param mixed $config 连接配置 | ||
71 | + * @param bool|string $name 连接标识 true 强制重新连接 | ||
72 | + * @return Connection | ||
73 | + * @throws Exception | ||
74 | + */ | ||
75 | + public static function connect($config = [], $name = false) | ||
76 | + { | ||
77 | + if (false === $name) { | ||
78 | + $name = md5(serialize($config)); | ||
79 | + } | ||
80 | + | ||
81 | + if (true === $name || !isset(self::$instance[$name])) { | ||
82 | + // 解析连接参数 支持数组和字符串 | ||
83 | + $options = self::parseConfig($config); | ||
84 | + | ||
85 | + if (empty($options['type'])) { | ||
86 | + throw new \InvalidArgumentException('Undefined db type'); | ||
87 | + } | ||
88 | + | ||
89 | + $class = false !== strpos($options['type'], '\\') ? | ||
90 | + $options['type'] : | ||
91 | + '\\think\\db\\connector\\' . ucwords($options['type']); | ||
92 | + | ||
93 | + // 记录初始化信息 | ||
94 | + if (App::$debug) { | ||
95 | + Log::record('[ DB ] INIT ' . $options['type'], 'info'); | ||
96 | + } | ||
97 | + | ||
98 | + if (true === $name) { | ||
99 | + $name = md5(serialize($config)); | ||
100 | + } | ||
101 | + | ||
102 | + self::$instance[$name] = new $class($options); | ||
103 | + } | ||
104 | + | ||
105 | + return self::$instance[$name]; | ||
106 | + } | ||
107 | + | ||
108 | + /** | ||
109 | + * 清除连接实例 | ||
110 | + * @access public | ||
111 | + * @return void | ||
112 | + */ | ||
113 | + public static function clear() | ||
114 | + { | ||
115 | + self::$instance = []; | ||
116 | + } | ||
117 | + | ||
118 | + /** | ||
119 | + * 数据库连接参数解析 | ||
120 | + * @access private | ||
121 | + * @param mixed $config 连接参数 | ||
122 | + * @return array | ||
123 | + */ | ||
124 | + private static function parseConfig($config) | ||
125 | + { | ||
126 | + if (empty($config)) { | ||
127 | + $config = Config::get('database'); | ||
128 | + } elseif (is_string($config) && false === strpos($config, '/')) { | ||
129 | + $config = Config::get($config); // 支持读取配置参数 | ||
130 | + } | ||
131 | + | ||
132 | + return is_string($config) ? self::parseDsn($config) : $config; | ||
133 | + } | ||
134 | + | ||
135 | + /** | ||
136 | + * DSN 解析 | ||
137 | + * 格式: mysql://username:passwd@localhost:3306/DbName?param1=val1¶m2=val2#utf8 | ||
138 | + * @access private | ||
139 | + * @param string $dsnStr 数据库 DSN 字符串解析 | ||
140 | + * @return array | ||
141 | + */ | ||
142 | + private static function parseDsn($dsnStr) | ||
143 | + { | ||
144 | + $info = parse_url($dsnStr); | ||
145 | + | ||
146 | + if (!$info) { | ||
147 | + return []; | ||
148 | + } | ||
149 | + | ||
150 | + $dsn = [ | ||
151 | + 'type' => $info['scheme'], | ||
152 | + 'username' => isset($info['user']) ? $info['user'] : '', | ||
153 | + 'password' => isset($info['pass']) ? $info['pass'] : '', | ||
154 | + 'hostname' => isset($info['host']) ? $info['host'] : '', | ||
155 | + 'hostport' => isset($info['port']) ? $info['port'] : '', | ||
156 | + 'database' => !empty($info['path']) ? ltrim($info['path'], '/') : '', | ||
157 | + 'charset' => isset($info['fragment']) ? $info['fragment'] : 'utf8', | ||
158 | + ]; | ||
159 | + | ||
160 | + if (isset($info['query'])) { | ||
161 | + parse_str($info['query'], $dsn['params']); | ||
162 | + } else { | ||
163 | + $dsn['params'] = []; | ||
164 | + } | ||
165 | + | ||
166 | + return $dsn; | ||
167 | + } | ||
168 | + | ||
169 | + /** | ||
170 | + * 调用驱动类的方法 | ||
171 | + * @access public | ||
172 | + * @param string $method 方法名 | ||
173 | + * @param array $params 参数 | ||
174 | + * @return mixed | ||
175 | + */ | ||
176 | + public static function __callStatic($method, $params) | ||
177 | + { | ||
178 | + return call_user_func_array([self::connect(), $method], $params); | ||
179 | + } | ||
180 | +} |
-
请 注册 或 登录 后发表评论