正在显示
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 | +} |
-
请 注册 或 登录 后发表评论