mirror of
https://gitee.com/technical-laohu/mpay.git
synced 2025-11-13 14:13:43 +08:00
框架更新
This commit is contained in:
67
vendor/topthink/framework/.github/ISSUE_TEMPLATE/1-bug-report.yml
vendored
Normal file
67
vendor/topthink/framework/.github/ISSUE_TEMPLATE/1-bug-report.yml
vendored
Normal file
@@ -0,0 +1,67 @@
|
||||
name: Bug 反馈
|
||||
description: 反馈您所遇到的问题,以帮助我们更好的改进
|
||||
labels: ["bug"]
|
||||
body:
|
||||
- type: dropdown
|
||||
id: addon
|
||||
attributes:
|
||||
label: 所属功能组件
|
||||
options:
|
||||
- 路由(Route)
|
||||
- 控制器(Controller)
|
||||
- 中间件(Middleware)
|
||||
- 容器(Container)
|
||||
- 服务(Service)
|
||||
- 门面(Facade)
|
||||
- 事件(Event)
|
||||
- 请求(Request)
|
||||
- 缓存(Cache)
|
||||
- 响应(Response)
|
||||
- 视图(View)
|
||||
- 异常(Exception)
|
||||
- 日志(Log)
|
||||
- 验证器(Validate)
|
||||
- 多语言(Lang)
|
||||
- Session/Cookie
|
||||
- 文件系统(Filesystem)
|
||||
- 命令行(Command)
|
||||
- 其它
|
||||
description: |
|
||||
* 模型(Model)和数据库(Db)功能请前往 https://github.com/top-think/think-orm/issues 反馈
|
||||
* 多应用(MultiApp)功能请前往 https://github.com/top-think/think-multi-app/issues 反馈
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
id: version
|
||||
attributes:
|
||||
label: ThinkPHP 版本
|
||||
description: 您所使用的 ThinkPHP 版本是?
|
||||
placeholder: 如:8.0.3
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
id: system
|
||||
attributes:
|
||||
label: 操作系统
|
||||
description: 您代码在什么系统上运行?
|
||||
placeholder: 如:Windows、Centos、Ubuntu、Debian
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: 错误信息
|
||||
description: 如果有报错信息,请附上相关错误信息或截图。如:错误提示语、出错文件路径、出错行号和 Traces 等信息
|
||||
placeholder: |
|
||||
信息:控制器不存在
|
||||
路径:vendor/topthink/framework/src/think/App.php
|
||||
行号:313
|
||||
Traces:
|
||||
......
|
||||
validations:
|
||||
required: false
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: 其它说明
|
||||
description: 如您还有其它需要补充,可在此输入。
|
||||
validations:
|
||||
required: false
|
||||
20
vendor/topthink/framework/.github/ISSUE_TEMPLATE/2-feature_request.md
vendored
Normal file
20
vendor/topthink/framework/.github/ISSUE_TEMPLATE/2-feature_request.md
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
---
|
||||
name: 功能请求
|
||||
about: 您对 ThinkPHP 有什么改进的想法或建议,可在此提出。
|
||||
title: ''
|
||||
labels: 'enhancement'
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**您的功能请求与问题相关吗?**
|
||||
[是的话请在此描述]
|
||||
|
||||
**描述您想要的解决方案**
|
||||
[有的话请在此描述]
|
||||
|
||||
**描述您考虑过的替代方案**
|
||||
[有的话请在此描述]
|
||||
|
||||
**其它信息**
|
||||
[其它相关信息或截图]
|
||||
10
vendor/topthink/framework/.github/ISSUE_TEMPLATE/3-custom.md
vendored
Normal file
10
vendor/topthink/framework/.github/ISSUE_TEMPLATE/3-custom.md
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
---
|
||||
name: 其它问题
|
||||
about: 其它问题可在此反馈
|
||||
title: ''
|
||||
labels: 'help wanted'
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
|
||||
8
vendor/topthink/framework/.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
8
vendor/topthink/framework/.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
blank_issues_enabled: true
|
||||
contact_links:
|
||||
- name: ThinkPHP 完全开发手册
|
||||
url: https://doc.thinkphp.cn/
|
||||
about: 在创建 Issue 之前,请仔细查阅开发手册,以便对其有更深入的了解,和更好地分析问题。
|
||||
- name: ThinkPHP 轻社区
|
||||
url: https://q.thinkphp.cn/
|
||||
about: 欢迎来到ThinkPHP轻社区和大家一起交流。
|
||||
48
vendor/topthink/framework/.github/workflows/build.yml
vendored
Normal file
48
vendor/topthink/framework/.github/workflows/build.yml
vendored
Normal file
@@ -0,0 +1,48 @@
|
||||
name: build
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- "8.0"
|
||||
pull_request:
|
||||
schedule:
|
||||
- cron: "0 0 * * *"
|
||||
|
||||
jobs:
|
||||
tests:
|
||||
runs-on: ubuntu-22.04
|
||||
|
||||
strategy:
|
||||
fail-fast: true
|
||||
matrix:
|
||||
php: [8.0, 8.1, 8.2]
|
||||
|
||||
name: PHP ${{ matrix.php }}
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 10
|
||||
|
||||
- name: Setup PHP
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: ${{ matrix.php }}
|
||||
tools: composer:v2
|
||||
coverage: xdebug
|
||||
|
||||
- name: Install dependencies
|
||||
uses: nick-fields/retry@v2
|
||||
with:
|
||||
timeout_minutes: 5
|
||||
max_attempts: 5
|
||||
command: composer update --prefer-dist --no-interaction --prefer-stable --no-suggest
|
||||
|
||||
- name: Execute tests
|
||||
run: vendor/bin/phpunit --coverage-clover build/logs/clover.xml
|
||||
|
||||
- name: Upload Scrutinizer coverage
|
||||
uses: sudo-bot/action-scrutinizer@latest
|
||||
with:
|
||||
cli-args: "--format=php-clover build/logs/clover.xml --revision=${{ github.event.pull_request.head.sha || github.sha }}"
|
||||
119
vendor/topthink/framework/CONTRIBUTING.md
vendored
Normal file
119
vendor/topthink/framework/CONTRIBUTING.md
vendored
Normal file
@@ -0,0 +1,119 @@
|
||||
如何贡献我的源代码
|
||||
===
|
||||
|
||||
此文档介绍了 ThinkPHP 团队的组成以及运转机制,您提交的代码将给 ThinkPHP 项目带来什么好处,以及如何才能加入我们的行列。
|
||||
|
||||
## 通过 Github 贡献代码
|
||||
|
||||
ThinkPHP 目前使用 Git 来控制程序版本,如果你想为 ThinkPHP 贡献源代码,请先大致了解 Git 的使用方法。我们目前把项目托管在 GitHub 上,任何 GitHub 用户都可以向我们贡献代码。
|
||||
|
||||
参与的方式很简单,`fork`一份 ThinkPHP 的代码到你的仓库中,修改后提交,并向我们发起`pull request`申请,我们会及时对代码进行审查并处理你的申请并。审查通过后,你的代码将被`merge`进我们的仓库中,这样你就会自动出现在贡献者名单里了,非常方便。
|
||||
|
||||
我们希望你贡献的代码符合:
|
||||
|
||||
* ThinkPHP 的编码规范
|
||||
* 适当的注释,能让其他人读懂
|
||||
* 遵循 Apache2 开源协议
|
||||
|
||||
**如果想要了解更多细节或有任何疑问,请继续阅读下面的内容**
|
||||
|
||||
### 注意事项
|
||||
|
||||
* 本项目代码格式化标准选用 [**PSR-2**](http://www.kancloud.cn/thinkphp/php-fig-psr/3141);
|
||||
* 类名和类文件名遵循 [**PSR-4**](http://www.kancloud.cn/thinkphp/php-fig-psr/3144);
|
||||
* 对于 Issues 的处理,请使用诸如 `fix #xxx(Issue ID)` 的 commit title 直接关闭 issue。
|
||||
* 系统会自动在 PHP 7.1 ~ 7.3 上测试修改,请确保你的修改符合 PHP 7.1 ~ 7.3 的语法规范;
|
||||
* 管理员不会合并造成 CI faild 的修改,若出现 CI faild 请检查自己的源代码或修改相应的[单元测试文件](tests);
|
||||
|
||||
## GitHub Issue
|
||||
|
||||
GitHub 提供了 Issue 功能,该功能可以用于:
|
||||
|
||||
* 提出 bug
|
||||
* 提出功能改进
|
||||
* 反馈使用体验
|
||||
|
||||
该功能不应该用于:
|
||||
|
||||
* 提出修改意见(涉及代码署名和修订追溯问题)
|
||||
* 不友善的言论
|
||||
|
||||
## 快速修改
|
||||
|
||||
**GitHub 提供了快速编辑文件的功能**
|
||||
|
||||
1. 登录 GitHub 帐号;
|
||||
2. 浏览项目文件,找到要进行修改的文件;
|
||||
3. 点击右上角铅笔图标进行修改;
|
||||
4. 填写 `Commit changes` 相关内容(Title 必填);
|
||||
5. 提交修改,等待 CI 验证和管理员合并。
|
||||
|
||||
**若您需要一次提交大量修改,请继续阅读下面的内容**
|
||||
|
||||
## 完整流程
|
||||
|
||||
1. `fork`本项目;
|
||||
2. 克隆(`clone`)你 `fork` 的项目到本地;
|
||||
3. 新建分支(`branch`)并检出(`checkout`)新分支;
|
||||
4. 添加本项目到你的本地 git 仓库作为上游(`upstream`);
|
||||
5. 进行修改,若你的修改包含方法或函数的增减,请记得修改[单元测试文件](tests);
|
||||
6. 变基(衍合 `rebase`)你的分支到上游 master 分支;
|
||||
7. `push` 你的本地仓库到 GitHub;
|
||||
8. 提交 `pull request`;
|
||||
9. 等待 CI 验证(若不通过则重复 5~7,GitHub 会自动更新你的 `pull request`);
|
||||
10. 等待管理员处理,并及时 `rebase` 你的分支到上游 master 分支(若上游 master 分支有修改)。
|
||||
|
||||
*若有必要,可以 `git push -f` 强行推送 rebase 后的分支到自己的 `fork`*
|
||||
|
||||
*绝对不可以使用 `git push -f` 强行推送修改到上游*
|
||||
|
||||
### 注意事项
|
||||
|
||||
* 若对上述流程有任何不清楚的地方,请查阅 GIT 教程,如 [这个](http://backlogtool.com/git-guide/cn/);
|
||||
* 对于代码**不同方面**的修改,请在自己 `fork` 的项目中**创建不同的分支**(原因参见`完整流程`第9条备注部分);
|
||||
* 变基及交互式变基操作参见 [Git 交互式变基](http://pakchoi.me/2015/03/17/git-interactive-rebase/)
|
||||
|
||||
## 推荐资源
|
||||
|
||||
### 开发环境
|
||||
|
||||
* XAMPP for Windows 5.5.x
|
||||
* WampServer (for Windows)
|
||||
* upupw Apache PHP5.4 ( for Windows)
|
||||
|
||||
或自行安装
|
||||
|
||||
- Apache / Nginx
|
||||
- PHP 7.1 ~ 7.3
|
||||
- MySQL / MariaDB
|
||||
|
||||
*Windows 用户推荐添加 PHP bin 目录到 PATH,方便使用 composer*
|
||||
|
||||
*Linux 用户自行配置环境, Mac 用户推荐使用内置 Apache 配合 Homebrew 安装 PHP 和 MariaDB*
|
||||
|
||||
### 编辑器
|
||||
|
||||
Sublime Text 3 + phpfmt 插件
|
||||
|
||||
phpfmt 插件参数
|
||||
|
||||
```json
|
||||
{
|
||||
"autocomplete": true,
|
||||
"enable_auto_align": true,
|
||||
"format_on_save": true,
|
||||
"indent_with_space": true,
|
||||
"psr1_naming": false,
|
||||
"psr2": true,
|
||||
"version": 4
|
||||
}
|
||||
```
|
||||
|
||||
或其他 编辑器 / IDE 配合 PSR2 自动格式化工具
|
||||
|
||||
### Git GUI
|
||||
|
||||
* SourceTree
|
||||
* GitHub Desktop
|
||||
|
||||
或其他 Git 图形界面客户端
|
||||
32
vendor/topthink/framework/LICENSE.txt
vendored
Normal file
32
vendor/topthink/framework/LICENSE.txt
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
|
||||
ThinkPHP遵循Apache2开源协议发布,并提供免费使用。
|
||||
版权所有Copyright © 2006-2023 by ThinkPHP (http://thinkphp.cn)
|
||||
All rights reserved。
|
||||
ThinkPHP® 商标和著作权所有者为上海顶想信息科技有限公司。
|
||||
|
||||
Apache Licence是著名的非盈利开源组织Apache采用的协议。
|
||||
该协议和BSD类似,鼓励代码共享和尊重原作者的著作权,
|
||||
允许代码修改,再作为开源或商业软件发布。需要满足
|
||||
的条件:
|
||||
1. 需要给代码的用户一份Apache Licence ;
|
||||
2. 如果你修改了代码,需要在被修改的文件中说明;
|
||||
3. 在延伸的代码中(修改和有源代码衍生的代码中)需要
|
||||
带有原来代码中的协议,商标,专利声明和其他原来作者规
|
||||
定需要包含的说明;
|
||||
4. 如果再发布的产品中包含一个Notice文件,则在Notice文
|
||||
件中需要带有本协议内容。你可以在Notice中增加自己的
|
||||
许可,但不可以表现为对Apache Licence构成更改。
|
||||
具体的协议参考:http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
83
vendor/topthink/framework/README.md
vendored
Normal file
83
vendor/topthink/framework/README.md
vendored
Normal file
@@ -0,0 +1,83 @@
|
||||

|
||||
|
||||
# ThinkPHP 8.0
|
||||
|
||||
[](https://github.com/top-think/framework/actions)
|
||||
[](https://scrutinizer-ci.com/g/top-think/framework/?branch=8.0)
|
||||
[](https://scrutinizer-ci.com/g/top-think/framework/?branch=8.0)
|
||||
[](https://packagist.org/packages/topthink/framework)
|
||||
[](https://packagist.org/packages/topthink/framework)
|
||||
[](http://www.php.net/)
|
||||
[](https://packagist.org/packages/topthink/framework)
|
||||
|
||||
## 主要特性
|
||||
|
||||
- 基于 PHP`8.0+`重构
|
||||
- 升级`PSR`依赖
|
||||
- 依赖`think-orm`3.0 版本
|
||||
- `6.0`/`6.1`无缝升级
|
||||
|
||||
> ThinkPHP8.0 的运行环境要求 PHP8.0+
|
||||
|
||||
现在开始,你可以使用官方提供的[ThinkChat](https://chat.topthink.com/),让你在学习 ThinkPHP 的旅途中享受私人 AI 助理服务!
|
||||
|
||||
[](https://chat.topthink.com/)
|
||||
|
||||
ThinkPHP 生态服务由[顶想云](https://www.topthink.com)(TOPThink Cloud)提供,为生态提供专业的开发者服务和价值之选。
|
||||
|
||||
## 文档
|
||||
|
||||
[完全开发手册](https://doc.thinkphp.cn)
|
||||
|
||||
## 赞助商
|
||||
|
||||
全新的[赞助计划](https://www.thinkphp.cn/sponsor)可以让你通过我们的网站、手册、欢迎页及 GIT 仓库获得巨大曝光,同时提升企业的品牌声誉,也更好保障 ThinkPHP 的可持续发展。
|
||||
|
||||
[](https://www.thinkphp.cn/sponsor/special)
|
||||
|
||||
[](https://www.thinkphp.cn/sponsor)
|
||||
|
||||
## 安装
|
||||
|
||||
```
|
||||
composer create-project topthink/think tp
|
||||
```
|
||||
|
||||
启动服务
|
||||
|
||||
```
|
||||
cd tp
|
||||
php think run
|
||||
```
|
||||
|
||||
然后就可以在浏览器中访问
|
||||
|
||||
```
|
||||
http://localhost:8000
|
||||
```
|
||||
|
||||
如果需要更新框架使用
|
||||
|
||||
```
|
||||
composer update topthink/framework
|
||||
```
|
||||
|
||||
## 命名规范
|
||||
|
||||
`ThinkPHP`遵循 PSR-2 命名规范和 PSR-4 自动加载规范。
|
||||
|
||||
## 参与开发
|
||||
|
||||
直接提交 PR 或者 Issue 即可
|
||||
|
||||
## 版权信息
|
||||
|
||||
ThinkPHP 遵循 Apache2 开源协议发布,并提供免费使用。
|
||||
|
||||
本项目包含的第三方源码和二进制文件之版权信息另行标注。
|
||||
|
||||
版权所有 Copyright © 2006-2023 by ThinkPHP (http://thinkphp.cn) All rights reserved。
|
||||
|
||||
ThinkPHP® 商标和著作权所有者为上海顶想信息科技有限公司。
|
||||
|
||||
更多细节参阅 [LICENSE.txt](LICENSE.txt)
|
||||
54
vendor/topthink/framework/composer.json
vendored
Normal file
54
vendor/topthink/framework/composer.json
vendored
Normal file
@@ -0,0 +1,54 @@
|
||||
{
|
||||
"name": "topthink/framework",
|
||||
"description": "The ThinkPHP Framework.",
|
||||
"keywords": [
|
||||
"framework",
|
||||
"thinkphp",
|
||||
"ORM"
|
||||
],
|
||||
"homepage": "http://thinkphp.cn/",
|
||||
"license": "Apache-2.0",
|
||||
"authors": [
|
||||
{
|
||||
"name": "liu21st",
|
||||
"email": "liu21st@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "yunwuxin",
|
||||
"email": "448901948@qq.com"
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": ">=8.0.0",
|
||||
"ext-json": "*",
|
||||
"ext-mbstring": "*",
|
||||
"psr/log": "^1.0|^2.0|^3.0",
|
||||
"psr/container": "^2.0",
|
||||
"psr/simple-cache": "^1.0|^2.0|^3.0",
|
||||
"psr/http-message": "^1.0",
|
||||
"topthink/think-orm": "^3.0",
|
||||
"topthink/think-helper": "^3.1"
|
||||
},
|
||||
"require-dev": {
|
||||
"mikey179/vfsstream": "^1.6",
|
||||
"mockery/mockery": "^1.2",
|
||||
"phpunit/phpunit": "^9.5",
|
||||
"guzzlehttp/psr7": "^2.1.0"
|
||||
},
|
||||
"autoload": {
|
||||
"files": [],
|
||||
"psr-4": {
|
||||
"think\\": "src/think/"
|
||||
}
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": {
|
||||
"think\\tests\\": "tests/"
|
||||
}
|
||||
},
|
||||
"minimum-stability": "dev",
|
||||
"prefer-stable": true,
|
||||
"config": {
|
||||
"sort-packages": true
|
||||
}
|
||||
}
|
||||
BIN
vendor/topthink/framework/logo.png
vendored
Normal file
BIN
vendor/topthink/framework/logo.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 6.8 KiB |
27
vendor/topthink/framework/phpunit.xml.dist
vendored
Normal file
27
vendor/topthink/framework/phpunit.xml.dist
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
backupGlobals="false"
|
||||
backupStaticAttributes="false"
|
||||
beStrictAboutTestsThatDoNotTestAnything="false"
|
||||
bootstrap="tests/bootstrap.php"
|
||||
colors="true"
|
||||
convertErrorsToExceptions="true"
|
||||
convertNoticesToExceptions="true"
|
||||
convertWarningsToExceptions="true"
|
||||
processIsolation="false"
|
||||
stopOnError="false"
|
||||
stopOnFailure="false"
|
||||
verbose="true"
|
||||
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.3/phpunit.xsd"
|
||||
>
|
||||
<coverage processUncoveredFiles="true">
|
||||
<include>
|
||||
<directory suffix=".php">./src/think</directory>
|
||||
</include>
|
||||
</coverage>
|
||||
<testsuites>
|
||||
<testsuite name="ThinkPHP Test Suite">
|
||||
<directory suffix="Test.php">./tests</directory>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
</phpunit>
|
||||
664
vendor/topthink/framework/src/helper.php
vendored
Normal file
664
vendor/topthink/framework/src/helper.php
vendored
Normal file
@@ -0,0 +1,664 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2023 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
declare(strict_types=1);
|
||||
|
||||
//------------------------
|
||||
// ThinkPHP 助手函数
|
||||
//-------------------------
|
||||
|
||||
use think\App;
|
||||
use think\Container;
|
||||
use think\exception\HttpException;
|
||||
use think\exception\HttpResponseException;
|
||||
use think\facade\Cache;
|
||||
use think\facade\Config;
|
||||
use think\facade\Cookie;
|
||||
use think\facade\Env;
|
||||
use think\facade\Event;
|
||||
use think\facade\Lang;
|
||||
use think\facade\Log;
|
||||
use think\facade\Request;
|
||||
use think\facade\Route;
|
||||
use think\facade\Session;
|
||||
use think\Response;
|
||||
use think\response\File;
|
||||
use think\response\Json;
|
||||
use think\response\Jsonp;
|
||||
use think\response\Redirect;
|
||||
use think\response\View;
|
||||
use think\response\Xml;
|
||||
use think\route\Url as UrlBuild;
|
||||
use think\Validate;
|
||||
|
||||
if (!function_exists('abort')) {
|
||||
/**
|
||||
* 抛出HTTP异常
|
||||
* @param integer|Response $code 状态码 或者 Response对象实例
|
||||
* @param string $message 错误信息
|
||||
* @param array $header 参数
|
||||
*/
|
||||
function abort($code, string $message = '', array $header = [])
|
||||
{
|
||||
if ($code instanceof Response) {
|
||||
throw new HttpResponseException($code);
|
||||
} else {
|
||||
throw new HttpException($code, $message, null, $header);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('app')) {
|
||||
/**
|
||||
* 快速获取容器中的实例 支持依赖注入
|
||||
* @template T
|
||||
* @param string|class-string<T> $name 类名或标识 默认获取当前应用实例
|
||||
* @param array $args 参数
|
||||
* @param bool $newInstance 是否每次创建新的实例
|
||||
* @return T|object|App
|
||||
*/
|
||||
function app(string $name = '', array $args = [], bool $newInstance = false)
|
||||
{
|
||||
return Container::getInstance()->make($name ?: App::class, $args, $newInstance);
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('bind')) {
|
||||
/**
|
||||
* 绑定一个类到容器
|
||||
* @param string|array $abstract 类标识、接口(支持批量绑定)
|
||||
* @param mixed $concrete 要绑定的类、闭包或者实例
|
||||
* @return Container
|
||||
*/
|
||||
function bind($abstract, $concrete = null)
|
||||
{
|
||||
return Container::getInstance()->bind($abstract, $concrete);
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('cache')) {
|
||||
/**
|
||||
* 缓存管理
|
||||
* @param string $name 缓存名称
|
||||
* @param mixed $value 缓存值
|
||||
* @param mixed $options 缓存参数
|
||||
* @param string $tag 缓存标签
|
||||
* @return mixed
|
||||
*/
|
||||
function cache(string $name = null, $value = '', $options = null, $tag = null)
|
||||
{
|
||||
if (is_null($name)) {
|
||||
return app('cache');
|
||||
}
|
||||
|
||||
if ('' === $value) {
|
||||
// 获取缓存
|
||||
return str_starts_with($name, '?') ? Cache::has(substr($name, 1)) : Cache::get($name);
|
||||
} elseif (is_null($value)) {
|
||||
// 删除缓存
|
||||
return Cache::delete($name);
|
||||
}
|
||||
|
||||
// 缓存数据
|
||||
if (is_array($options)) {
|
||||
$expire = $options['expire'] ?? null; //修复查询缓存无法设置过期时间
|
||||
} else {
|
||||
$expire = $options;
|
||||
}
|
||||
|
||||
if (is_null($tag)) {
|
||||
return Cache::set($name, $value, $expire);
|
||||
} else {
|
||||
return Cache::tag($tag)->set($name, $value, $expire);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('config')) {
|
||||
/**
|
||||
* 获取和设置配置参数
|
||||
* @param string|array $name 参数名
|
||||
* @param mixed $value 参数值
|
||||
* @return mixed
|
||||
*/
|
||||
function config($name = '', $value = null)
|
||||
{
|
||||
if (is_array($name)) {
|
||||
return Config::set($name, $value);
|
||||
}
|
||||
|
||||
return str_starts_with($name, '?') ? Config::has(substr($name, 1)) : Config::get($name, $value);
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('cookie')) {
|
||||
/**
|
||||
* Cookie管理
|
||||
* @param string $name cookie名称
|
||||
* @param mixed $value cookie值
|
||||
* @param mixed $option 参数
|
||||
* @return mixed
|
||||
*/
|
||||
function cookie(string $name, $value = '', $option = null)
|
||||
{
|
||||
if (is_null($value)) {
|
||||
// 删除
|
||||
Cookie::delete($name, $option ?: []);
|
||||
} elseif ('' === $value) {
|
||||
// 获取
|
||||
return str_starts_with($name, '?') ? Cookie::has(substr($name, 1)) : Cookie::get($name);
|
||||
} else {
|
||||
// 设置
|
||||
return Cookie::set($name, $value, $option);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('download')) {
|
||||
/**
|
||||
* 获取\think\response\Download对象实例
|
||||
* @param string $filename 要下载的文件
|
||||
* @param string $name 显示文件名
|
||||
* @param bool $content 是否为内容
|
||||
* @param int $expire 有效期(秒)
|
||||
* @return \think\response\File
|
||||
*/
|
||||
function download(string $filename, string $name = '', bool $content = false, int $expire = 180): File
|
||||
{
|
||||
return Response::create($filename, 'file')->name($name)->isContent($content)->expire($expire);
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('dump')) {
|
||||
/**
|
||||
* 浏览器友好的变量输出
|
||||
* @param mixed $vars 要输出的变量
|
||||
* @return void
|
||||
*/
|
||||
function dump(...$vars)
|
||||
{
|
||||
ob_start();
|
||||
var_dump(...$vars);
|
||||
|
||||
$output = ob_get_clean();
|
||||
$output = preg_replace('/\]\=\>\n(\s+)/m', '] => ', $output);
|
||||
|
||||
if (PHP_SAPI == 'cli') {
|
||||
$output = PHP_EOL . $output . PHP_EOL;
|
||||
} else {
|
||||
if (!extension_loaded('xdebug')) {
|
||||
$output = htmlspecialchars($output, ENT_SUBSTITUTE);
|
||||
}
|
||||
$output = '<pre>' . $output . '</pre>';
|
||||
}
|
||||
|
||||
echo $output;
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('env')) {
|
||||
/**
|
||||
* 获取环境变量值
|
||||
* @access public
|
||||
* @param string $name 环境变量名(支持二级 .号分割)
|
||||
* @param string $default 默认值
|
||||
* @return mixed
|
||||
*/
|
||||
function env(string $name = null, $default = null)
|
||||
{
|
||||
return Env::get($name, $default);
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('event')) {
|
||||
/**
|
||||
* 触发事件
|
||||
* @param mixed $event 事件名(或者类名)
|
||||
* @param mixed $args 参数
|
||||
* @return mixed
|
||||
*/
|
||||
function event($event, $args = null)
|
||||
{
|
||||
return Event::trigger($event, $args);
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('halt')) {
|
||||
/**
|
||||
* 调试变量并且中断输出
|
||||
* @param mixed $vars 调试变量或者信息
|
||||
*/
|
||||
function halt(...$vars)
|
||||
{
|
||||
dump(...$vars);
|
||||
|
||||
throw new HttpResponseException(Response::create());
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('input')) {
|
||||
/**
|
||||
* 获取输入数据 支持默认值和过滤
|
||||
* @param string $key 获取的变量名
|
||||
* @param mixed $default 默认值
|
||||
* @param string|array|null $filter 过滤方法
|
||||
* @return mixed
|
||||
*/
|
||||
function input(string $key = '', $default = null, $filter = '')
|
||||
{
|
||||
if (str_starts_with($key, '?')) {
|
||||
$key = substr($key, 1);
|
||||
$has = true;
|
||||
}
|
||||
|
||||
if ($pos = strpos($key, '.')) {
|
||||
// 指定参数来源
|
||||
$method = substr($key, 0, $pos);
|
||||
if (in_array($method, ['get', 'post', 'put', 'patch', 'delete', 'route', 'param', 'request', 'session', 'cookie', 'server', 'env', 'path', 'file'])) {
|
||||
$key = substr($key, $pos + 1);
|
||||
if ('server' == $method && is_null($default)) {
|
||||
$default = '';
|
||||
}
|
||||
} else {
|
||||
$method = 'param';
|
||||
}
|
||||
} else {
|
||||
// 默认为自动判断
|
||||
$method = 'param';
|
||||
}
|
||||
|
||||
return isset($has) ?
|
||||
request()->has($key, $method) :
|
||||
request()->$method($key, $default, $filter);
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('invoke')) {
|
||||
/**
|
||||
* 调用反射实例化对象或者执行方法 支持依赖注入
|
||||
* @param mixed $call 类名或者callable
|
||||
* @param array $args 参数
|
||||
* @return mixed
|
||||
*/
|
||||
function invoke($call, array $args = [])
|
||||
{
|
||||
if (is_callable($call)) {
|
||||
return Container::getInstance()->invoke($call, $args);
|
||||
}
|
||||
|
||||
return Container::getInstance()->invokeClass($call, $args);
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('json')) {
|
||||
/**
|
||||
* 获取\think\response\Json对象实例
|
||||
* @param mixed $data 返回的数据
|
||||
* @param int $code 状态码
|
||||
* @param array $header 头部
|
||||
* @param array $options 参数
|
||||
* @return \think\response\Json
|
||||
*/
|
||||
function json($data = [], $code = 200, $header = [], $options = []): Json
|
||||
{
|
||||
return Response::create($data, 'json', $code)->header($header)->options($options);
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('jsonp')) {
|
||||
/**
|
||||
* 获取\think\response\Jsonp对象实例
|
||||
* @param mixed $data 返回的数据
|
||||
* @param int $code 状态码
|
||||
* @param array $header 头部
|
||||
* @param array $options 参数
|
||||
* @return \think\response\Jsonp
|
||||
*/
|
||||
function jsonp($data = [], $code = 200, $header = [], $options = []): Jsonp
|
||||
{
|
||||
return Response::create($data, 'jsonp', $code)->header($header)->options($options);
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('lang')) {
|
||||
/**
|
||||
* 获取语言变量值
|
||||
* @param string $name 语言变量名
|
||||
* @param array $vars 动态变量值
|
||||
* @param string $lang 语言
|
||||
* @return mixed
|
||||
*/
|
||||
function lang(string $name, array $vars = [], string $lang = '')
|
||||
{
|
||||
return Lang::get($name, $vars, $lang);
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('parse_name')) {
|
||||
/**
|
||||
* 字符串命名风格转换
|
||||
* type 0 将Java风格转换为C的风格 1 将C风格转换为Java的风格
|
||||
* @param string $name 字符串
|
||||
* @param int $type 转换类型
|
||||
* @param bool $ucfirst 首字母是否大写(驼峰规则)
|
||||
* @return string
|
||||
*/
|
||||
function parse_name(string $name, int $type = 0, bool $ucfirst = true): string
|
||||
{
|
||||
if ($type) {
|
||||
$name = preg_replace_callback('/_([a-zA-Z])/', function ($match) {
|
||||
return strtoupper($match[1]);
|
||||
}, $name);
|
||||
|
||||
return $ucfirst ? ucfirst($name) : lcfirst($name);
|
||||
}
|
||||
|
||||
return strtolower(trim(preg_replace('/[A-Z]/', '_\\0', $name), '_'));
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('redirect')) {
|
||||
/**
|
||||
* 获取\think\response\Redirect对象实例
|
||||
* @param string $url 重定向地址
|
||||
* @param int $code 状态码
|
||||
* @return \think\response\Redirect
|
||||
*/
|
||||
function redirect(string $url = '', int $code = 302): Redirect
|
||||
{
|
||||
return Response::create($url, 'redirect', $code);
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('request')) {
|
||||
/**
|
||||
* 获取当前Request对象实例
|
||||
* @return Request
|
||||
*/
|
||||
function request(): \think\Request
|
||||
{
|
||||
return app('request');
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('response')) {
|
||||
/**
|
||||
* 创建普通 Response 对象实例
|
||||
* @param mixed $data 输出数据
|
||||
* @param int|string $code 状态码
|
||||
* @param array $header 头信息
|
||||
* @param string $type
|
||||
* @return Response
|
||||
*/
|
||||
function response($data = '', $code = 200, $header = [], $type = 'html'): Response
|
||||
{
|
||||
return Response::create($data, $type, $code)->header($header);
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('session')) {
|
||||
/**
|
||||
* Session管理
|
||||
* @param string $name session名称
|
||||
* @param mixed $value session值
|
||||
* @return mixed
|
||||
*/
|
||||
function session($name = '', $value = '')
|
||||
{
|
||||
if (is_null($name)) {
|
||||
// 清除
|
||||
Session::clear();
|
||||
} elseif ('' === $name) {
|
||||
return Session::all();
|
||||
} elseif (is_null($value)) {
|
||||
// 删除
|
||||
Session::delete($name);
|
||||
} elseif ('' === $value) {
|
||||
// 判断或获取
|
||||
return str_starts_with($name, '?') ? Session::has(substr($name, 1)) : Session::get($name);
|
||||
} else {
|
||||
// 设置
|
||||
Session::set($name, $value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('token')) {
|
||||
/**
|
||||
* 获取Token令牌
|
||||
* @param string $name 令牌名称
|
||||
* @param mixed $type 令牌生成方法
|
||||
* @return string
|
||||
*/
|
||||
function token(string $name = '__token__', string $type = 'md5'): string
|
||||
{
|
||||
return Request::buildToken($name, $type);
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('token_field')) {
|
||||
/**
|
||||
* 生成令牌隐藏表单
|
||||
* @param string $name 令牌名称
|
||||
* @param mixed $type 令牌生成方法
|
||||
* @return string
|
||||
*/
|
||||
function token_field(string $name = '__token__', string $type = 'md5'): string
|
||||
{
|
||||
$token = Request::buildToken($name, $type);
|
||||
|
||||
return '<input type="hidden" name="' . $name . '" value="' . $token . '" />';
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('token_meta')) {
|
||||
/**
|
||||
* 生成令牌meta
|
||||
* @param string $name 令牌名称
|
||||
* @param mixed $type 令牌生成方法
|
||||
* @return string
|
||||
*/
|
||||
function token_meta(string $name = '__token__', string $type = 'md5'): string
|
||||
{
|
||||
$token = Request::buildToken($name, $type);
|
||||
|
||||
return '<meta name="csrf-token" content="' . $token . '">';
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('trace')) {
|
||||
/**
|
||||
* 记录日志信息
|
||||
* @param mixed $log log信息 支持字符串和数组
|
||||
* @param string $level 日志级别
|
||||
* @return array|void
|
||||
*/
|
||||
function trace($log = '[think]', string $level = 'log')
|
||||
{
|
||||
if ('[think]' === $log) {
|
||||
return Log::getLog();
|
||||
}
|
||||
|
||||
Log::record($log, $level);
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('url')) {
|
||||
/**
|
||||
* Url生成
|
||||
* @param string $url 路由地址
|
||||
* @param array $vars 变量
|
||||
* @param bool|string $suffix 生成的URL后缀
|
||||
* @param bool|string $domain 域名
|
||||
* @return UrlBuild
|
||||
*/
|
||||
function url(string $url = '', array $vars = [], $suffix = true, $domain = false): UrlBuild
|
||||
{
|
||||
return Route::buildUrl($url, $vars)->suffix($suffix)->domain($domain);
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('validate')) {
|
||||
/**
|
||||
* 生成验证对象
|
||||
* @param string|array $validate 验证器类名或者验证规则数组
|
||||
* @param array $message 错误提示信息
|
||||
* @param bool $batch 是否批量验证
|
||||
* @param bool $failException 是否抛出异常
|
||||
* @return Validate
|
||||
*/
|
||||
function validate($validate = '', array $message = [], bool $batch = false, bool $failException = true): Validate
|
||||
{
|
||||
if (is_array($validate) || '' === $validate) {
|
||||
$v = new Validate();
|
||||
if (is_array($validate)) {
|
||||
$v->rule($validate);
|
||||
}
|
||||
} else {
|
||||
if (str_contains($validate, '.')) {
|
||||
// 支持场景
|
||||
[$validate, $scene] = explode('.', $validate);
|
||||
}
|
||||
|
||||
$class = str_contains($validate, '\\') ? $validate : app()->parseClass('validate', $validate);
|
||||
|
||||
$v = new $class();
|
||||
|
||||
if (!empty($scene)) {
|
||||
$v->scene($scene);
|
||||
}
|
||||
}
|
||||
|
||||
return $v->message($message)->batch($batch)->failException($failException);
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('view')) {
|
||||
/**
|
||||
* 渲染模板输出
|
||||
* @param string $template 模板文件
|
||||
* @param array $vars 模板变量
|
||||
* @param int $code 状态码
|
||||
* @param callable $filter 内容过滤
|
||||
* @return \think\response\View
|
||||
*/
|
||||
function view(string $template = '', $vars = [], $code = 200, $filter = null): View
|
||||
{
|
||||
return Response::create($template, 'view', $code)->assign($vars)->filter($filter);
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('display')) {
|
||||
/**
|
||||
* 渲染模板输出
|
||||
* @param string $content 渲染内容
|
||||
* @param array $vars 模板变量
|
||||
* @param int $code 状态码
|
||||
* @param callable $filter 内容过滤
|
||||
* @return \think\response\View
|
||||
*/
|
||||
function display(string $content, $vars = [], $code = 200, $filter = null): View
|
||||
{
|
||||
return Response::create($content, 'view', $code)->isContent(true)->assign($vars)->filter($filter);
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('xml')) {
|
||||
/**
|
||||
* 获取\think\response\Xml对象实例
|
||||
* @param mixed $data 返回的数据
|
||||
* @param int $code 状态码
|
||||
* @param array $header 头部
|
||||
* @param array $options 参数
|
||||
* @return \think\response\Xml
|
||||
*/
|
||||
function xml($data = [], $code = 200, $header = [], $options = []): Xml
|
||||
{
|
||||
return Response::create($data, 'xml', $code)->header($header)->options($options);
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('app_path')) {
|
||||
/**
|
||||
* 获取当前应用目录
|
||||
*
|
||||
* @param string $path
|
||||
* @return string
|
||||
*/
|
||||
function app_path($path = '')
|
||||
{
|
||||
return app()->getAppPath() . ($path ? $path . DIRECTORY_SEPARATOR : $path);
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('base_path')) {
|
||||
/**
|
||||
* 获取应用基础目录
|
||||
*
|
||||
* @param string $path
|
||||
* @return string
|
||||
*/
|
||||
function base_path($path = '')
|
||||
{
|
||||
return app()->getBasePath() . ($path ? $path . DIRECTORY_SEPARATOR : $path);
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('config_path')) {
|
||||
/**
|
||||
* 获取应用配置目录
|
||||
*
|
||||
* @param string $path
|
||||
* @return string
|
||||
*/
|
||||
function config_path($path = '')
|
||||
{
|
||||
return app()->getConfigPath() . ($path ? $path . DIRECTORY_SEPARATOR : $path);
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('public_path')) {
|
||||
/**
|
||||
* 获取web根目录
|
||||
*
|
||||
* @param string $path
|
||||
* @return string
|
||||
*/
|
||||
function public_path($path = '')
|
||||
{
|
||||
return app()->getRootPath() . 'public' . DIRECTORY_SEPARATOR . ($path ? ltrim($path, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR : $path);
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('runtime_path')) {
|
||||
/**
|
||||
* 获取应用运行时目录
|
||||
*
|
||||
* @param string $path
|
||||
* @return string
|
||||
*/
|
||||
function runtime_path($path = '')
|
||||
{
|
||||
return app()->getRuntimePath() . ($path ? $path . DIRECTORY_SEPARATOR : $path);
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('root_path')) {
|
||||
/**
|
||||
* 获取项目根目录
|
||||
*
|
||||
* @param string $path
|
||||
* @return string
|
||||
*/
|
||||
function root_path($path = '')
|
||||
{
|
||||
return app()->getRootPath() . ($path ? $path . DIRECTORY_SEPARATOR : $path);
|
||||
}
|
||||
}
|
||||
152
vendor/topthink/framework/src/lang/zh-cn.php
vendored
Normal file
152
vendor/topthink/framework/src/lang/zh-cn.php
vendored
Normal file
@@ -0,0 +1,152 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2023 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
// 核心中文语言包
|
||||
return [
|
||||
// 系统错误提示
|
||||
'Undefined variable' => '未定义变量',
|
||||
'Undefined index' => '未定义数组索引',
|
||||
'Undefined offset' => '未定义数组下标',
|
||||
'Parse error' => '语法解析错误',
|
||||
'Type error' => '类型错误',
|
||||
'Fatal error' => '致命错误',
|
||||
'syntax error' => '语法错误',
|
||||
|
||||
// 框架核心错误提示
|
||||
'dispatch type not support' => '不支持的调度类型',
|
||||
'method param miss' => '方法参数错误',
|
||||
'method not exists' => '方法不存在',
|
||||
'function not exists' => '函数不存在',
|
||||
'app not exists' => '应用不存在',
|
||||
'controller not exists' => '控制器不存在',
|
||||
'class not exists' => '类不存在',
|
||||
'property not exists' => '类的属性不存在',
|
||||
'template not exists' => '模板文件不存在',
|
||||
'illegal controller name' => '非法的控制器名称',
|
||||
'illegal action name' => '非法的操作名称',
|
||||
'url suffix deny' => '禁止的URL后缀访问',
|
||||
'Undefined cache config' => '缓存配置未定义',
|
||||
'Route Not Found' => '当前访问路由未定义或不匹配',
|
||||
'Undefined db config' => '数据库配置未定义',
|
||||
'Undefined log config' => '日志配置未定义',
|
||||
'Undefined db type' => '未定义数据库类型',
|
||||
'variable type error' => '变量类型错误',
|
||||
'PSR-4 error' => 'PSR-4 规范错误',
|
||||
'not support type' => '不支持的分页索引字段类型',
|
||||
'not support total' => '简洁模式下不能获取数据总数',
|
||||
'not support last' => '简洁模式下不能获取最后一页',
|
||||
'error session handler' => '错误的SESSION处理器类',
|
||||
'not allow php tag' => '模板不允许使用PHP语法',
|
||||
'not support' => '不支持',
|
||||
'database config error' => '数据库配置信息错误',
|
||||
'redisd master' => 'Redisd 主服务器错误',
|
||||
'redisd slave' => 'Redisd 从服务器错误',
|
||||
'must run at sae' => '必须在SAE运行',
|
||||
'memcache init error' => '未开通Memcache服务,请在SAE管理平台初始化Memcache服务',
|
||||
'KVDB init error' => '没有初始化KVDB,请在SAE管理平台初始化KVDB服务',
|
||||
'fields not exists' => '数据表字段不存在',
|
||||
'where express error' => '查询表达式错误',
|
||||
'no data to update' => '没有任何数据需要更新',
|
||||
'miss data to insert' => '缺少需要写入的数据',
|
||||
'miss complex primary data' => '缺少复合主键数据',
|
||||
'miss update condition' => '缺少更新条件',
|
||||
'model data Not Found' => '模型数据不存在',
|
||||
'table data not Found' => '表数据不存在',
|
||||
'delete without condition' => '没有条件不会执行删除操作',
|
||||
'miss relation data' => '缺少关联表数据',
|
||||
'tag attr must' => '模板标签属性必须',
|
||||
'tag error' => '模板标签错误',
|
||||
'cache write error' => '缓存写入失败',
|
||||
'sae mc write error' => 'SAE mc 写入错误',
|
||||
'route name not exists' => '路由标识不存在(或参数不够)',
|
||||
'invalid request' => '非法请求',
|
||||
'bind attr has exists' => '模型的属性已经存在',
|
||||
'relation data not exists' => '关联数据不存在',
|
||||
'relation not support' => '关联不支持',
|
||||
'chunk not support order' => 'Chunk不支持调用order方法',
|
||||
'route pattern error' => '路由变量规则定义错误',
|
||||
'route behavior will not support' => '路由行为废弃(使用中间件替代)',
|
||||
'closure not support cache(true)' => '使用闭包查询不支持cache(true),请指定缓存Key',
|
||||
|
||||
// 上传错误信息
|
||||
'unknown upload error' => '未知上传错误!',
|
||||
'file write error' => '文件写入失败!',
|
||||
'upload temp dir not found' => '找不到临时文件夹!',
|
||||
'no file to uploaded' => '没有文件被上传!',
|
||||
'only the portion of file is uploaded' => '文件只有部分被上传!',
|
||||
'upload File size exceeds the maximum value' => '上传文件大小超过了最大值!',
|
||||
'upload write error' => '文件上传保存错误!',
|
||||
'has the same filename: {:filename}' => '存在同名文件:{:filename}',
|
||||
'upload illegal files' => '非法上传文件',
|
||||
'illegal image files' => '非法图片文件',
|
||||
'extensions to upload is not allowed' => '上传文件后缀不允许',
|
||||
'mimetype to upload is not allowed' => '上传文件MIME类型不允许!',
|
||||
'filesize not match' => '上传文件大小不符!',
|
||||
'directory {:path} creation failed' => '目录 {:path} 创建失败!',
|
||||
|
||||
'The middleware must return Response instance' => '中间件方法必须返回Response对象实例',
|
||||
'The queue was exhausted, with no response returned' => '中间件队列为空',
|
||||
// Validate Error Message
|
||||
':attribute require' => ':attribute不能为空',
|
||||
':attribute must' => ':attribute必须',
|
||||
':attribute must be numeric' => ':attribute必须是数字',
|
||||
':attribute must be integer' => ':attribute必须是整数',
|
||||
':attribute must be float' => ':attribute必须是浮点数',
|
||||
':attribute must be string' => ':attribute必须是字符串',
|
||||
':attribute must start with :rule' => ':attribute必须以 :rule 开头',
|
||||
':attribute must end with :rule' => ':attribute必须以 :rule 结尾',
|
||||
':attribute must contain :rule' => ':attribute必须包含 :rule',
|
||||
':attribute must be bool' => ':attribute必须是布尔值',
|
||||
':attribute not a valid email address' => ':attribute格式不符',
|
||||
':attribute not a valid mobile' => ':attribute格式不符',
|
||||
':attribute must be a array' => ':attribute必须是数组',
|
||||
':attribute must be yes,on or 1' => ':attribute必须是yes、on或者1',
|
||||
':attribute not a valid datetime' => ':attribute不是一个有效的日期或时间格式',
|
||||
':attribute not a valid file' => ':attribute不是有效的上传文件',
|
||||
':attribute not a valid image' => ':attribute不是有效的图像文件',
|
||||
':attribute must be alpha' => ':attribute只能是字母',
|
||||
':attribute must be alpha-numeric' => ':attribute只能是字母和数字',
|
||||
':attribute must be alpha-numeric, dash, underscore' => ':attribute只能是字母、数字和下划线_及破折号-',
|
||||
':attribute not a valid domain or ip' => ':attribute不是有效的域名或者IP',
|
||||
':attribute must be chinese' => ':attribute只能是汉字',
|
||||
':attribute must be chinese or alpha' => ':attribute只能是汉字、字母',
|
||||
':attribute must be chinese,alpha-numeric' => ':attribute只能是汉字、字母和数字',
|
||||
':attribute must be chinese,alpha-numeric,underscore, dash' => ':attribute只能是汉字、字母、数字和下划线_及破折号-',
|
||||
':attribute not a valid url' => ':attribute不是有效的URL地址',
|
||||
':attribute not a valid ip' => ':attribute不是有效的IP地址',
|
||||
':attribute must be dateFormat of :rule' => ':attribute必须使用日期格式 :rule',
|
||||
':attribute must be in :rule' => ':attribute必须在 :rule 范围内',
|
||||
':attribute be notin :rule' => ':attribute不能在 :rule 范围内',
|
||||
':attribute must between :1 - :2' => ':attribute只能在 :1 - :2 之间',
|
||||
':attribute not between :1 - :2' => ':attribute不能在 :1 - :2 之间',
|
||||
'size of :attribute must be :rule' => ':attribute长度不符合要求 :rule',
|
||||
'max size of :attribute must be :rule' => ':attribute长度不能超过 :rule',
|
||||
'min size of :attribute must be :rule' => ':attribute长度不能小于 :rule',
|
||||
':attribute cannot be less than :rule' => ':attribute日期不能小于 :rule',
|
||||
':attribute cannot exceed :rule' => ':attribute日期不能超过 :rule',
|
||||
':attribute not within :rule' => '不在有效期内 :rule',
|
||||
'access IP is not allowed' => '不允许的IP访问',
|
||||
'access IP denied' => '禁止的IP访问',
|
||||
':attribute out of accord with :2' => ':attribute和确认字段:2不一致',
|
||||
':attribute cannot be same with :2' => ':attribute和比较字段:2不能相同',
|
||||
':attribute must greater than or equal :rule' => ':attribute必须大于等于 :rule',
|
||||
':attribute must greater than :rule' => ':attribute必须大于 :rule',
|
||||
':attribute must less than or equal :rule' => ':attribute必须小于等于 :rule',
|
||||
':attribute must less than :rule' => ':attribute必须小于 :rule',
|
||||
':attribute must equal :rule' => ':attribute必须等于 :rule',
|
||||
':attribute has exists' => ':attribute已存在',
|
||||
':attribute not conform to the rules' => ':attribute不符合指定规则',
|
||||
'invalid Request method' => '无效的请求类型',
|
||||
'invalid token' => '令牌数据无效',
|
||||
'not conform to the rules' => '规则错误',
|
||||
|
||||
'record has update' => '记录已经被更新了',
|
||||
];
|
||||
620
vendor/topthink/framework/src/think/App.php
vendored
Normal file
620
vendor/topthink/framework/src/think/App.php
vendored
Normal file
@@ -0,0 +1,620 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2023 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace think;
|
||||
|
||||
use Composer\InstalledVersions;
|
||||
use think\event\AppInit;
|
||||
use think\helper\Str;
|
||||
use think\initializer\BootService;
|
||||
use think\initializer\Error;
|
||||
use think\initializer\RegisterService;
|
||||
|
||||
/**
|
||||
* App 基础类
|
||||
* @property Route $route
|
||||
* @property Config $config
|
||||
* @property Cache $cache
|
||||
* @property Request $request
|
||||
* @property Http $http
|
||||
* @property Console $console
|
||||
* @property Env $env
|
||||
* @property Event $event
|
||||
* @property Middleware $middleware
|
||||
* @property Log $log
|
||||
* @property Lang $lang
|
||||
* @property Db $db
|
||||
* @property Cookie $cookie
|
||||
* @property Session $session
|
||||
* @property Validate $validate
|
||||
*/
|
||||
class App extends Container
|
||||
{
|
||||
const VERSION = '8.0.0';
|
||||
|
||||
/**
|
||||
* 应用调试模式
|
||||
* @var bool
|
||||
*/
|
||||
protected $appDebug = false;
|
||||
|
||||
/**
|
||||
* 环境变量标识
|
||||
* @var string
|
||||
*/
|
||||
protected $envName = '';
|
||||
|
||||
/**
|
||||
* 应用开始时间
|
||||
* @var float
|
||||
*/
|
||||
protected $beginTime;
|
||||
|
||||
/**
|
||||
* 应用内存初始占用
|
||||
* @var integer
|
||||
*/
|
||||
protected $beginMem;
|
||||
|
||||
/**
|
||||
* 当前应用类库命名空间
|
||||
* @var string
|
||||
*/
|
||||
protected $namespace = 'app';
|
||||
|
||||
/**
|
||||
* 应用根目录
|
||||
* @var string
|
||||
*/
|
||||
protected $rootPath = '';
|
||||
|
||||
/**
|
||||
* 框架目录
|
||||
* @var string
|
||||
*/
|
||||
protected $thinkPath = '';
|
||||
|
||||
/**
|
||||
* 应用目录
|
||||
* @var string
|
||||
*/
|
||||
protected $appPath = '';
|
||||
|
||||
/**
|
||||
* Runtime目录
|
||||
* @var string
|
||||
*/
|
||||
protected $runtimePath = '';
|
||||
|
||||
/**
|
||||
* 路由定义目录
|
||||
* @var string
|
||||
*/
|
||||
protected $routePath = '';
|
||||
|
||||
/**
|
||||
* 配置后缀
|
||||
* @var string
|
||||
*/
|
||||
protected $configExt = '.php';
|
||||
|
||||
/**
|
||||
* 应用初始化器
|
||||
* @var array
|
||||
*/
|
||||
protected $initializers = [
|
||||
Error::class,
|
||||
RegisterService::class,
|
||||
BootService::class,
|
||||
];
|
||||
|
||||
/**
|
||||
* 注册的系统服务
|
||||
* @var array
|
||||
*/
|
||||
protected $services = [];
|
||||
|
||||
/**
|
||||
* 初始化
|
||||
* @var bool
|
||||
*/
|
||||
protected $initialized = false;
|
||||
|
||||
/**
|
||||
* 容器绑定标识
|
||||
* @var array
|
||||
*/
|
||||
protected $bind = [
|
||||
'app' => App::class,
|
||||
'cache' => Cache::class,
|
||||
'config' => Config::class,
|
||||
'console' => Console::class,
|
||||
'cookie' => Cookie::class,
|
||||
'db' => Db::class,
|
||||
'env' => Env::class,
|
||||
'event' => Event::class,
|
||||
'http' => Http::class,
|
||||
'lang' => Lang::class,
|
||||
'log' => Log::class,
|
||||
'middleware' => Middleware::class,
|
||||
'request' => Request::class,
|
||||
'response' => Response::class,
|
||||
'route' => Route::class,
|
||||
'session' => Session::class,
|
||||
'validate' => Validate::class,
|
||||
'view' => View::class,
|
||||
'think\DbManager' => Db::class,
|
||||
'think\LogManager' => Log::class,
|
||||
'think\CacheManager' => Cache::class,
|
||||
|
||||
// 接口依赖注入
|
||||
'Psr\Log\LoggerInterface' => Log::class,
|
||||
];
|
||||
|
||||
/**
|
||||
* 架构方法
|
||||
* @access public
|
||||
* @param string $rootPath 应用根目录
|
||||
*/
|
||||
public function __construct(string $rootPath = '')
|
||||
{
|
||||
$this->thinkPath = realpath(dirname(__DIR__)) . DIRECTORY_SEPARATOR;
|
||||
$this->rootPath = $rootPath ? rtrim($rootPath, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR : $this->getDefaultRootPath();
|
||||
$this->appPath = $this->rootPath . 'app' . DIRECTORY_SEPARATOR;
|
||||
$this->runtimePath = $this->rootPath . 'runtime' . DIRECTORY_SEPARATOR;
|
||||
|
||||
if (is_file($this->appPath . 'provider.php')) {
|
||||
$this->bind(include $this->appPath . 'provider.php');
|
||||
}
|
||||
|
||||
static::setInstance($this);
|
||||
|
||||
$this->instance('app', $this);
|
||||
$this->instance('think\Container', $this);
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册服务
|
||||
* @access public
|
||||
* @param Service|string $service 服务
|
||||
* @param bool $force 强制重新注册
|
||||
* @return Service|null
|
||||
*/
|
||||
public function register(Service|string $service, bool $force = false)
|
||||
{
|
||||
$registered = $this->getService($service);
|
||||
|
||||
if ($registered && !$force) {
|
||||
return $registered;
|
||||
}
|
||||
|
||||
if (is_string($service)) {
|
||||
$service = new $service($this);
|
||||
}
|
||||
|
||||
if (method_exists($service, 'register')) {
|
||||
$service->register();
|
||||
}
|
||||
|
||||
if (property_exists($service, 'bind')) {
|
||||
$this->bind($service->bind);
|
||||
}
|
||||
|
||||
$this->services[] = $service;
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行服务
|
||||
* @access public
|
||||
* @param Service $service 服务
|
||||
* @return mixed
|
||||
*/
|
||||
public function bootService(Service $service)
|
||||
{
|
||||
if (method_exists($service, 'boot')) {
|
||||
return $this->invoke([$service, 'boot']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取服务
|
||||
* @param string|Service $service
|
||||
* @return Service|null
|
||||
*/
|
||||
public function getService(Service|string $service): ?Service
|
||||
{
|
||||
$name = is_string($service) ? $service : $service::class;
|
||||
return array_values(array_filter($this->services, function ($value) use ($name) {
|
||||
return $value instanceof $name;
|
||||
}, ARRAY_FILTER_USE_BOTH))[0] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 开启应用调试模式
|
||||
* @access public
|
||||
* @param bool $debug 开启应用调试模式
|
||||
* @return $this
|
||||
*/
|
||||
public function debug(bool $debug = true)
|
||||
{
|
||||
$this->appDebug = $debug;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否为调试模式
|
||||
* @access public
|
||||
* @return bool
|
||||
*/
|
||||
public function isDebug(): bool
|
||||
{
|
||||
return $this->appDebug;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置应用命名空间
|
||||
* @access public
|
||||
* @param string $namespace 应用命名空间
|
||||
* @return $this
|
||||
*/
|
||||
public function setNamespace(string $namespace)
|
||||
{
|
||||
$this->namespace = $namespace;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取应用类库命名空间
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function getNamespace(): string
|
||||
{
|
||||
return $this->namespace;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置环境变量标识
|
||||
* @access public
|
||||
* @param string $name 环境标识
|
||||
* @return $this
|
||||
*/
|
||||
public function setEnvName(string $name)
|
||||
{
|
||||
$this->envName = $name;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取框架版本
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function version(): string
|
||||
{
|
||||
return ltrim(InstalledVersions::getPrettyVersion('topthink/framework'), 'v');
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取应用根目录
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function getRootPath(): string
|
||||
{
|
||||
return $this->rootPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取应用基础目录
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function getBasePath(): string
|
||||
{
|
||||
return $this->rootPath . 'app' . DIRECTORY_SEPARATOR;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前应用目录
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function getAppPath(): string
|
||||
{
|
||||
return $this->appPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置应用目录
|
||||
* @param string $path 应用目录
|
||||
*/
|
||||
public function setAppPath(string $path)
|
||||
{
|
||||
$this->appPath = $path;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取应用运行时目录
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function getRuntimePath(): string
|
||||
{
|
||||
return $this->runtimePath;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置runtime目录
|
||||
* @param string $path 定义目录
|
||||
*/
|
||||
public function setRuntimePath(string $path): void
|
||||
{
|
||||
$this->runtimePath = $path;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取核心框架目录
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function getThinkPath(): string
|
||||
{
|
||||
return $this->thinkPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取应用配置目录
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function getConfigPath(): string
|
||||
{
|
||||
return $this->rootPath . 'config' . DIRECTORY_SEPARATOR;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取配置后缀
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function getConfigExt(): string
|
||||
{
|
||||
return $this->configExt;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取应用开启时间
|
||||
* @access public
|
||||
* @return float
|
||||
*/
|
||||
public function getBeginTime(): float
|
||||
{
|
||||
return $this->beginTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取应用初始内存占用
|
||||
* @access public
|
||||
* @return integer
|
||||
*/
|
||||
public function getBeginMem(): int
|
||||
{
|
||||
return $this->beginMem;
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载环境变量定义
|
||||
* @access public
|
||||
* @param string $envName 环境标识
|
||||
* @return void
|
||||
*/
|
||||
public function loadEnv(string $envName = ''): void
|
||||
{
|
||||
// 加载环境变量
|
||||
$envFile = $envName ? $this->rootPath . '.env.' . $envName : $this->rootPath . '.env';
|
||||
|
||||
if (is_file($envFile)) {
|
||||
$this->env->load($envFile);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化应用
|
||||
* @access public
|
||||
* @return $this
|
||||
*/
|
||||
public function initialize()
|
||||
{
|
||||
$this->initialized = true;
|
||||
|
||||
$this->beginTime = microtime(true);
|
||||
$this->beginMem = memory_get_usage();
|
||||
|
||||
$this->loadEnv($this->envName);
|
||||
|
||||
$this->configExt = $this->env->get('config_ext', '.php');
|
||||
|
||||
$this->debugModeInit();
|
||||
|
||||
// 加载全局初始化文件
|
||||
$this->load();
|
||||
|
||||
// 加载应用默认语言包
|
||||
$this->loadLangPack();
|
||||
|
||||
// 监听AppInit
|
||||
$this->event->trigger(AppInit::class);
|
||||
|
||||
date_default_timezone_set($this->config->get('app.default_timezone', 'Asia/Shanghai'));
|
||||
|
||||
// 初始化
|
||||
foreach ($this->initializers as $initializer) {
|
||||
$this->make($initializer)->init($this);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否初始化过
|
||||
* @return bool
|
||||
*/
|
||||
public function initialized()
|
||||
{
|
||||
return $this->initialized;
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载语言包
|
||||
* @return void
|
||||
*/
|
||||
public function loadLangPack(): void
|
||||
{
|
||||
// 加载默认语言包
|
||||
$langSet = $this->lang->defaultLangSet();
|
||||
$this->lang->switchLangSet($langSet);
|
||||
}
|
||||
|
||||
/**
|
||||
* 引导应用
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function boot(): void
|
||||
{
|
||||
array_walk($this->services, function ($service) {
|
||||
$this->bootService($service);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载应用文件和配置
|
||||
* @access protected
|
||||
* @return void
|
||||
*/
|
||||
protected function load(): void
|
||||
{
|
||||
$appPath = $this->getAppPath();
|
||||
|
||||
if (is_file($appPath . 'common.php')) {
|
||||
include_once $appPath . 'common.php';
|
||||
}
|
||||
|
||||
include_once $this->thinkPath . 'helper.php';
|
||||
|
||||
$configPath = $this->getConfigPath();
|
||||
|
||||
$files = [];
|
||||
|
||||
if (is_dir($configPath)) {
|
||||
$files = glob($configPath . '*' . $this->configExt);
|
||||
}
|
||||
|
||||
foreach ($files as $file) {
|
||||
$this->config->load($file, pathinfo($file, PATHINFO_FILENAME));
|
||||
}
|
||||
|
||||
if (is_file($appPath . 'event.php')) {
|
||||
$this->loadEvent(include $appPath . 'event.php');
|
||||
}
|
||||
|
||||
if (is_file($appPath . 'service.php')) {
|
||||
$services = include $appPath . 'service.php';
|
||||
foreach ($services as $service) {
|
||||
$this->register($service);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 调试模式设置
|
||||
* @access protected
|
||||
* @return void
|
||||
*/
|
||||
protected function debugModeInit(): void
|
||||
{
|
||||
// 应用调试模式
|
||||
if (!$this->appDebug) {
|
||||
$this->appDebug = $this->env->get('app_debug') ? true : false;
|
||||
ini_set('display_errors', 'Off');
|
||||
}
|
||||
|
||||
if (!$this->runningInConsole()) {
|
||||
//重新申请一块比较大的buffer
|
||||
if (ob_get_level() > 0) {
|
||||
$output = ob_get_clean();
|
||||
}
|
||||
ob_start();
|
||||
if (!empty($output)) {
|
||||
echo $output;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册应用事件
|
||||
* @access protected
|
||||
* @param array $event 事件数据
|
||||
* @return void
|
||||
*/
|
||||
public function loadEvent(array $event): void
|
||||
{
|
||||
if (isset($event['bind'])) {
|
||||
$this->event->bind($event['bind']);
|
||||
}
|
||||
|
||||
if (isset($event['listen'])) {
|
||||
$this->event->listenEvents($event['listen']);
|
||||
}
|
||||
|
||||
if (isset($event['subscribe'])) {
|
||||
$this->event->subscribe($event['subscribe']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析应用类的类名
|
||||
* @access public
|
||||
* @param string $layer 层名 controller model ...
|
||||
* @param string $name 类名
|
||||
* @return string
|
||||
*/
|
||||
public function parseClass(string $layer, string $name): string
|
||||
{
|
||||
$name = str_replace(['/', '.'], '\\', $name);
|
||||
$array = explode('\\', $name);
|
||||
$class = Str::studly(array_pop($array));
|
||||
$path = $array ? implode('\\', $array) . '\\' : '';
|
||||
|
||||
return $this->namespace . '\\' . $layer . '\\' . $path . $class;
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否运行在命令行下
|
||||
* @return bool
|
||||
*/
|
||||
public function runningInConsole(): bool
|
||||
{
|
||||
return php_sapi_name() === 'cli' || php_sapi_name() === 'phpdbg';
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取应用根目录
|
||||
* @access protected
|
||||
* @return string
|
||||
*/
|
||||
protected function getDefaultRootPath(): string
|
||||
{
|
||||
return dirname($this->thinkPath, 4) . DIRECTORY_SEPARATOR;
|
||||
}
|
||||
}
|
||||
200
vendor/topthink/framework/src/think/Cache.php
vendored
Normal file
200
vendor/topthink/framework/src/think/Cache.php
vendored
Normal file
@@ -0,0 +1,200 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2023 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
declare(strict_types = 1);
|
||||
|
||||
namespace think;
|
||||
|
||||
use DateInterval;
|
||||
use DateTimeInterface;
|
||||
use Psr\SimpleCache\CacheInterface;
|
||||
use think\cache\Driver;
|
||||
use think\cache\TagSet;
|
||||
use think\exception\InvalidArgumentException;
|
||||
use think\helper\Arr;
|
||||
|
||||
/**
|
||||
* 缓存管理类
|
||||
* @mixin Driver
|
||||
* @mixin \think\cache\driver\File
|
||||
*/
|
||||
class Cache extends Manager implements CacheInterface
|
||||
{
|
||||
|
||||
protected $namespace = '\\think\\cache\\driver\\';
|
||||
|
||||
/**
|
||||
* 默认驱动
|
||||
* @return string|null
|
||||
*/
|
||||
public function getDefaultDriver(): ?string
|
||||
{
|
||||
return $this->getConfig('default');
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取缓存配置
|
||||
* @access public
|
||||
* @param null|string $name 名称
|
||||
* @param mixed $default 默认值
|
||||
* @return mixed
|
||||
*/
|
||||
public function getConfig(string $name = null, $default = null)
|
||||
{
|
||||
if (!is_null($name)) {
|
||||
return $this->app->config->get('cache.' . $name, $default);
|
||||
}
|
||||
|
||||
return $this->app->config->get('cache');
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取驱动配置
|
||||
* @param string $store
|
||||
* @param string $name
|
||||
* @param mixed $default
|
||||
* @return array
|
||||
*/
|
||||
public function getStoreConfig(string $store, string $name = null, $default = null)
|
||||
{
|
||||
if ($config = $this->getConfig("stores.{$store}")) {
|
||||
return Arr::get($config, $name, $default);
|
||||
}
|
||||
|
||||
throw new \InvalidArgumentException("Store [$store] not found.");
|
||||
}
|
||||
|
||||
protected function resolveType(string $name)
|
||||
{
|
||||
return $this->getStoreConfig($name, 'type', 'file');
|
||||
}
|
||||
|
||||
protected function resolveConfig(string $name)
|
||||
{
|
||||
return $this->getStoreConfig($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* 连接或者切换缓存
|
||||
* @access public
|
||||
* @param string|null $name 连接配置名
|
||||
* @return Driver
|
||||
*/
|
||||
public function store(string $name = null)
|
||||
{
|
||||
return $this->driver($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* 清空缓冲池
|
||||
* @access public
|
||||
* @return bool
|
||||
*/
|
||||
public function clear(): bool
|
||||
{
|
||||
return $this->store()->clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* 读取缓存
|
||||
* @access public
|
||||
* @param string $key 缓存变量名
|
||||
* @param mixed $default 默认值
|
||||
* @return mixed
|
||||
*/
|
||||
public function get($key, mixed $default = null): mixed
|
||||
{
|
||||
return $this->store()->get($key, $default);
|
||||
}
|
||||
|
||||
/**
|
||||
* 写入缓存
|
||||
* @access public
|
||||
* @param string $key 缓存变量名
|
||||
* @param mixed $value 存储数据
|
||||
* @param int|DateTimeInterface|DateInterval $ttl 有效时间 0为永久
|
||||
* @return bool
|
||||
*/
|
||||
public function set($key, $value, $ttl = null): bool
|
||||
{
|
||||
return $this->store()->set($key, $value, $ttl);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除缓存
|
||||
* @access public
|
||||
* @param string $key 缓存变量名
|
||||
* @return bool
|
||||
*/
|
||||
public function delete($key): bool
|
||||
{
|
||||
return $this->store()->delete($key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 读取缓存
|
||||
* @access public
|
||||
* @param iterable $keys 缓存变量名
|
||||
* @param mixed $default 默认值
|
||||
* @return iterable
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
public function getMultiple($keys, $default = null): iterable
|
||||
{
|
||||
return $this->store()->getMultiple($keys, $default);
|
||||
}
|
||||
|
||||
/**
|
||||
* 写入缓存
|
||||
* @access public
|
||||
* @param iterable $values 缓存数据
|
||||
* @param null|int|\DateInterval $ttl 有效时间 0为永久
|
||||
* @return bool
|
||||
*/
|
||||
public function setMultiple($values, $ttl = null): bool
|
||||
{
|
||||
return $this->store()->setMultiple($values, $ttl);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除缓存
|
||||
* @access public
|
||||
* @param iterable $keys 缓存变量名
|
||||
* @return bool
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
public function deleteMultiple($keys): bool
|
||||
{
|
||||
return $this->store()->deleteMultiple($keys);
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断缓存是否存在
|
||||
* @access public
|
||||
* @param string $key 缓存变量名
|
||||
* @return bool
|
||||
*/
|
||||
public function has($key): bool
|
||||
{
|
||||
return $this->store()->has($key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 缓存标签
|
||||
* @access public
|
||||
* @param string|array $name 标签名
|
||||
* @return TagSet
|
||||
*/
|
||||
public function tag($name)
|
||||
{
|
||||
return $this->store()->tag($name);
|
||||
}
|
||||
|
||||
}
|
||||
173
vendor/topthink/framework/src/think/Config.php
vendored
Normal file
173
vendor/topthink/framework/src/think/Config.php
vendored
Normal file
@@ -0,0 +1,173 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2023 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace think;
|
||||
|
||||
/**
|
||||
* 配置管理类
|
||||
* @package think
|
||||
*/
|
||||
class Config
|
||||
{
|
||||
/**
|
||||
* 配置参数
|
||||
* @var array
|
||||
*/
|
||||
protected $config = [];
|
||||
|
||||
/**
|
||||
* 构造方法
|
||||
* @access public
|
||||
*/
|
||||
public function __construct(protected string $path = '', protected string $ext = '.php')
|
||||
{
|
||||
}
|
||||
|
||||
public static function __make(App $app)
|
||||
{
|
||||
$path = $app->getConfigPath();
|
||||
$ext = $app->getConfigExt();
|
||||
|
||||
return new static($path, $ext);
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载配置文件(多种格式)
|
||||
* @access public
|
||||
* @param string $file 配置文件名
|
||||
* @param string $name 一级配置名
|
||||
* @return array
|
||||
*/
|
||||
public function load(string $file, string $name = ''): array
|
||||
{
|
||||
if (is_file($file)) {
|
||||
$filename = $file;
|
||||
} elseif (is_file($this->path . $file . $this->ext)) {
|
||||
$filename = $this->path . $file . $this->ext;
|
||||
}
|
||||
|
||||
if (isset($filename)) {
|
||||
return $this->parse($filename, $name);
|
||||
}
|
||||
|
||||
return $this->config;
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析配置文件
|
||||
* @access public
|
||||
* @param string $file 配置文件名
|
||||
* @param string $name 一级配置名
|
||||
* @return array
|
||||
*/
|
||||
protected function parse(string $file, string $name): array
|
||||
{
|
||||
$type = pathinfo($file, PATHINFO_EXTENSION);
|
||||
$config = [];
|
||||
$config = match ($type) {
|
||||
'php' => include $file,
|
||||
'yml','yaml' => function_exists('yaml_parse_file') ? yaml_parse_file($file) : [],
|
||||
'ini' => parse_ini_file($file, true, INI_SCANNER_TYPED) ?: [],
|
||||
'json' => json_decode(file_get_contents($file), true),
|
||||
default => [],
|
||||
};
|
||||
|
||||
return is_array($config) ? $this->set($config, strtolower($name)) : [];
|
||||
}
|
||||
|
||||
/**
|
||||
* 检测配置是否存在
|
||||
* @access public
|
||||
* @param string $name 配置参数名(支持多级配置 .号分割)
|
||||
* @return bool
|
||||
*/
|
||||
public function has(string $name): bool
|
||||
{
|
||||
if (!str_contains($name, '.') && !isset($this->config[strtolower($name)])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return !is_null($this->get($name));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取一级配置
|
||||
* @access protected
|
||||
* @param string $name 一级配置名
|
||||
* @return array
|
||||
*/
|
||||
protected function pull(string $name): array
|
||||
{
|
||||
$name = strtolower($name);
|
||||
|
||||
return $this->config[$name] ?? [];
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取配置参数 为空则获取所有配置
|
||||
* @access public
|
||||
* @param string $name 配置参数名(支持多级配置 .号分割)
|
||||
* @param mixed $default 默认值
|
||||
* @return mixed
|
||||
*/
|
||||
public function get(string $name = null, $default = null)
|
||||
{
|
||||
// 无参数时获取所有
|
||||
if (empty($name)) {
|
||||
return $this->config;
|
||||
}
|
||||
|
||||
if (!str_contains($name, '.')) {
|
||||
return $this->pull($name);
|
||||
}
|
||||
|
||||
$name = explode('.', $name);
|
||||
$name[0] = strtolower($name[0]);
|
||||
$config = $this->config;
|
||||
|
||||
// 按.拆分成多维数组进行判断
|
||||
foreach ($name as $val) {
|
||||
if (isset($config[$val])) {
|
||||
$config = $config[$val];
|
||||
} else {
|
||||
return $default;
|
||||
}
|
||||
}
|
||||
|
||||
return $config;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置配置参数 name为数组则为批量设置
|
||||
* @access public
|
||||
* @param array $config 配置参数
|
||||
* @param string $name 配置名
|
||||
* @return array
|
||||
*/
|
||||
public function set(array $config, string $name = null): array
|
||||
{
|
||||
if (empty($name)) {
|
||||
$this->config = array_merge($this->config, array_change_key_case($config));
|
||||
return $this->config;
|
||||
}
|
||||
|
||||
if (isset($this->config[$name])) {
|
||||
$result = array_merge($this->config[$name], $config);
|
||||
} else {
|
||||
$result = $config;
|
||||
}
|
||||
|
||||
$this->config[$name] = $result;
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
787
vendor/topthink/framework/src/think/Console.php
vendored
Normal file
787
vendor/topthink/framework/src/think/Console.php
vendored
Normal file
@@ -0,0 +1,787 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | TopThink [ WE CAN DO IT JUST THINK IT ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2015 http://www.topthink.com All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: zhangyajun <448901948@qq.com>
|
||||
// +----------------------------------------------------------------------
|
||||
declare (strict_types = 1);
|
||||
|
||||
namespace think;
|
||||
|
||||
use Closure;
|
||||
use InvalidArgumentException;
|
||||
use LogicException;
|
||||
use think\console\Command;
|
||||
use think\console\command\Clear;
|
||||
use think\console\command\Help;
|
||||
use think\console\command\Help as HelpCommand;
|
||||
use think\console\command\Lists;
|
||||
use think\console\command\make\Command as MakeCommand;
|
||||
use think\console\command\make\Controller;
|
||||
use think\console\command\make\Event;
|
||||
use think\console\command\make\Listener;
|
||||
use think\console\command\make\Middleware;
|
||||
use think\console\command\make\Model;
|
||||
use think\console\command\make\Service;
|
||||
use think\console\command\make\Subscribe;
|
||||
use think\console\command\make\Validate;
|
||||
use think\console\command\optimize\Route;
|
||||
use think\console\command\optimize\Schema;
|
||||
use think\console\command\RouteList;
|
||||
use think\console\command\RunServer;
|
||||
use think\console\command\ServiceDiscover;
|
||||
use think\console\command\VendorPublish;
|
||||
use think\console\command\Version;
|
||||
use think\console\Input;
|
||||
use think\console\input\Argument as InputArgument;
|
||||
use think\console\input\Definition as InputDefinition;
|
||||
use think\console\input\Option as InputOption;
|
||||
use think\console\Output;
|
||||
use think\console\output\driver\Buffer;
|
||||
|
||||
/**
|
||||
* 控制台应用管理类
|
||||
*/
|
||||
class Console
|
||||
{
|
||||
/** @var Command[] */
|
||||
protected $commands = [];
|
||||
|
||||
protected $wantHelps = false;
|
||||
|
||||
protected $catchExceptions = true;
|
||||
protected $autoExit = true;
|
||||
protected $definition;
|
||||
protected $defaultCommand = 'list';
|
||||
|
||||
protected $defaultCommands = [
|
||||
'help' => Help::class,
|
||||
'list' => Lists::class,
|
||||
'clear' => Clear::class,
|
||||
'make:command' => MakeCommand::class,
|
||||
'make:controller' => Controller::class,
|
||||
'make:model' => Model::class,
|
||||
'make:middleware' => Middleware::class,
|
||||
'make:validate' => Validate::class,
|
||||
'make:event' => Event::class,
|
||||
'make:listener' => Listener::class,
|
||||
'make:service' => Service::class,
|
||||
'make:subscribe' => Subscribe::class,
|
||||
'optimize:route' => Route::class,
|
||||
'optimize:schema' => Schema::class,
|
||||
'run' => RunServer::class,
|
||||
'version' => Version::class,
|
||||
'route:list' => RouteList::class,
|
||||
'service:discover' => ServiceDiscover::class,
|
||||
'vendor:publish' => VendorPublish::class,
|
||||
];
|
||||
|
||||
/**
|
||||
* 启动器
|
||||
* @var array
|
||||
*/
|
||||
protected static $startCallbacks = [];
|
||||
|
||||
public function __construct(protected App $app)
|
||||
{
|
||||
$this->initialize();
|
||||
|
||||
$this->definition = $this->getDefaultInputDefinition();
|
||||
|
||||
//加载指令
|
||||
$this->loadCommands();
|
||||
|
||||
// 设置执行用户
|
||||
$user = $this->app->config->get('console.user');
|
||||
if (!empty($user)) {
|
||||
$this->setUser($user);
|
||||
}
|
||||
|
||||
$this->start();
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化
|
||||
*/
|
||||
protected function initialize():void
|
||||
{
|
||||
if (!$this->app->initialized()) {
|
||||
$this->app->initialize();
|
||||
}
|
||||
$this->makeRequest();
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造request
|
||||
*/
|
||||
protected function makeRequest():void
|
||||
{
|
||||
$url = $this->app->config->get('app.url', 'http://localhost');
|
||||
|
||||
$components = parse_url($url);
|
||||
|
||||
$server = $_SERVER;
|
||||
|
||||
if (isset($components['path'])) {
|
||||
$server = array_merge($server, [
|
||||
'SCRIPT_FILENAME' => $components['path'],
|
||||
'SCRIPT_NAME' => $components['path'],
|
||||
'REQUEST_URI' => $components['path'],
|
||||
]);
|
||||
}
|
||||
|
||||
if (isset($components['host'])) {
|
||||
$server['SERVER_NAME'] = $components['host'];
|
||||
$server['HTTP_HOST'] = $components['host'];
|
||||
}
|
||||
|
||||
if (isset($components['scheme'])) {
|
||||
if ('https' === $components['scheme']) {
|
||||
$server['HTTPS'] = 'on';
|
||||
$server['SERVER_PORT'] = 443;
|
||||
} else {
|
||||
unset($server['HTTPS']);
|
||||
$server['SERVER_PORT'] = 80;
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($components['port'])) {
|
||||
$server['SERVER_PORT'] = $components['port'];
|
||||
$server['HTTP_HOST'] .= ':' . $components['port'];
|
||||
}
|
||||
|
||||
/** @var Request $request */
|
||||
$request = $this->app->make('request');
|
||||
|
||||
$request->withServer($server);
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加初始化器
|
||||
* @param Closure $callback
|
||||
*/
|
||||
public static function starting(Closure $callback): void
|
||||
{
|
||||
static::$startCallbacks[] = $callback;
|
||||
}
|
||||
|
||||
/**
|
||||
* 清空启动器
|
||||
*/
|
||||
public static function flushStartCallbacks(): void
|
||||
{
|
||||
static::$startCallbacks = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置执行用户
|
||||
* @param $user
|
||||
*/
|
||||
public static function setUser(string $user): void
|
||||
{
|
||||
if (extension_loaded('posix')) {
|
||||
$user = posix_getpwnam($user);
|
||||
|
||||
if (!empty($user)) {
|
||||
posix_setgid($user['gid']);
|
||||
posix_setuid($user['uid']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 启动
|
||||
*/
|
||||
protected function start(): void
|
||||
{
|
||||
foreach (static::$startCallbacks as $callback) {
|
||||
$callback($this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载指令
|
||||
* @access protected
|
||||
*/
|
||||
protected function loadCommands(): void
|
||||
{
|
||||
$commands = $this->app->config->get('console.commands', []);
|
||||
$commands = array_merge($this->defaultCommands, $commands);
|
||||
|
||||
$this->addCommands($commands);
|
||||
}
|
||||
|
||||
/**
|
||||
* @access public
|
||||
* @param string $command
|
||||
* @param array $parameters
|
||||
* @param string $driver
|
||||
* @return Output|Buffer
|
||||
*/
|
||||
public function call(string $command, array $parameters = [], string $driver = 'buffer')
|
||||
{
|
||||
array_unshift($parameters, $command);
|
||||
|
||||
$input = new Input($parameters);
|
||||
$output = new Output($driver);
|
||||
|
||||
$this->setCatchExceptions(false);
|
||||
$this->find($command)->run($input, $output);
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行当前的指令
|
||||
* @access public
|
||||
* @return int
|
||||
* @throws \Exception
|
||||
* @api
|
||||
*/
|
||||
public function run()
|
||||
{
|
||||
$input = new Input();
|
||||
$output = new Output();
|
||||
|
||||
$this->configureIO($input, $output);
|
||||
|
||||
try {
|
||||
$exitCode = $this->doRun($input, $output);
|
||||
} catch (\Exception $e) {
|
||||
if (!$this->catchExceptions) {
|
||||
throw $e;
|
||||
}
|
||||
|
||||
$output->renderException($e);
|
||||
|
||||
$exitCode = $e->getCode();
|
||||
if (is_numeric($exitCode)) {
|
||||
$exitCode = (int) $exitCode;
|
||||
if (0 === $exitCode) {
|
||||
$exitCode = 1;
|
||||
}
|
||||
} else {
|
||||
$exitCode = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->autoExit) {
|
||||
if ($exitCode > 255) {
|
||||
$exitCode = 255;
|
||||
}
|
||||
|
||||
exit($exitCode);
|
||||
}
|
||||
|
||||
return $exitCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行指令
|
||||
* @access public
|
||||
* @param Input $input
|
||||
* @param Output $output
|
||||
* @return int
|
||||
*/
|
||||
public function doRun(Input $input, Output $output)
|
||||
{
|
||||
if (true === $input->hasParameterOption(['--version', '-V'])) {
|
||||
$output->writeln($this->getLongVersion());
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
$name = $this->getCommandName($input);
|
||||
|
||||
if (true === $input->hasParameterOption(['--help', '-h'])) {
|
||||
if (!$name) {
|
||||
$name = 'help';
|
||||
$input = new Input(['help']);
|
||||
} else {
|
||||
$this->wantHelps = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$name) {
|
||||
$name = $this->defaultCommand;
|
||||
$input = new Input([$this->defaultCommand]);
|
||||
}
|
||||
|
||||
$command = $this->find($name);
|
||||
|
||||
return $this->doRunCommand($command, $input, $output);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置输入参数定义
|
||||
* @access public
|
||||
* @param InputDefinition $definition
|
||||
*/
|
||||
public function setDefinition(InputDefinition $definition): void
|
||||
{
|
||||
$this->definition = $definition;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取输入参数定义
|
||||
* @access public
|
||||
* @return InputDefinition The InputDefinition instance
|
||||
*/
|
||||
public function getDefinition(): InputDefinition
|
||||
{
|
||||
return $this->definition;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the help message.
|
||||
* @access public
|
||||
* @return string A help message.
|
||||
*/
|
||||
public function getHelp(): string
|
||||
{
|
||||
return $this->getLongVersion();
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否捕获异常
|
||||
* @access public
|
||||
* @param bool $boolean
|
||||
* @api
|
||||
*/
|
||||
public function setCatchExceptions(bool $boolean): void
|
||||
{
|
||||
$this->catchExceptions = $boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否自动退出
|
||||
* @access public
|
||||
* @param bool $boolean
|
||||
* @api
|
||||
*/
|
||||
public function setAutoExit(bool $boolean): void
|
||||
{
|
||||
$this->autoExit = $boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取完整的版本号
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function getLongVersion(): string
|
||||
{
|
||||
if ($this->app->version()) {
|
||||
return sprintf('version <comment>%s</comment>', $this->app->version());
|
||||
}
|
||||
|
||||
return '<info>Console Tool</info>';
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加指令集
|
||||
* @access public
|
||||
* @param array $commands
|
||||
*/
|
||||
public function addCommands(array $commands): void
|
||||
{
|
||||
foreach ($commands as $key => $command) {
|
||||
if (is_subclass_of($command, Command::class)) {
|
||||
// 注册指令
|
||||
$this->addCommand($command, is_numeric($key) ? '' : $key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加一个指令
|
||||
* @access public
|
||||
* @param string|Command $command 指令对象或者指令类名
|
||||
* @param string $name 指令名 留空则自动获取
|
||||
* @return Command|void
|
||||
*/
|
||||
public function addCommand(string|Command $command, string $name = '')
|
||||
{
|
||||
if ($name) {
|
||||
$this->commands[$name] = $command;
|
||||
return;
|
||||
}
|
||||
|
||||
if (is_string($command)) {
|
||||
$command = $this->app->invokeClass($command);
|
||||
}
|
||||
|
||||
$command->setConsole($this);
|
||||
|
||||
if (!$command->isEnabled()) {
|
||||
$command->setConsole(null);
|
||||
return;
|
||||
}
|
||||
|
||||
$command->setApp($this->app);
|
||||
|
||||
if (null === $command->getDefinition()) {
|
||||
throw new LogicException(sprintf('Command class "%s" is not correctly initialized. You probably forgot to call the parent constructor.', $command::class));
|
||||
}
|
||||
|
||||
$this->commands[$command->getName()] = $command;
|
||||
|
||||
foreach ($command->getAliases() as $alias) {
|
||||
$this->commands[$alias] = $command;
|
||||
}
|
||||
|
||||
return $command;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指令
|
||||
* @access public
|
||||
* @param string $name 指令名称
|
||||
* @return Command
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
public function getCommand(string $name): Command
|
||||
{
|
||||
if (!isset($this->commands[$name])) {
|
||||
throw new InvalidArgumentException(sprintf('The command "%s" does not exist.', $name));
|
||||
}
|
||||
|
||||
$command = $this->commands[$name];
|
||||
|
||||
if (is_string($command)) {
|
||||
$command = $this->app->invokeClass($command);
|
||||
/** @var Command $command */
|
||||
$command->setConsole($this);
|
||||
$command->setApp($this->app);
|
||||
}
|
||||
|
||||
if ($this->wantHelps) {
|
||||
$this->wantHelps = false;
|
||||
|
||||
/** @var HelpCommand $helpCommand */
|
||||
$helpCommand = $this->getCommand('help');
|
||||
$helpCommand->setCommand($command);
|
||||
|
||||
return $helpCommand;
|
||||
}
|
||||
|
||||
return $command;
|
||||
}
|
||||
|
||||
/**
|
||||
* 某个指令是否存在
|
||||
* @access public
|
||||
* @param string $name 指令名称
|
||||
* @return bool
|
||||
*/
|
||||
public function hasCommand(string $name): bool
|
||||
{
|
||||
return isset($this->commands[$name]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有的命名空间
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function getNamespaces(): array
|
||||
{
|
||||
$namespaces = [];
|
||||
foreach ($this->commands as $key => $command) {
|
||||
if (is_string($command)) {
|
||||
$namespaces = array_merge($namespaces, $this->extractAllNamespaces($key));
|
||||
} else {
|
||||
$namespaces = array_merge($namespaces, $this->extractAllNamespaces($command->getName()));
|
||||
|
||||
foreach ($command->getAliases() as $alias) {
|
||||
$namespaces = array_merge($namespaces, $this->extractAllNamespaces($alias));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return array_values(array_unique(array_filter($namespaces)));
|
||||
}
|
||||
|
||||
/**
|
||||
* 查找注册命名空间中的名称或缩写。
|
||||
* @access public
|
||||
* @param string $namespace
|
||||
* @return string
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
public function findNamespace(string $namespace): string
|
||||
{
|
||||
$allNamespaces = $this->getNamespaces();
|
||||
$expr = preg_replace_callback('{([^:]+|)}', function ($matches) {
|
||||
return preg_quote($matches[1]) . '[^:]*';
|
||||
}, $namespace);
|
||||
$namespaces = preg_grep('{^' . $expr . '}', $allNamespaces);
|
||||
|
||||
if (empty($namespaces)) {
|
||||
$message = sprintf('There are no commands defined in the "%s" namespace.', $namespace);
|
||||
|
||||
if ($alternatives = $this->findAlternatives($namespace, $allNamespaces)) {
|
||||
if (1 == count($alternatives)) {
|
||||
$message .= "\n\nDid you mean this?\n ";
|
||||
} else {
|
||||
$message .= "\n\nDid you mean one of these?\n ";
|
||||
}
|
||||
|
||||
$message .= implode("\n ", $alternatives);
|
||||
}
|
||||
|
||||
throw new InvalidArgumentException($message);
|
||||
}
|
||||
|
||||
$exact = in_array($namespace, $namespaces, true);
|
||||
if (count($namespaces) > 1 && !$exact) {
|
||||
throw new InvalidArgumentException(sprintf('The namespace "%s" is ambiguous (%s).', $namespace, $this->getAbbreviationSuggestions(array_values($namespaces))));
|
||||
}
|
||||
|
||||
return $exact ? $namespace : reset($namespaces);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查找指令
|
||||
* @access public
|
||||
* @param string $name 名称或者别名
|
||||
* @return Command
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
public function find(string $name): Command
|
||||
{
|
||||
$allCommands = array_keys($this->commands);
|
||||
|
||||
$expr = preg_replace_callback('{([^:]+|)}', function ($matches) {
|
||||
return preg_quote($matches[1]) . '[^:]*';
|
||||
}, $name);
|
||||
|
||||
$commands = preg_grep('{^' . $expr . '}', $allCommands);
|
||||
|
||||
if (empty($commands) || count(preg_grep('{^' . $expr . '$}', $commands)) < 1) {
|
||||
if (false !== $pos = strrpos($name, ':')) {
|
||||
$this->findNamespace(substr($name, 0, $pos));
|
||||
}
|
||||
|
||||
$message = sprintf('Command "%s" is not defined.', $name);
|
||||
|
||||
if ($alternatives = $this->findAlternatives($name, $allCommands)) {
|
||||
if (1 == count($alternatives)) {
|
||||
$message .= "\n\nDid you mean this?\n ";
|
||||
} else {
|
||||
$message .= "\n\nDid you mean one of these?\n ";
|
||||
}
|
||||
$message .= implode("\n ", $alternatives);
|
||||
}
|
||||
|
||||
throw new InvalidArgumentException($message);
|
||||
}
|
||||
|
||||
$exact = in_array($name, $commands, true);
|
||||
if (count($commands) > 1 && !$exact) {
|
||||
$suggestions = $this->getAbbreviationSuggestions(array_values($commands));
|
||||
|
||||
throw new InvalidArgumentException(sprintf('Command "%s" is ambiguous (%s).', $name, $suggestions));
|
||||
}
|
||||
|
||||
return $this->getCommand($exact ? $name : reset($commands));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有的指令
|
||||
* @access public
|
||||
* @param string $namespace 命名空间
|
||||
* @return Command[]
|
||||
* @api
|
||||
*/
|
||||
public function all(string $namespace = null): array
|
||||
{
|
||||
if (null === $namespace) {
|
||||
return $this->commands;
|
||||
}
|
||||
|
||||
$commands = [];
|
||||
foreach ($this->commands as $name => $command) {
|
||||
if ($this->extractNamespace($name, substr_count($namespace, ':') + 1) === $namespace) {
|
||||
$commands[$name] = $command;
|
||||
}
|
||||
}
|
||||
|
||||
return $commands;
|
||||
}
|
||||
|
||||
/**
|
||||
* 配置基于用户的参数和选项的输入和输出实例。
|
||||
* @access protected
|
||||
* @param Input $input 输入实例
|
||||
* @param Output $output 输出实例
|
||||
*/
|
||||
protected function configureIO(Input $input, Output $output): void
|
||||
{
|
||||
if (true === $input->hasParameterOption(['--ansi'])) {
|
||||
$output->setDecorated(true);
|
||||
} elseif (true === $input->hasParameterOption(['--no-ansi'])) {
|
||||
$output->setDecorated(false);
|
||||
}
|
||||
|
||||
if (true === $input->hasParameterOption(['--no-interaction', '-n'])) {
|
||||
$input->setInteractive(false);
|
||||
}
|
||||
|
||||
if (true === $input->hasParameterOption(['--quiet', '-q'])) {
|
||||
$output->setVerbosity(Output::VERBOSITY_QUIET);
|
||||
} elseif ($input->hasParameterOption('-vvv') || $input->hasParameterOption('--verbose=3') || $input->getParameterOption('--verbose') === 3) {
|
||||
$output->setVerbosity(Output::VERBOSITY_DEBUG);
|
||||
} elseif ($input->hasParameterOption('-vv') || $input->hasParameterOption('--verbose=2') || $input->getParameterOption('--verbose') === 2) {
|
||||
$output->setVerbosity(Output::VERBOSITY_VERY_VERBOSE);
|
||||
} elseif ($input->hasParameterOption('-v') || $input->hasParameterOption('--verbose=1') || $input->hasParameterOption('--verbose') || $input->getParameterOption('--verbose')) {
|
||||
$output->setVerbosity(Output::VERBOSITY_VERBOSE);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行指令
|
||||
* @access protected
|
||||
* @param Command $command 指令实例
|
||||
* @param Input $input 输入实例
|
||||
* @param Output $output 输出实例
|
||||
* @return int
|
||||
* @throws \Exception
|
||||
*/
|
||||
protected function doRunCommand(Command $command, Input $input, Output $output)
|
||||
{
|
||||
return $command->run($input, $output);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指令的基础名称
|
||||
* @access protected
|
||||
* @param Input $input
|
||||
* @return string
|
||||
*/
|
||||
protected function getCommandName(Input $input): string
|
||||
{
|
||||
return $input->getFirstArgument() ?: '';
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取默认输入定义
|
||||
* @access protected
|
||||
* @return InputDefinition
|
||||
*/
|
||||
protected function getDefaultInputDefinition(): InputDefinition
|
||||
{
|
||||
return new InputDefinition([
|
||||
new InputArgument('command', InputArgument::REQUIRED, 'The command to execute'),
|
||||
new InputOption('--help', '-h', InputOption::VALUE_NONE, 'Display this help message'),
|
||||
new InputOption('--version', '-V', InputOption::VALUE_NONE, 'Display this console version'),
|
||||
new InputOption('--quiet', '-q', InputOption::VALUE_NONE, 'Do not output any message'),
|
||||
new InputOption('--verbose', '-v|vv|vvv', InputOption::VALUE_NONE, 'Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug'),
|
||||
new InputOption('--ansi', '', InputOption::VALUE_NONE, 'Force ANSI output'),
|
||||
new InputOption('--no-ansi', '', InputOption::VALUE_NONE, 'Disable ANSI output'),
|
||||
new InputOption('--no-interaction', '-n', InputOption::VALUE_NONE, 'Do not ask any interactive question'),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取可能的建议
|
||||
* @access private
|
||||
* @param array $abbrevs
|
||||
* @return string
|
||||
*/
|
||||
private function getAbbreviationSuggestions(array $abbrevs): string
|
||||
{
|
||||
return sprintf('%s, %s%s', $abbrevs[0], $abbrevs[1], count($abbrevs) > 2 ? sprintf(' and %d more', count($abbrevs) - 2) : '');
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回命名空间部分
|
||||
* @access public
|
||||
* @param string $name 指令
|
||||
* @param int $limit 部分的命名空间的最大数量
|
||||
* @return string
|
||||
*/
|
||||
public function extractNamespace(string $name, int $limit = 0): string
|
||||
{
|
||||
$parts = explode(':', $name);
|
||||
array_pop($parts);
|
||||
|
||||
return implode(':', 0 === $limit ? $parts : array_slice($parts, 0, $limit));
|
||||
}
|
||||
|
||||
/**
|
||||
* 查找可替代的建议
|
||||
* @access private
|
||||
* @param string $name
|
||||
* @param array|\Traversable $collection
|
||||
* @return array
|
||||
*/
|
||||
private function findAlternatives(string $name, array|\Traversable $collection): array
|
||||
{
|
||||
$threshold = 1e3;
|
||||
$alternatives = [];
|
||||
|
||||
$collectionParts = [];
|
||||
foreach ($collection as $item) {
|
||||
$collectionParts[$item] = explode(':', $item);
|
||||
}
|
||||
|
||||
foreach (explode(':', $name) as $i => $subname) {
|
||||
foreach ($collectionParts as $collectionName => $parts) {
|
||||
$exists = isset($alternatives[$collectionName]);
|
||||
if (!isset($parts[$i]) && $exists) {
|
||||
$alternatives[$collectionName] += $threshold;
|
||||
continue;
|
||||
} elseif (!isset($parts[$i])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$lev = levenshtein($subname, $parts[$i]);
|
||||
if ($lev <= strlen($subname) / 3 || '' !== $subname && str_contains($parts[$i], $subname)) {
|
||||
$alternatives[$collectionName] = $exists ? $alternatives[$collectionName] + $lev : $lev;
|
||||
} elseif ($exists) {
|
||||
$alternatives[$collectionName] += $threshold;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($collection as $item) {
|
||||
$lev = levenshtein($name, $item);
|
||||
if ($lev <= strlen($name) / 3 || str_contains($item, $name)) {
|
||||
$alternatives[$item] = isset($alternatives[$item]) ? $alternatives[$item] - $lev : $lev;
|
||||
}
|
||||
}
|
||||
|
||||
$alternatives = array_filter($alternatives, function ($lev) use ($threshold) {
|
||||
return $lev < 2 * $threshold;
|
||||
});
|
||||
asort($alternatives);
|
||||
|
||||
return array_keys($alternatives);
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回所有的命名空间
|
||||
* @access private
|
||||
* @param string $name
|
||||
* @return array
|
||||
*/
|
||||
private function extractAllNamespaces(string $name): array
|
||||
{
|
||||
$parts = explode(':', $name, -1);
|
||||
$namespaces = [];
|
||||
|
||||
foreach ($parts as $part) {
|
||||
if (count($namespaces)) {
|
||||
$namespaces[] = end($namespaces) . ':' . $part;
|
||||
} else {
|
||||
$namespaces[] = $part;
|
||||
}
|
||||
}
|
||||
|
||||
return $namespaces;
|
||||
}
|
||||
|
||||
}
|
||||
558
vendor/topthink/framework/src/think/Container.php
vendored
Normal file
558
vendor/topthink/framework/src/think/Container.php
vendored
Normal file
@@ -0,0 +1,558 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2023 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace think;
|
||||
|
||||
use ArrayAccess;
|
||||
use ArrayIterator;
|
||||
use Closure;
|
||||
use Countable;
|
||||
use InvalidArgumentException;
|
||||
use IteratorAggregate;
|
||||
use Psr\Container\ContainerInterface;
|
||||
use ReflectionClass;
|
||||
use ReflectionException;
|
||||
use ReflectionNamedType;
|
||||
use ReflectionFunction;
|
||||
use ReflectionFunctionAbstract;
|
||||
use ReflectionMethod;
|
||||
use think\exception\ClassNotFoundException;
|
||||
use think\exception\FuncNotFoundException;
|
||||
use think\helper\Str;
|
||||
use Traversable;
|
||||
|
||||
/**
|
||||
* 容器管理类 支持PSR-11
|
||||
*/
|
||||
class Container implements ContainerInterface, ArrayAccess, IteratorAggregate, Countable
|
||||
{
|
||||
/**
|
||||
* 容器对象实例
|
||||
* @var Container|Closure
|
||||
*/
|
||||
protected static $instance;
|
||||
|
||||
/**
|
||||
* 容器中的对象实例
|
||||
* @var array
|
||||
*/
|
||||
protected $instances = [];
|
||||
|
||||
/**
|
||||
* 容器绑定标识
|
||||
* @var array
|
||||
*/
|
||||
protected $bind = [];
|
||||
|
||||
/**
|
||||
* 容器回调
|
||||
* @var array
|
||||
*/
|
||||
protected $invokeCallback = [];
|
||||
|
||||
/**
|
||||
* 获取当前容器的实例(单例)
|
||||
* @access public
|
||||
* @return static
|
||||
*/
|
||||
public static function getInstance()
|
||||
{
|
||||
if (is_null(static::$instance)) {
|
||||
static::$instance = new static;
|
||||
}
|
||||
|
||||
if (static::$instance instanceof Closure) {
|
||||
return (static::$instance)();
|
||||
}
|
||||
|
||||
return static::$instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置当前容器的实例
|
||||
* @access public
|
||||
* @param object|Closure $instance
|
||||
* @return void
|
||||
*/
|
||||
public static function setInstance($instance): void
|
||||
{
|
||||
static::$instance = $instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册一个容器对象回调
|
||||
*
|
||||
* @param string|Closure $abstract
|
||||
* @param Closure|null $callback
|
||||
* @return void
|
||||
*/
|
||||
public function resolving(string|Closure $abstract, Closure $callback = null): void
|
||||
{
|
||||
if ($abstract instanceof Closure) {
|
||||
$this->invokeCallback['*'][] = $abstract;
|
||||
return;
|
||||
}
|
||||
|
||||
$abstract = $this->getAlias($abstract);
|
||||
|
||||
$this->invokeCallback[$abstract][] = $callback;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取容器中的对象实例 不存在则创建
|
||||
* @template T
|
||||
* @param string|class-string<T> $abstract 类名或者标识
|
||||
* @param array $vars 变量
|
||||
* @param bool $newInstance 是否每次创建新的实例
|
||||
* @return T|object
|
||||
*/
|
||||
public static function pull(string $abstract, array $vars = [], bool $newInstance = false)
|
||||
{
|
||||
return static::getInstance()->make($abstract, $vars, $newInstance);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取容器中的对象实例
|
||||
* @template T
|
||||
* @param string|class-string<T> $abstract 类名或者标识
|
||||
* @return T|object
|
||||
*/
|
||||
public function get(string $abstract)
|
||||
{
|
||||
if ($this->has($abstract)) {
|
||||
return $this->make($abstract);
|
||||
}
|
||||
|
||||
throw new ClassNotFoundException('class not exists: ' . $abstract, $abstract);
|
||||
}
|
||||
|
||||
/**
|
||||
* 绑定一个类、闭包、实例、接口实现到容器
|
||||
* @access public
|
||||
* @param string|array $abstract 类标识、接口
|
||||
* @param mixed $concrete 要绑定的类、闭包或者实例
|
||||
* @return $this
|
||||
*/
|
||||
public function bind(string|array $abstract, $concrete = null)
|
||||
{
|
||||
if (is_array($abstract)) {
|
||||
foreach ($abstract as $key => $val) {
|
||||
$this->bind($key, $val);
|
||||
}
|
||||
} elseif ($concrete instanceof Closure) {
|
||||
$this->bind[$abstract] = $concrete;
|
||||
} elseif (is_object($concrete)) {
|
||||
$this->instance($abstract, $concrete);
|
||||
} else {
|
||||
$abstract = $this->getAlias($abstract);
|
||||
if ($abstract != $concrete) {
|
||||
$this->bind[$abstract] = $concrete;
|
||||
}
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据别名获取真实类名
|
||||
* @param string $abstract
|
||||
* @return string
|
||||
*/
|
||||
public function getAlias(string $abstract): string
|
||||
{
|
||||
if (isset($this->bind[$abstract])) {
|
||||
$bind = $this->bind[$abstract];
|
||||
|
||||
if (is_string($bind)) {
|
||||
return $this->getAlias($bind);
|
||||
}
|
||||
}
|
||||
|
||||
return $abstract;
|
||||
}
|
||||
|
||||
/**
|
||||
* 绑定一个类实例到容器
|
||||
* @access public
|
||||
* @param string $abstract 类名或者标识
|
||||
* @param object $instance 类的实例
|
||||
* @return $this
|
||||
*/
|
||||
public function instance(string $abstract, $instance)
|
||||
{
|
||||
$abstract = $this->getAlias($abstract);
|
||||
|
||||
$this->instances[$abstract] = $instance;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断容器中是否存在类及标识
|
||||
* @access public
|
||||
* @param string $abstract 类名或者标识
|
||||
* @return bool
|
||||
*/
|
||||
public function bound(string $abstract): bool
|
||||
{
|
||||
return isset($this->bind[$abstract]) || isset($this->instances[$abstract]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断容器中是否存在类及标识
|
||||
* @access public
|
||||
* @param string $name 类名或者标识
|
||||
* @return bool
|
||||
*/
|
||||
public function has(string $name): bool
|
||||
{
|
||||
return $this->bound($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断容器中是否存在对象实例
|
||||
* @access public
|
||||
* @param string $abstract 类名或者标识
|
||||
* @return bool
|
||||
*/
|
||||
public function exists(string $abstract): bool
|
||||
{
|
||||
$abstract = $this->getAlias($abstract);
|
||||
|
||||
return isset($this->instances[$abstract]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建类的实例 已经存在则直接获取
|
||||
* @template T
|
||||
* @param string|class-string<T> $abstract 类名或者标识
|
||||
* @param array $vars 变量
|
||||
* @param bool $newInstance 是否每次创建新的实例
|
||||
* @return T|object
|
||||
*/
|
||||
public function make(string $abstract, array $vars = [], bool $newInstance = false)
|
||||
{
|
||||
$abstract = $this->getAlias($abstract);
|
||||
|
||||
if (isset($this->instances[$abstract]) && !$newInstance) {
|
||||
return $this->instances[$abstract];
|
||||
}
|
||||
|
||||
if (isset($this->bind[$abstract]) && $this->bind[$abstract] instanceof Closure) {
|
||||
$object = $this->invokeFunction($this->bind[$abstract], $vars);
|
||||
} else {
|
||||
$object = $this->invokeClass($abstract, $vars);
|
||||
}
|
||||
|
||||
if (!$newInstance) {
|
||||
$this->instances[$abstract] = $object;
|
||||
}
|
||||
|
||||
return $object;
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除容器中的对象实例
|
||||
* @access public
|
||||
* @param string $name 类名或者标识
|
||||
* @return void
|
||||
*/
|
||||
public function delete(string $name)
|
||||
{
|
||||
$name = $this->getAlias($name);
|
||||
|
||||
if (isset($this->instances[$name])) {
|
||||
unset($this->instances[$name]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行函数或者闭包方法 支持参数调用
|
||||
* @access public
|
||||
* @param string|Closure $function 函数或者闭包
|
||||
* @param array $vars 参数
|
||||
* @return mixed
|
||||
*/
|
||||
public function invokeFunction(string|Closure $function, array $vars = [])
|
||||
{
|
||||
try {
|
||||
$reflect = new ReflectionFunction($function);
|
||||
} catch (ReflectionException $e) {
|
||||
throw new FuncNotFoundException("function not exists: {$function}()", $function, $e);
|
||||
}
|
||||
|
||||
$args = $this->bindParams($reflect, $vars);
|
||||
|
||||
return $function(...$args);
|
||||
}
|
||||
|
||||
/**
|
||||
* 调用反射执行类的方法 支持参数绑定
|
||||
* @access public
|
||||
* @param mixed $method 方法
|
||||
* @param array $vars 参数
|
||||
* @param bool $accessible 设置是否可访问
|
||||
* @return mixed
|
||||
*/
|
||||
public function invokeMethod($method, array $vars = [], bool $accessible = false)
|
||||
{
|
||||
if (is_array($method)) {
|
||||
[$class, $method] = $method;
|
||||
|
||||
$class = is_object($class) ? $class : $this->invokeClass($class);
|
||||
} else {
|
||||
// 静态方法
|
||||
[$class, $method] = explode('::', $method);
|
||||
}
|
||||
|
||||
try {
|
||||
$reflect = new ReflectionMethod($class, $method);
|
||||
} catch (ReflectionException $e) {
|
||||
$class = is_object($class) ? $class::class : $class;
|
||||
throw new FuncNotFoundException('method not exists: ' . $class . '::' . $method . '()', "{$class}::{$method}", $e);
|
||||
}
|
||||
|
||||
$args = $this->bindParams($reflect, $vars);
|
||||
|
||||
if ($accessible) {
|
||||
$reflect->setAccessible($accessible);
|
||||
}
|
||||
|
||||
return $reflect->invokeArgs(is_object($class) ? $class : null, $args);
|
||||
}
|
||||
|
||||
/**
|
||||
* 调用反射执行类的方法 支持参数绑定
|
||||
* @access public
|
||||
* @param object $instance 对象实例
|
||||
* @param mixed $reflect 反射类
|
||||
* @param array $vars 参数
|
||||
* @return mixed
|
||||
*/
|
||||
public function invokeReflectMethod($instance, $reflect, array $vars = [])
|
||||
{
|
||||
$args = $this->bindParams($reflect, $vars);
|
||||
|
||||
return $reflect->invokeArgs($instance, $args);
|
||||
}
|
||||
|
||||
/**
|
||||
* 调用反射执行callable 支持参数绑定
|
||||
* @access public
|
||||
* @param mixed $callable
|
||||
* @param array $vars 参数
|
||||
* @param bool $accessible 设置是否可访问
|
||||
* @return mixed
|
||||
*/
|
||||
public function invoke($callable, array $vars = [], bool $accessible = false)
|
||||
{
|
||||
if ($callable instanceof Closure) {
|
||||
return $this->invokeFunction($callable, $vars);
|
||||
} elseif (is_string($callable) && !str_contains($callable, '::')) {
|
||||
return $this->invokeFunction($callable, $vars);
|
||||
} else {
|
||||
return $this->invokeMethod($callable, $vars, $accessible);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 调用反射执行类的实例化 支持依赖注入
|
||||
* @access public
|
||||
* @param string $class 类名
|
||||
* @param array $vars 参数
|
||||
* @return mixed
|
||||
*/
|
||||
public function invokeClass(string $class, array $vars = [])
|
||||
{
|
||||
try {
|
||||
$reflect = new ReflectionClass($class);
|
||||
} catch (ReflectionException $e) {
|
||||
throw new ClassNotFoundException('class not exists: ' . $class, $class, $e);
|
||||
}
|
||||
|
||||
if ($reflect->hasMethod('__make')) {
|
||||
$method = $reflect->getMethod('__make');
|
||||
if ($method->isPublic() && $method->isStatic()) {
|
||||
$args = $this->bindParams($method, $vars);
|
||||
$object = $method->invokeArgs(null, $args);
|
||||
$this->invokeAfter($class, $object);
|
||||
return $object;
|
||||
}
|
||||
}
|
||||
|
||||
$constructor = $reflect->getConstructor();
|
||||
|
||||
$args = $constructor ? $this->bindParams($constructor, $vars) : [];
|
||||
|
||||
$object = $reflect->newInstanceArgs($args);
|
||||
|
||||
$this->invokeAfter($class, $object);
|
||||
|
||||
return $object;
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行invokeClass回调
|
||||
* @access protected
|
||||
* @param string $class 对象类名
|
||||
* @param object $object 容器对象实例
|
||||
* @return void
|
||||
*/
|
||||
protected function invokeAfter(string $class, $object): void
|
||||
{
|
||||
if (isset($this->invokeCallback['*'])) {
|
||||
foreach ($this->invokeCallback['*'] as $callback) {
|
||||
$callback($object, $this);
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($this->invokeCallback[$class])) {
|
||||
foreach ($this->invokeCallback[$class] as $callback) {
|
||||
$callback($object, $this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 绑定参数
|
||||
* @access protected
|
||||
* @param ReflectionFunctionAbstract $reflect 反射类
|
||||
* @param array $vars 参数
|
||||
* @return array
|
||||
*/
|
||||
protected function bindParams(ReflectionFunctionAbstract $reflect, array $vars = []): array
|
||||
{
|
||||
if ($reflect->getNumberOfParameters() == 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
// 判断数组类型 数字数组时按顺序绑定参数
|
||||
reset($vars);
|
||||
$type = key($vars) === 0 ? 1 : 0;
|
||||
$params = $reflect->getParameters();
|
||||
$args = [];
|
||||
|
||||
foreach ($params as $param) {
|
||||
$name = $param->getName();
|
||||
$lowerName = Str::snake($name);
|
||||
$reflectionType = $param->getType();
|
||||
|
||||
if ($param->isVariadic()) {
|
||||
return array_merge($args, array_values($vars));
|
||||
} elseif ($reflectionType && $reflectionType instanceof ReflectionNamedType && $reflectionType->isBuiltin() === false) {
|
||||
$args[] = $this->getObjectParam($reflectionType->getName(), $vars);
|
||||
} elseif (1 == $type && !empty($vars)) {
|
||||
$args[] = array_shift($vars);
|
||||
} elseif (0 == $type && array_key_exists($name, $vars)) {
|
||||
$args[] = $vars[$name];
|
||||
} elseif (0 == $type && array_key_exists($lowerName, $vars)) {
|
||||
$args[] = $vars[$lowerName];
|
||||
} elseif ($param->isDefaultValueAvailable()) {
|
||||
$args[] = $param->getDefaultValue();
|
||||
} else {
|
||||
throw new InvalidArgumentException('method param miss:' . $name);
|
||||
}
|
||||
}
|
||||
|
||||
return $args;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建工厂对象实例
|
||||
* @param string $name 工厂类名
|
||||
* @param string $namespace 默认命名空间
|
||||
* @param array $args
|
||||
* @return mixed
|
||||
* @deprecated
|
||||
* @access public
|
||||
*/
|
||||
public static function factory(string $name, string $namespace = '', ...$args)
|
||||
{
|
||||
$class = str_contains($name, '\\') ? $name : $namespace . ucwords($name);
|
||||
|
||||
return Container::getInstance()->invokeClass($class, $args);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取对象类型的参数值
|
||||
* @access protected
|
||||
* @param string $className 类名
|
||||
* @param array $vars 参数
|
||||
* @return mixed
|
||||
*/
|
||||
protected function getObjectParam(string $className, array &$vars)
|
||||
{
|
||||
$array = $vars;
|
||||
$value = array_shift($array);
|
||||
|
||||
if ($value instanceof $className) {
|
||||
$result = $value;
|
||||
array_shift($vars);
|
||||
} else {
|
||||
$result = $this->make($className);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function __set($name, $value)
|
||||
{
|
||||
$this->bind($name, $value);
|
||||
}
|
||||
|
||||
public function __get($name)
|
||||
{
|
||||
return $this->get($name);
|
||||
}
|
||||
|
||||
public function __isset($name): bool
|
||||
{
|
||||
return $this->exists($name);
|
||||
}
|
||||
|
||||
public function __unset($name)
|
||||
{
|
||||
$this->delete($name);
|
||||
}
|
||||
|
||||
public function offsetExists(mixed $key): bool
|
||||
{
|
||||
return $this->exists($key);
|
||||
}
|
||||
|
||||
public function offsetGet(mixed $key): mixed
|
||||
{
|
||||
return $this->make($key);
|
||||
}
|
||||
|
||||
public function offsetSet(mixed $key, mixed $value): void
|
||||
{
|
||||
$this->bind($key, $value);
|
||||
}
|
||||
|
||||
public function offsetUnset(mixed $key): void
|
||||
{
|
||||
$this->delete($key);
|
||||
}
|
||||
|
||||
//Countable
|
||||
public function count(): int
|
||||
{
|
||||
return count($this->instances);
|
||||
}
|
||||
|
||||
//IteratorAggregate
|
||||
public function getIterator(): Traversable
|
||||
{
|
||||
return new ArrayIterator($this->instances);
|
||||
}
|
||||
}
|
||||
220
vendor/topthink/framework/src/think/Cookie.php
vendored
Normal file
220
vendor/topthink/framework/src/think/Cookie.php
vendored
Normal file
@@ -0,0 +1,220 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2023 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
declare (strict_types = 1);
|
||||
|
||||
namespace think;
|
||||
|
||||
use DateTimeInterface;
|
||||
|
||||
/**
|
||||
* Cookie管理类
|
||||
* @package think
|
||||
*/
|
||||
class Cookie
|
||||
{
|
||||
/**
|
||||
* 配置参数
|
||||
* @var array
|
||||
*/
|
||||
protected $config = [
|
||||
// cookie 保存时间
|
||||
'expire' => 0,
|
||||
// cookie 保存路径
|
||||
'path' => '/',
|
||||
// cookie 有效域名
|
||||
'domain' => '',
|
||||
// cookie 启用安全传输
|
||||
'secure' => false,
|
||||
// httponly设置
|
||||
'httponly' => false,
|
||||
// samesite 设置,支持 'strict' 'lax'
|
||||
'samesite' => '',
|
||||
];
|
||||
|
||||
/**
|
||||
* Cookie写入数据
|
||||
* @var array
|
||||
*/
|
||||
protected $cookie = [];
|
||||
|
||||
/**
|
||||
* 构造方法
|
||||
* @access public
|
||||
*/
|
||||
public function __construct(protected Request $request, array $config = [])
|
||||
{
|
||||
$this->config = array_merge($this->config, array_change_key_case($config));
|
||||
}
|
||||
|
||||
public static function __make(Request $request, Config $config)
|
||||
{
|
||||
return new static($request, $config->get('cookie'));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取cookie
|
||||
* @access public
|
||||
* @param mixed $name 数据名称
|
||||
* @param string $default 默认值
|
||||
* @return mixed
|
||||
*/
|
||||
public function get(string $name = '', $default = null)
|
||||
{
|
||||
return $this->request->cookie($name, $default);
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否存在Cookie参数
|
||||
* @access public
|
||||
* @param string $name 变量名
|
||||
* @return bool
|
||||
*/
|
||||
public function has(string $name): bool
|
||||
{
|
||||
return $this->request->has($name, 'cookie');
|
||||
}
|
||||
|
||||
/**
|
||||
* Cookie 设置
|
||||
*
|
||||
* @access public
|
||||
* @param string $name cookie名称
|
||||
* @param string $value cookie值
|
||||
* @param mixed $option 可选参数
|
||||
* @return void
|
||||
*/
|
||||
public function set(string $name, string $value, $option = null): void
|
||||
{
|
||||
// 参数设置(会覆盖黙认设置)
|
||||
if (!is_null($option)) {
|
||||
if (is_numeric($option) || $option instanceof DateTimeInterface) {
|
||||
$option = ['expire' => $option];
|
||||
}
|
||||
|
||||
$config = array_merge($this->config, array_change_key_case($option));
|
||||
} else {
|
||||
$config = $this->config;
|
||||
}
|
||||
|
||||
if ($config['expire'] instanceof DateTimeInterface) {
|
||||
$expire = $config['expire']->getTimestamp();
|
||||
} else {
|
||||
$expire = !empty($config['expire']) ? time() + intval($config['expire']) : 0;
|
||||
}
|
||||
|
||||
$this->setCookie($name, $value, $expire, $config);
|
||||
}
|
||||
|
||||
/**
|
||||
* Cookie 保存
|
||||
*
|
||||
* @access public
|
||||
* @param string $name cookie名称
|
||||
* @param string $value cookie值
|
||||
* @param int $expire 有效期
|
||||
* @param array $option 可选参数
|
||||
* @return void
|
||||
*/
|
||||
protected function setCookie(string $name, string $value, int $expire, array $option = []): void
|
||||
{
|
||||
$this->cookie[$name] = [$value, $expire, $option];
|
||||
}
|
||||
|
||||
/**
|
||||
* 永久保存Cookie数据
|
||||
* @access public
|
||||
* @param string $name cookie名称
|
||||
* @param string $value cookie值
|
||||
* @param mixed $option 可选参数 可能会是 null|integer|string
|
||||
* @return void
|
||||
*/
|
||||
public function forever(string $name, string $value = '', $option = null): void
|
||||
{
|
||||
if (is_null($option) || is_numeric($option)) {
|
||||
$option = [];
|
||||
}
|
||||
|
||||
$option['expire'] = 315360000;
|
||||
|
||||
$this->set($name, $value, $option);
|
||||
}
|
||||
|
||||
/**
|
||||
* Cookie删除
|
||||
* @access public
|
||||
* @param string $name cookie名称
|
||||
* @param array $options cookie参数
|
||||
* @return void
|
||||
*/
|
||||
public function delete(string $name, array $options = []): void
|
||||
{
|
||||
$config = array_merge($this->config, array_change_key_case($options));
|
||||
$this->setCookie($name, '', time() - 3600, $config);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取cookie保存数据
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function getCookie(): array
|
||||
{
|
||||
return $this->cookie;
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存Cookie
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function save(): void
|
||||
{
|
||||
foreach ($this->cookie as $name => $val) {
|
||||
[$value, $expire, $option] = $val;
|
||||
|
||||
$this->saveCookie(
|
||||
$name,
|
||||
$value,
|
||||
$expire,
|
||||
$option['path'],
|
||||
$option['domain'],
|
||||
$option['secure'] ? true : false,
|
||||
$option['httponly'] ? true : false,
|
||||
$option['samesite']
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存Cookie
|
||||
* @access public
|
||||
* @param string $name cookie名称
|
||||
* @param string $value cookie值
|
||||
* @param int $expire cookie过期时间
|
||||
* @param string $path 有效的服务器路径
|
||||
* @param string $domain 有效域名/子域名
|
||||
* @param bool $secure 是否仅仅通过HTTPS
|
||||
* @param bool $httponly 仅可通过HTTP访问
|
||||
* @param string $samesite 防止CSRF攻击和用户追踪
|
||||
* @return void
|
||||
*/
|
||||
protected function saveCookie(string $name, string $value, int $expire, string $path, string $domain, bool $secure, bool $httponly, string $samesite): void
|
||||
{
|
||||
setcookie($name, $value, [
|
||||
'expires' => $expire,
|
||||
'path' => $path,
|
||||
'domain' => $domain,
|
||||
'secure' => $secure,
|
||||
'httponly' => $httponly,
|
||||
'samesite' => $samesite,
|
||||
]);
|
||||
}
|
||||
}
|
||||
117
vendor/topthink/framework/src/think/Db.php
vendored
Normal file
117
vendor/topthink/framework/src/think/Db.php
vendored
Normal file
@@ -0,0 +1,117 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2023 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace think;
|
||||
|
||||
/**
|
||||
* 数据库管理类
|
||||
* @package think
|
||||
* @property Config $config
|
||||
*/
|
||||
class Db extends DbManager
|
||||
{
|
||||
/**
|
||||
* @param Event $event
|
||||
* @param Config $config
|
||||
* @param Log $log
|
||||
* @param Cache $cache
|
||||
* @return Db
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
public static function __make(Event $event, Config $config, Log $log, Cache $cache)
|
||||
{
|
||||
$db = new static();
|
||||
$db->setConfig($config);
|
||||
$db->setEvent($event);
|
||||
$db->setLog($log);
|
||||
|
||||
$store = $db->getConfig('cache_store');
|
||||
$db->setCache($cache->store($store));
|
||||
$db->triggerSql();
|
||||
|
||||
return $db;
|
||||
}
|
||||
|
||||
/**
|
||||
* 注入模型对象
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
protected function modelMaker(): void
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置配置对象
|
||||
* @access public
|
||||
* @param Config $config 配置对象
|
||||
* @return void
|
||||
*/
|
||||
public function setConfig($config): void
|
||||
{
|
||||
$this->config = $config;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取配置参数
|
||||
* @access public
|
||||
* @param string $name 配置参数
|
||||
* @param mixed $default 默认值
|
||||
* @return mixed
|
||||
*/
|
||||
public function getConfig(string $name = '', $default = null)
|
||||
{
|
||||
if ('' !== $name) {
|
||||
return $this->config->get('database.' . $name, $default);
|
||||
}
|
||||
|
||||
return $this->config->get('database', []);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置Event对象
|
||||
* @param Event $event
|
||||
*/
|
||||
public function setEvent(Event $event): void
|
||||
{
|
||||
$this->event = $event;
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册回调方法
|
||||
* @access public
|
||||
* @param string $event 事件名
|
||||
* @param callable $callback 回调方法
|
||||
* @return void
|
||||
*/
|
||||
public function event(string $event, callable $callback): void
|
||||
{
|
||||
if ($this->event) {
|
||||
$this->event->listen('db.' . $event, $callback);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 触发事件
|
||||
* @access public
|
||||
* @param string $event 事件名
|
||||
* @param mixed $params 传入参数
|
||||
* @param bool $once
|
||||
* @return mixed
|
||||
*/
|
||||
public function trigger(string $event, $params = null, bool $once = false)
|
||||
{
|
||||
if ($this->event) {
|
||||
return $this->event->trigger('db.' . $event, $params, $once);
|
||||
}
|
||||
}
|
||||
}
|
||||
199
vendor/topthink/framework/src/think/Env.php
vendored
Normal file
199
vendor/topthink/framework/src/think/Env.php
vendored
Normal file
@@ -0,0 +1,199 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2023 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace think;
|
||||
|
||||
use ArrayAccess;
|
||||
|
||||
/**
|
||||
* Env管理类
|
||||
* @package think
|
||||
*/
|
||||
class Env implements ArrayAccess
|
||||
{
|
||||
/**
|
||||
* 环境变量数据
|
||||
* @var array
|
||||
*/
|
||||
protected $data = [];
|
||||
|
||||
/**
|
||||
* 数据转换映射
|
||||
* @var array
|
||||
*/
|
||||
protected $convert = [
|
||||
'true' => true,
|
||||
'false' => false,
|
||||
'off' => false,
|
||||
'on' => true,
|
||||
];
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->data = $_ENV;
|
||||
}
|
||||
|
||||
/**
|
||||
* 读取环境变量定义文件
|
||||
* @access public
|
||||
* @param string $file 环境变量定义文件
|
||||
* @return void
|
||||
*/
|
||||
public function load(string $file): void
|
||||
{
|
||||
$env = parse_ini_file($file, true, INI_SCANNER_RAW) ?: [];
|
||||
$this->set($env);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取环境变量值
|
||||
* @access public
|
||||
* @param string $name 环境变量名
|
||||
* @param mixed $default 默认值
|
||||
* @return mixed
|
||||
*/
|
||||
public function get(string $name = null, $default = null)
|
||||
{
|
||||
if (is_null($name)) {
|
||||
return $this->data;
|
||||
}
|
||||
|
||||
$name = strtoupper(str_replace('.', '_', $name));
|
||||
if (isset($this->data[$name])) {
|
||||
$result = $this->data[$name];
|
||||
|
||||
if (is_string($result) && isset($this->convert[$result])) {
|
||||
return $this->convert[$result];
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
return $this->getEnv($name, $default);
|
||||
}
|
||||
|
||||
protected function getEnv(string $name, $default = null)
|
||||
{
|
||||
$result = getenv('PHP_' . $name);
|
||||
|
||||
if (false === $result) {
|
||||
return $default;
|
||||
}
|
||||
|
||||
if (isset($this->convert[$result])) {
|
||||
$result = $this->convert[$result];
|
||||
}
|
||||
|
||||
if (!isset($this->data[$name])) {
|
||||
$this->data[$name] = $result;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置环境变量值
|
||||
* @access public
|
||||
* @param string|array $env 环境变量
|
||||
* @param mixed $value 值
|
||||
* @return void
|
||||
*/
|
||||
public function set($env, $value = null): void
|
||||
{
|
||||
if (is_array($env)) {
|
||||
$env = array_change_key_case($env, CASE_UPPER);
|
||||
|
||||
foreach ($env as $key => $val) {
|
||||
if (is_array($val)) {
|
||||
foreach ($val as $k => $v) {
|
||||
if (is_string($k)) {
|
||||
$this->data[$key . '_' . strtoupper($k)] = $v;
|
||||
} else {
|
||||
$this->data[$key][$k] = $v;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$this->data[$key] = $val;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$name = strtoupper(str_replace('.', '_', $env));
|
||||
|
||||
$this->data[$name] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检测是否存在环境变量
|
||||
* @access public
|
||||
* @param string $name 参数名
|
||||
* @return bool
|
||||
*/
|
||||
public function has(string $name): bool
|
||||
{
|
||||
return !is_null($this->get($name));
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置环境变量
|
||||
* @access public
|
||||
* @param string $name 参数名
|
||||
* @param mixed $value 值
|
||||
*/
|
||||
public function __set(string $name, $value): void
|
||||
{
|
||||
$this->set($name, $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取环境变量
|
||||
* @access public
|
||||
* @param string $name 参数名
|
||||
* @return mixed
|
||||
*/
|
||||
public function __get(string $name)
|
||||
{
|
||||
return $this->get($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* 检测是否存在环境变量
|
||||
* @access public
|
||||
* @param string $name 参数名
|
||||
* @return bool
|
||||
*/
|
||||
public function __isset(string $name): bool
|
||||
{
|
||||
return $this->has($name);
|
||||
}
|
||||
|
||||
// ArrayAccess
|
||||
public function offsetSet(mixed $name, mixed $value): void
|
||||
{
|
||||
$this->set($name, $value);
|
||||
}
|
||||
|
||||
public function offsetExists(mixed $name): bool
|
||||
{
|
||||
return $this->__isset($name);
|
||||
}
|
||||
|
||||
public function offsetUnset(mixed $name): void
|
||||
{
|
||||
throw new Exception('not support: unset');
|
||||
}
|
||||
|
||||
public function offsetGet(mixed $name): mixed
|
||||
{
|
||||
return $this->get($name);
|
||||
}
|
||||
}
|
||||
271
vendor/topthink/framework/src/think/Event.php
vendored
Normal file
271
vendor/topthink/framework/src/think/Event.php
vendored
Normal file
@@ -0,0 +1,271 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2023 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace think;
|
||||
|
||||
use ReflectionClass;
|
||||
use ReflectionMethod;
|
||||
|
||||
/**
|
||||
* 事件管理类
|
||||
* @package think
|
||||
*/
|
||||
class Event
|
||||
{
|
||||
/**
|
||||
* 监听者
|
||||
* @var array
|
||||
*/
|
||||
protected $listener = [];
|
||||
|
||||
/**
|
||||
* 事件别名
|
||||
* @var array
|
||||
*/
|
||||
protected $bind = [
|
||||
'AppInit' => event\AppInit::class,
|
||||
'HttpRun' => event\HttpRun::class,
|
||||
'HttpEnd' => event\HttpEnd::class,
|
||||
'RouteLoaded' => event\RouteLoaded::class,
|
||||
'LogWrite' => event\LogWrite::class,
|
||||
'LogRecord' => event\LogRecord::class,
|
||||
];
|
||||
|
||||
/**
|
||||
* 应用对象
|
||||
* @var App
|
||||
*/
|
||||
protected $app;
|
||||
|
||||
public function __construct(App $app)
|
||||
{
|
||||
$this->app = $app;
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量注册事件监听
|
||||
* @access public
|
||||
* @param array $events 事件定义
|
||||
* @return $this
|
||||
*/
|
||||
public function listenEvents(array $events)
|
||||
{
|
||||
foreach ($events as $event => $listeners) {
|
||||
if (isset($this->bind[$event])) {
|
||||
$event = $this->bind[$event];
|
||||
}
|
||||
|
||||
$this->listener[$event] = array_merge($this->listener[$event] ?? [], $listeners);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册事件监听
|
||||
* @access public
|
||||
* @param string $event 事件名称
|
||||
* @param mixed $listener 监听操作(或者类名)
|
||||
* @param bool $first 是否优先执行
|
||||
* @return $this
|
||||
*/
|
||||
public function listen(string $event, $listener, bool $first = false)
|
||||
{
|
||||
if (isset($this->bind[$event])) {
|
||||
$event = $this->bind[$event];
|
||||
}
|
||||
|
||||
if ($first && isset($this->listener[$event])) {
|
||||
array_unshift($this->listener[$event], $listener);
|
||||
} else {
|
||||
$this->listener[$event][] = $listener;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否存在事件监听
|
||||
* @access public
|
||||
* @param string $event 事件名称
|
||||
* @return bool
|
||||
*/
|
||||
public function hasListener(string $event): bool
|
||||
{
|
||||
if (isset($this->bind[$event])) {
|
||||
$event = $this->bind[$event];
|
||||
}
|
||||
|
||||
return isset($this->listener[$event]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除事件监听
|
||||
* @access public
|
||||
* @param string $event 事件名称
|
||||
* @return void
|
||||
*/
|
||||
public function remove(string $event): void
|
||||
{
|
||||
if (isset($this->bind[$event])) {
|
||||
$event = $this->bind[$event];
|
||||
}
|
||||
|
||||
unset($this->listener[$event]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 指定事件别名标识 便于调用
|
||||
* @access public
|
||||
* @param array $events 事件别名
|
||||
* @return $this
|
||||
*/
|
||||
public function bind(array $events)
|
||||
{
|
||||
$this->bind = array_merge($this->bind, $events);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册事件订阅者
|
||||
* @access public
|
||||
* @param mixed $subscriber 订阅者
|
||||
* @return $this
|
||||
*/
|
||||
public function subscribe($subscriber)
|
||||
{
|
||||
$subscribers = (array) $subscriber;
|
||||
|
||||
foreach ($subscribers as $subscriber) {
|
||||
if (is_string($subscriber)) {
|
||||
$subscriber = $this->app->make($subscriber);
|
||||
}
|
||||
|
||||
if (method_exists($subscriber, 'subscribe')) {
|
||||
// 手动订阅
|
||||
$subscriber->subscribe($this);
|
||||
} else {
|
||||
// 智能订阅
|
||||
$this->observe($subscriber);
|
||||
}
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 自动注册事件观察者
|
||||
* @access public
|
||||
* @param string|object $observer 观察者
|
||||
* @param null|string $prefix 事件名前缀
|
||||
* @return $this
|
||||
*/
|
||||
public function observe($observer, string $prefix = '')
|
||||
{
|
||||
if (is_string($observer)) {
|
||||
$observer = $this->app->make($observer);
|
||||
}
|
||||
|
||||
$reflect = new ReflectionClass($observer);
|
||||
$methods = $reflect->getMethods(ReflectionMethod::IS_PUBLIC);
|
||||
|
||||
if (empty($prefix) && $reflect->hasProperty('eventPrefix')) {
|
||||
$reflectProperty = $reflect->getProperty('eventPrefix');
|
||||
$reflectProperty->setAccessible(true);
|
||||
$prefix = $reflectProperty->getValue($observer);
|
||||
}
|
||||
|
||||
foreach ($methods as $method) {
|
||||
$name = $method->getName();
|
||||
if (str_starts_with($name, 'on')) {
|
||||
$this->listen($prefix . substr($name, 2), [$observer, $name]);
|
||||
}
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 触发事件
|
||||
* @access public
|
||||
* @param string|object $event 事件名称
|
||||
* @param mixed $params 传入参数
|
||||
* @param bool $once 只获取一个有效返回值
|
||||
* @return mixed
|
||||
*/
|
||||
public function trigger($event, $params = null, bool $once = false)
|
||||
{
|
||||
if (is_object($event)) {
|
||||
$params = $event;
|
||||
$event = $event::class;
|
||||
}
|
||||
|
||||
if (isset($this->bind[$event])) {
|
||||
$event = $this->bind[$event];
|
||||
}
|
||||
|
||||
$result = [];
|
||||
$listeners = $this->listener[$event] ?? [];
|
||||
|
||||
if (str_contains($event, '.')) {
|
||||
[$prefix, $event] = explode('.', $event, 2);
|
||||
if (isset($this->listener[$prefix . '.*'])) {
|
||||
$listeners = array_merge($listeners, $this->listener[$prefix . '.*']);
|
||||
}
|
||||
}
|
||||
|
||||
$listeners = array_unique($listeners, SORT_REGULAR);
|
||||
|
||||
foreach ($listeners as $key => $listener) {
|
||||
$result[$key] = $this->dispatch($listener, $params);
|
||||
|
||||
if (false === $result[$key] || (!is_null($result[$key]) && $once)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $once ? end($result) : $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 触发事件(只获取一个有效返回值)
|
||||
* @param $event
|
||||
* @param null $params
|
||||
* @return mixed
|
||||
*/
|
||||
public function until($event, $params = null)
|
||||
{
|
||||
return $this->trigger($event, $params, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行事件调度
|
||||
* @access protected
|
||||
* @param mixed $event 事件方法
|
||||
* @param mixed $params 参数
|
||||
* @return mixed
|
||||
*/
|
||||
protected function dispatch($event, $params = null)
|
||||
{
|
||||
if (!is_string($event)) {
|
||||
$call = $event;
|
||||
} elseif (str_contains($event, '::')) {
|
||||
$call = $event;
|
||||
} else {
|
||||
$obj = $this->app->make($event);
|
||||
$call = [$obj, 'handle'];
|
||||
}
|
||||
|
||||
return $this->app->invoke($call, [$params]);
|
||||
}
|
||||
}
|
||||
59
vendor/topthink/framework/src/think/Exception.php
vendored
Normal file
59
vendor/topthink/framework/src/think/Exception.php
vendored
Normal file
@@ -0,0 +1,59 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2023 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: 麦当苗儿 <zuojiazi@vip.qq.com> <http://zjzit.cn>
|
||||
// +----------------------------------------------------------------------
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace think;
|
||||
|
||||
/**
|
||||
* 异常基础类
|
||||
* @package think
|
||||
*/
|
||||
class Exception extends \Exception
|
||||
{
|
||||
/**
|
||||
* 保存异常页面显示的额外Debug数据
|
||||
* @var array
|
||||
*/
|
||||
protected $data = [];
|
||||
|
||||
/**
|
||||
* 设置异常额外的Debug数据
|
||||
* 数据将会显示为下面的格式
|
||||
*
|
||||
* Exception Data
|
||||
* --------------------------------------------------
|
||||
* Label 1
|
||||
* key1 value1
|
||||
* key2 value2
|
||||
* Label 2
|
||||
* key1 value1
|
||||
* key2 value2
|
||||
*
|
||||
* @access protected
|
||||
* @param string $label 数据分类,用于异常页面显示
|
||||
* @param array $data 需要显示的数据,必须为关联数组
|
||||
*/
|
||||
final protected function setData(string $label, array $data)
|
||||
{
|
||||
$this->data[$label] = $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取异常额外Debug数据
|
||||
* 主要用于输出到异常页面便于调试
|
||||
* @access public
|
||||
* @return array 由setData设置的Debug数据
|
||||
*/
|
||||
final public function getData(): array
|
||||
{
|
||||
return $this->data;
|
||||
}
|
||||
}
|
||||
99
vendor/topthink/framework/src/think/Facade.php
vendored
Normal file
99
vendor/topthink/framework/src/think/Facade.php
vendored
Normal file
@@ -0,0 +1,99 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2023 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
namespace think;
|
||||
|
||||
/**
|
||||
* Facade管理类
|
||||
*/
|
||||
class Facade
|
||||
{
|
||||
/**
|
||||
* 始终创建新的对象实例
|
||||
* @var bool
|
||||
*/
|
||||
protected static $alwaysNewInstance;
|
||||
|
||||
/**
|
||||
* 创建Facade实例
|
||||
* @static
|
||||
* @access protected
|
||||
* @param string $class 类名或标识
|
||||
* @param array $args 变量
|
||||
* @param bool $newInstance 是否每次创建新的实例
|
||||
* @return object
|
||||
*/
|
||||
protected static function createFacade(string $class = '', array $args = [], bool $newInstance = false)
|
||||
{
|
||||
$class = $class ?: static::class;
|
||||
|
||||
$facadeClass = static::getFacadeClass();
|
||||
|
||||
if ($facadeClass) {
|
||||
$class = $facadeClass;
|
||||
}
|
||||
|
||||
if (static::$alwaysNewInstance) {
|
||||
$newInstance = true;
|
||||
}
|
||||
|
||||
return Container::getInstance()->make($class, $args, $newInstance);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前Facade对应类名
|
||||
* @access protected
|
||||
* @return string
|
||||
*/
|
||||
protected static function getFacadeClass()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* 带参数实例化当前Facade类
|
||||
* @access public
|
||||
* @return object
|
||||
*/
|
||||
public static function instance(...$args)
|
||||
{
|
||||
if (__CLASS__ != static::class) {
|
||||
return self::createFacade('', $args);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 调用类的实例
|
||||
* @access public
|
||||
* @param string $class 类名或者标识
|
||||
* @param array|true $args 变量
|
||||
* @param bool $newInstance 是否每次创建新的实例
|
||||
* @return object
|
||||
*/
|
||||
public static function make(string $class, $args = [], $newInstance = false)
|
||||
{
|
||||
if (__CLASS__ != static::class) {
|
||||
return self::__callStatic('make', func_get_args());
|
||||
}
|
||||
|
||||
if (true === $args) {
|
||||
// 总是创建新的实例化对象
|
||||
$newInstance = true;
|
||||
$args = [];
|
||||
}
|
||||
|
||||
return self::createFacade($class, $args, $newInstance);
|
||||
}
|
||||
|
||||
// 调用实际类的方法
|
||||
public static function __callStatic($method, $params)
|
||||
{
|
||||
return call_user_func_array([static::createFacade(), $method], $params);
|
||||
}
|
||||
}
|
||||
198
vendor/topthink/framework/src/think/File.php
vendored
Normal file
198
vendor/topthink/framework/src/think/File.php
vendored
Normal file
@@ -0,0 +1,198 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2023 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace think;
|
||||
|
||||
use SplFileInfo;
|
||||
use Closure;
|
||||
use think\exception\FileException;
|
||||
|
||||
/**
|
||||
* 文件上传类
|
||||
* @package think
|
||||
*/
|
||||
class File extends SplFileInfo
|
||||
{
|
||||
|
||||
/**
|
||||
* 文件hash规则
|
||||
* @var array
|
||||
*/
|
||||
protected $hash = [];
|
||||
|
||||
protected $hashName;
|
||||
|
||||
/**
|
||||
* 保存的文件后缀
|
||||
* @var string
|
||||
*/
|
||||
protected $extension;
|
||||
|
||||
public function __construct(string $path, bool $checkPath = true)
|
||||
{
|
||||
if ($checkPath && !is_file($path)) {
|
||||
throw new FileException(sprintf('The file "%s" does not exist', $path));
|
||||
}
|
||||
|
||||
parent::__construct($path);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文件的哈希散列值
|
||||
* @access public
|
||||
* @param string $type
|
||||
* @return string
|
||||
*/
|
||||
public function hash(string $type = 'sha1'): string
|
||||
{
|
||||
if (!isset($this->hash[$type])) {
|
||||
$this->hash[$type] = hash_file($type, $this->getPathname());
|
||||
}
|
||||
|
||||
return $this->hash[$type];
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文件的MD5值
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function md5(): string
|
||||
{
|
||||
return $this->hash('md5');
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文件的SHA1值
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function sha1(): string
|
||||
{
|
||||
return $this->hash('sha1');
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文件类型信息
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function getMime(): string
|
||||
{
|
||||
$finfo = finfo_open(FILEINFO_MIME_TYPE);
|
||||
|
||||
return finfo_file($finfo, $this->getPathname());
|
||||
}
|
||||
|
||||
/**
|
||||
* 移动文件
|
||||
* @access public
|
||||
* @param string $directory 保存路径
|
||||
* @param string|null $name 保存的文件名
|
||||
* @return File
|
||||
*/
|
||||
public function move(string $directory, string $name = null): File
|
||||
{
|
||||
$target = $this->getTargetFile($directory, $name);
|
||||
|
||||
set_error_handler(function ($type, $msg) use (&$error) {
|
||||
$error = $msg;
|
||||
});
|
||||
$renamed = rename($this->getPathname(), (string) $target);
|
||||
restore_error_handler();
|
||||
if (!$renamed) {
|
||||
throw new FileException(sprintf('Could not move the file "%s" to "%s" (%s)', $this->getPathname(), $target, strip_tags($error)));
|
||||
}
|
||||
|
||||
@chmod((string) $target, 0666 & ~umask());
|
||||
|
||||
return $target;
|
||||
}
|
||||
|
||||
/**
|
||||
* 实例化一个新文件
|
||||
* @param string $directory
|
||||
* @param null|string $name
|
||||
* @return File
|
||||
*/
|
||||
protected function getTargetFile(string $directory, string $name = null): File
|
||||
{
|
||||
if (!is_dir($directory)) {
|
||||
if (false === @mkdir($directory, 0777, true) && !is_dir($directory)) {
|
||||
throw new FileException(sprintf('Unable to create the "%s" directory', $directory));
|
||||
}
|
||||
} elseif (!is_writable($directory)) {
|
||||
throw new FileException(sprintf('Unable to write in the "%s" directory', $directory));
|
||||
}
|
||||
|
||||
$target = rtrim($directory, '/\\') . \DIRECTORY_SEPARATOR . (null === $name ? $this->getBasename() : $this->getName($name));
|
||||
|
||||
return new self($target, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文件名
|
||||
* @param string $name
|
||||
* @return string
|
||||
*/
|
||||
protected function getName(string $name): string
|
||||
{
|
||||
$originalName = str_replace('\\', '/', $name);
|
||||
$pos = strrpos($originalName, '/');
|
||||
$originalName = false === $pos ? $originalName : substr($originalName, $pos + 1);
|
||||
|
||||
return $originalName;
|
||||
}
|
||||
|
||||
/**
|
||||
* 文件扩展名
|
||||
* @return string
|
||||
*/
|
||||
public function extension(): string
|
||||
{
|
||||
return $this->getExtension();
|
||||
}
|
||||
|
||||
/**
|
||||
* 指定保存文件的扩展名
|
||||
* @param string $extension
|
||||
* @return void
|
||||
*/
|
||||
public function setExtension(string $extension): void
|
||||
{
|
||||
$this->extension = $extension;
|
||||
}
|
||||
|
||||
/**
|
||||
* 自动生成文件名
|
||||
* @access public
|
||||
* @param string|Closure|null $rule
|
||||
* @return string
|
||||
*/
|
||||
public function hashName(string|Closure|null $rule = null): string
|
||||
{
|
||||
if (!$this->hashName) {
|
||||
if ($rule instanceof Closure) {
|
||||
$this->hashName = call_user_func_array($rule, [$this]);
|
||||
} else {
|
||||
$this->hashName = match (true) {
|
||||
in_array($rule, hash_algos()) && $hash = $this->hash($rule) => substr($hash, 0, 2) . DIRECTORY_SEPARATOR . substr($hash, 2),
|
||||
is_callable($rule) => call_user_func($rule),
|
||||
default => date('Ymd') . DIRECTORY_SEPARATOR . md5(microtime(true) . $this->getPathname()),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
$extension = $this->extension ?? $this->extension();
|
||||
return $this->hashName . ($extension ? '.' . $extension : '');
|
||||
}
|
||||
}
|
||||
279
vendor/topthink/framework/src/think/Http.php
vendored
Normal file
279
vendor/topthink/framework/src/think/Http.php
vendored
Normal file
@@ -0,0 +1,279 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2023 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace think;
|
||||
|
||||
use think\event\HttpEnd;
|
||||
use think\event\HttpRun;
|
||||
use think\event\RouteLoaded;
|
||||
use think\exception\Handle;
|
||||
use Throwable;
|
||||
|
||||
/**
|
||||
* Web应用管理类
|
||||
* @package think
|
||||
*/
|
||||
class Http
|
||||
{
|
||||
/**
|
||||
* 应用名称
|
||||
* @var string
|
||||
*/
|
||||
protected $name;
|
||||
|
||||
/**
|
||||
* 应用路径
|
||||
* @var string
|
||||
*/
|
||||
protected $path;
|
||||
|
||||
/**
|
||||
* 路由路径
|
||||
* @var string
|
||||
*/
|
||||
protected $routePath;
|
||||
|
||||
/**
|
||||
* 是否绑定应用
|
||||
* @var bool
|
||||
*/
|
||||
protected $isBind = false;
|
||||
|
||||
public function __construct(protected App $app)
|
||||
{
|
||||
$this->routePath = $this->app->getRootPath() . 'route' . DIRECTORY_SEPARATOR;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置应用名称
|
||||
* @access public
|
||||
* @param string $name 应用名称
|
||||
* @return $this
|
||||
*/
|
||||
public function name(string $name)
|
||||
{
|
||||
$this->name = $name;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取应用名称
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function getName(): string
|
||||
{
|
||||
return $this->name ?: '';
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置应用目录
|
||||
* @access public
|
||||
* @param string $path 应用目录
|
||||
* @return $this
|
||||
*/
|
||||
public function path(string $path)
|
||||
{
|
||||
if (str_ends_with($path, DIRECTORY_SEPARATOR)) {
|
||||
$path .= DIRECTORY_SEPARATOR;
|
||||
}
|
||||
|
||||
$this->path = $path;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取应用路径
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function getPath(): string
|
||||
{
|
||||
return $this->path ?: '';
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取路由目录
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function getRoutePath(): string
|
||||
{
|
||||
return $this->routePath;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置路由目录
|
||||
* @access public
|
||||
* @param string $path 路由定义目录
|
||||
*/
|
||||
public function setRoutePath(string $path): void
|
||||
{
|
||||
$this->routePath = $path;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置应用绑定
|
||||
* @access public
|
||||
* @param bool $bind 是否绑定
|
||||
* @return $this
|
||||
*/
|
||||
public function setBind(bool $bind = true)
|
||||
{
|
||||
$this->isBind = $bind;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否绑定应用
|
||||
* @access public
|
||||
* @return bool
|
||||
*/
|
||||
public function isBind(): bool
|
||||
{
|
||||
return $this->isBind;
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行应用程序
|
||||
* @access public
|
||||
* @param Request|null $request
|
||||
* @return Response
|
||||
*/
|
||||
public function run(Request $request = null): Response
|
||||
{
|
||||
//初始化
|
||||
$this->initialize();
|
||||
|
||||
//自动创建request对象
|
||||
$request = $request ?? $this->app->make('request', [], true);
|
||||
$this->app->instance('request', $request);
|
||||
|
||||
try {
|
||||
$response = $this->runWithRequest($request);
|
||||
} catch (Throwable $e) {
|
||||
$this->reportException($e);
|
||||
|
||||
$response = $this->renderException($request, $e);
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化
|
||||
*/
|
||||
protected function initialize()
|
||||
{
|
||||
if (!$this->app->initialized()) {
|
||||
$this->app->initialize();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行应用程序
|
||||
* @param Request $request
|
||||
* @return mixed
|
||||
*/
|
||||
protected function runWithRequest(Request $request)
|
||||
{
|
||||
// 加载全局中间件
|
||||
$this->loadMiddleware();
|
||||
|
||||
// 监听HttpRun
|
||||
$this->app->event->trigger(HttpRun::class);
|
||||
|
||||
return $this->app->middleware->pipeline()
|
||||
->send($request)
|
||||
->then(function ($request) {
|
||||
return $this->dispatchToRoute($request);
|
||||
});
|
||||
}
|
||||
|
||||
protected function dispatchToRoute($request)
|
||||
{
|
||||
$withRoute = $this->app->config->get('app.with_route', true) ? function () {
|
||||
$this->loadRoutes();
|
||||
} : false;
|
||||
|
||||
return $this->app->route->dispatch($request, $withRoute);
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载全局中间件
|
||||
*/
|
||||
protected function loadMiddleware(): void
|
||||
{
|
||||
if (is_file($this->app->getBasePath() . 'middleware.php')) {
|
||||
$this->app->middleware->import(include $this->app->getBasePath() . 'middleware.php');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载路由
|
||||
* @access protected
|
||||
* @return void
|
||||
*/
|
||||
protected function loadRoutes(): void
|
||||
{
|
||||
// 加载路由定义
|
||||
$routePath = $this->getRoutePath();
|
||||
|
||||
if (is_dir($routePath)) {
|
||||
$files = glob($routePath . '*.php');
|
||||
foreach ($files as $file) {
|
||||
include $file;
|
||||
}
|
||||
}
|
||||
|
||||
$this->app->event->trigger(RouteLoaded::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Report the exception to the exception handler.
|
||||
*
|
||||
* @param Throwable $e
|
||||
* @return void
|
||||
*/
|
||||
protected function reportException(Throwable $e)
|
||||
{
|
||||
$this->app->make(Handle::class)->report($e);
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the exception to a response.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param Throwable $e
|
||||
* @return Response
|
||||
*/
|
||||
protected function renderException($request, Throwable $e)
|
||||
{
|
||||
return $this->app->make(Handle::class)->render($request, $e);
|
||||
}
|
||||
|
||||
/**
|
||||
* HttpEnd
|
||||
* @param Response $response
|
||||
* @return void
|
||||
*/
|
||||
public function end(Response $response): void
|
||||
{
|
||||
$this->app->event->trigger(HttpEnd::class, $response);
|
||||
|
||||
//执行中间件
|
||||
$this->app->middleware->end($response);
|
||||
|
||||
// 写入日志
|
||||
$this->app->log->save();
|
||||
}
|
||||
}
|
||||
271
vendor/topthink/framework/src/think/Lang.php
vendored
Normal file
271
vendor/topthink/framework/src/think/Lang.php
vendored
Normal file
@@ -0,0 +1,271 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2023 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace think;
|
||||
|
||||
/**
|
||||
* 多语言管理类
|
||||
* @package think
|
||||
*/
|
||||
class Lang
|
||||
{
|
||||
protected $app;
|
||||
|
||||
/**
|
||||
* 配置参数
|
||||
* @var array
|
||||
*/
|
||||
protected $config = [
|
||||
// 默认语言
|
||||
'default_lang' => 'zh-cn',
|
||||
// 允许的语言列表
|
||||
'allow_lang_list' => [],
|
||||
// 是否使用Cookie记录
|
||||
'use_cookie' => true,
|
||||
// 扩展语言包
|
||||
'extend_list' => [],
|
||||
// 多语言cookie变量
|
||||
'cookie_var' => 'think_lang',
|
||||
// 多语言header变量
|
||||
'header_var' => 'think-lang',
|
||||
// 多语言自动侦测变量名
|
||||
'detect_var' => 'lang',
|
||||
// Accept-Language转义为对应语言包名称
|
||||
'accept_language' => [
|
||||
'zh-hans-cn' => 'zh-cn',
|
||||
],
|
||||
// 是否支持语言分组
|
||||
'allow_group' => false,
|
||||
];
|
||||
|
||||
/**
|
||||
* 多语言信息
|
||||
* @var array
|
||||
*/
|
||||
private $lang = [];
|
||||
|
||||
/**
|
||||
* 当前语言
|
||||
* @var string
|
||||
*/
|
||||
private $range = 'zh-cn';
|
||||
|
||||
/**
|
||||
* 构造方法
|
||||
* @access public
|
||||
* @param array $config
|
||||
*/
|
||||
public function __construct(App $app, array $config = [])
|
||||
{
|
||||
$this->config = array_merge($this->config, array_change_key_case($config));
|
||||
$this->range = $this->config['default_lang'];
|
||||
$this->app = $app;
|
||||
}
|
||||
|
||||
public static function __make(App $app, Config $config)
|
||||
{
|
||||
return new static($app, $config->get('lang'));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前语言配置
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function getConfig(): array
|
||||
{
|
||||
return $this->config;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置当前语言
|
||||
* @access public
|
||||
* @param string $lang 语言
|
||||
* @return void
|
||||
*/
|
||||
public function setLangSet(string $lang): void
|
||||
{
|
||||
$this->range = $lang;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前语言
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function getLangSet(): string
|
||||
{
|
||||
return $this->range;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取默认语言
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function defaultLangSet()
|
||||
{
|
||||
return $this->config['default_lang'];
|
||||
}
|
||||
|
||||
/**
|
||||
* 切换语言
|
||||
* @access public
|
||||
* @param string $langset 语言
|
||||
* @return void
|
||||
*/
|
||||
public function switchLangSet(string $langset)
|
||||
{
|
||||
if (empty($langset)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->setLangSet($langset);
|
||||
|
||||
// 加载系统语言包
|
||||
$this->load([
|
||||
$this->app->getThinkPath() . 'lang' . DIRECTORY_SEPARATOR . $langset . '.php',
|
||||
]);
|
||||
|
||||
// 加载系统语言包
|
||||
$files = glob($this->app->getAppPath() . 'lang' . DIRECTORY_SEPARATOR . $langset . '.*');
|
||||
$this->load($files);
|
||||
|
||||
// 加载扩展(自定义)语言包
|
||||
$list = $this->app->config->get('lang.extend_list', []);
|
||||
|
||||
if (isset($list[$langset])) {
|
||||
$this->load($list[$langset]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载语言定义(不区分大小写)
|
||||
* @access public
|
||||
* @param string|array $file 语言文件
|
||||
* @param string $range 语言作用域
|
||||
* @return array
|
||||
*/
|
||||
public function load($file, $range = ''): array
|
||||
{
|
||||
$range = $range ?: $this->range;
|
||||
if (!isset($this->lang[$range])) {
|
||||
$this->lang[$range] = [];
|
||||
}
|
||||
|
||||
$lang = [];
|
||||
|
||||
foreach ((array) $file as $name) {
|
||||
if (is_file($name)) {
|
||||
$result = $this->parse($name);
|
||||
$lang = array_change_key_case($result) + $lang;
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($lang)) {
|
||||
$this->lang[$range] = $lang + $this->lang[$range];
|
||||
}
|
||||
|
||||
return $this->lang[$range];
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析语言文件
|
||||
* @access protected
|
||||
* @param string $file 语言文件名
|
||||
* @return array
|
||||
*/
|
||||
protected function parse(string $file): array
|
||||
{
|
||||
$type = pathinfo($file, PATHINFO_EXTENSION);
|
||||
$result = match ($type) {
|
||||
'php' => include $file,
|
||||
'yml','yaml'=> function_exists('yaml_parse_file') ? yaml_parse_file($file) : [],
|
||||
'json' => json_decode(file_get_contents($file), true),
|
||||
default => [],
|
||||
};
|
||||
|
||||
return is_array($result) ? $result : [];
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否存在语言定义(不区分大小写)
|
||||
* @access public
|
||||
* @param string|null $name 语言变量
|
||||
* @param string $range 语言作用域
|
||||
* @return bool
|
||||
*/
|
||||
public function has(string $name, string $range = ''): bool
|
||||
{
|
||||
$range = $range ?: $this->range;
|
||||
|
||||
if ($this->config['allow_group'] && str_contains($name, '.')) {
|
||||
[$name1, $name2] = explode('.', $name, 2);
|
||||
return isset($this->lang[$range][strtolower($name1)][$name2]);
|
||||
}
|
||||
|
||||
return isset($this->lang[$range][strtolower($name)]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取语言定义(不区分大小写)
|
||||
* @access public
|
||||
* @param string|null $name 语言变量
|
||||
* @param array $vars 变量替换
|
||||
* @param string $range 语言作用域
|
||||
* @return mixed
|
||||
*/
|
||||
public function get(string $name = null, array $vars = [], string $range = '')
|
||||
{
|
||||
$range = $range ?: $this->range;
|
||||
|
||||
if (!isset($this->lang[$range])) {
|
||||
$this->switchLangSet($range);
|
||||
}
|
||||
|
||||
// 空参数返回所有定义
|
||||
if (is_null($name)) {
|
||||
return $this->lang[$range] ?? [];
|
||||
}
|
||||
|
||||
if ($this->config['allow_group'] && str_contains($name, '.')) {
|
||||
[$name1, $name2] = explode('.', $name, 2);
|
||||
|
||||
$value = $this->lang[$range][strtolower($name1)][$name2] ?? $name;
|
||||
} else {
|
||||
$value = $this->lang[$range][strtolower($name)] ?? $name;
|
||||
}
|
||||
|
||||
// 变量解析
|
||||
if (!empty($vars) && is_array($vars)) {
|
||||
/**
|
||||
* Notes:
|
||||
* 为了检测的方便,数字索引的判断仅仅是参数数组的第一个元素的key为数字0
|
||||
* 数字索引采用的是系统的 sprintf 函数替换,用法请参考 sprintf 函数
|
||||
*/
|
||||
if (key($vars) === 0) {
|
||||
// 数字索引解析
|
||||
array_unshift($vars, $value);
|
||||
$value = call_user_func_array('sprintf', $vars);
|
||||
} else {
|
||||
// 关联索引解析
|
||||
$replace = array_keys($vars);
|
||||
foreach ($replace as &$v) {
|
||||
$v = "{:{$v}}";
|
||||
}
|
||||
$value = str_replace($replace, $vars, $value);
|
||||
}
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
249
vendor/topthink/framework/src/think/Log.php
vendored
Normal file
249
vendor/topthink/framework/src/think/Log.php
vendored
Normal file
@@ -0,0 +1,249 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2023 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace think;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Psr\Log\LoggerTrait;
|
||||
use Stringable;
|
||||
use think\event\LogWrite;
|
||||
use think\helper\Arr;
|
||||
use think\log\Channel;
|
||||
use think\log\ChannelSet;
|
||||
|
||||
/**
|
||||
* 日志管理类
|
||||
* @package think
|
||||
* @mixin Channel
|
||||
*/
|
||||
class Log extends Manager implements LoggerInterface
|
||||
{
|
||||
use LoggerTrait;
|
||||
const EMERGENCY = 'emergency';
|
||||
const ALERT = 'alert';
|
||||
const CRITICAL = 'critical';
|
||||
const ERROR = 'error';
|
||||
const WARNING = 'warning';
|
||||
const NOTICE = 'notice';
|
||||
const INFO = 'info';
|
||||
const DEBUG = 'debug';
|
||||
const SQL = 'sql';
|
||||
|
||||
protected $namespace = '\\think\\log\\driver\\';
|
||||
|
||||
/**
|
||||
* 默认驱动
|
||||
* @return string|null
|
||||
*/
|
||||
public function getDefaultDriver(): ?string
|
||||
{
|
||||
return $this->getConfig('default');
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取日志配置
|
||||
* @access public
|
||||
* @param null|string $name 名称
|
||||
* @param mixed $default 默认值
|
||||
* @return mixed
|
||||
*/
|
||||
public function getConfig(string $name = null, $default = null)
|
||||
{
|
||||
if (!is_null($name)) {
|
||||
return $this->app->config->get('log.' . $name, $default);
|
||||
}
|
||||
|
||||
return $this->app->config->get('log');
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取渠道配置
|
||||
* @param string $channel
|
||||
* @param string $name
|
||||
* @param mixed $default
|
||||
* @return array
|
||||
*/
|
||||
public function getChannelConfig(string $channel, string $name = null, $default = null)
|
||||
{
|
||||
if ($config = $this->getConfig("channels.{$channel}")) {
|
||||
return Arr::get($config, $name, $default);
|
||||
}
|
||||
|
||||
throw new InvalidArgumentException("Channel [$channel] not found.");
|
||||
}
|
||||
|
||||
/**
|
||||
* driver()的别名
|
||||
* @param string|array $name 渠道名
|
||||
* @return Channel|ChannelSet
|
||||
*/
|
||||
public function channel(string|array $name = null)
|
||||
{
|
||||
if (is_array($name)) {
|
||||
return new ChannelSet($this, $name);
|
||||
}
|
||||
|
||||
return $this->driver($name);
|
||||
}
|
||||
|
||||
protected function resolveType(string $name)
|
||||
{
|
||||
return $this->getChannelConfig($name, 'type', 'file');
|
||||
}
|
||||
|
||||
public function createDriver(string $name)
|
||||
{
|
||||
$driver = parent::createDriver($name);
|
||||
|
||||
$lazy = !$this->getChannelConfig($name, "realtime_write", false) && !$this->app->runningInConsole();
|
||||
$allow = array_merge($this->getConfig("level", []), $this->getChannelConfig($name, "level", []));
|
||||
|
||||
return new Channel($name, $driver, $allow, $lazy, $this->app->event);
|
||||
}
|
||||
|
||||
protected function resolveConfig(string $name)
|
||||
{
|
||||
return $this->getChannelConfig($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* 清空日志信息
|
||||
* @access public
|
||||
* @param string|array $channel 日志通道名
|
||||
* @return $this
|
||||
*/
|
||||
public function clear(string|array $channel = '*')
|
||||
{
|
||||
if ('*' == $channel) {
|
||||
$channel = array_keys($this->drivers);
|
||||
}
|
||||
|
||||
$this->channel($channel)->clear();
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 关闭本次请求日志写入
|
||||
* @access public
|
||||
* @param string|array $channel 日志通道名
|
||||
* @return $this
|
||||
*/
|
||||
public function close(string|array $channel = '*')
|
||||
{
|
||||
if ('*' == $channel) {
|
||||
$channel = array_keys($this->drivers);
|
||||
}
|
||||
|
||||
$this->channel($channel)->close();
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取日志信息
|
||||
* @access public
|
||||
* @param string $channel 日志通道名
|
||||
* @return array
|
||||
*/
|
||||
public function getLog(string $channel = null): array
|
||||
{
|
||||
return $this->channel($channel)->getLog();
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存日志信息
|
||||
* @access public
|
||||
* @return bool
|
||||
*/
|
||||
public function save(): bool
|
||||
{
|
||||
/** @var Channel $channel */
|
||||
foreach ($this->drivers as $channel) {
|
||||
$channel->save();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 记录日志信息
|
||||
* @access public
|
||||
* @param mixed $msg 日志信息
|
||||
* @param string $type 日志级别
|
||||
* @param array $context 替换内容
|
||||
* @param bool $lazy
|
||||
* @return $this
|
||||
*/
|
||||
public function record($msg, string $type = 'info', array $context = [], bool $lazy = true)
|
||||
{
|
||||
$channel = $this->getConfig('type_channel.' . $type);
|
||||
|
||||
$this->channel($channel)->record($msg, $type, $context, $lazy);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 实时写入日志信息
|
||||
* @access public
|
||||
* @param mixed $msg 调试信息
|
||||
* @param string $type 日志级别
|
||||
* @param array $context 替换内容
|
||||
* @return $this
|
||||
*/
|
||||
public function write($msg, string $type = 'info', array $context = [])
|
||||
{
|
||||
return $this->record($msg, $type, $context, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册日志写入事件监听
|
||||
* @param $listener
|
||||
* @return Event
|
||||
*/
|
||||
public function listen($listener)
|
||||
{
|
||||
return $this->app->event->listen(LogWrite::class, $listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* 记录日志信息
|
||||
* @access public
|
||||
* @param mixed $level 日志级别
|
||||
* @param string|Stringable $message 日志信息
|
||||
* @param array $context 替换内容
|
||||
* @return void
|
||||
*/
|
||||
public function log($level, $message, array $context = []): void
|
||||
{
|
||||
$this->record($message, $level, $context);
|
||||
}
|
||||
|
||||
/**
|
||||
* 记录sql信息
|
||||
* @access public
|
||||
* @param string|Stringable $message 日志信息
|
||||
* @param array $context 替换内容
|
||||
* @return void
|
||||
*/
|
||||
public function sql($message, array $context = []): void
|
||||
{
|
||||
$this->log(__FUNCTION__, $message, $context);
|
||||
}
|
||||
|
||||
public function __call($method, $parameters)
|
||||
{
|
||||
$this->log($method, ...$parameters);
|
||||
}
|
||||
}
|
||||
173
vendor/topthink/framework/src/think/Manager.php
vendored
Normal file
173
vendor/topthink/framework/src/think/Manager.php
vendored
Normal file
@@ -0,0 +1,173 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2023 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: yunwuxin <448901948@qq.com>
|
||||
// +----------------------------------------------------------------------
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace think;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use think\helper\Str;
|
||||
|
||||
abstract class Manager
|
||||
{
|
||||
/**
|
||||
* 驱动
|
||||
* @var array
|
||||
*/
|
||||
protected $drivers = [];
|
||||
|
||||
/**
|
||||
* 驱动的命名空间
|
||||
* @var string
|
||||
*/
|
||||
protected $namespace = null;
|
||||
|
||||
public function __construct(protected App $app)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取驱动实例
|
||||
* @param null|string $name
|
||||
* @return mixed
|
||||
*/
|
||||
protected function driver(string $name = null)
|
||||
{
|
||||
$name = $name ?: $this->getDefaultDriver();
|
||||
|
||||
if (is_null($name)) {
|
||||
throw new InvalidArgumentException(sprintf(
|
||||
'Unable to resolve NULL driver for [%s].',
|
||||
static::class
|
||||
));
|
||||
}
|
||||
|
||||
return $this->drivers[$name] = $this->getDriver($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取驱动实例
|
||||
* @param string $name
|
||||
* @return mixed
|
||||
*/
|
||||
protected function getDriver(string $name)
|
||||
{
|
||||
return $this->drivers[$name] ?? $this->createDriver($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取驱动类型
|
||||
* @param string $name
|
||||
* @return mixed
|
||||
*/
|
||||
protected function resolveType(string $name)
|
||||
{
|
||||
return $name;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取驱动配置
|
||||
* @param string $name
|
||||
* @return mixed
|
||||
*/
|
||||
protected function resolveConfig(string $name)
|
||||
{
|
||||
return $name;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取驱动类
|
||||
* @param string $type
|
||||
* @return string
|
||||
*/
|
||||
protected function resolveClass(string $type): string
|
||||
{
|
||||
if ($this->namespace || str_contains($type, '\\')) {
|
||||
$class = str_contains($type, '\\') ? $type : $this->namespace . Str::studly($type);
|
||||
|
||||
if (class_exists($class)) {
|
||||
return $class;
|
||||
}
|
||||
}
|
||||
|
||||
throw new InvalidArgumentException("Driver [$type] not supported.");
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取驱动参数
|
||||
* @param $name
|
||||
* @return array
|
||||
*/
|
||||
protected function resolveParams($name): array
|
||||
{
|
||||
$config = $this->resolveConfig($name);
|
||||
return [$config];
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建驱动
|
||||
*
|
||||
* @param string $name
|
||||
* @return mixed
|
||||
*
|
||||
*/
|
||||
protected function createDriver(string $name)
|
||||
{
|
||||
$type = $this->resolveType($name);
|
||||
|
||||
$method = 'create' . Str::studly($type) . 'Driver';
|
||||
|
||||
$params = $this->resolveParams($name);
|
||||
|
||||
if (method_exists($this, $method)) {
|
||||
return $this->$method(...$params);
|
||||
}
|
||||
|
||||
$class = $this->resolveClass($type);
|
||||
|
||||
return $this->app->invokeClass($class, $params);
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除一个驱动实例
|
||||
*
|
||||
* @param array|string|null $name
|
||||
* @return $this
|
||||
*/
|
||||
public function forgetDriver($name = null)
|
||||
{
|
||||
$name = $name ?? $this->getDefaultDriver();
|
||||
|
||||
foreach ((array) $name as $cacheName) {
|
||||
if (isset($this->drivers[$cacheName])) {
|
||||
unset($this->drivers[$cacheName]);
|
||||
}
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 默认驱动
|
||||
* @return string|null
|
||||
*/
|
||||
abstract public function getDefaultDriver();
|
||||
|
||||
/**
|
||||
* 动态调用
|
||||
* @param string $method
|
||||
* @param array $parameters
|
||||
* @return mixed
|
||||
*/
|
||||
public function __call($method, $parameters)
|
||||
{
|
||||
return $this->driver()->$method(...$parameters);
|
||||
}
|
||||
}
|
||||
244
vendor/topthink/framework/src/think/Middleware.php
vendored
Normal file
244
vendor/topthink/framework/src/think/Middleware.php
vendored
Normal file
@@ -0,0 +1,244 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2023 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: Slince <taosikai@yeah.net>
|
||||
// +----------------------------------------------------------------------
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace think;
|
||||
|
||||
use Closure;
|
||||
use LogicException;
|
||||
use think\exception\Handle;
|
||||
use Throwable;
|
||||
|
||||
/**
|
||||
* 中间件管理类
|
||||
* @package think
|
||||
*/
|
||||
class Middleware
|
||||
{
|
||||
/**
|
||||
* 中间件执行队列
|
||||
* @var array
|
||||
*/
|
||||
protected $queue = [];
|
||||
|
||||
public function __construct(protected App $app)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* 导入中间件
|
||||
* @access public
|
||||
* @param array $middlewares
|
||||
* @param string $type 中间件类型
|
||||
* @return void
|
||||
*/
|
||||
public function import(array $middlewares = [], string $type = 'global'): void
|
||||
{
|
||||
foreach ($middlewares as $middleware) {
|
||||
$this->add($middleware, $type);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册中间件
|
||||
* @access public
|
||||
* @param mixed $middleware
|
||||
* @param string $type 中间件类型
|
||||
* @return void
|
||||
*/
|
||||
public function add(array|string|Closure $middleware, string $type = 'global'): void
|
||||
{
|
||||
$middleware = $this->buildMiddleware($middleware, $type);
|
||||
|
||||
if (!empty($middleware)) {
|
||||
$this->queue[$type][] = $middleware;
|
||||
$this->queue[$type] = array_unique($this->queue[$type], SORT_REGULAR);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册路由中间件
|
||||
* @access public
|
||||
* @param mixed $middleware
|
||||
* @return void
|
||||
*/
|
||||
public function route(array|string|Closure $middleware): void
|
||||
{
|
||||
$this->add($middleware, 'route');
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册控制器中间件
|
||||
* @access public
|
||||
* @param mixed $middleware
|
||||
* @return void
|
||||
*/
|
||||
public function controller(array|string|Closure $middleware): void
|
||||
{
|
||||
$this->add($middleware, 'controller');
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册中间件到开始位置
|
||||
* @access public
|
||||
* @param mixed $middleware
|
||||
* @param string $type 中间件类型
|
||||
*/
|
||||
public function unshift(array|string|Closure $middleware, string $type = 'global')
|
||||
{
|
||||
$middleware = $this->buildMiddleware($middleware, $type);
|
||||
|
||||
if (!empty($middleware)) {
|
||||
if (!isset($this->queue[$type])) {
|
||||
$this->queue[$type] = [];
|
||||
}
|
||||
|
||||
array_unshift($this->queue[$type], $middleware);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取注册的中间件
|
||||
* @access public
|
||||
* @param string $type 中间件类型
|
||||
* @return array
|
||||
*/
|
||||
public function all(string $type = 'global'): array
|
||||
{
|
||||
return $this->queue[$type] ?? [];
|
||||
}
|
||||
|
||||
/**
|
||||
* 调度管道
|
||||
* @access public
|
||||
* @param string $type 中间件类型
|
||||
* @return Pipeline
|
||||
*/
|
||||
public function pipeline(string $type = 'global')
|
||||
{
|
||||
return (new Pipeline())
|
||||
->through(array_map(function ($middleware) {
|
||||
return function ($request, $next) use ($middleware) {
|
||||
[$call, $params] = $middleware;
|
||||
if (is_array($call) && is_string($call[0])) {
|
||||
$call = [$this->app->make($call[0]), $call[1]];
|
||||
}
|
||||
$response = call_user_func($call, $request, $next, ...$params);
|
||||
|
||||
if (!$response instanceof Response) {
|
||||
throw new LogicException('The middleware must return Response instance');
|
||||
}
|
||||
return $response;
|
||||
};
|
||||
}, $this->sortMiddleware($this->queue[$type] ?? [])))
|
||||
->whenException([$this, 'handleException']);
|
||||
}
|
||||
|
||||
/**
|
||||
* 结束调度
|
||||
* @param Response $response
|
||||
*/
|
||||
public function end(Response $response)
|
||||
{
|
||||
foreach ($this->queue as $queue) {
|
||||
foreach ($queue as $middleware) {
|
||||
[$call] = $middleware;
|
||||
if (is_array($call) && is_string($call[0])) {
|
||||
$instance = $this->app->make($call[0]);
|
||||
if (method_exists($instance, 'end')) {
|
||||
$instance->end($response);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 异常处理
|
||||
* @param Request $passable
|
||||
* @param Throwable $e
|
||||
* @return Response
|
||||
*/
|
||||
public function handleException($passable, Throwable $e)
|
||||
{
|
||||
/** @var Handle $handler */
|
||||
$handler = $this->app->make(Handle::class);
|
||||
|
||||
$handler->report($e);
|
||||
|
||||
return $handler->render($passable, $e);
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析中间件
|
||||
* @access protected
|
||||
* @param array|string|Closure $middleware
|
||||
* @param string $type 中间件类型
|
||||
* @return array
|
||||
*/
|
||||
protected function buildMiddleware(array|string|Closure $middleware, string $type): array
|
||||
{
|
||||
if (is_array($middleware)) {
|
||||
[$middleware, $params] = $middleware;
|
||||
}
|
||||
|
||||
if ($middleware instanceof Closure) {
|
||||
return [$middleware, $params ?? []];
|
||||
}
|
||||
|
||||
//中间件别名检查
|
||||
$alias = $this->app->config->get('middleware.alias', []);
|
||||
|
||||
if (isset($alias[$middleware])) {
|
||||
$middleware = $alias[$middleware];
|
||||
}
|
||||
|
||||
if (is_array($middleware)) {
|
||||
$this->import($middleware, $type);
|
||||
return [];
|
||||
}
|
||||
|
||||
return [[$middleware, 'handle'], $params ?? []];
|
||||
}
|
||||
|
||||
/**
|
||||
* 中间件排序
|
||||
* @param array $middlewares
|
||||
* @return array
|
||||
*/
|
||||
protected function sortMiddleware(array $middlewares)
|
||||
{
|
||||
$priority = $this->app->config->get('middleware.priority', []);
|
||||
uasort($middlewares, function ($a, $b) use ($priority) {
|
||||
$aPriority = $this->getMiddlewarePriority($priority, $a);
|
||||
$bPriority = $this->getMiddlewarePriority($priority, $b);
|
||||
return $bPriority - $aPriority;
|
||||
});
|
||||
|
||||
return $middlewares;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取中间件优先级
|
||||
* @param $priority
|
||||
* @param $middleware
|
||||
* @return int
|
||||
*/
|
||||
protected function getMiddlewarePriority($priority, $middleware)
|
||||
{
|
||||
[$call] = $middleware;
|
||||
if (is_array($call) && is_string($call[0])) {
|
||||
$index = array_search($call[0], array_reverse($priority));
|
||||
return false === $index ? -1 : $index;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
106
vendor/topthink/framework/src/think/Pipeline.php
vendored
Normal file
106
vendor/topthink/framework/src/think/Pipeline.php
vendored
Normal file
@@ -0,0 +1,106 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2023 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: yunwuxin <448901948@qq.com>
|
||||
// +----------------------------------------------------------------------
|
||||
namespace think;
|
||||
|
||||
use Closure;
|
||||
use Exception;
|
||||
use Throwable;
|
||||
|
||||
class Pipeline
|
||||
{
|
||||
protected $passable;
|
||||
|
||||
protected $pipes = [];
|
||||
|
||||
protected $exceptionHandler;
|
||||
|
||||
/**
|
||||
* 初始数据
|
||||
* @param $passable
|
||||
* @return $this
|
||||
*/
|
||||
public function send($passable)
|
||||
{
|
||||
$this->passable = $passable;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 调用栈
|
||||
* @param $pipes
|
||||
* @return $this
|
||||
*/
|
||||
public function through($pipes)
|
||||
{
|
||||
$this->pipes = is_array($pipes) ? $pipes : func_get_args();
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行
|
||||
* @param Closure $destination
|
||||
* @return mixed
|
||||
*/
|
||||
public function then(Closure $destination)
|
||||
{
|
||||
$pipeline = array_reduce(
|
||||
array_reverse($this->pipes),
|
||||
$this->carry(),
|
||||
function ($passable) use ($destination) {
|
||||
try {
|
||||
return $destination($passable);
|
||||
} catch (Throwable | Exception $e) {
|
||||
return $this->handleException($passable, $e);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
return $pipeline($this->passable);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置异常处理器
|
||||
* @param callable $handler
|
||||
* @return $this
|
||||
*/
|
||||
public function whenException($handler)
|
||||
{
|
||||
$this->exceptionHandler = $handler;
|
||||
return $this;
|
||||
}
|
||||
|
||||
protected function carry()
|
||||
{
|
||||
return function ($stack, $pipe) {
|
||||
return function ($passable) use ($stack, $pipe) {
|
||||
try {
|
||||
return $pipe($passable, $stack);
|
||||
} catch (Throwable | Exception $e) {
|
||||
return $this->handleException($passable, $e);
|
||||
}
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 异常处理
|
||||
* @param $passable
|
||||
* @param $e
|
||||
* @return mixed
|
||||
*/
|
||||
protected function handleException($passable, Throwable $e)
|
||||
{
|
||||
if ($this->exceptionHandler) {
|
||||
return call_user_func($this->exceptionHandler, $passable, $e);
|
||||
}
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
2163
vendor/topthink/framework/src/think/Request.php
vendored
Normal file
2163
vendor/topthink/framework/src/think/Request.php
vendored
Normal file
File diff suppressed because it is too large
Load Diff
415
vendor/topthink/framework/src/think/Response.php
vendored
Normal file
415
vendor/topthink/framework/src/think/Response.php
vendored
Normal file
@@ -0,0 +1,415 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2023 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace think;
|
||||
|
||||
/**
|
||||
* 响应输出基础类
|
||||
* @package think
|
||||
*/
|
||||
abstract class Response
|
||||
{
|
||||
/**
|
||||
* 原始数据
|
||||
* @var mixed
|
||||
*/
|
||||
protected $data;
|
||||
|
||||
/**
|
||||
* 当前contentType
|
||||
* @var string
|
||||
*/
|
||||
protected $contentType = 'text/html';
|
||||
|
||||
/**
|
||||
* 字符集
|
||||
* @var string
|
||||
*/
|
||||
protected $charset = 'utf-8';
|
||||
|
||||
/**
|
||||
* 状态码
|
||||
* @var integer
|
||||
*/
|
||||
protected $code = 200;
|
||||
|
||||
/**
|
||||
* 是否允许请求缓存
|
||||
* @var bool
|
||||
*/
|
||||
protected $allowCache = true;
|
||||
|
||||
/**
|
||||
* 输出参数
|
||||
* @var array
|
||||
*/
|
||||
protected $options = [];
|
||||
|
||||
/**
|
||||
* header参数
|
||||
* @var array
|
||||
*/
|
||||
protected $header = [];
|
||||
|
||||
/**
|
||||
* 输出内容
|
||||
* @var string
|
||||
*/
|
||||
protected $content = null;
|
||||
|
||||
/**
|
||||
* Cookie对象
|
||||
* @var Cookie
|
||||
*/
|
||||
protected $cookie;
|
||||
|
||||
/**
|
||||
* Session对象
|
||||
* @var Session
|
||||
*/
|
||||
protected $session;
|
||||
|
||||
/**
|
||||
* 初始化
|
||||
* @access protected
|
||||
* @param mixed $data 输出数据
|
||||
* @param int $code 状态码
|
||||
*/
|
||||
protected function init($data = '', int $code = 200)
|
||||
{
|
||||
$this->data($data);
|
||||
$this->code = $code;
|
||||
|
||||
$this->contentType($this->contentType, $this->charset);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建Response对象
|
||||
* @access public
|
||||
* @param mixed $data 输出数据
|
||||
* @param string $type 输出类型
|
||||
* @param int $code 状态码
|
||||
* @return Response
|
||||
*/
|
||||
public static function create($data = '', string $type = 'html', int $code = 200): Response
|
||||
{
|
||||
$class = str_contains($type, '\\') ? $type : '\\think\\response\\' . ucfirst(strtolower($type));
|
||||
|
||||
return Container::getInstance()->invokeClass($class, [$data, $code]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置Session对象
|
||||
* @access public
|
||||
* @param Session $session Session对象
|
||||
* @return $this
|
||||
*/
|
||||
public function setSession(Session $session)
|
||||
{
|
||||
$this->session = $session;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送数据到客户端
|
||||
* @access public
|
||||
* @return void
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public function send(): void
|
||||
{
|
||||
// 处理输出数据
|
||||
$data = $this->getContent();
|
||||
|
||||
if (!headers_sent()) {
|
||||
if (!empty($this->header)) {
|
||||
// 发送状态码
|
||||
http_response_code($this->code);
|
||||
// 发送头部信息
|
||||
foreach ($this->header as $name => $val) {
|
||||
header($name . (!is_null($val) ? ':' . $val : ''));
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->cookie) {
|
||||
$this->cookie->save();
|
||||
}
|
||||
}
|
||||
|
||||
$this->sendData($data);
|
||||
|
||||
if (function_exists('fastcgi_finish_request')) {
|
||||
// 提高页面响应
|
||||
fastcgi_finish_request();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理数据
|
||||
* @access protected
|
||||
* @param mixed $data 要处理的数据
|
||||
* @return mixed
|
||||
*/
|
||||
protected function output($data)
|
||||
{
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 输出数据
|
||||
* @access protected
|
||||
* @param string $data 要处理的数据
|
||||
* @return void
|
||||
*/
|
||||
protected function sendData(string $data): void
|
||||
{
|
||||
echo $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 输出的参数
|
||||
* @access public
|
||||
* @param mixed $options 输出参数
|
||||
* @return $this
|
||||
*/
|
||||
public function options(array $options = [])
|
||||
{
|
||||
$this->options = array_merge($this->options, $options);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 输出数据设置
|
||||
* @access public
|
||||
* @param mixed $data 输出数据
|
||||
* @return $this
|
||||
*/
|
||||
public function data($data)
|
||||
{
|
||||
$this->data = $data;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否允许请求缓存
|
||||
* @access public
|
||||
* @param bool $cache 允许请求缓存
|
||||
* @return $this
|
||||
*/
|
||||
public function allowCache(bool $cache)
|
||||
{
|
||||
$this->allowCache = $cache;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否允许请求缓存
|
||||
* @access public
|
||||
* @return bool
|
||||
*/
|
||||
public function isAllowCache()
|
||||
{
|
||||
return $this->allowCache;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置Cookie
|
||||
* @access public
|
||||
* @param string $name cookie名称
|
||||
* @param string $value cookie值
|
||||
* @param mixed $option 可选参数
|
||||
* @return $this
|
||||
*/
|
||||
public function cookie(string $name, string $value, $option = null)
|
||||
{
|
||||
$this->cookie->set($name, $value, $option);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置响应头
|
||||
* @access public
|
||||
* @param array $header 参数
|
||||
* @return $this
|
||||
*/
|
||||
public function header(array $header = [])
|
||||
{
|
||||
$this->header = array_merge($this->header, $header);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置页面输出内容
|
||||
* @access public
|
||||
* @param mixed $content
|
||||
* @return $this
|
||||
*/
|
||||
public function content($content)
|
||||
{
|
||||
if (
|
||||
null !== $content && !is_string($content) && !is_numeric($content) && !is_callable([
|
||||
$content,
|
||||
'__toString',
|
||||
])
|
||||
) {
|
||||
throw new \InvalidArgumentException(sprintf('variable type error: %s', gettype($content)));
|
||||
}
|
||||
|
||||
$this->content = (string) $content;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送HTTP状态
|
||||
* @access public
|
||||
* @param integer $code 状态码
|
||||
* @return $this
|
||||
*/
|
||||
public function code(int $code)
|
||||
{
|
||||
$this->code = $code;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* LastModified
|
||||
* @access public
|
||||
* @param string $time
|
||||
* @return $this
|
||||
*/
|
||||
public function lastModified(string $time)
|
||||
{
|
||||
$this->header['Last-Modified'] = $time;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Expires
|
||||
* @access public
|
||||
* @param string $time
|
||||
* @return $this
|
||||
*/
|
||||
public function expires(string $time)
|
||||
{
|
||||
$this->header['Expires'] = $time;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* ETag
|
||||
* @access public
|
||||
* @param string $eTag
|
||||
* @return $this
|
||||
*/
|
||||
public function eTag(string $eTag)
|
||||
{
|
||||
$this->header['ETag'] = $eTag;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 页面缓存控制
|
||||
* @access public
|
||||
* @param string $cache 状态码
|
||||
* @return $this
|
||||
*/
|
||||
public function cacheControl(string $cache)
|
||||
{
|
||||
$this->header['Cache-control'] = $cache;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 页面输出类型
|
||||
* @access public
|
||||
* @param string $contentType 输出类型
|
||||
* @param string $charset 输出编码
|
||||
* @return $this
|
||||
*/
|
||||
public function contentType(string $contentType, string $charset = 'utf-8')
|
||||
{
|
||||
$this->header['Content-Type'] = $contentType . '; charset=' . $charset;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取头部信息
|
||||
* @access public
|
||||
* @param string $name 头部名称
|
||||
* @return mixed
|
||||
*/
|
||||
public function getHeader(string $name = '')
|
||||
{
|
||||
if (!empty($name)) {
|
||||
return $this->header[$name] ?? null;
|
||||
}
|
||||
|
||||
return $this->header;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取原始数据
|
||||
* @access public
|
||||
* @return mixed
|
||||
*/
|
||||
public function getData()
|
||||
{
|
||||
return $this->data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取输出数据
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function getContent(): string
|
||||
{
|
||||
if (null == $this->content) {
|
||||
$content = $this->output($this->data);
|
||||
|
||||
if (
|
||||
null !== $content && !is_string($content) && !is_numeric($content) && !is_callable([
|
||||
$content,
|
||||
'__toString',
|
||||
])
|
||||
) {
|
||||
throw new \InvalidArgumentException(sprintf('variable type error: %s', gettype($content)));
|
||||
}
|
||||
|
||||
$this->content = (string) $content;
|
||||
}
|
||||
|
||||
return $this->content;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取状态码
|
||||
* @access public
|
||||
* @return integer
|
||||
*/
|
||||
public function getCode(): int
|
||||
{
|
||||
return $this->code;
|
||||
}
|
||||
}
|
||||
909
vendor/topthink/framework/src/think/Route.php
vendored
Normal file
909
vendor/topthink/framework/src/think/Route.php
vendored
Normal file
@@ -0,0 +1,909 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2023 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
declare (strict_types = 1);
|
||||
|
||||
namespace think;
|
||||
|
||||
use Closure;
|
||||
use think\exception\RouteNotFoundException;
|
||||
use think\route\Dispatch;
|
||||
use think\route\dispatch\Callback;
|
||||
use think\route\dispatch\Url as UrlDispatch;
|
||||
use think\route\Domain;
|
||||
use think\route\Resource;
|
||||
use think\route\ResourceRegister;
|
||||
use think\route\Rule;
|
||||
use think\route\RuleGroup;
|
||||
use think\route\RuleItem;
|
||||
use think\route\RuleName;
|
||||
use think\route\Url as UrlBuild;
|
||||
|
||||
/**
|
||||
* 路由管理类
|
||||
* @package think
|
||||
*/
|
||||
class Route
|
||||
{
|
||||
/**
|
||||
* REST定义
|
||||
* @var array
|
||||
*/
|
||||
protected $rest = [
|
||||
'index' => ['get', '', 'index'],
|
||||
'create' => ['get', '/create', 'create'],
|
||||
'edit' => ['get', '/<id>/edit', 'edit'],
|
||||
'read' => ['get', '/<id>', 'read'],
|
||||
'save' => ['post', '', 'save'],
|
||||
'update' => ['put', '/<id>', 'update'],
|
||||
'delete' => ['delete', '/<id>', 'delete'],
|
||||
];
|
||||
|
||||
/**
|
||||
* 配置参数
|
||||
* @var array
|
||||
*/
|
||||
protected $config = [
|
||||
// pathinfo分隔符
|
||||
'pathinfo_depr' => '/',
|
||||
// 是否开启路由延迟解析
|
||||
'url_lazy_route' => false,
|
||||
// 是否强制使用路由
|
||||
'url_route_must' => false,
|
||||
// 是否区分大小写
|
||||
'url_case_sensitive' => false,
|
||||
// 合并路由规则
|
||||
'route_rule_merge' => false,
|
||||
// 路由是否完全匹配
|
||||
'route_complete_match' => false,
|
||||
// 去除斜杠
|
||||
'remove_slash' => false,
|
||||
// 使用注解路由
|
||||
'route_annotation' => false,
|
||||
// 默认的路由变量规则
|
||||
'default_route_pattern' => '[\w\.]+',
|
||||
// URL伪静态后缀
|
||||
'url_html_suffix' => 'html',
|
||||
// 访问控制器层名称
|
||||
'controller_layer' => 'controller',
|
||||
// 空控制器名
|
||||
'empty_controller' => 'Error',
|
||||
// 是否使用控制器后缀
|
||||
'controller_suffix' => false,
|
||||
// 默认控制器名
|
||||
'default_controller' => 'Index',
|
||||
// 默认操作名
|
||||
'default_action' => 'index',
|
||||
// 操作方法后缀
|
||||
'action_suffix' => '',
|
||||
// 非路由变量是否使用普通参数方式(用于URL生成)
|
||||
'url_common_param' => true,
|
||||
];
|
||||
|
||||
/**
|
||||
* 请求对象
|
||||
* @var Request
|
||||
*/
|
||||
protected $request;
|
||||
|
||||
/**
|
||||
* @var RuleName
|
||||
*/
|
||||
protected $ruleName;
|
||||
|
||||
/**
|
||||
* 当前HOST
|
||||
* @var string
|
||||
*/
|
||||
protected $host;
|
||||
|
||||
/**
|
||||
* 当前分组对象
|
||||
* @var RuleGroup
|
||||
*/
|
||||
protected $group;
|
||||
|
||||
/**
|
||||
* 路由绑定
|
||||
* @var array
|
||||
*/
|
||||
protected $bind = [];
|
||||
|
||||
/**
|
||||
* 域名对象
|
||||
* @var Domain[]
|
||||
*/
|
||||
protected $domains = [];
|
||||
|
||||
/**
|
||||
* 跨域路由规则
|
||||
* @var RuleGroup
|
||||
*/
|
||||
protected $cross;
|
||||
|
||||
/**
|
||||
* 路由是否延迟解析
|
||||
* @var bool
|
||||
*/
|
||||
protected $lazy = false;
|
||||
|
||||
/**
|
||||
* (分组)路由规则是否合并解析
|
||||
* @var bool
|
||||
*/
|
||||
protected $mergeRuleRegex = false;
|
||||
|
||||
/**
|
||||
* 是否去除URL最后的斜线
|
||||
* @var bool
|
||||
*/
|
||||
protected $removeSlash = false;
|
||||
|
||||
public function __construct(protected App $app)
|
||||
{
|
||||
$this->ruleName = new RuleName();
|
||||
$this->setDefaultDomain();
|
||||
|
||||
if (is_file($this->app->getRuntimePath() . 'route.php')) {
|
||||
// 读取路由映射文件
|
||||
$this->import(include $this->app->getRuntimePath() . 'route.php');
|
||||
}
|
||||
|
||||
$this->config = array_merge($this->config, $this->app->config->get('route'));
|
||||
|
||||
$this->init();
|
||||
}
|
||||
|
||||
protected function init()
|
||||
{
|
||||
if (!empty($this->config['middleware'])) {
|
||||
$this->app->middleware->import($this->config['middleware'], 'route');
|
||||
}
|
||||
|
||||
$this->lazy($this->config['url_lazy_route']);
|
||||
$this->mergeRuleRegex = $this->config['route_rule_merge'];
|
||||
$this->removeSlash = $this->config['remove_slash'];
|
||||
|
||||
$this->group->removeSlash($this->removeSlash);
|
||||
|
||||
// 注册全局MISS路由
|
||||
$this->miss(function () {
|
||||
return Response::create('', 'html', 204)->header(['Allow' => 'GET, POST, PUT, DELETE']);
|
||||
}, 'options');
|
||||
}
|
||||
|
||||
public function config(string $name = null)
|
||||
{
|
||||
if (is_null($name)) {
|
||||
return $this->config;
|
||||
}
|
||||
|
||||
return $this->config[$name] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置路由域名及分组(包括资源路由)是否延迟解析
|
||||
* @access public
|
||||
* @param bool $lazy 路由是否延迟解析
|
||||
* @return $this
|
||||
*/
|
||||
public function lazy(bool $lazy = true)
|
||||
{
|
||||
$this->lazy = $lazy;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置路由域名及分组(包括资源路由)是否合并解析
|
||||
* @access public
|
||||
* @param bool $merge 路由是否合并解析
|
||||
* @return $this
|
||||
*/
|
||||
public function mergeRuleRegex(bool $merge = true)
|
||||
{
|
||||
$this->mergeRuleRegex = $merge;
|
||||
$this->group->mergeRuleRegex($merge);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化默认域名
|
||||
* @access protected
|
||||
* @return void
|
||||
*/
|
||||
protected function setDefaultDomain(): void
|
||||
{
|
||||
// 注册默认域名
|
||||
$domain = new Domain($this);
|
||||
|
||||
$this->domains['-'] = $domain;
|
||||
|
||||
// 默认分组
|
||||
$this->group = $domain;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置当前分组
|
||||
* @access public
|
||||
* @param RuleGroup $group 域名
|
||||
* @return void
|
||||
*/
|
||||
public function setGroup(RuleGroup $group): void
|
||||
{
|
||||
$this->group = $group;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定标识的路由分组 不指定则获取当前分组
|
||||
* @access public
|
||||
* @param string $name 分组标识
|
||||
* @return RuleGroup
|
||||
*/
|
||||
public function getGroup(string $name = null)
|
||||
{
|
||||
return $name ? $this->ruleName->getGroup($name) : $this->group;
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册变量规则
|
||||
* @access public
|
||||
* @param array $pattern 变量规则
|
||||
* @return $this
|
||||
*/
|
||||
public function pattern(array $pattern)
|
||||
{
|
||||
$this->group->pattern($pattern);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册路由参数
|
||||
* @access public
|
||||
* @param array $option 参数
|
||||
* @return $this
|
||||
*/
|
||||
public function option(array $option)
|
||||
{
|
||||
$this->group->option($option);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册域名路由
|
||||
* @access public
|
||||
* @param string|array $name 子域名
|
||||
* @param mixed $rule 路由规则
|
||||
* @return Domain
|
||||
*/
|
||||
public function domain(string | array $name, $rule = null): Domain
|
||||
{
|
||||
// 支持多个域名使用相同路由规则
|
||||
$domainName = is_array($name) ? array_shift($name) : $name;
|
||||
|
||||
if (!isset($this->domains[$domainName])) {
|
||||
$domain = (new Domain($this, $domainName, $rule, $this->lazy))
|
||||
->removeSlash($this->removeSlash)
|
||||
->mergeRuleRegex($this->mergeRuleRegex);
|
||||
|
||||
$this->domains[$domainName] = $domain;
|
||||
} else {
|
||||
$domain = $this->domains[$domainName];
|
||||
$domain->parseGroupRule($rule);
|
||||
}
|
||||
|
||||
if (is_array($name) && !empty($name)) {
|
||||
foreach ($name as $item) {
|
||||
$this->domains[$item] = $domainName;
|
||||
}
|
||||
}
|
||||
|
||||
// 返回域名对象
|
||||
return $domain;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取域名
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function getDomains(): array
|
||||
{
|
||||
return $this->domains;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取RuleName对象
|
||||
* @access public
|
||||
* @return RuleName
|
||||
*/
|
||||
public function getRuleName(): RuleName
|
||||
{
|
||||
return $this->ruleName;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置路由绑定
|
||||
* @access public
|
||||
* @param string $bind 绑定信息
|
||||
* @param string $domain 域名
|
||||
* @return $this
|
||||
*/
|
||||
public function bind(string $bind, string $domain = null)
|
||||
{
|
||||
$domain = is_null($domain) ? '-' : $domain;
|
||||
|
||||
$this->bind[$domain] = $bind;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 读取路由绑定信息
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function getBind(): array
|
||||
{
|
||||
return $this->bind;
|
||||
}
|
||||
|
||||
/**
|
||||
* 读取路由绑定
|
||||
* @access public
|
||||
* @param string $domain 域名
|
||||
* @return string|null
|
||||
*/
|
||||
public function getDomainBind(string $domain = null)
|
||||
{
|
||||
if (is_null($domain)) {
|
||||
$domain = $this->host;
|
||||
} elseif (!str_contains($domain, '.') && $this->request) {
|
||||
$domain .= '.' . $this->request->rootDomain();
|
||||
}
|
||||
|
||||
if ($this->request) {
|
||||
$subDomain = $this->request->subDomain();
|
||||
|
||||
if (str_contains($subDomain, '.')) {
|
||||
$name = '*' . strstr($subDomain, '.');
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($this->bind[$domain])) {
|
||||
$result = $this->bind[$domain];
|
||||
} elseif (isset($name) && isset($this->bind[$name])) {
|
||||
$result = $this->bind[$name];
|
||||
} elseif (!empty($subDomain) && isset($this->bind['*'])) {
|
||||
$result = $this->bind['*'];
|
||||
} else {
|
||||
$result = null;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 读取路由标识
|
||||
* @access public
|
||||
* @param string $name 路由标识
|
||||
* @param string $domain 域名
|
||||
* @param string $method 请求类型
|
||||
* @return array
|
||||
*/
|
||||
public function getName(string $name = null, string $domain = null, string $method = '*'): array
|
||||
{
|
||||
return $this->ruleName->getName($name, $domain, $method);
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量导入路由标识
|
||||
* @access public
|
||||
* @param array $name 路由标识
|
||||
* @return void
|
||||
*/
|
||||
public function import(array $name): void
|
||||
{
|
||||
$this->ruleName->import($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册路由标识
|
||||
* @access public
|
||||
* @param string $name 路由标识
|
||||
* @param RuleItem $ruleItem 路由规则
|
||||
* @param bool $first 是否优先
|
||||
* @return void
|
||||
*/
|
||||
public function setName(string $name, RuleItem $ruleItem, bool $first = false): void
|
||||
{
|
||||
$this->ruleName->setName($name, $ruleItem, $first);
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存路由规则
|
||||
* @access public
|
||||
* @param string $rule 路由规则
|
||||
* @param RuleItem $ruleItem RuleItem对象
|
||||
* @return void
|
||||
*/
|
||||
public function setRule(string $rule, RuleItem $ruleItem = null): void
|
||||
{
|
||||
$this->ruleName->setRule($rule, $ruleItem);
|
||||
}
|
||||
|
||||
/**
|
||||
* 读取路由
|
||||
* @access public
|
||||
* @param string $rule 路由规则
|
||||
* @return RuleItem[]
|
||||
*/
|
||||
public function getRule(string $rule): array
|
||||
{
|
||||
return $this->ruleName->getRule($rule);
|
||||
}
|
||||
|
||||
/**
|
||||
* 读取路由列表
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function getRuleList(): array
|
||||
{
|
||||
return $this->ruleName->getRuleList();
|
||||
}
|
||||
|
||||
/**
|
||||
* 清空路由规则
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function clear(): void
|
||||
{
|
||||
$this->ruleName->clear();
|
||||
|
||||
if ($this->group) {
|
||||
$this->group->clear();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册路由规则
|
||||
* @access public
|
||||
* @param string $rule 路由规则
|
||||
* @param mixed $route 路由地址
|
||||
* @param string $method 请求类型
|
||||
* @return RuleItem
|
||||
*/
|
||||
public function rule(string $rule, $route = null, string $method = '*'): RuleItem
|
||||
{
|
||||
return $this->group->addRule($rule, $route, $method);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置路由规则全局有效
|
||||
* @access public
|
||||
* @param Rule $rule 路由规则
|
||||
* @return $this
|
||||
*/
|
||||
public function setCrossDomainRule(Rule $rule)
|
||||
{
|
||||
if (!isset($this->cross)) {
|
||||
$this->cross = (new RuleGroup($this))->mergeRuleRegex($this->mergeRuleRegex);
|
||||
}
|
||||
|
||||
$this->cross->addRuleItem($rule);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册路由分组
|
||||
* @access public
|
||||
* @param string|Closure $name 分组名称或者参数
|
||||
* @param mixed $route 分组路由
|
||||
* @return RuleGroup
|
||||
*/
|
||||
public function group(string | Closure $name, $route = null): RuleGroup
|
||||
{
|
||||
if ($name instanceof Closure) {
|
||||
$route = $name;
|
||||
$name = '';
|
||||
}
|
||||
|
||||
return (new RuleGroup($this, $this->group, $name, $route, $this->lazy))
|
||||
->removeSlash($this->removeSlash)
|
||||
->mergeRuleRegex($this->mergeRuleRegex);
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册路由
|
||||
* @access public
|
||||
* @param string $rule 路由规则
|
||||
* @param mixed $route 路由地址
|
||||
* @return RuleItem
|
||||
*/
|
||||
public function any(string $rule, $route): RuleItem
|
||||
{
|
||||
return $this->rule($rule, $route, '*');
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册GET路由
|
||||
* @access public
|
||||
* @param string $rule 路由规则
|
||||
* @param mixed $route 路由地址
|
||||
* @return RuleItem
|
||||
*/
|
||||
public function get(string $rule, $route): RuleItem
|
||||
{
|
||||
return $this->rule($rule, $route, 'GET');
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册POST路由
|
||||
* @access public
|
||||
* @param string $rule 路由规则
|
||||
* @param mixed $route 路由地址
|
||||
* @return RuleItem
|
||||
*/
|
||||
public function post(string $rule, $route): RuleItem
|
||||
{
|
||||
return $this->rule($rule, $route, 'POST');
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册PUT路由
|
||||
* @access public
|
||||
* @param string $rule 路由规则
|
||||
* @param mixed $route 路由地址
|
||||
* @return RuleItem
|
||||
*/
|
||||
public function put(string $rule, $route): RuleItem
|
||||
{
|
||||
return $this->rule($rule, $route, 'PUT');
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册DELETE路由
|
||||
* @access public
|
||||
* @param string $rule 路由规则
|
||||
* @param mixed $route 路由地址
|
||||
* @return RuleItem
|
||||
*/
|
||||
public function delete(string $rule, $route): RuleItem
|
||||
{
|
||||
return $this->rule($rule, $route, 'DELETE');
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册PATCH路由
|
||||
* @access public
|
||||
* @param string $rule 路由规则
|
||||
* @param mixed $route 路由地址
|
||||
* @return RuleItem
|
||||
*/
|
||||
public function patch(string $rule, $route): RuleItem
|
||||
{
|
||||
return $this->rule($rule, $route, 'PATCH');
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册HEAD路由
|
||||
* @access public
|
||||
* @param string $rule 路由规则
|
||||
* @param mixed $route 路由地址
|
||||
* @return RuleItem
|
||||
*/
|
||||
public function head(string $rule, $route): RuleItem
|
||||
{
|
||||
return $this->rule($rule, $route, 'HEAD');
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册OPTIONS路由
|
||||
* @access public
|
||||
* @param string $rule 路由规则
|
||||
* @param mixed $route 路由地址
|
||||
* @return RuleItem
|
||||
*/
|
||||
public function options(string $rule, $route): RuleItem
|
||||
{
|
||||
return $this->rule($rule, $route, 'OPTIONS');
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册资源路由
|
||||
* @access public
|
||||
* @param string $rule 路由规则
|
||||
* @param string $route 路由地址
|
||||
* @return Resource|ResourceRegister
|
||||
*/
|
||||
public function resource(string $rule, string $route)
|
||||
{
|
||||
$resource = new Resource($this, $this->group, $rule, $route, $this->rest);
|
||||
|
||||
if (!$this->lazy) {
|
||||
return new ResourceRegister($resource);
|
||||
}
|
||||
|
||||
return $resource;
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册视图路由
|
||||
* @access public
|
||||
* @param string $rule 路由规则
|
||||
* @param string $template 路由模板地址
|
||||
* @param array $vars 模板变量
|
||||
* @return RuleItem
|
||||
*/
|
||||
public function view(string $rule, string $template = '', array $vars = []): RuleItem
|
||||
{
|
||||
return $this->rule($rule, function () use ($vars, $template) {
|
||||
return Response::create($template, 'view')->assign($vars);
|
||||
}, 'GET');
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册重定向路由
|
||||
* @access public
|
||||
* @param string $rule 路由规则
|
||||
* @param string $route 路由地址
|
||||
* @param int $status 状态码
|
||||
* @return RuleItem
|
||||
*/
|
||||
public function redirect(string $rule, string $route = '', int $status = 301): RuleItem
|
||||
{
|
||||
return $this->rule($rule, function (Request $request) use ($status, $route) {
|
||||
$search = $replace = [];
|
||||
$matches = $request->rule()->getVars();
|
||||
|
||||
foreach ($matches as $key => $value) {
|
||||
$search[] = '<' . $key . '>';
|
||||
$replace[] = $value;
|
||||
|
||||
$search[] = ':' . $key;
|
||||
$replace[] = $value;
|
||||
}
|
||||
|
||||
$route = str_replace($search, $replace, $route);
|
||||
return Response::create($route, 'redirect')->code($status);
|
||||
}, '*');
|
||||
}
|
||||
|
||||
/**
|
||||
* rest方法定义和修改
|
||||
* @access public
|
||||
* @param string|array $name 方法名称
|
||||
* @param array|bool $resource 资源
|
||||
* @return $this
|
||||
*/
|
||||
public function rest(string | array $name, array | bool $resource = [])
|
||||
{
|
||||
if (is_array($name)) {
|
||||
$this->rest = $resource ? $name : array_merge($this->rest, $name);
|
||||
} else {
|
||||
$this->rest[$name] = $resource;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取rest方法定义的参数
|
||||
* @access public
|
||||
* @param string $name 方法名称
|
||||
* @return array|null
|
||||
*/
|
||||
public function getRest(string $name = null)
|
||||
{
|
||||
if (is_null($name)) {
|
||||
return $this->rest;
|
||||
}
|
||||
|
||||
return $this->rest[$name] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册未匹配路由规则后的处理
|
||||
* @access public
|
||||
* @param string|Closure $route 路由地址
|
||||
* @param string $method 请求类型
|
||||
* @return RuleItem
|
||||
*/
|
||||
public function miss(string | Closure $route, string $method = '*'): RuleItem
|
||||
{
|
||||
return $this->group->miss($route, $method);
|
||||
}
|
||||
|
||||
/**
|
||||
* 路由调度
|
||||
* @param Request $request
|
||||
* @param Closure|bool $withRoute
|
||||
* @return Response
|
||||
*/
|
||||
public function dispatch(Request $request, Closure | bool $withRoute = true)
|
||||
{
|
||||
$this->request = $request;
|
||||
$this->host = $this->request->host(true);
|
||||
|
||||
if ($withRoute) {
|
||||
//加载路由
|
||||
if ($withRoute instanceof Closure) {
|
||||
$withRoute();
|
||||
}
|
||||
$dispatch = $this->check();
|
||||
} else {
|
||||
$dispatch = $this->url($this->path());
|
||||
}
|
||||
|
||||
$dispatch->init($this->app);
|
||||
|
||||
return $this->app->middleware->pipeline('route')
|
||||
->send($request)
|
||||
->then(function () use ($dispatch) {
|
||||
return $dispatch->run();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 检测URL路由
|
||||
* @access public
|
||||
* @return Dispatch|false
|
||||
* @throws RouteNotFoundException
|
||||
*/
|
||||
public function check()
|
||||
{
|
||||
// 自动检测域名路由
|
||||
$url = str_replace($this->config['pathinfo_depr'], '|', $this->path());
|
||||
|
||||
$completeMatch = $this->config['route_complete_match'];
|
||||
|
||||
$result = $this->checkDomain()->check($this->request, $url, $completeMatch);
|
||||
|
||||
if (false === $result && !empty($this->cross)) {
|
||||
// 检测跨域路由
|
||||
$result = $this->cross->check($this->request, $url, $completeMatch);
|
||||
}
|
||||
|
||||
if (false !== $result) {
|
||||
return $result;
|
||||
} elseif ($this->config['url_route_must']) {
|
||||
throw new RouteNotFoundException();
|
||||
}
|
||||
|
||||
return $this->url($url);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前请求URL的pathinfo信息(不含URL后缀)
|
||||
* @access protected
|
||||
* @return string
|
||||
*/
|
||||
protected function path(): string
|
||||
{
|
||||
$suffix = $this->config['url_html_suffix'];
|
||||
$pathinfo = $this->request->pathinfo();
|
||||
|
||||
if (false === $suffix) {
|
||||
// 禁止伪静态访问
|
||||
$path = $pathinfo;
|
||||
} elseif ($suffix) {
|
||||
// 去除正常的URL后缀
|
||||
$path = preg_replace('/\.(' . ltrim($suffix, '.') . ')$/i', '', $pathinfo);
|
||||
} else {
|
||||
// 允许任何后缀访问
|
||||
$path = preg_replace('/\.' . $this->request->ext() . '$/i', '', $pathinfo);
|
||||
}
|
||||
|
||||
return $path;
|
||||
}
|
||||
|
||||
/**
|
||||
* 默认URL解析
|
||||
* @access public
|
||||
* @param string $url URL地址
|
||||
* @return Dispatch
|
||||
*/
|
||||
public function url(string $url): Dispatch
|
||||
{
|
||||
if ($this->request->method() == 'OPTIONS') {
|
||||
// 自动响应options请求
|
||||
return new Callback($this->request, $this->group, function () {
|
||||
return Response::create('', 'html', 204)->header(['Allow' => 'GET, POST, PUT, DELETE']);
|
||||
});
|
||||
}
|
||||
|
||||
return new UrlDispatch($this->request, $this->group, $url);
|
||||
}
|
||||
|
||||
/**
|
||||
* 检测域名的路由规则
|
||||
* @access protected
|
||||
* @return Domain
|
||||
*/
|
||||
protected function checkDomain(): Domain
|
||||
{
|
||||
$item = false;
|
||||
|
||||
if (count($this->domains) > 1) {
|
||||
// 获取当前子域名
|
||||
$subDomain = $this->request->subDomain();
|
||||
|
||||
$domain = $subDomain ? explode('.', $subDomain) : [];
|
||||
$domain2 = $domain ? array_pop($domain) : '';
|
||||
|
||||
if ($domain) {
|
||||
// 存在三级域名
|
||||
$domain3 = array_pop($domain);
|
||||
}
|
||||
|
||||
if (isset($this->domains[$this->host])) {
|
||||
// 子域名配置
|
||||
$item = $this->domains[$this->host];
|
||||
} elseif (isset($this->domains[$subDomain])) {
|
||||
$item = $this->domains[$subDomain];
|
||||
} elseif (isset($this->domains['*.' . $domain2]) && !empty($domain3)) {
|
||||
// 泛三级域名
|
||||
$item = $this->domains['*.' . $domain2];
|
||||
$panDomain = $domain3;
|
||||
} elseif (isset($this->domains['*']) && !empty($domain2)) {
|
||||
// 泛二级域名
|
||||
if ('www' != $domain2) {
|
||||
$item = $this->domains['*'];
|
||||
$panDomain = $domain2;
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($panDomain)) {
|
||||
// 保存当前泛域名
|
||||
$this->request->setPanDomain($panDomain);
|
||||
}
|
||||
}
|
||||
|
||||
if (false === $item) {
|
||||
// 检测全局域名规则
|
||||
$item = $this->domains['-'];
|
||||
}
|
||||
|
||||
if (is_string($item)) {
|
||||
$item = $this->domains[$item];
|
||||
}
|
||||
|
||||
return $item;
|
||||
}
|
||||
|
||||
/**
|
||||
* URL生成 支持路由反射
|
||||
* @access public
|
||||
* @param string $url 路由地址
|
||||
* @param array $vars 参数 ['a'=>'val1', 'b'=>'val2']
|
||||
* @return UrlBuild
|
||||
*/
|
||||
public function buildUrl(string $url = '', array $vars = []): UrlBuild
|
||||
{
|
||||
return $this->app->make(UrlBuild::class, [$this, $this->app, $url, $vars], true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置全局的路由分组参数
|
||||
* @access public
|
||||
* @param string $method 方法名
|
||||
* @param array $args 调用参数
|
||||
* @return RuleGroup
|
||||
*/
|
||||
public function __call($method, $args)
|
||||
{
|
||||
return call_user_func_array([$this->group, $method], $args);
|
||||
}
|
||||
}
|
||||
63
vendor/topthink/framework/src/think/Service.php
vendored
Normal file
63
vendor/topthink/framework/src/think/Service.php
vendored
Normal file
@@ -0,0 +1,63 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2023 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: yunwuxin <448901948@qq.com>
|
||||
// +----------------------------------------------------------------------
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace think;
|
||||
|
||||
use Closure;
|
||||
use think\event\RouteLoaded;
|
||||
|
||||
/**
|
||||
* 系统服务基础类
|
||||
* @method void register()
|
||||
* @method void boot()
|
||||
*/
|
||||
abstract class Service
|
||||
{
|
||||
public function __construct(protected App $app)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载路由
|
||||
* @access protected
|
||||
* @param string $path 路由路径
|
||||
*/
|
||||
protected function loadRoutesFrom(string $path)
|
||||
{
|
||||
$this->registerRoutes(function () use ($path) {
|
||||
include $path;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册路由
|
||||
* @param Closure $closure
|
||||
*/
|
||||
protected function registerRoutes(Closure $closure)
|
||||
{
|
||||
$this->app->event->listen(RouteLoaded::class, $closure);
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加指令
|
||||
* @access protected
|
||||
* @param array|string $commands 指令
|
||||
*/
|
||||
protected function commands($commands)
|
||||
{
|
||||
$commands = is_array($commands) ? $commands : func_get_args();
|
||||
|
||||
Console::starting(function (Console $console) use ($commands) {
|
||||
$console->addCommands($commands);
|
||||
});
|
||||
}
|
||||
}
|
||||
65
vendor/topthink/framework/src/think/Session.php
vendored
Normal file
65
vendor/topthink/framework/src/think/Session.php
vendored
Normal file
@@ -0,0 +1,65 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2023 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace think;
|
||||
|
||||
use think\helper\Arr;
|
||||
use think\session\Store;
|
||||
|
||||
/**
|
||||
* Session管理类
|
||||
* @package think
|
||||
* @mixin Store
|
||||
*/
|
||||
class Session extends Manager
|
||||
{
|
||||
protected $namespace = '\\think\\session\\driver\\';
|
||||
|
||||
protected function createDriver(string $name)
|
||||
{
|
||||
$handler = parent::createDriver($name);
|
||||
|
||||
return new Store($this->getConfig('name') ?: 'PHPSESSID', $handler, $this->getConfig('serialize'));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取Session配置
|
||||
* @access public
|
||||
* @param null|string $name 名称
|
||||
* @param mixed $default 默认值
|
||||
* @return mixed
|
||||
*/
|
||||
public function getConfig(string $name = null, $default = null)
|
||||
{
|
||||
if (!is_null($name)) {
|
||||
return $this->app->config->get('session.' . $name, $default);
|
||||
}
|
||||
|
||||
return $this->app->config->get('session');
|
||||
}
|
||||
|
||||
protected function resolveConfig(string $name)
|
||||
{
|
||||
$config = $this->app->config->get('session', []);
|
||||
Arr::forget($config, 'type');
|
||||
return $config;
|
||||
}
|
||||
|
||||
/**
|
||||
* 默认驱动
|
||||
* @return string|null
|
||||
*/
|
||||
public function getDefaultDriver()
|
||||
{
|
||||
return $this->app->config->get('session.type', 'file');
|
||||
}
|
||||
}
|
||||
1698
vendor/topthink/framework/src/think/Validate.php
vendored
Normal file
1698
vendor/topthink/framework/src/think/Validate.php
vendored
Normal file
File diff suppressed because it is too large
Load Diff
187
vendor/topthink/framework/src/think/View.php
vendored
Normal file
187
vendor/topthink/framework/src/think/View.php
vendored
Normal file
@@ -0,0 +1,187 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2023 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace think;
|
||||
|
||||
use think\contract\TemplateHandlerInterface;
|
||||
use think\helper\Arr;
|
||||
|
||||
/**
|
||||
* 视图类
|
||||
* @package think
|
||||
*/
|
||||
class View extends Manager
|
||||
{
|
||||
|
||||
protected $namespace = '\\think\\view\\driver\\';
|
||||
|
||||
/**
|
||||
* 模板变量
|
||||
* @var array
|
||||
*/
|
||||
protected $data = [];
|
||||
|
||||
/**
|
||||
* 内容过滤
|
||||
* @var mixed
|
||||
*/
|
||||
protected $filter;
|
||||
|
||||
/**
|
||||
* 获取模板引擎
|
||||
* @access public
|
||||
* @param string $type 模板引擎类型
|
||||
* @return TemplateHandlerInterface
|
||||
*/
|
||||
public function engine(string $type = null)
|
||||
{
|
||||
return $this->driver($type);
|
||||
}
|
||||
|
||||
/**
|
||||
* 模板变量赋值
|
||||
* @access public
|
||||
* @param string|array $name 模板变量
|
||||
* @param mixed $value 变量值
|
||||
* @return $this
|
||||
*/
|
||||
public function assign(string|array $name, $value = null)
|
||||
{
|
||||
if (is_array($name)) {
|
||||
$this->data = array_merge($this->data, $name);
|
||||
} else {
|
||||
$this->data[$name] = $value;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 视图过滤
|
||||
* @access public
|
||||
* @param Callable $filter 过滤方法或闭包
|
||||
* @return $this
|
||||
*/
|
||||
public function filter(callable $filter = null)
|
||||
{
|
||||
$this->filter = $filter;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析和获取模板内容 用于输出
|
||||
* @access public
|
||||
* @param string $template 模板文件名或者内容
|
||||
* @param array $vars 模板变量
|
||||
* @return string
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function fetch(string $template = '', array $vars = []): string
|
||||
{
|
||||
return $this->getContent(function () use ($vars, $template) {
|
||||
$this->engine()->fetch($template, array_merge($this->data, $vars));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 渲染内容输出
|
||||
* @access public
|
||||
* @param string $content 内容
|
||||
* @param array $vars 模板变量
|
||||
* @return string
|
||||
*/
|
||||
public function display(string $content, array $vars = []): string
|
||||
{
|
||||
return $this->getContent(function () use ($vars, $content) {
|
||||
$this->engine()->display($content, array_merge($this->data, $vars));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取模板引擎渲染内容
|
||||
* @param $callback
|
||||
* @return string
|
||||
* @throws \Exception
|
||||
*/
|
||||
protected function getContent($callback): string
|
||||
{
|
||||
// 页面缓存
|
||||
ob_start();
|
||||
ob_implicit_flush(false);
|
||||
|
||||
// 渲染输出
|
||||
try {
|
||||
$callback();
|
||||
} catch (\Exception $e) {
|
||||
ob_end_clean();
|
||||
throw $e;
|
||||
}
|
||||
|
||||
// 获取并清空缓存
|
||||
$content = ob_get_clean();
|
||||
|
||||
if ($this->filter) {
|
||||
$content = call_user_func_array($this->filter, [$content]);
|
||||
}
|
||||
|
||||
return $content;
|
||||
}
|
||||
|
||||
/**
|
||||
* 模板变量赋值
|
||||
* @access public
|
||||
* @param string $name 变量名
|
||||
* @param mixed $value 变量值
|
||||
*/
|
||||
public function __set($name, $value)
|
||||
{
|
||||
$this->data[$name] = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* 取得模板显示变量的值
|
||||
* @access protected
|
||||
* @param string $name 模板变量
|
||||
* @return mixed
|
||||
*/
|
||||
public function __get($name)
|
||||
{
|
||||
return $this->data[$name];
|
||||
}
|
||||
|
||||
/**
|
||||
* 检测模板变量是否设置
|
||||
* @access public
|
||||
* @param string $name 模板变量名
|
||||
* @return bool
|
||||
*/
|
||||
public function __isset($name)
|
||||
{
|
||||
return isset($this->data[$name]);
|
||||
}
|
||||
|
||||
protected function resolveConfig(string $name)
|
||||
{
|
||||
$config = $this->app->config->get('view', []);
|
||||
Arr::forget($config, 'type');
|
||||
return $config;
|
||||
}
|
||||
|
||||
/**
|
||||
* 默认驱动
|
||||
* @return string|null
|
||||
*/
|
||||
public function getDefaultDriver()
|
||||
{
|
||||
return $this->app->config->get('view.type', 'php');
|
||||
}
|
||||
}
|
||||
360
vendor/topthink/framework/src/think/cache/Driver.php
vendored
Normal file
360
vendor/topthink/framework/src/think/cache/Driver.php
vendored
Normal file
@@ -0,0 +1,360 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2023 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
declare (strict_types = 1);
|
||||
|
||||
namespace think\cache;
|
||||
|
||||
use Closure;
|
||||
use DateInterval;
|
||||
use DateTime;
|
||||
use DateTimeInterface;
|
||||
use Exception;
|
||||
use think\Container;
|
||||
use think\contract\CacheHandlerInterface;
|
||||
use think\exception\InvalidArgumentException;
|
||||
use throwable;
|
||||
|
||||
/**
|
||||
* 缓存基础类
|
||||
*/
|
||||
abstract class Driver implements CacheHandlerInterface
|
||||
{
|
||||
/**
|
||||
* 驱动句柄
|
||||
* @var object
|
||||
*/
|
||||
protected $handler = null;
|
||||
|
||||
/**
|
||||
* 缓存读取次数
|
||||
* @var integer
|
||||
*/
|
||||
protected $readTimes = 0;
|
||||
|
||||
/**
|
||||
* 缓存写入次数
|
||||
* @var integer
|
||||
*/
|
||||
protected $writeTimes = 0;
|
||||
|
||||
/**
|
||||
* 缓存参数
|
||||
* @var array
|
||||
*/
|
||||
protected $options = [];
|
||||
|
||||
/**
|
||||
* 缓存标签
|
||||
* @var array
|
||||
*/
|
||||
protected $tag = [];
|
||||
|
||||
/**
|
||||
* 获取有效期
|
||||
* @access protected
|
||||
* @param integer|DateInterval|DateTimeInterface $expire 有效期
|
||||
* @return int
|
||||
*/
|
||||
protected function getExpireTime(int|DateInterval|DateTimeInterface $expire): int
|
||||
{
|
||||
if ($expire instanceof DateTimeInterface) {
|
||||
$expire = $expire->getTimestamp() - time();
|
||||
} elseif ($expire instanceof DateInterval) {
|
||||
$expire = DateTime::createFromFormat('U', (string) time())
|
||||
->add($expire)
|
||||
->format('U') - time();
|
||||
}
|
||||
|
||||
return $expire;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取实际的缓存标识
|
||||
* @access public
|
||||
* @param string $name 缓存名
|
||||
* @return string
|
||||
*/
|
||||
public function getCacheKey(string $name): string
|
||||
{
|
||||
return $this->options['prefix'] . $name;
|
||||
}
|
||||
|
||||
/**
|
||||
* 读取缓存并删除
|
||||
* @access public
|
||||
* @param string $name 缓存变量名
|
||||
* @return mixed
|
||||
*/
|
||||
public function pull($name)
|
||||
{
|
||||
$result = $this->get($name, false);
|
||||
|
||||
if ($result) {
|
||||
$this->delete($name);
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 追加(数组)缓存
|
||||
* @access public
|
||||
* @param string $name 缓存变量名
|
||||
* @param mixed $value 存储数据
|
||||
* @return void
|
||||
*/
|
||||
public function push($name, $value): void
|
||||
{
|
||||
$item = $this->get($name, []);
|
||||
|
||||
if (!is_array($item)) {
|
||||
throw new InvalidArgumentException('only array cache can be push');
|
||||
}
|
||||
|
||||
$item[] = $value;
|
||||
|
||||
if (count($item) > 1000) {
|
||||
array_shift($item);
|
||||
}
|
||||
|
||||
$item = array_unique($item);
|
||||
|
||||
$this->set($name, $item);
|
||||
}
|
||||
|
||||
/**
|
||||
* 追加TagSet数据
|
||||
* @access public
|
||||
* @param string $name 缓存变量名
|
||||
* @param mixed $value 存储数据
|
||||
* @return void
|
||||
*/
|
||||
public function append($name, $value): void
|
||||
{
|
||||
$this->push($name, $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* 如果不存在则写入缓存
|
||||
* @access public
|
||||
* @param string $name 缓存变量名
|
||||
* @param mixed $value 存储数据
|
||||
* @param int|DateInterval|DateTimeInterface $expire 有效时间 0为永久
|
||||
* @return mixed
|
||||
*/
|
||||
public function remember($name, $value, $expire = null)
|
||||
{
|
||||
if ($this->has($name)) {
|
||||
if (($hit = $this->get($name)) !== null) {
|
||||
return $hit;
|
||||
}
|
||||
}
|
||||
|
||||
$time = time();
|
||||
|
||||
while ($time + 5 > time() && $this->has($name . '_lock')) {
|
||||
// 存在锁定则等待
|
||||
usleep(200000);
|
||||
}
|
||||
|
||||
try {
|
||||
// 锁定
|
||||
$this->set($name . '_lock', true);
|
||||
|
||||
if ($value instanceof Closure) {
|
||||
// 获取缓存数据
|
||||
$value = Container::getInstance()->invokeFunction($value);
|
||||
}
|
||||
|
||||
// 缓存数据
|
||||
$this->set($name, $value, $expire);
|
||||
|
||||
// 解锁
|
||||
$this->delete($name . '_lock');
|
||||
} catch (Exception|throwable $e) {
|
||||
$this->delete($name . '_lock');
|
||||
throw $e;
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* 缓存标签
|
||||
* @access public
|
||||
* @param string|array $name 标签名
|
||||
* @return TagSet
|
||||
*/
|
||||
public function tag($name)
|
||||
{
|
||||
$name = (array) $name;
|
||||
$key = implode('-', $name);
|
||||
|
||||
if (!isset($this->tag[$key])) {
|
||||
$this->tag[$key] = new TagSet($name, $this);
|
||||
}
|
||||
|
||||
return $this->tag[$key];
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取标签包含的缓存标识
|
||||
* @access public
|
||||
* @param string $tag 标签标识
|
||||
* @return array
|
||||
*/
|
||||
public function getTagItems(string $tag): array
|
||||
{
|
||||
$name = $this->getTagKey($tag);
|
||||
return $this->get($name, []);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取实际标签名
|
||||
* @access public
|
||||
* @param string $tag 标签名
|
||||
* @return string
|
||||
*/
|
||||
public function getTagKey(string $tag): string
|
||||
{
|
||||
return $this->options['tag_prefix'] . md5($tag);
|
||||
}
|
||||
|
||||
/**
|
||||
* 序列化数据
|
||||
* @access protected
|
||||
* @param mixed $data 缓存数据
|
||||
* @return string
|
||||
*/
|
||||
protected function serialize($data): string
|
||||
{
|
||||
if (is_numeric($data)) {
|
||||
return (string) $data;
|
||||
}
|
||||
|
||||
$serialize = $this->options['serialize'][0] ?? "serialize";
|
||||
|
||||
return $serialize($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 反序列化数据
|
||||
* @access protected
|
||||
* @param string $data 缓存数据
|
||||
* @return mixed
|
||||
*/
|
||||
protected function unserialize(string $data)
|
||||
{
|
||||
if (is_numeric($data)) {
|
||||
return $data;
|
||||
}
|
||||
|
||||
$unserialize = $this->options['serialize'][1] ?? "unserialize";
|
||||
|
||||
return $unserialize($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回句柄对象,可执行其它高级方法
|
||||
*
|
||||
* @access public
|
||||
* @return object
|
||||
*/
|
||||
public function handler()
|
||||
{
|
||||
return $this->handler;
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回缓存读取次数
|
||||
* @return int
|
||||
* @deprecated
|
||||
* @access public
|
||||
*/
|
||||
public function getReadTimes(): int
|
||||
{
|
||||
return $this->readTimes;
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回缓存写入次数
|
||||
* @return int
|
||||
* @deprecated
|
||||
* @access public
|
||||
*/
|
||||
public function getWriteTimes(): int
|
||||
{
|
||||
return $this->writeTimes;
|
||||
}
|
||||
|
||||
/**
|
||||
* 读取缓存
|
||||
* @access public
|
||||
* @param iterable $keys 缓存变量名
|
||||
* @param mixed $default 默认值
|
||||
* @return iterable
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
public function getMultiple($keys, $default = null): iterable
|
||||
{
|
||||
$result = [];
|
||||
|
||||
foreach ($keys as $key) {
|
||||
$result[$key] = $this->get($key, $default);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 写入缓存
|
||||
* @access public
|
||||
* @param iterable $values 缓存数据
|
||||
* @param null|int|\DateInterval|DateTimeInterface $ttl 有效时间 0为永久
|
||||
* @return bool
|
||||
*/
|
||||
public function setMultiple($values, $ttl = null): bool
|
||||
{
|
||||
foreach ($values as $key => $val) {
|
||||
$result = $this->set($key, $val, $ttl);
|
||||
|
||||
if (false === $result) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除缓存
|
||||
* @access public
|
||||
* @param iterable $keys 缓存变量名
|
||||
* @return bool
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
public function deleteMultiple($keys): bool
|
||||
{
|
||||
foreach ($keys as $key) {
|
||||
$result = $this->delete($key);
|
||||
|
||||
if (false === $result) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function __call($method, $args)
|
||||
{
|
||||
return call_user_func_array([$this->handler, $method], $args);
|
||||
}
|
||||
}
|
||||
121
vendor/topthink/framework/src/think/cache/TagSet.php
vendored
Normal file
121
vendor/topthink/framework/src/think/cache/TagSet.php
vendored
Normal file
@@ -0,0 +1,121 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2023 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
declare(strict_types = 1);
|
||||
|
||||
namespace think\cache;
|
||||
|
||||
use DateInterval;
|
||||
use DateTimeInterface;
|
||||
|
||||
/**
|
||||
* 标签集合
|
||||
*/
|
||||
class TagSet
|
||||
{
|
||||
/**
|
||||
* 架构函数
|
||||
* @access public
|
||||
* @param array $tag 缓存标签
|
||||
* @param Driver $handler 缓存对象
|
||||
*/
|
||||
public function __construct(protected array $tag, protected Driver $handler)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* 写入缓存
|
||||
* @access public
|
||||
* @param string $name 缓存变量名
|
||||
* @param mixed $value 存储数据
|
||||
* @param integer|DateInterval|DateTimeInterface $expire 有效时间(秒)
|
||||
* @return bool
|
||||
*/
|
||||
public function set($name, $value, $expire = null): bool
|
||||
{
|
||||
$this->handler->set($name, $value, $expire);
|
||||
|
||||
$this->append($name);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 追加缓存标识到标签
|
||||
* @access public
|
||||
* @param string $name 缓存变量名
|
||||
* @return void
|
||||
*/
|
||||
public function append(string $name): void
|
||||
{
|
||||
$name = $this->handler->getCacheKey($name);
|
||||
|
||||
foreach ($this->tag as $tag) {
|
||||
$key = $this->handler->getTagKey($tag);
|
||||
$this->handler->append($key, $name);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 写入缓存
|
||||
* @access public
|
||||
* @param iterable $values 缓存数据
|
||||
* @param null|int|DateInterval|DateTimeInterface $ttl 有效时间 0为永久
|
||||
* @return bool
|
||||
*/
|
||||
public function setMultiple($values, $ttl = null): bool
|
||||
{
|
||||
foreach ($values as $key => $val) {
|
||||
$result = $this->set($key, $val, $ttl);
|
||||
|
||||
if (false === $result) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 如果不存在则写入缓存
|
||||
* @access public
|
||||
* @param string $name 缓存变量名
|
||||
* @param mixed $value 存储数据
|
||||
* @param int $expire 有效时间 0为永久
|
||||
* @return mixed
|
||||
*/
|
||||
public function remember($name, $value, $expire = null)
|
||||
{
|
||||
$result = $this->handler->remember($name, $value, $expire);
|
||||
|
||||
$this->append($name);
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除缓存
|
||||
* @access public
|
||||
* @return bool
|
||||
*/
|
||||
public function clear(): bool
|
||||
{
|
||||
// 指定标签清除
|
||||
foreach ($this->tag as $tag) {
|
||||
$keys = $this->handler->getTagItems($tag);
|
||||
if (!empty($keys)) $this->handler->clearTag($keys);
|
||||
|
||||
$key = $this->handler->getTagKey($tag);
|
||||
$this->handler->delete($key);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
302
vendor/topthink/framework/src/think/cache/driver/File.php
vendored
Normal file
302
vendor/topthink/framework/src/think/cache/driver/File.php
vendored
Normal file
@@ -0,0 +1,302 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2023 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
declare (strict_types = 1);
|
||||
|
||||
namespace think\cache\driver;
|
||||
|
||||
use DateTimeInterface;
|
||||
use FilesystemIterator;
|
||||
use think\App;
|
||||
use think\cache\Driver;
|
||||
|
||||
/**
|
||||
* 文件缓存类
|
||||
*/
|
||||
class File extends Driver
|
||||
{
|
||||
/**
|
||||
* 配置参数
|
||||
* @var array
|
||||
*/
|
||||
protected $options = [
|
||||
'expire' => 0,
|
||||
'cache_subdir' => true,
|
||||
'prefix' => '',
|
||||
'path' => '',
|
||||
'hash_type' => 'md5',
|
||||
'data_compress' => false,
|
||||
'tag_prefix' => 'tag:',
|
||||
'serialize' => [],
|
||||
];
|
||||
|
||||
/**
|
||||
* 架构函数
|
||||
* @param App $app
|
||||
* @param array $options 参数
|
||||
*/
|
||||
public function __construct(App $app, array $options = [])
|
||||
{
|
||||
if (!empty($options)) {
|
||||
$this->options = array_merge($this->options, $options);
|
||||
}
|
||||
|
||||
if (empty($this->options['path'])) {
|
||||
$this->options['path'] = $app->getRuntimePath() . 'cache';
|
||||
}
|
||||
|
||||
if (!str_ends_with($this->options['path'], DIRECTORY_SEPARATOR)) {
|
||||
$this->options['path'] .= DIRECTORY_SEPARATOR;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 取得变量的存储文件名
|
||||
* @access public
|
||||
* @param string $name 缓存变量名
|
||||
* @return string
|
||||
*/
|
||||
public function getCacheKey(string $name): string
|
||||
{
|
||||
$name = hash($this->options['hash_type'], $name);
|
||||
|
||||
if ($this->options['cache_subdir']) {
|
||||
// 使用子目录
|
||||
$name = substr($name, 0, 2) . DIRECTORY_SEPARATOR . substr($name, 2);
|
||||
}
|
||||
|
||||
if ($this->options['prefix']) {
|
||||
$name = $this->options['prefix'] . DIRECTORY_SEPARATOR . $name;
|
||||
}
|
||||
|
||||
return $this->options['path'] . $name . '.php';
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取缓存数据
|
||||
* @param string $name 缓存标识名
|
||||
* @return array|null
|
||||
*/
|
||||
protected function getRaw(string $name)
|
||||
{
|
||||
$filename = $this->getCacheKey($name);
|
||||
|
||||
if (!is_file($filename)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$content = @file_get_contents($filename);
|
||||
|
||||
if (false !== $content) {
|
||||
$expire = (int) substr($content, 8, 12);
|
||||
if (0 != $expire && time() - $expire > filemtime($filename)) {
|
||||
//缓存过期删除缓存文件
|
||||
$this->unlink($filename);
|
||||
return;
|
||||
}
|
||||
|
||||
$content = substr($content, 32);
|
||||
|
||||
if ($this->options['data_compress'] && function_exists('gzcompress')) {
|
||||
//启用数据压缩
|
||||
$content = gzuncompress($content);
|
||||
}
|
||||
|
||||
return is_string($content) ? ['content' => (string) $content, 'expire' => $expire] : null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断缓存是否存在
|
||||
* @access public
|
||||
* @param string $name 缓存变量名
|
||||
* @return bool
|
||||
*/
|
||||
public function has($name): bool
|
||||
{
|
||||
return $this->getRaw($name) !== null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 读取缓存
|
||||
* @access public
|
||||
* @param string $name 缓存变量名
|
||||
* @param mixed $default 默认值
|
||||
* @return mixed
|
||||
*/
|
||||
public function get($name, $default = null): mixed
|
||||
{
|
||||
$raw = $this->getRaw($name);
|
||||
|
||||
return is_null($raw) ? $default : $this->unserialize($raw['content']);
|
||||
}
|
||||
|
||||
/**
|
||||
* 写入缓存
|
||||
* @access public
|
||||
* @param string $name 缓存变量名
|
||||
* @param mixed $value 存储数据
|
||||
* @param int|\DateInterval|DateTimeInterface|null $expire 有效时间 0为永久
|
||||
* @return bool
|
||||
*/
|
||||
public function set($name, $value, $expire = null): bool
|
||||
{
|
||||
if (is_null($expire)) {
|
||||
$expire = $this->options['expire'];
|
||||
}
|
||||
|
||||
$expire = $this->getExpireTime($expire);
|
||||
$filename = $this->getCacheKey($name);
|
||||
|
||||
$dir = dirname($filename);
|
||||
|
||||
if (!is_dir($dir)) {
|
||||
try {
|
||||
mkdir($dir, 0755, true);
|
||||
} catch (\Exception $e) {
|
||||
// 创建失败
|
||||
}
|
||||
}
|
||||
|
||||
$data = $this->serialize($value);
|
||||
|
||||
if ($this->options['data_compress'] && function_exists('gzcompress')) {
|
||||
//数据压缩
|
||||
$data = gzcompress($data, 3);
|
||||
}
|
||||
|
||||
$data = "<?php\n//" . sprintf('%012d', $expire) . "\n exit();?>\n" . $data;
|
||||
|
||||
if (str_contains($filename, '://') && !str_starts_with($filename, 'file://')) {
|
||||
//虚拟文件不加锁
|
||||
$result = file_put_contents($filename, $data);
|
||||
} else {
|
||||
$result = file_put_contents($filename, $data, LOCK_EX);
|
||||
}
|
||||
|
||||
if ($result) {
|
||||
clearstatcache();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 自增缓存(针对数值缓存)
|
||||
* @access public
|
||||
* @param string $name 缓存变量名
|
||||
* @param int $step 步长
|
||||
* @return false|int
|
||||
*/
|
||||
public function inc($name, $step = 1)
|
||||
{
|
||||
if ($raw = $this->getRaw($name)) {
|
||||
$value = $this->unserialize($raw['content']) + $step;
|
||||
$expire = $raw['expire'];
|
||||
} else {
|
||||
$value = $step;
|
||||
$expire = 0;
|
||||
}
|
||||
|
||||
return $this->set($name, $value, $expire) ? $value : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 自减缓存(针对数值缓存)
|
||||
* @access public
|
||||
* @param string $name 缓存变量名
|
||||
* @param int $step 步长
|
||||
* @return false|int
|
||||
*/
|
||||
public function dec($name, $step = 1)
|
||||
{
|
||||
return $this->inc($name, -$step);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除缓存
|
||||
* @access public
|
||||
* @param string $name 缓存变量名
|
||||
* @return bool
|
||||
*/
|
||||
public function delete($name): bool
|
||||
{
|
||||
return $this->unlink($this->getCacheKey($name));
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除缓存
|
||||
* @access public
|
||||
* @return bool
|
||||
*/
|
||||
public function clear(): bool
|
||||
{
|
||||
$dirname = $this->options['path'] . $this->options['prefix'];
|
||||
|
||||
$this->rmdir($dirname);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除缓存标签
|
||||
* @access public
|
||||
* @param array $keys 缓存标识列表
|
||||
* @return void
|
||||
*/
|
||||
public function clearTag($keys): void
|
||||
{
|
||||
foreach ($keys as $key) {
|
||||
$this->unlink($key);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断文件是否存在后,删除
|
||||
* @access private
|
||||
* @param string $path
|
||||
* @return bool
|
||||
*/
|
||||
private function unlink(string $path): bool
|
||||
{
|
||||
try {
|
||||
return is_file($path) && unlink($path);
|
||||
} catch (\Exception $e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除文件夹
|
||||
* @param $dirname
|
||||
* @return bool
|
||||
*/
|
||||
private function rmdir($dirname)
|
||||
{
|
||||
if (!is_dir($dirname)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$items = new FilesystemIterator($dirname);
|
||||
|
||||
foreach ($items as $item) {
|
||||
if ($item->isDir() && !$item->isLink()) {
|
||||
$this->rmdir($item->getPathname());
|
||||
} else {
|
||||
$this->unlink($item->getPathname());
|
||||
}
|
||||
}
|
||||
|
||||
@rmdir($dirname);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
198
vendor/topthink/framework/src/think/cache/driver/Memcache.php
vendored
Normal file
198
vendor/topthink/framework/src/think/cache/driver/Memcache.php
vendored
Normal file
@@ -0,0 +1,198 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2023 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
declare (strict_types = 1);
|
||||
|
||||
namespace think\cache\driver;
|
||||
|
||||
use DateInterval;
|
||||
use DateTimeInterface;
|
||||
use think\cache\Driver;
|
||||
|
||||
/**
|
||||
* Memcache缓存类
|
||||
*/
|
||||
class Memcache extends Driver
|
||||
{
|
||||
/**
|
||||
* 配置参数
|
||||
* @var array
|
||||
*/
|
||||
protected $options = [
|
||||
'host' => '127.0.0.1',
|
||||
'port' => 11211,
|
||||
'expire' => 0,
|
||||
'timeout' => 0, // 超时时间(单位:毫秒)
|
||||
'persistent' => true,
|
||||
'prefix' => '',
|
||||
'tag_prefix' => 'tag:',
|
||||
'serialize' => [],
|
||||
];
|
||||
|
||||
/**
|
||||
* 架构函数
|
||||
* @access public
|
||||
* @param array $options 缓存参数
|
||||
* @throws \BadFunctionCallException
|
||||
*/
|
||||
public function __construct(array $options = [])
|
||||
{
|
||||
if (!extension_loaded('memcache')) {
|
||||
throw new \BadFunctionCallException('not support: memcache');
|
||||
}
|
||||
|
||||
if (!empty($options)) {
|
||||
$this->options = array_merge($this->options, $options);
|
||||
}
|
||||
|
||||
$this->handler = new \Memcache;
|
||||
|
||||
// 支持集群
|
||||
$hosts = (array) $this->options['host'];
|
||||
$ports = (array) $this->options['port'];
|
||||
|
||||
if (empty($ports[0])) {
|
||||
$ports[0] = 11211;
|
||||
}
|
||||
|
||||
// 建立连接
|
||||
foreach ($hosts as $i => $host) {
|
||||
$port = $ports[$i] ?? $ports[0];
|
||||
$this->options['timeout'] > 0 ?
|
||||
$this->handler->addServer($host, (int) $port, $this->options['persistent'], 1, (int) $this->options['timeout']) :
|
||||
$this->handler->addServer($host, (int) $port, $this->options['persistent'], 1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断缓存
|
||||
* @access public
|
||||
* @param string $name 缓存变量名
|
||||
* @return bool
|
||||
*/
|
||||
public function has($name): bool
|
||||
{
|
||||
$key = $this->getCacheKey($name);
|
||||
|
||||
return false !== $this->handler->get($key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 读取缓存
|
||||
* @access public
|
||||
* @param string $name 缓存变量名
|
||||
* @param mixed $default 默认值
|
||||
* @return mixed
|
||||
*/
|
||||
public function get($name, $default = null): mixed
|
||||
{
|
||||
$result = $this->handler->get($this->getCacheKey($name));
|
||||
|
||||
return false !== $result ? $this->unserialize($result) : $default;
|
||||
}
|
||||
|
||||
/**
|
||||
* 写入缓存
|
||||
* @access public
|
||||
* @param string $name 缓存变量名
|
||||
* @param mixed $value 存储数据
|
||||
* @param int|DateTimeInterface|DateInterval $expire 有效时间(秒)
|
||||
* @return bool
|
||||
*/
|
||||
public function set($name, $value, $expire = null): bool
|
||||
{
|
||||
if (is_null($expire)) {
|
||||
$expire = $this->options['expire'];
|
||||
}
|
||||
|
||||
$key = $this->getCacheKey($name);
|
||||
$expire = $this->getExpireTime($expire);
|
||||
$value = $this->serialize($value);
|
||||
|
||||
if ($this->handler->set($key, $value, 0, $expire)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 自增缓存(针对数值缓存)
|
||||
* @access public
|
||||
* @param string $name 缓存变量名
|
||||
* @param int $step 步长
|
||||
* @return false|int
|
||||
*/
|
||||
public function inc($name, $step = 1)
|
||||
{
|
||||
$key = $this->getCacheKey($name);
|
||||
|
||||
if ($this->handler->get($key)) {
|
||||
return $this->handler->increment($key, $step);
|
||||
}
|
||||
|
||||
return $this->handler->set($key, $step);
|
||||
}
|
||||
|
||||
/**
|
||||
* 自减缓存(针对数值缓存)
|
||||
* @access public
|
||||
* @param string $name 缓存变量名
|
||||
* @param int $step 步长
|
||||
* @return false|int
|
||||
*/
|
||||
public function dec($name, $step = 1)
|
||||
{
|
||||
$key = $this->getCacheKey($name);
|
||||
$value = $this->handler->get($key) - $step;
|
||||
$res = $this->handler->set($key, $value);
|
||||
|
||||
return !$res ? false : $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除缓存
|
||||
* @access public
|
||||
* @param string $name 缓存变量名
|
||||
* @param bool|false $ttl
|
||||
* @return bool
|
||||
*/
|
||||
public function delete($name, $ttl = false): bool
|
||||
{
|
||||
$key = $this->getCacheKey($name);
|
||||
|
||||
return false === $ttl ?
|
||||
$this->handler->delete($key) :
|
||||
$this->handler->delete($key, $ttl);
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除缓存
|
||||
* @access public
|
||||
* @return bool
|
||||
*/
|
||||
public function clear(): bool
|
||||
{
|
||||
return $this->handler->flush();
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除缓存标签
|
||||
* @access public
|
||||
* @param array $keys 缓存标识列表
|
||||
* @return void
|
||||
*/
|
||||
public function clearTag($keys): void
|
||||
{
|
||||
foreach ($keys as $key) {
|
||||
$this->handler->delete($key);
|
||||
}
|
||||
}
|
||||
}
|
||||
210
vendor/topthink/framework/src/think/cache/driver/Memcached.php
vendored
Normal file
210
vendor/topthink/framework/src/think/cache/driver/Memcached.php
vendored
Normal file
@@ -0,0 +1,210 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2023 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
declare (strict_types = 1);
|
||||
|
||||
namespace think\cache\driver;
|
||||
|
||||
use DateInterval;
|
||||
use DateTimeInterface;
|
||||
use think\cache\Driver;
|
||||
|
||||
/**
|
||||
* Memcached缓存类
|
||||
*/
|
||||
class Memcached extends Driver
|
||||
{
|
||||
/**
|
||||
* 配置参数
|
||||
* @var array
|
||||
*/
|
||||
protected $options = [
|
||||
'host' => '127.0.0.1',
|
||||
'port' => 11211,
|
||||
'expire' => 0,
|
||||
'timeout' => 0, // 超时时间(单位:毫秒)
|
||||
'prefix' => '',
|
||||
'username' => '', //账号
|
||||
'password' => '', //密码
|
||||
'option' => [],
|
||||
'tag_prefix' => 'tag:',
|
||||
'serialize' => [],
|
||||
];
|
||||
|
||||
/**
|
||||
* 架构函数
|
||||
* @access public
|
||||
* @param array $options 缓存参数
|
||||
*/
|
||||
public function __construct(array $options = [])
|
||||
{
|
||||
if (!extension_loaded('memcached')) {
|
||||
throw new \BadFunctionCallException('not support: memcached');
|
||||
}
|
||||
|
||||
if (!empty($options)) {
|
||||
$this->options = array_merge($this->options, $options);
|
||||
}
|
||||
|
||||
$this->handler = new \Memcached;
|
||||
|
||||
if (!empty($this->options['option'])) {
|
||||
$this->handler->setOptions($this->options['option']);
|
||||
}
|
||||
|
||||
// 设置连接超时时间(单位:毫秒)
|
||||
if ($this->options['timeout'] > 0) {
|
||||
$this->handler->setOption(\Memcached::OPT_CONNECT_TIMEOUT, $this->options['timeout']);
|
||||
}
|
||||
|
||||
// 支持集群
|
||||
$hosts = (array) $this->options['host'];
|
||||
$ports = (array) $this->options['port'];
|
||||
if (empty($ports[0])) {
|
||||
$ports[0] = 11211;
|
||||
}
|
||||
|
||||
// 建立连接
|
||||
$servers = [];
|
||||
foreach ($hosts as $i => $host) {
|
||||
$servers[] = [$host, $ports[$i] ?? $ports[0], 1];
|
||||
}
|
||||
|
||||
$this->handler->addServers($servers);
|
||||
|
||||
if ('' != $this->options['username']) {
|
||||
$this->handler->setOption(\Memcached::OPT_BINARY_PROTOCOL, true);
|
||||
$this->handler->setSaslAuthData($this->options['username'], $this->options['password']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断缓存
|
||||
* @access public
|
||||
* @param string $name 缓存变量名
|
||||
* @return bool
|
||||
*/
|
||||
public function has($name): bool
|
||||
{
|
||||
$key = $this->getCacheKey($name);
|
||||
|
||||
return $this->handler->get($key) ? true : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 读取缓存
|
||||
* @access public
|
||||
* @param string $name 缓存变量名
|
||||
* @param mixed $default 默认值
|
||||
* @return mixed
|
||||
*/
|
||||
public function get($name, $default = null): mixed
|
||||
{
|
||||
$result = $this->handler->get($this->getCacheKey($name));
|
||||
|
||||
return false !== $result ? $this->unserialize($result) : $default;
|
||||
}
|
||||
|
||||
/**
|
||||
* 写入缓存
|
||||
* @access public
|
||||
* @param string $name 缓存变量名
|
||||
* @param mixed $value 存储数据
|
||||
* @param integer|DateInterval|DateTimeInterface $expire 有效时间(秒)
|
||||
* @return bool
|
||||
*/
|
||||
public function set($name, $value, $expire = null): bool
|
||||
{
|
||||
if (is_null($expire)) {
|
||||
$expire = $this->options['expire'];
|
||||
}
|
||||
|
||||
$key = $this->getCacheKey($name);
|
||||
$expire = $this->getExpireTime($expire);
|
||||
$value = $this->serialize($value);
|
||||
|
||||
if ($this->handler->set($key, $value, $expire)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 自增缓存(针对数值缓存)
|
||||
* @access public
|
||||
* @param string $name 缓存变量名
|
||||
* @param int $step 步长
|
||||
* @return false|int
|
||||
*/
|
||||
public function inc($name, $step = 1)
|
||||
{
|
||||
$key = $this->getCacheKey($name);
|
||||
|
||||
if ($this->handler->get($key)) {
|
||||
return $this->handler->increment($key, $step);
|
||||
}
|
||||
|
||||
return $this->handler->set($key, $step);
|
||||
}
|
||||
|
||||
/**
|
||||
* 自减缓存(针对数值缓存)
|
||||
* @access public
|
||||
* @param string $name 缓存变量名
|
||||
* @param int $step 步长
|
||||
* @return false|int
|
||||
*/
|
||||
public function dec($name, $step = 1)
|
||||
{
|
||||
$key = $this->getCacheKey($name);
|
||||
$value = $this->handler->get($key) - $step;
|
||||
$res = $this->handler->set($key, $value);
|
||||
|
||||
return !$res ? false : $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除缓存
|
||||
* @access public
|
||||
* @param string $name 缓存变量名
|
||||
* @param bool|false $ttl
|
||||
* @return bool
|
||||
*/
|
||||
public function delete($name, $ttl = false): bool
|
||||
{
|
||||
$key = $this->getCacheKey($name);
|
||||
|
||||
return false === $ttl ?
|
||||
$this->handler->delete($key) :
|
||||
$this->handler->delete($key, $ttl);
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除缓存
|
||||
* @access public
|
||||
* @return bool
|
||||
*/
|
||||
public function clear(): bool
|
||||
{
|
||||
return $this->handler->flush();
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除缓存标签
|
||||
* @access public
|
||||
* @param array $keys 缓存标识列表
|
||||
* @return void
|
||||
*/
|
||||
public function clearTag($keys): void
|
||||
{
|
||||
$this->handler->deleteMulti($keys);
|
||||
}
|
||||
}
|
||||
242
vendor/topthink/framework/src/think/cache/driver/Redis.php
vendored
Normal file
242
vendor/topthink/framework/src/think/cache/driver/Redis.php
vendored
Normal file
@@ -0,0 +1,242 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2023 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
declare (strict_types = 1);
|
||||
|
||||
namespace think\cache\driver;
|
||||
|
||||
use DateInterval;
|
||||
use DateTimeInterface;
|
||||
use think\cache\Driver;
|
||||
|
||||
class Redis extends Driver
|
||||
{
|
||||
/** @var \Predis\Client|\Redis */
|
||||
protected $handler;
|
||||
|
||||
/**
|
||||
* 配置参数
|
||||
* @var array
|
||||
*/
|
||||
protected $options = [
|
||||
'host' => '127.0.0.1',
|
||||
'port' => 6379,
|
||||
'password' => '',
|
||||
'select' => 0,
|
||||
'timeout' => 0,
|
||||
'expire' => 0,
|
||||
'persistent' => false,
|
||||
'prefix' => '',
|
||||
'tag_prefix' => 'tag:',
|
||||
'serialize' => [],
|
||||
];
|
||||
|
||||
/**
|
||||
* 架构函数
|
||||
* @access public
|
||||
* @param array $options 缓存参数
|
||||
*/
|
||||
public function __construct(array $options = [])
|
||||
{
|
||||
if (!empty($options)) {
|
||||
$this->options = array_merge($this->options, $options);
|
||||
}
|
||||
}
|
||||
|
||||
public function handler()
|
||||
{
|
||||
if (!$this->handler) {
|
||||
if (extension_loaded('redis')) {
|
||||
$this->handler = new \Redis;
|
||||
|
||||
if ($this->options['persistent']) {
|
||||
$this->handler->pconnect($this->options['host'], (int) $this->options['port'], (int) $this->options['timeout'], 'persistent_id_' . $this->options['select']);
|
||||
} else {
|
||||
$this->handler->connect($this->options['host'], (int) $this->options['port'], (int) $this->options['timeout']);
|
||||
}
|
||||
|
||||
if ('' != $this->options['password']) {
|
||||
$this->handler->auth($this->options['password']);
|
||||
}
|
||||
} elseif (class_exists('\Predis\Client')) {
|
||||
$params = [];
|
||||
foreach ($this->options as $key => $val) {
|
||||
if (in_array($key, ['aggregate', 'cluster', 'connections', 'exceptions', 'prefix', 'profile', 'replication', 'parameters'])) {
|
||||
$params[$key] = $val;
|
||||
unset($this->options[$key]);
|
||||
}
|
||||
}
|
||||
|
||||
if ('' == $this->options['password']) {
|
||||
unset($this->options['password']);
|
||||
}
|
||||
|
||||
$this->handler = new \Predis\Client($this->options, $params);
|
||||
|
||||
$this->options['prefix'] = '';
|
||||
} else {
|
||||
throw new \BadFunctionCallException('not support: redis');
|
||||
}
|
||||
|
||||
if (0 != $this->options['select']) {
|
||||
$this->handler->select((int) $this->options['select']);
|
||||
}
|
||||
}
|
||||
|
||||
return $this->handler;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断缓存
|
||||
* @access public
|
||||
* @param string $name 缓存变量名
|
||||
* @return bool
|
||||
*/
|
||||
public function has($name): bool
|
||||
{
|
||||
return $this->handler()->exists($this->getCacheKey($name)) ? true : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 读取缓存
|
||||
* @access public
|
||||
* @param string $name 缓存变量名
|
||||
* @param mixed $default 默认值
|
||||
* @return mixed
|
||||
*/
|
||||
public function get($name, $default = null): mixed
|
||||
{
|
||||
$key = $this->getCacheKey($name);
|
||||
$value = $this->handler()->get($key);
|
||||
|
||||
if (false === $value || is_null($value)) {
|
||||
return $default;
|
||||
}
|
||||
|
||||
return $this->unserialize($value);
|
||||
}
|
||||
|
||||
/**
|
||||
* 写入缓存
|
||||
* @access public
|
||||
* @param string $name 缓存变量名
|
||||
* @param mixed $value 存储数据
|
||||
* @param integer|DateInterval|DateTimeInterface $expire 有效时间(秒)
|
||||
* @return bool
|
||||
*/
|
||||
public function set($name, $value, $expire = null): bool
|
||||
{
|
||||
if (is_null($expire)) {
|
||||
$expire = $this->options['expire'];
|
||||
}
|
||||
|
||||
$key = $this->getCacheKey($name);
|
||||
$expire = $this->getExpireTime($expire);
|
||||
$value = $this->serialize($value);
|
||||
|
||||
if ($expire) {
|
||||
$this->handler()->setex($key, $expire, $value);
|
||||
} else {
|
||||
$this->handler()->set($key, $value);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 自增缓存(针对数值缓存)
|
||||
* @access public
|
||||
* @param string $name 缓存变量名
|
||||
* @param int $step 步长
|
||||
* @return false|int
|
||||
*/
|
||||
public function inc($name, $step = 1)
|
||||
{
|
||||
$key = $this->getCacheKey($name);
|
||||
|
||||
return $this->handler()->incrby($key, $step);
|
||||
}
|
||||
|
||||
/**
|
||||
* 自减缓存(针对数值缓存)
|
||||
* @access public
|
||||
* @param string $name 缓存变量名
|
||||
* @param int $step 步长
|
||||
* @return false|int
|
||||
*/
|
||||
public function dec($name, $step = 1)
|
||||
{
|
||||
$key = $this->getCacheKey($name);
|
||||
|
||||
return $this->handler()->decrby($key, $step);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除缓存
|
||||
* @access public
|
||||
* @param string $name 缓存变量名
|
||||
* @return bool
|
||||
*/
|
||||
public function delete($name): bool
|
||||
{
|
||||
$key = $this->getCacheKey($name);
|
||||
$result = $this->handler()->del($key);
|
||||
return $result > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除缓存
|
||||
* @access public
|
||||
* @return bool
|
||||
*/
|
||||
public function clear(): bool
|
||||
{
|
||||
$this->handler()->flushDB();
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除缓存标签
|
||||
* @access public
|
||||
* @param array $keys 缓存标识列表
|
||||
* @return void
|
||||
*/
|
||||
public function clearTag($keys): void
|
||||
{
|
||||
// 指定标签清除
|
||||
$this->handler()->del($keys);
|
||||
}
|
||||
|
||||
/**
|
||||
* 追加TagSet数据
|
||||
* @access public
|
||||
* @param string $name 缓存标识
|
||||
* @param mixed $value 数据
|
||||
* @return void
|
||||
*/
|
||||
public function append($name, $value): void
|
||||
{
|
||||
$key = $this->getCacheKey($name);
|
||||
$this->handler()->sAdd($key, $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取标签包含的缓存标识
|
||||
* @access public
|
||||
* @param string $tag 缓存标签
|
||||
* @return array
|
||||
*/
|
||||
public function getTagItems($tag): array
|
||||
{
|
||||
$name = $this->getTagKey($tag);
|
||||
$key = $this->getCacheKey($name);
|
||||
return $this->handler()->sMembers($key);
|
||||
}
|
||||
}
|
||||
165
vendor/topthink/framework/src/think/cache/driver/Wincache.php
vendored
Normal file
165
vendor/topthink/framework/src/think/cache/driver/Wincache.php
vendored
Normal file
@@ -0,0 +1,165 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2023 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
declare (strict_types = 1);
|
||||
|
||||
namespace think\cache\driver;
|
||||
|
||||
use DateInterval;
|
||||
use DateTimeInterface;
|
||||
use think\cache\Driver;
|
||||
|
||||
/**
|
||||
* Wincache缓存驱动
|
||||
*/
|
||||
class Wincache extends Driver
|
||||
{
|
||||
/**
|
||||
* 配置参数
|
||||
* @var array
|
||||
*/
|
||||
protected $options = [
|
||||
'prefix' => '',
|
||||
'expire' => 0,
|
||||
'tag_prefix' => 'tag:',
|
||||
'serialize' => [],
|
||||
];
|
||||
|
||||
/**
|
||||
* 架构函数
|
||||
* @access public
|
||||
* @param array $options 缓存参数
|
||||
* @throws \BadFunctionCallException
|
||||
*/
|
||||
public function __construct(array $options = [])
|
||||
{
|
||||
if (!function_exists('wincache_ucache_info')) {
|
||||
throw new \BadFunctionCallException('not support: WinCache');
|
||||
}
|
||||
|
||||
if (!empty($options)) {
|
||||
$this->options = array_merge($this->options, $options);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断缓存
|
||||
* @access public
|
||||
* @param string $name 缓存变量名
|
||||
* @return bool
|
||||
*/
|
||||
public function has($name): bool
|
||||
{
|
||||
$this->readTimes++;
|
||||
|
||||
$key = $this->getCacheKey($name);
|
||||
|
||||
return wincache_ucache_exists($key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 读取缓存
|
||||
* @access public
|
||||
* @param string $name 缓存变量名
|
||||
* @param mixed $default 默认值
|
||||
* @return mixed
|
||||
*/
|
||||
public function get($name, $default = null): mixed
|
||||
{
|
||||
$key = $this->getCacheKey($name);
|
||||
|
||||
return wincache_ucache_exists($key) ? $this->unserialize(wincache_ucache_get($key)) : $default;
|
||||
}
|
||||
|
||||
/**
|
||||
* 写入缓存
|
||||
* @access public
|
||||
* @param string $name 缓存变量名
|
||||
* @param mixed $value 存储数据
|
||||
* @param integer|DateInterval|DateTimeInterface $expire 有效时间(秒)
|
||||
* @return bool
|
||||
*/
|
||||
public function set($name, $value, $expire = null): bool
|
||||
{
|
||||
if (is_null($expire)) {
|
||||
$expire = $this->options['expire'];
|
||||
}
|
||||
|
||||
$key = $this->getCacheKey($name);
|
||||
$expire = $this->getExpireTime($expire);
|
||||
$value = $this->serialize($value);
|
||||
|
||||
if (wincache_ucache_set($key, $value, $expire)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 自增缓存(针对数值缓存)
|
||||
* @access public
|
||||
* @param string $name 缓存变量名
|
||||
* @param int $step 步长
|
||||
* @return false|int
|
||||
*/
|
||||
public function inc($name, $step = 1)
|
||||
{
|
||||
$key = $this->getCacheKey($name);
|
||||
|
||||
return wincache_ucache_inc($key, $step);
|
||||
}
|
||||
|
||||
/**
|
||||
* 自减缓存(针对数值缓存)
|
||||
* @access public
|
||||
* @param string $name 缓存变量名
|
||||
* @param int $step 步长
|
||||
* @return false|int
|
||||
*/
|
||||
public function dec($name, $step = 1)
|
||||
{
|
||||
$key = $this->getCacheKey($name);
|
||||
|
||||
return wincache_ucache_dec($key, $step);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除缓存
|
||||
* @access public
|
||||
* @param string $name 缓存变量名
|
||||
* @return bool
|
||||
*/
|
||||
public function delete($name): bool
|
||||
{
|
||||
return wincache_ucache_delete($this->getCacheKey($name));
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除缓存
|
||||
* @access public
|
||||
* @return bool
|
||||
*/
|
||||
public function clear(): bool
|
||||
{
|
||||
return wincache_ucache_clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除缓存标签
|
||||
* @access public
|
||||
* @param array $keys 缓存标识列表
|
||||
* @return void
|
||||
*/
|
||||
public function clearTag($keys): void
|
||||
{
|
||||
wincache_ucache_delete($keys);
|
||||
}
|
||||
}
|
||||
504
vendor/topthink/framework/src/think/console/Command.php
vendored
Normal file
504
vendor/topthink/framework/src/think/console/Command.php
vendored
Normal file
@@ -0,0 +1,504 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2015 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: yunwuxin <448901948@qq.com>
|
||||
// +----------------------------------------------------------------------
|
||||
declare (strict_types = 1);
|
||||
|
||||
namespace think\console;
|
||||
|
||||
use Exception;
|
||||
use InvalidArgumentException;
|
||||
use LogicException;
|
||||
use think\App;
|
||||
use think\Console;
|
||||
use think\console\input\Argument;
|
||||
use think\console\input\Definition;
|
||||
use think\console\input\Option;
|
||||
|
||||
abstract class Command
|
||||
{
|
||||
|
||||
/** @var Console */
|
||||
private $console;
|
||||
private $name;
|
||||
private $processTitle;
|
||||
private $aliases = [];
|
||||
private $definition;
|
||||
private $help;
|
||||
private $description;
|
||||
private $ignoreValidationErrors = false;
|
||||
private $consoleDefinitionMerged = false;
|
||||
private $consoleDefinitionMergedWithArgs = false;
|
||||
private $synopsis = [];
|
||||
private $usages = [];
|
||||
|
||||
/** @var Input */
|
||||
protected $input;
|
||||
|
||||
/** @var Output */
|
||||
protected $output;
|
||||
|
||||
/** @var App */
|
||||
protected $app;
|
||||
|
||||
/**
|
||||
* 构造方法
|
||||
* @throws LogicException
|
||||
* @api
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->definition = new Definition();
|
||||
|
||||
$this->configure();
|
||||
|
||||
if (!$this->name) {
|
||||
throw new LogicException(sprintf('The command defined in "%s" cannot have an empty name.', get_class($this)));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 忽略验证错误
|
||||
*/
|
||||
public function ignoreValidationErrors(): void
|
||||
{
|
||||
$this->ignoreValidationErrors = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置控制台
|
||||
* @param Console $console
|
||||
*/
|
||||
public function setConsole(Console $console = null): void
|
||||
{
|
||||
$this->console = $console;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取控制台
|
||||
* @return Console
|
||||
* @api
|
||||
*/
|
||||
public function getConsole(): Console
|
||||
{
|
||||
return $this->console;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置app
|
||||
* @param App $app
|
||||
*/
|
||||
public function setApp(App $app)
|
||||
{
|
||||
$this->app = $app;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取app
|
||||
* @return App
|
||||
*/
|
||||
public function getApp()
|
||||
{
|
||||
return $this->app;
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否有效
|
||||
* @return bool
|
||||
*/
|
||||
public function isEnabled(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 配置指令
|
||||
*/
|
||||
protected function configure()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行指令
|
||||
* @param Input $input
|
||||
* @param Output $output
|
||||
* @return null|int
|
||||
* @throws LogicException
|
||||
* @see setCode()
|
||||
*/
|
||||
protected function execute(Input $input, Output $output)
|
||||
{
|
||||
return $this->app->invoke([$this, 'handle']);
|
||||
}
|
||||
|
||||
/**
|
||||
* 用户验证
|
||||
* @param Input $input
|
||||
* @param Output $output
|
||||
*/
|
||||
protected function interact(Input $input, Output $output)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化
|
||||
* @param Input $input An InputInterface instance
|
||||
* @param Output $output An OutputInterface instance
|
||||
*/
|
||||
protected function initialize(Input $input, Output $output)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行
|
||||
* @param Input $input
|
||||
* @param Output $output
|
||||
* @return int
|
||||
* @throws Exception
|
||||
* @see setCode()
|
||||
* @see execute()
|
||||
*/
|
||||
public function run(Input $input, Output $output): int
|
||||
{
|
||||
$this->input = $input;
|
||||
$this->output = $output;
|
||||
|
||||
$this->getSynopsis(true);
|
||||
$this->getSynopsis(false);
|
||||
|
||||
$this->mergeConsoleDefinition();
|
||||
|
||||
try {
|
||||
$input->bind($this->definition);
|
||||
} catch (Exception $e) {
|
||||
if (!$this->ignoreValidationErrors) {
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
$this->initialize($input, $output);
|
||||
|
||||
if (null !== $this->processTitle) {
|
||||
if (function_exists('cli_set_process_title')) {
|
||||
if (false === @cli_set_process_title($this->processTitle)) {
|
||||
if ('Darwin' === PHP_OS) {
|
||||
$output->writeln('<comment>Running "cli_get_process_title" as an unprivileged user is not supported on MacOS.</comment>');
|
||||
} else {
|
||||
$error = error_get_last();
|
||||
trigger_error($error['message'], E_USER_WARNING);
|
||||
}
|
||||
}
|
||||
} elseif (function_exists('setproctitle')) {
|
||||
setproctitle($this->processTitle);
|
||||
} elseif (Output::VERBOSITY_VERY_VERBOSE === $output->getVerbosity()) {
|
||||
$output->writeln('<comment>Install the proctitle PECL to be able to change the process title.</comment>');
|
||||
}
|
||||
}
|
||||
|
||||
if ($input->isInteractive()) {
|
||||
$this->interact($input, $output);
|
||||
}
|
||||
|
||||
$input->validate();
|
||||
|
||||
$statusCode = $this->execute($input, $output);
|
||||
|
||||
return is_numeric($statusCode) ? (int) $statusCode : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 合并参数定义
|
||||
* @param bool $mergeArgs
|
||||
*/
|
||||
public function mergeConsoleDefinition(bool $mergeArgs = true)
|
||||
{
|
||||
if (null === $this->console
|
||||
|| (true === $this->consoleDefinitionMerged
|
||||
&& ($this->consoleDefinitionMergedWithArgs || !$mergeArgs))
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($mergeArgs) {
|
||||
$currentArguments = $this->definition->getArguments();
|
||||
$this->definition->setArguments($this->console->getDefinition()->getArguments());
|
||||
$this->definition->addArguments($currentArguments);
|
||||
}
|
||||
|
||||
$this->definition->addOptions($this->console->getDefinition()->getOptions());
|
||||
|
||||
$this->consoleDefinitionMerged = true;
|
||||
if ($mergeArgs) {
|
||||
$this->consoleDefinitionMergedWithArgs = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置参数定义
|
||||
* @param array|Definition $definition
|
||||
* @return Command
|
||||
* @api
|
||||
*/
|
||||
public function setDefinition($definition)
|
||||
{
|
||||
if ($definition instanceof Definition) {
|
||||
$this->definition = $definition;
|
||||
} else {
|
||||
$this->definition->setDefinition($definition);
|
||||
}
|
||||
|
||||
$this->consoleDefinitionMerged = false;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取参数定义
|
||||
* @return Definition
|
||||
* @api
|
||||
*/
|
||||
public function getDefinition(): Definition
|
||||
{
|
||||
return $this->definition;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前指令的参数定义
|
||||
* @return Definition
|
||||
*/
|
||||
public function getNativeDefinition(): Definition
|
||||
{
|
||||
return $this->getDefinition();
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加参数
|
||||
* @param string $name 名称
|
||||
* @param int $mode 类型
|
||||
* @param string $description 描述
|
||||
* @param mixed $default 默认值
|
||||
* @return Command
|
||||
*/
|
||||
public function addArgument(string $name, int $mode = null, string $description = '', $default = null)
|
||||
{
|
||||
$this->definition->addArgument(new Argument($name, $mode, $description, $default));
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加选项
|
||||
* @param string $name 选项名称
|
||||
* @param string $shortcut 别名
|
||||
* @param int $mode 类型
|
||||
* @param string $description 描述
|
||||
* @param mixed $default 默认值
|
||||
* @return Command
|
||||
*/
|
||||
public function addOption(string $name, string $shortcut = null, int $mode = null, string $description = '', $default = null)
|
||||
{
|
||||
$this->definition->addOption(new Option($name, $shortcut, $mode, $description, $default));
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置指令名称
|
||||
* @param string $name
|
||||
* @return Command
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
public function setName(string $name)
|
||||
{
|
||||
$this->validateName($name);
|
||||
|
||||
$this->name = $name;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置进程名称
|
||||
*
|
||||
* PHP 5.5+ or the proctitle PECL library is required
|
||||
*
|
||||
* @param string $title The process title
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setProcessTitle($title)
|
||||
{
|
||||
$this->processTitle = $title;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指令名称
|
||||
* @return string
|
||||
*/
|
||||
public function getName(): string
|
||||
{
|
||||
return $this->name ?: '';
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置描述
|
||||
* @param string $description
|
||||
* @return Command
|
||||
*/
|
||||
public function setDescription(string $description)
|
||||
{
|
||||
$this->description = $description;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取描述
|
||||
* @return string
|
||||
*/
|
||||
public function getDescription(): string
|
||||
{
|
||||
return $this->description ?: '';
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置帮助信息
|
||||
* @param string $help
|
||||
* @return Command
|
||||
*/
|
||||
public function setHelp(string $help)
|
||||
{
|
||||
$this->help = $help;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取帮助信息
|
||||
* @return string
|
||||
*/
|
||||
public function getHelp(): string
|
||||
{
|
||||
return $this->help ?: '';
|
||||
}
|
||||
|
||||
/**
|
||||
* 描述信息
|
||||
* @return string
|
||||
*/
|
||||
public function getProcessedHelp(): string
|
||||
{
|
||||
$name = $this->name;
|
||||
|
||||
$placeholders = [
|
||||
'%command.name%',
|
||||
'%command.full_name%',
|
||||
];
|
||||
$replacements = [
|
||||
$name,
|
||||
$_SERVER['PHP_SELF'] . ' ' . $name,
|
||||
];
|
||||
|
||||
return str_replace($placeholders, $replacements, $this->getHelp());
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置别名
|
||||
* @param string[] $aliases
|
||||
* @return Command
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
public function setAliases(iterable $aliases)
|
||||
{
|
||||
foreach ($aliases as $alias) {
|
||||
$this->validateName($alias);
|
||||
}
|
||||
|
||||
$this->aliases = $aliases;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取别名
|
||||
* @return array
|
||||
*/
|
||||
public function getAliases(): array
|
||||
{
|
||||
return $this->aliases;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取简介
|
||||
* @param bool $short 是否简单的
|
||||
* @return string
|
||||
*/
|
||||
public function getSynopsis(bool $short = false): string
|
||||
{
|
||||
$key = $short ? 'short' : 'long';
|
||||
|
||||
if (!isset($this->synopsis[$key])) {
|
||||
$this->synopsis[$key] = trim(sprintf('%s %s', $this->name, $this->definition->getSynopsis($short)));
|
||||
}
|
||||
|
||||
return $this->synopsis[$key];
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加用法介绍
|
||||
* @param string $usage
|
||||
* @return $this
|
||||
*/
|
||||
public function addUsage(string $usage)
|
||||
{
|
||||
if (!str_starts_with($usage, $this->name)) {
|
||||
$usage = sprintf('%s %s', $this->name, $usage);
|
||||
}
|
||||
|
||||
$this->usages[] = $usage;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用法介绍
|
||||
* @return array
|
||||
*/
|
||||
public function getUsages(): array
|
||||
{
|
||||
return $this->usages;
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证指令名称
|
||||
* @param string $name
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
private function validateName(string $name)
|
||||
{
|
||||
if (!preg_match('/^[^\:]++(\:[^\:]++)*$/', $name)) {
|
||||
throw new InvalidArgumentException(sprintf('Command name "%s" is invalid.', $name));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 输出表格
|
||||
* @param Table $table
|
||||
* @return string
|
||||
*/
|
||||
protected function table(Table $table): string
|
||||
{
|
||||
$content = $table->render();
|
||||
$this->output->writeln($content);
|
||||
return $content;
|
||||
}
|
||||
|
||||
}
|
||||
465
vendor/topthink/framework/src/think/console/Input.php
vendored
Normal file
465
vendor/topthink/framework/src/think/console/Input.php
vendored
Normal file
@@ -0,0 +1,465 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2015 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: yunwuxin <448901948@qq.com>
|
||||
// +----------------------------------------------------------------------
|
||||
declare (strict_types = 1);
|
||||
|
||||
namespace think\console;
|
||||
|
||||
use think\console\input\Argument;
|
||||
use think\console\input\Definition;
|
||||
use think\console\input\Option;
|
||||
|
||||
class Input
|
||||
{
|
||||
|
||||
/**
|
||||
* @var Definition
|
||||
*/
|
||||
protected $definition;
|
||||
|
||||
/**
|
||||
* @var Option[]
|
||||
*/
|
||||
protected $options = [];
|
||||
|
||||
/**
|
||||
* @var Argument[]
|
||||
*/
|
||||
protected $arguments = [];
|
||||
|
||||
protected $interactive = true;
|
||||
|
||||
private $tokens;
|
||||
private $parsed;
|
||||
|
||||
public function __construct($argv = null)
|
||||
{
|
||||
if (null === $argv) {
|
||||
$argv = $_SERVER['argv'];
|
||||
// 去除命令名
|
||||
array_shift($argv);
|
||||
}
|
||||
|
||||
$this->tokens = $argv;
|
||||
|
||||
$this->definition = new Definition();
|
||||
}
|
||||
|
||||
protected function setTokens(array $tokens)
|
||||
{
|
||||
$this->tokens = $tokens;
|
||||
}
|
||||
|
||||
/**
|
||||
* 绑定实例
|
||||
* @param Definition $definition A InputDefinition instance
|
||||
*/
|
||||
public function bind(Definition $definition): void
|
||||
{
|
||||
$this->arguments = [];
|
||||
$this->options = [];
|
||||
$this->definition = $definition;
|
||||
|
||||
$this->parse();
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析参数
|
||||
*/
|
||||
protected function parse(): void
|
||||
{
|
||||
$parseOptions = true;
|
||||
$this->parsed = $this->tokens;
|
||||
while (null !== $token = array_shift($this->parsed)) {
|
||||
if ($parseOptions && '' == $token) {
|
||||
$this->parseArgument($token);
|
||||
} elseif ($parseOptions && '--' == $token) {
|
||||
$parseOptions = false;
|
||||
} elseif ($parseOptions && str_starts_with($token, '--')) {
|
||||
$this->parseLongOption($token);
|
||||
} elseif ($parseOptions && '-' === $token[0] && '-' !== $token) {
|
||||
$this->parseShortOption($token);
|
||||
} else {
|
||||
$this->parseArgument($token);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析短选项
|
||||
* @param string $token 当前的指令.
|
||||
*/
|
||||
private function parseShortOption(string $token): void
|
||||
{
|
||||
$name = substr($token, 1);
|
||||
|
||||
if (strlen($name) > 1) {
|
||||
if ($this->definition->hasShortcut($name[0])
|
||||
&& $this->definition->getOptionForShortcut($name[0])->acceptValue()
|
||||
) {
|
||||
$this->addShortOption($name[0], substr($name, 1));
|
||||
} else {
|
||||
$this->parseShortOptionSet($name);
|
||||
}
|
||||
} else {
|
||||
$this->addShortOption($name, null);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析短选项
|
||||
* @param string $name 当前指令
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
private function parseShortOptionSet(string $name): void
|
||||
{
|
||||
$len = strlen($name);
|
||||
for ($i = 0; $i < $len; ++$i) {
|
||||
if (!$this->definition->hasShortcut($name[$i])) {
|
||||
throw new \RuntimeException(sprintf('The "-%s" option does not exist.', $name[$i]));
|
||||
}
|
||||
|
||||
$option = $this->definition->getOptionForShortcut($name[$i]);
|
||||
if ($option->acceptValue()) {
|
||||
$this->addLongOption($option->getName(), $i === $len - 1 ? null : substr($name, $i + 1));
|
||||
|
||||
break;
|
||||
} else {
|
||||
$this->addLongOption($option->getName(), null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析完整选项
|
||||
* @param string $token 当前指令
|
||||
*/
|
||||
private function parseLongOption(string $token): void
|
||||
{
|
||||
$name = substr($token, 2);
|
||||
|
||||
if (false !== $pos = strpos($name, '=')) {
|
||||
$this->addLongOption(substr($name, 0, $pos), substr($name, $pos + 1));
|
||||
} else {
|
||||
$this->addLongOption($name, null);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析参数
|
||||
* @param string $token 当前指令
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
private function parseArgument(string $token): void
|
||||
{
|
||||
$c = count($this->arguments);
|
||||
|
||||
if ($this->definition->hasArgument($c)) {
|
||||
$arg = $this->definition->getArgument($c);
|
||||
|
||||
$this->arguments[$arg->getName()] = $arg->isArray() ? [$token] : $token;
|
||||
|
||||
} elseif ($this->definition->hasArgument($c - 1) && $this->definition->getArgument($c - 1)->isArray()) {
|
||||
$arg = $this->definition->getArgument($c - 1);
|
||||
|
||||
$this->arguments[$arg->getName()][] = $token;
|
||||
} else {
|
||||
throw new \RuntimeException('Too many arguments.');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加一个短选项的值
|
||||
* @param string $shortcut 短名称
|
||||
* @param mixed $value 值
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
private function addShortOption(string $shortcut, $value): void
|
||||
{
|
||||
if (!$this->definition->hasShortcut($shortcut)) {
|
||||
throw new \RuntimeException(sprintf('The "-%s" option does not exist.', $shortcut));
|
||||
}
|
||||
|
||||
$this->addLongOption($this->definition->getOptionForShortcut($shortcut)->getName(), $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加一个完整选项的值
|
||||
* @param string $name 选项名
|
||||
* @param mixed $value 值
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
private function addLongOption(string $name, $value): void
|
||||
{
|
||||
if (!$this->definition->hasOption($name)) {
|
||||
throw new \RuntimeException(sprintf('The "--%s" option does not exist.', $name));
|
||||
}
|
||||
|
||||
$option = $this->definition->getOption($name);
|
||||
|
||||
if (false === $value) {
|
||||
$value = null;
|
||||
}
|
||||
|
||||
if (null !== $value && !$option->acceptValue()) {
|
||||
throw new \RuntimeException(sprintf('The "--%s" option does not accept a value.', $name, $value));
|
||||
}
|
||||
|
||||
if (null === $value && $option->acceptValue() && count($this->parsed)) {
|
||||
$next = array_shift($this->parsed);
|
||||
if (isset($next[0]) && '-' !== $next[0]) {
|
||||
$value = $next;
|
||||
} elseif (empty($next)) {
|
||||
$value = '';
|
||||
} else {
|
||||
array_unshift($this->parsed, $next);
|
||||
}
|
||||
}
|
||||
|
||||
if (null === $value) {
|
||||
if ($option->isValueRequired()) {
|
||||
throw new \RuntimeException(sprintf('The "--%s" option requires a value.', $name));
|
||||
}
|
||||
|
||||
if (!$option->isArray()) {
|
||||
$value = $option->isValueOptional() ? $option->getDefault() : true;
|
||||
}
|
||||
}
|
||||
|
||||
if ($option->isArray()) {
|
||||
$this->options[$name][] = $value;
|
||||
} else {
|
||||
$this->options[$name] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取第一个参数
|
||||
* @return string|null
|
||||
*/
|
||||
public function getFirstArgument()
|
||||
{
|
||||
foreach ($this->tokens as $token) {
|
||||
if ($token && '-' === $token[0]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
return $token;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查原始参数是否包含某个值
|
||||
* @param string|array $values 需要检查的值
|
||||
* @return bool
|
||||
*/
|
||||
public function hasParameterOption($values): bool
|
||||
{
|
||||
$values = (array) $values;
|
||||
|
||||
foreach ($this->tokens as $token) {
|
||||
foreach ($values as $value) {
|
||||
if ($token === $value || str_starts_with($token, $value . '=')) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取原始选项的值
|
||||
* @param string|array $values 需要检查的值
|
||||
* @param mixed $default 默认值
|
||||
* @return mixed The option value
|
||||
*/
|
||||
public function getParameterOption($values, $default = false)
|
||||
{
|
||||
$values = (array) $values;
|
||||
$tokens = $this->tokens;
|
||||
|
||||
while (0 < count($tokens)) {
|
||||
$token = array_shift($tokens);
|
||||
|
||||
foreach ($values as $value) {
|
||||
if ($token === $value || str_starts_with($token, $value . '=')) {
|
||||
if (false !== $pos = strpos($token, '=')) {
|
||||
return substr($token, $pos + 1);
|
||||
}
|
||||
|
||||
return array_shift($tokens);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $default;
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证输入
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
public function validate()
|
||||
{
|
||||
if (count($this->arguments) < $this->definition->getArgumentRequiredCount()) {
|
||||
throw new \RuntimeException('Not enough arguments.');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查输入是否是交互的
|
||||
* @return bool
|
||||
*/
|
||||
public function isInteractive(): bool
|
||||
{
|
||||
return $this->interactive;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置输入的交互
|
||||
* @param bool
|
||||
*/
|
||||
public function setInteractive(bool $interactive): void
|
||||
{
|
||||
$this->interactive = $interactive;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有的参数
|
||||
* @return Argument[]
|
||||
*/
|
||||
public function getArguments(): array
|
||||
{
|
||||
return array_merge($this->definition->getArgumentDefaults(), $this->arguments);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据名称获取参数
|
||||
* @param string $name 参数名
|
||||
* @return mixed
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public function getArgument(string $name)
|
||||
{
|
||||
if (!$this->definition->hasArgument($name)) {
|
||||
throw new \InvalidArgumentException(sprintf('The "%s" argument does not exist.', $name));
|
||||
}
|
||||
|
||||
return $this->arguments[$name] ?? $this->definition->getArgument($name)
|
||||
->getDefault();
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置参数的值
|
||||
* @param string $name 参数名
|
||||
* @param string $value 值
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public function setArgument(string $name, $value)
|
||||
{
|
||||
if (!$this->definition->hasArgument($name)) {
|
||||
throw new \InvalidArgumentException(sprintf('The "%s" argument does not exist.', $name));
|
||||
}
|
||||
|
||||
$this->arguments[$name] = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查是否存在某个参数
|
||||
* @param string|int $name 参数名或位置
|
||||
* @return bool
|
||||
*/
|
||||
public function hasArgument(string|int $name): bool
|
||||
{
|
||||
return $this->definition->hasArgument($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有的选项
|
||||
* @return Option[]
|
||||
*/
|
||||
public function getOptions(): array
|
||||
{
|
||||
return array_merge($this->definition->getOptionDefaults(), $this->options);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取选项值
|
||||
* @param string $name 选项名称
|
||||
* @return mixed
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public function getOption(string $name)
|
||||
{
|
||||
if (!$this->definition->hasOption($name)) {
|
||||
throw new \InvalidArgumentException(sprintf('The "%s" option does not exist.', $name));
|
||||
}
|
||||
|
||||
return $this->options[$name] ?? $this->definition->getOption($name)->getDefault();
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置选项值
|
||||
* @param string $name 选项名
|
||||
* @param string|bool $value 值
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public function setOption(string $name, $value): void
|
||||
{
|
||||
if (!$this->definition->hasOption($name)) {
|
||||
throw new \InvalidArgumentException(sprintf('The "%s" option does not exist.', $name));
|
||||
}
|
||||
|
||||
$this->options[$name] = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否有某个选项
|
||||
* @param string $name 选项名
|
||||
* @return bool
|
||||
*/
|
||||
public function hasOption(string $name): bool
|
||||
{
|
||||
return $this->definition->hasOption($name) && isset($this->options[$name]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 转义指令
|
||||
* @param string $token
|
||||
* @return string
|
||||
*/
|
||||
public function escapeToken(string $token): string
|
||||
{
|
||||
return preg_match('{^[\w-]+$}', $token) ? $token : escapeshellarg($token);
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回传递给命令的参数的字符串
|
||||
* @return string
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
$tokens = array_map(function ($token) {
|
||||
if (preg_match('{^(-[^=]+=)(.+)}', $token, $match)) {
|
||||
return $match[1] . $this->escapeToken($match[2]);
|
||||
}
|
||||
|
||||
if ($token && '-' !== $token[0]) {
|
||||
return $this->escapeToken($token);
|
||||
}
|
||||
|
||||
return $token;
|
||||
}, $this->tokens);
|
||||
|
||||
return implode(' ', $tokens);
|
||||
}
|
||||
}
|
||||
19
vendor/topthink/framework/src/think/console/LICENSE
vendored
Normal file
19
vendor/topthink/framework/src/think/console/LICENSE
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
Copyright (c) 2004-2016 Fabien Potencier
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is furnished
|
||||
to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
231
vendor/topthink/framework/src/think/console/Output.php
vendored
Normal file
231
vendor/topthink/framework/src/think/console/Output.php
vendored
Normal file
@@ -0,0 +1,231 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2020 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: yunwuxin <448901948@qq.com>
|
||||
// +----------------------------------------------------------------------
|
||||
declare (strict_types = 1);
|
||||
|
||||
namespace think\console;
|
||||
|
||||
use Exception;
|
||||
use think\console\output\Ask;
|
||||
use think\console\output\Descriptor;
|
||||
use think\console\output\driver\Buffer;
|
||||
use think\console\output\driver\Console;
|
||||
use think\console\output\driver\Nothing;
|
||||
use think\console\output\Question;
|
||||
use think\console\output\question\Choice;
|
||||
use think\console\output\question\Confirmation;
|
||||
use Throwable;
|
||||
|
||||
/**
|
||||
* Class Output
|
||||
* @package think\console
|
||||
*
|
||||
* @see \think\console\output\driver\Console::setDecorated
|
||||
* @method void setDecorated($decorated)
|
||||
*
|
||||
* @see \think\console\output\driver\Buffer::fetch
|
||||
* @method string fetch()
|
||||
*
|
||||
* @method void info($message)
|
||||
* @method void error($message)
|
||||
* @method void comment($message)
|
||||
* @method void warning($message)
|
||||
* @method void highlight($message)
|
||||
* @method void question($message)
|
||||
*/
|
||||
class Output
|
||||
{
|
||||
// 不显示信息(静默)
|
||||
const VERBOSITY_QUIET = 0;
|
||||
// 正常信息
|
||||
const VERBOSITY_NORMAL = 1;
|
||||
// 详细信息
|
||||
const VERBOSITY_VERBOSE = 2;
|
||||
// 非常详细的信息
|
||||
const VERBOSITY_VERY_VERBOSE = 3;
|
||||
// 调试信息
|
||||
const VERBOSITY_DEBUG = 4;
|
||||
|
||||
const OUTPUT_NORMAL = 0;
|
||||
const OUTPUT_RAW = 1;
|
||||
const OUTPUT_PLAIN = 2;
|
||||
|
||||
// 输出信息级别
|
||||
private $verbosity = self::VERBOSITY_NORMAL;
|
||||
|
||||
/** @var Buffer|Console|Nothing */
|
||||
private $handle = null;
|
||||
|
||||
protected $styles = [
|
||||
'info',
|
||||
'error',
|
||||
'comment',
|
||||
'question',
|
||||
'highlight',
|
||||
'warning',
|
||||
];
|
||||
|
||||
public function __construct($driver = 'console')
|
||||
{
|
||||
$class = '\\think\\console\\output\\driver\\' . ucwords($driver);
|
||||
|
||||
$this->handle = new $class($this);
|
||||
}
|
||||
|
||||
public function ask(Input $input, $question, $default = null, $validator = null)
|
||||
{
|
||||
$question = new Question($question, $default);
|
||||
$question->setValidator($validator);
|
||||
|
||||
return $this->askQuestion($input, $question);
|
||||
}
|
||||
|
||||
public function askHidden(Input $input, $question, $validator = null)
|
||||
{
|
||||
$question = new Question($question);
|
||||
|
||||
$question->setHidden(true);
|
||||
$question->setValidator($validator);
|
||||
|
||||
return $this->askQuestion($input, $question);
|
||||
}
|
||||
|
||||
public function confirm(Input $input, $question, $default = true)
|
||||
{
|
||||
return $this->askQuestion($input, new Confirmation($question, $default));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function choice(Input $input, $question, array $choices, $default = null)
|
||||
{
|
||||
if (null !== $default) {
|
||||
$values = array_flip($choices);
|
||||
$default = $values[$default];
|
||||
}
|
||||
|
||||
return $this->askQuestion($input, new Choice($question, $choices, $default));
|
||||
}
|
||||
|
||||
protected function askQuestion(Input $input, Question $question)
|
||||
{
|
||||
$ask = new Ask($input, $this, $question);
|
||||
$answer = $ask->run();
|
||||
|
||||
if ($input->isInteractive()) {
|
||||
$this->newLine();
|
||||
}
|
||||
|
||||
return $answer;
|
||||
}
|
||||
|
||||
protected function block(string $style, string $message): void
|
||||
{
|
||||
$this->writeln("<{$style}>{$message}</$style>");
|
||||
}
|
||||
|
||||
/**
|
||||
* 输出空行
|
||||
* @param int $count
|
||||
*/
|
||||
public function newLine(int $count = 1): void
|
||||
{
|
||||
$this->write(str_repeat(PHP_EOL, $count));
|
||||
}
|
||||
|
||||
/**
|
||||
* 输出信息并换行
|
||||
* @param string $messages
|
||||
* @param int $type
|
||||
*/
|
||||
public function writeln(string $messages, int $type = 0): void
|
||||
{
|
||||
$this->write($messages, true, $type);
|
||||
}
|
||||
|
||||
/**
|
||||
* 输出信息
|
||||
* @param string $messages
|
||||
* @param bool $newline
|
||||
* @param int $type
|
||||
*/
|
||||
public function write(string $messages, bool $newline = false, int $type = 0): void
|
||||
{
|
||||
$this->handle->write($messages, $newline, $type);
|
||||
}
|
||||
|
||||
public function renderException(Throwable $e): void
|
||||
{
|
||||
$this->handle->renderException($e);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置输出信息级别
|
||||
* @param int $level 输出信息级别
|
||||
*/
|
||||
public function setVerbosity(int $level)
|
||||
{
|
||||
$this->verbosity = $level;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取输出信息级别
|
||||
* @return int
|
||||
*/
|
||||
public function getVerbosity(): int
|
||||
{
|
||||
return $this->verbosity;
|
||||
}
|
||||
|
||||
public function isQuiet(): bool
|
||||
{
|
||||
return self::VERBOSITY_QUIET === $this->verbosity;
|
||||
}
|
||||
|
||||
public function isVerbose(): bool
|
||||
{
|
||||
return self::VERBOSITY_VERBOSE <= $this->verbosity;
|
||||
}
|
||||
|
||||
public function isVeryVerbose(): bool
|
||||
{
|
||||
return self::VERBOSITY_VERY_VERBOSE <= $this->verbosity;
|
||||
}
|
||||
|
||||
public function isDebug(): bool
|
||||
{
|
||||
return self::VERBOSITY_DEBUG <= $this->verbosity;
|
||||
}
|
||||
|
||||
public function describe($object, array $options = []): void
|
||||
{
|
||||
$descriptor = new Descriptor();
|
||||
$options = array_merge([
|
||||
'raw_text' => false,
|
||||
], $options);
|
||||
|
||||
$descriptor->describe($this, $object, $options);
|
||||
}
|
||||
|
||||
public function __call($method, $args)
|
||||
{
|
||||
if (in_array($method, $this->styles)) {
|
||||
array_unshift($args, $method);
|
||||
return call_user_func_array([$this, 'block'], $args);
|
||||
}
|
||||
|
||||
if ($this->handle && method_exists($this->handle, $method)) {
|
||||
return call_user_func_array([$this->handle, $method], $args);
|
||||
} else {
|
||||
throw new Exception('method not exists:' . __CLASS__ . '->' . $method);
|
||||
}
|
||||
}
|
||||
}
|
||||
300
vendor/topthink/framework/src/think/console/Table.php
vendored
Normal file
300
vendor/topthink/framework/src/think/console/Table.php
vendored
Normal file
@@ -0,0 +1,300 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2015 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: yunwuxin <448901948@qq.com>
|
||||
// +----------------------------------------------------------------------
|
||||
declare (strict_types = 1);
|
||||
|
||||
namespace think\console;
|
||||
|
||||
class Table
|
||||
{
|
||||
const ALIGN_LEFT = 1;
|
||||
const ALIGN_RIGHT = 0;
|
||||
const ALIGN_CENTER = 2;
|
||||
|
||||
/**
|
||||
* 头信息数据
|
||||
* @var array
|
||||
*/
|
||||
protected $header = [];
|
||||
|
||||
/**
|
||||
* 头部对齐方式 默认1 ALGIN_LEFT 0 ALIGN_RIGHT 2 ALIGN_CENTER
|
||||
* @var int
|
||||
*/
|
||||
protected $headerAlign = 1;
|
||||
|
||||
/**
|
||||
* 表格数据(二维数组)
|
||||
* @var array
|
||||
*/
|
||||
protected $rows = [];
|
||||
|
||||
/**
|
||||
* 单元格对齐方式 默认1 ALGIN_LEFT 0 ALIGN_RIGHT 2 ALIGN_CENTER
|
||||
* @var int
|
||||
*/
|
||||
protected $cellAlign = 1;
|
||||
|
||||
/**
|
||||
* 单元格宽度信息
|
||||
* @var array
|
||||
*/
|
||||
protected $colWidth = [];
|
||||
|
||||
/**
|
||||
* 表格输出样式
|
||||
* @var string
|
||||
*/
|
||||
protected $style = 'default';
|
||||
|
||||
/**
|
||||
* 表格样式定义
|
||||
* @var array
|
||||
*/
|
||||
protected $format = [
|
||||
'compact' => [],
|
||||
'default' => [
|
||||
'top' => ['+', '-', '+', '+'],
|
||||
'cell' => ['|', ' ', '|', '|'],
|
||||
'middle' => ['+', '-', '+', '+'],
|
||||
'bottom' => ['+', '-', '+', '+'],
|
||||
'cross-top' => ['+', '-', '-', '+'],
|
||||
'cross-bottom' => ['+', '-', '-', '+'],
|
||||
],
|
||||
'markdown' => [
|
||||
'top' => [' ', ' ', ' ', ' '],
|
||||
'cell' => ['|', ' ', '|', '|'],
|
||||
'middle' => ['|', '-', '|', '|'],
|
||||
'bottom' => [' ', ' ', ' ', ' '],
|
||||
'cross-top' => ['|', ' ', ' ', '|'],
|
||||
'cross-bottom' => ['|', ' ', ' ', '|'],
|
||||
],
|
||||
'borderless' => [
|
||||
'top' => ['=', '=', ' ', '='],
|
||||
'cell' => [' ', ' ', ' ', ' '],
|
||||
'middle' => ['=', '=', ' ', '='],
|
||||
'bottom' => ['=', '=', ' ', '='],
|
||||
'cross-top' => ['=', '=', ' ', '='],
|
||||
'cross-bottom' => ['=', '=', ' ', '='],
|
||||
],
|
||||
'box' => [
|
||||
'top' => ['┌', '─', '┬', '┐'],
|
||||
'cell' => ['│', ' ', '│', '│'],
|
||||
'middle' => ['├', '─', '┼', '┤'],
|
||||
'bottom' => ['└', '─', '┴', '┘'],
|
||||
'cross-top' => ['├', '─', '┴', '┤'],
|
||||
'cross-bottom' => ['├', '─', '┬', '┤'],
|
||||
],
|
||||
'box-double' => [
|
||||
'top' => ['╔', '═', '╤', '╗'],
|
||||
'cell' => ['║', ' ', '│', '║'],
|
||||
'middle' => ['╠', '─', '╪', '╣'],
|
||||
'bottom' => ['╚', '═', '╧', '╝'],
|
||||
'cross-top' => ['╠', '═', '╧', '╣'],
|
||||
'cross-bottom' => ['╠', '═', '╤', '╣'],
|
||||
],
|
||||
];
|
||||
|
||||
/**
|
||||
* 设置表格头信息 以及对齐方式
|
||||
* @access public
|
||||
* @param array $header 要输出的Header信息
|
||||
* @param int $align 对齐方式 默认1 ALGIN_LEFT 0 ALIGN_RIGHT 2 ALIGN_CENTER
|
||||
* @return void
|
||||
*/
|
||||
public function setHeader(array $header, int $align = 1): void
|
||||
{
|
||||
$this->header = $header;
|
||||
$this->headerAlign = $align;
|
||||
|
||||
$this->checkColWidth($header);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置输出表格数据 及对齐方式
|
||||
* @access public
|
||||
* @param array $rows 要输出的表格数据(二维数组)
|
||||
* @param int $align 对齐方式 默认1 ALGIN_LEFT 0 ALIGN_RIGHT 2 ALIGN_CENTER
|
||||
* @return void
|
||||
*/
|
||||
public function setRows(array $rows, int $align = 1): void
|
||||
{
|
||||
$this->rows = $rows;
|
||||
$this->cellAlign = $align;
|
||||
|
||||
foreach ($rows as $row) {
|
||||
$this->checkColWidth($row);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置全局单元格对齐方式
|
||||
* @param int $align 对齐方式 默认1 ALGIN_LEFT 0 ALIGN_RIGHT 2 ALIGN_CENTER
|
||||
* @return $this
|
||||
*/
|
||||
public function setCellAlign(int $align = 1)
|
||||
{
|
||||
$this->cellAlign = $align;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查列数据的显示宽度
|
||||
* @access public
|
||||
* @param mixed $row 行数据
|
||||
* @return void
|
||||
*/
|
||||
protected function checkColWidth($row): void
|
||||
{
|
||||
if (is_array($row)) {
|
||||
foreach ($row as $key => $cell) {
|
||||
$width = mb_strwidth((string) $cell);
|
||||
if (!isset($this->colWidth[$key]) || $width > $this->colWidth[$key]) {
|
||||
$this->colWidth[$key] = $width;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 增加一行表格数据
|
||||
* @access public
|
||||
* @param mixed $row 行数据
|
||||
* @param bool $first 是否在开头插入
|
||||
* @return void
|
||||
*/
|
||||
public function addRow($row, bool $first = false): void
|
||||
{
|
||||
if ($first) {
|
||||
array_unshift($this->rows, $row);
|
||||
} else {
|
||||
$this->rows[] = $row;
|
||||
}
|
||||
|
||||
$this->checkColWidth($row);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置输出表格的样式
|
||||
* @access public
|
||||
* @param string $style 样式名
|
||||
* @return void
|
||||
*/
|
||||
public function setStyle(string $style): void
|
||||
{
|
||||
$this->style = isset($this->format[$style]) ? $style : 'default';
|
||||
}
|
||||
|
||||
/**
|
||||
* 输出分隔行
|
||||
* @access public
|
||||
* @param string $pos 位置
|
||||
* @return string
|
||||
*/
|
||||
protected function renderSeparator(string $pos): string
|
||||
{
|
||||
$style = $this->getStyle($pos);
|
||||
$array = [];
|
||||
|
||||
foreach ($this->colWidth as $width) {
|
||||
$array[] = str_repeat($style[1], $width + 2);
|
||||
}
|
||||
|
||||
return $style[0] . implode($style[2], $array) . $style[3] . PHP_EOL;
|
||||
}
|
||||
|
||||
/**
|
||||
* 输出表格头部
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
protected function renderHeader(): string
|
||||
{
|
||||
$style = $this->getStyle('cell');
|
||||
$content = $this->renderSeparator('top');
|
||||
|
||||
foreach ($this->header as $key => $header) {
|
||||
$array[] = ' ' . str_pad($header, $this->colWidth[$key], $style[1], $this->headerAlign);
|
||||
}
|
||||
|
||||
if (!empty($array)) {
|
||||
$content .= $style[0] . implode(' ' . $style[2], $array) . ' ' . $style[3] . PHP_EOL;
|
||||
|
||||
if (!empty($this->rows)) {
|
||||
$content .= $this->renderSeparator('middle');
|
||||
}
|
||||
}
|
||||
|
||||
return $content;
|
||||
}
|
||||
|
||||
protected function getStyle(string $style): array
|
||||
{
|
||||
if ($this->format[$this->style]) {
|
||||
$style = $this->format[$this->style][$style];
|
||||
} else {
|
||||
$style = [' ', ' ', ' ', ' '];
|
||||
}
|
||||
|
||||
return $style;
|
||||
}
|
||||
|
||||
/**
|
||||
* 输出表格
|
||||
* @access public
|
||||
* @param array $dataList 表格数据
|
||||
* @return string
|
||||
*/
|
||||
public function render(array $dataList = []): string
|
||||
{
|
||||
if (!empty($dataList)) {
|
||||
$this->setRows($dataList);
|
||||
}
|
||||
|
||||
// 输出头部
|
||||
$content = $this->renderHeader();
|
||||
$style = $this->getStyle('cell');
|
||||
|
||||
if (!empty($this->rows)) {
|
||||
foreach ($this->rows as $row) {
|
||||
if (is_string($row) && '-' === $row) {
|
||||
$content .= $this->renderSeparator('middle');
|
||||
} elseif (is_scalar($row)) {
|
||||
$content .= $this->renderSeparator('cross-top');
|
||||
$width = 3 * (count($this->colWidth) - 1) + array_reduce($this->colWidth, function ($a, $b) {
|
||||
return $a + $b;
|
||||
});
|
||||
$array = str_pad($row, $width);
|
||||
|
||||
$content .= $style[0] . ' ' . $array . ' ' . $style[3] . PHP_EOL;
|
||||
$content .= $this->renderSeparator('cross-bottom');
|
||||
} else {
|
||||
$array = [];
|
||||
|
||||
foreach ($row as $key => $val) {
|
||||
$width = $this->colWidth[$key];
|
||||
// form https://github.com/symfony/console/blob/20c9821c8d1c2189f287dcee709b2f86353ea08f/Helper/Table.php#L467
|
||||
// str_pad won't work properly with multi-byte strings, we need to fix the padding
|
||||
if (false !== $encoding = mb_detect_encoding((string) $val, null, true)) {
|
||||
$width += strlen((string) $val) - mb_strwidth((string) $val, $encoding);
|
||||
}
|
||||
$array[] = ' ' . str_pad((string) $val, $width, ' ', $this->cellAlign);
|
||||
}
|
||||
|
||||
$content .= $style[0] . implode(' ' . $style[2], $array) . ' ' . $style[3] . PHP_EOL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$content .= $this->renderSeparator('bottom');
|
||||
|
||||
return $content;
|
||||
}
|
||||
}
|
||||
1
vendor/topthink/framework/src/think/console/bin/README.md
vendored
Normal file
1
vendor/topthink/framework/src/think/console/bin/README.md
vendored
Normal file
@@ -0,0 +1 @@
|
||||
console 工具使用 hiddeninput.exe 在 windows 上隐藏密码输入,该二进制文件由第三方提供,相关源码和其他细节可以在 [Hidden Input](https://github.com/Seldaek/hidden-input) 找到。
|
||||
BIN
vendor/topthink/framework/src/think/console/bin/hiddeninput.exe
vendored
Normal file
BIN
vendor/topthink/framework/src/think/console/bin/hiddeninput.exe
vendored
Normal file
Binary file not shown.
85
vendor/topthink/framework/src/think/console/command/Clear.php
vendored
Normal file
85
vendor/topthink/framework/src/think/console/command/Clear.php
vendored
Normal file
@@ -0,0 +1,85 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006-2016 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
namespace think\console\command;
|
||||
|
||||
use think\console\Command;
|
||||
use think\console\Input;
|
||||
use think\console\input\Option;
|
||||
use think\console\Output;
|
||||
|
||||
class Clear extends Command
|
||||
{
|
||||
protected function configure()
|
||||
{
|
||||
// 指令配置
|
||||
$this->setName('clear')
|
||||
->addOption('path', 'd', Option::VALUE_OPTIONAL, 'path to clear', null)
|
||||
->addOption('cache', 'c', Option::VALUE_NONE, 'clear cache file')
|
||||
->addOption('log', 'l', Option::VALUE_NONE, 'clear log file')
|
||||
->addOption('dir', 'r', Option::VALUE_NONE, 'clear empty dir')
|
||||
->addOption('expire', 'e', Option::VALUE_NONE, 'clear cache file if cache has expired')
|
||||
->setDescription('Clear runtime file');
|
||||
}
|
||||
|
||||
protected function execute(Input $input, Output $output)
|
||||
{
|
||||
$runtimePath = $this->app->getRootPath() . 'runtime' . DIRECTORY_SEPARATOR;
|
||||
|
||||
if ($input->getOption('cache')) {
|
||||
$path = $runtimePath . 'cache';
|
||||
} elseif ($input->getOption('log')) {
|
||||
$path = $runtimePath . 'log';
|
||||
} else {
|
||||
$path = $input->getOption('path') ?: $runtimePath;
|
||||
}
|
||||
|
||||
$rmdir = $input->getOption('dir') ? true : false;
|
||||
// --expire 仅当 --cache 时生效
|
||||
$cache_expire = $input->getOption('expire') && $input->getOption('cache') ? true : false;
|
||||
$this->clear(rtrim($path, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR, $rmdir, $cache_expire);
|
||||
|
||||
$output->writeln("<info>Clear Successed</info>");
|
||||
}
|
||||
|
||||
protected function clear(string $path, bool $rmdir, bool $cache_expire): void
|
||||
{
|
||||
$files = is_dir($path) ? scandir($path) : [];
|
||||
|
||||
foreach ($files as $file) {
|
||||
if ('.' != $file && '..' != $file && is_dir($path . $file)) {
|
||||
$this->clear($path . $file . DIRECTORY_SEPARATOR, $rmdir, $cache_expire);
|
||||
if ($rmdir) {
|
||||
@rmdir($path . $file);
|
||||
}
|
||||
} elseif ('.gitignore' != $file && is_file($path . $file)) {
|
||||
if ($cache_expire) {
|
||||
if ($this->cacheHasExpired($path . $file)) {
|
||||
unlink($path . $file);
|
||||
}
|
||||
} else {
|
||||
unlink($path . $file);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 缓存文件是否已过期
|
||||
* @param $filename string 文件路径
|
||||
* @return bool
|
||||
*/
|
||||
protected function cacheHasExpired($filename) {
|
||||
$content = file_get_contents($filename);
|
||||
$expire = (int) substr($content, 8, 12);
|
||||
return 0 != $expire && time() - $expire > filemtime($filename);
|
||||
}
|
||||
|
||||
}
|
||||
70
vendor/topthink/framework/src/think/console/command/Help.php
vendored
Normal file
70
vendor/topthink/framework/src/think/console/command/Help.php
vendored
Normal file
@@ -0,0 +1,70 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2015 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: yunwuxin <448901948@qq.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace think\console\command;
|
||||
|
||||
use think\console\Command;
|
||||
use think\console\Input;
|
||||
use think\console\input\Argument as InputArgument;
|
||||
use think\console\input\Option as InputOption;
|
||||
use think\console\Output;
|
||||
|
||||
class Help extends Command
|
||||
{
|
||||
|
||||
private $command;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function configure()
|
||||
{
|
||||
$this->ignoreValidationErrors();
|
||||
|
||||
$this->setName('help')->setDefinition([
|
||||
new InputArgument('command_name', InputArgument::OPTIONAL, 'The command name', 'help'),
|
||||
new InputOption('raw', null, InputOption::VALUE_NONE, 'To output raw command help'),
|
||||
])->setDescription('Displays help for a command')->setHelp(
|
||||
<<<EOF
|
||||
The <info>%command.name%</info> command displays help for a given command:
|
||||
|
||||
<info>php %command.full_name% list</info>
|
||||
|
||||
To display the list of available commands, please use the <info>list</info> command.
|
||||
EOF
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the command.
|
||||
* @param Command $command The command to set
|
||||
*/
|
||||
public function setCommand(Command $command): void
|
||||
{
|
||||
$this->command = $command;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function execute(Input $input, Output $output)
|
||||
{
|
||||
if (null === $this->command) {
|
||||
$this->command = $this->getConsole()->find($input->getArgument('command_name'));
|
||||
}
|
||||
|
||||
$output->describe($this->command, [
|
||||
'raw_text' => $input->getOption('raw'),
|
||||
]);
|
||||
|
||||
$this->command = null;
|
||||
}
|
||||
}
|
||||
74
vendor/topthink/framework/src/think/console/command/Lists.php
vendored
Normal file
74
vendor/topthink/framework/src/think/console/command/Lists.php
vendored
Normal file
@@ -0,0 +1,74 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2015 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: yunwuxin <448901948@qq.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace think\console\command;
|
||||
|
||||
use think\console\Command;
|
||||
use think\console\Input;
|
||||
use think\console\input\Argument as InputArgument;
|
||||
use think\console\input\Definition as InputDefinition;
|
||||
use think\console\input\Option as InputOption;
|
||||
use think\console\Output;
|
||||
|
||||
class Lists extends Command
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function configure()
|
||||
{
|
||||
$this->setName('list')->setDefinition($this->createDefinition())->setDescription('Lists commands')->setHelp(
|
||||
<<<EOF
|
||||
The <info>%command.name%</info> command lists all commands:
|
||||
|
||||
<info>php %command.full_name%</info>
|
||||
|
||||
You can also display the commands for a specific namespace:
|
||||
|
||||
<info>php %command.full_name% test</info>
|
||||
|
||||
It's also possible to get raw list of commands (useful for embedding command runner):
|
||||
|
||||
<info>php %command.full_name% --raw</info>
|
||||
EOF
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getNativeDefinition(): InputDefinition
|
||||
{
|
||||
return $this->createDefinition();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function execute(Input $input, Output $output)
|
||||
{
|
||||
$output->describe($this->getConsole(), [
|
||||
'raw_text' => $input->getOption('raw'),
|
||||
'namespace' => $input->getArgument('namespace'),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
private function createDefinition(): InputDefinition
|
||||
{
|
||||
return new InputDefinition([
|
||||
new InputArgument('namespace', InputArgument::OPTIONAL, 'The namespace name'),
|
||||
new InputOption('raw', null, InputOption::VALUE_NONE, 'To output raw command list'),
|
||||
]);
|
||||
}
|
||||
}
|
||||
99
vendor/topthink/framework/src/think/console/command/Make.php
vendored
Normal file
99
vendor/topthink/framework/src/think/console/command/Make.php
vendored
Normal file
@@ -0,0 +1,99 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2016 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: 刘志淳 <chun@engineer.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace think\console\command;
|
||||
|
||||
use think\console\Command;
|
||||
use think\console\Input;
|
||||
use think\console\input\Argument;
|
||||
use think\console\Output;
|
||||
|
||||
abstract class Make extends Command
|
||||
{
|
||||
protected $type;
|
||||
|
||||
abstract protected function getStub();
|
||||
|
||||
protected function configure()
|
||||
{
|
||||
$this->addArgument('name', Argument::REQUIRED, "The name of the class");
|
||||
}
|
||||
|
||||
protected function execute(Input $input, Output $output)
|
||||
{
|
||||
$name = trim($input->getArgument('name'));
|
||||
|
||||
$classname = $this->getClassName($name);
|
||||
|
||||
$pathname = $this->getPathName($classname);
|
||||
|
||||
if (is_file($pathname)) {
|
||||
$output->writeln('<error>' . $this->type . ':' . $classname . ' already exists!</error>');
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!is_dir(dirname($pathname))) {
|
||||
mkdir(dirname($pathname), 0755, true);
|
||||
}
|
||||
|
||||
file_put_contents($pathname, $this->buildClass($classname));
|
||||
|
||||
$output->writeln('<info>' . $this->type . ':' . $classname . ' created successfully.</info>');
|
||||
}
|
||||
|
||||
protected function buildClass(string $name)
|
||||
{
|
||||
$stub = file_get_contents($this->getStub());
|
||||
|
||||
$namespace = trim(implode('\\', array_slice(explode('\\', $name), 0, -1)), '\\');
|
||||
|
||||
$class = str_replace($namespace . '\\', '', $name);
|
||||
|
||||
return str_replace(['{%className%}', '{%actionSuffix%}', '{%namespace%}', '{%app_namespace%}'], [
|
||||
$class,
|
||||
$this->app->config->get('route.action_suffix'),
|
||||
$namespace,
|
||||
$this->app->getNamespace(),
|
||||
], $stub);
|
||||
}
|
||||
|
||||
protected function getPathName(string $name): string
|
||||
{
|
||||
$name = substr($name, 4);
|
||||
|
||||
return $this->app->getBasePath() . ltrim(str_replace('\\', '/', $name), '/') . '.php';
|
||||
}
|
||||
|
||||
protected function getClassName(string $name): string
|
||||
{
|
||||
if (str_contains($name, '\\')) {
|
||||
return $name;
|
||||
}
|
||||
|
||||
if (str_contains($name, '@')) {
|
||||
[$app, $name] = explode('@', $name);
|
||||
} else {
|
||||
$app = '';
|
||||
}
|
||||
|
||||
if (str_contains($name, '/')) {
|
||||
$name = str_replace('/', '\\', $name);
|
||||
}
|
||||
|
||||
return $this->getNamespace($app) . '\\' . $name;
|
||||
}
|
||||
|
||||
protected function getNamespace(string $app): string
|
||||
{
|
||||
return 'app' . ($app ? '\\' . $app : '');
|
||||
}
|
||||
|
||||
}
|
||||
128
vendor/topthink/framework/src/think/console/command/RouteList.php
vendored
Normal file
128
vendor/topthink/framework/src/think/console/command/RouteList.php
vendored
Normal file
@@ -0,0 +1,128 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006-2016 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: yunwuxin <448901948@qq.com>
|
||||
// +----------------------------------------------------------------------
|
||||
namespace think\console\command;
|
||||
|
||||
use think\console\Command;
|
||||
use think\console\Input;
|
||||
use think\console\input\Argument;
|
||||
use think\console\input\Option;
|
||||
use think\console\Output;
|
||||
use think\console\Table;
|
||||
use think\event\RouteLoaded;
|
||||
|
||||
class RouteList extends Command
|
||||
{
|
||||
protected $sortBy = [
|
||||
'rule' => 0,
|
||||
'route' => 1,
|
||||
'method' => 2,
|
||||
'name' => 3,
|
||||
'domain' => 4,
|
||||
];
|
||||
|
||||
protected function configure()
|
||||
{
|
||||
$this->setName('route:list')
|
||||
->addArgument('dir', Argument::OPTIONAL, 'dir name .')
|
||||
->addArgument('style', Argument::OPTIONAL, "the style of the table.", 'default')
|
||||
->addOption('sort', 's', Option::VALUE_OPTIONAL, 'order by rule name.', 0)
|
||||
->addOption('more', 'm', Option::VALUE_NONE, 'show route options.')
|
||||
->setDescription('show route list.');
|
||||
}
|
||||
|
||||
protected function execute(Input $input, Output $output)
|
||||
{
|
||||
$dir = $input->getArgument('dir') ?: '';
|
||||
|
||||
$filename = $this->app->getRootPath() . 'runtime' . DIRECTORY_SEPARATOR . ($dir ? $dir . DIRECTORY_SEPARATOR : '') . 'route_list.php';
|
||||
|
||||
if (is_file($filename)) {
|
||||
unlink($filename);
|
||||
} elseif (!is_dir(dirname($filename))) {
|
||||
mkdir(dirname($filename), 0755);
|
||||
}
|
||||
|
||||
$content = $this->getRouteList($dir);
|
||||
file_put_contents($filename, 'Route List' . PHP_EOL . $content);
|
||||
}
|
||||
|
||||
protected function getRouteList(string $dir = null): string
|
||||
{
|
||||
$this->app->route->clear();
|
||||
$this->app->route->lazy(false);
|
||||
|
||||
if ($dir) {
|
||||
$path = $this->app->getRootPath() . 'route' . DIRECTORY_SEPARATOR . $dir . DIRECTORY_SEPARATOR;
|
||||
} else {
|
||||
$path = $this->app->getRootPath() . 'route' . DIRECTORY_SEPARATOR;
|
||||
}
|
||||
|
||||
$files = is_dir($path) ? scandir($path) : [];
|
||||
|
||||
foreach ($files as $file) {
|
||||
if (str_contains($file, '.php')) {
|
||||
include $path . $file;
|
||||
}
|
||||
}
|
||||
|
||||
//触发路由载入完成事件
|
||||
$this->app->event->trigger(RouteLoaded::class);
|
||||
|
||||
$table = new Table();
|
||||
|
||||
if ($this->input->hasOption('more')) {
|
||||
$header = ['Rule', 'Route', 'Method', 'Name', 'Domain', 'Option', 'Pattern'];
|
||||
} else {
|
||||
$header = ['Rule', 'Route', 'Method', 'Name'];
|
||||
}
|
||||
|
||||
$table->setHeader($header);
|
||||
|
||||
$routeList = $this->app->route->getRuleList();
|
||||
$rows = [];
|
||||
|
||||
foreach ($routeList as $item) {
|
||||
$item['route'] = $item['route'] instanceof \Closure ? '<Closure>' : $item['route'];
|
||||
$row = [$item['rule'], $item['route'], $item['method'], $item['name']];
|
||||
|
||||
if ($this->input->hasOption('more')) {
|
||||
array_push($row, $item['domain'], json_encode($item['option']), json_encode($item['pattern']));
|
||||
}
|
||||
|
||||
$rows[] = $row;
|
||||
}
|
||||
|
||||
if ($this->input->getOption('sort')) {
|
||||
$sort = strtolower($this->input->getOption('sort'));
|
||||
|
||||
if (isset($this->sortBy[$sort])) {
|
||||
$sort = $this->sortBy[$sort];
|
||||
}
|
||||
|
||||
uasort($rows, function ($a, $b) use ($sort) {
|
||||
$itemA = $a[$sort] ?? null;
|
||||
$itemB = $b[$sort] ?? null;
|
||||
|
||||
return strcasecmp($itemA, $itemB);
|
||||
});
|
||||
}
|
||||
|
||||
$table->setRows($rows);
|
||||
|
||||
if ($this->input->getArgument('style')) {
|
||||
$style = $this->input->getArgument('style');
|
||||
$table->setStyle($style);
|
||||
}
|
||||
|
||||
return $this->table($table);
|
||||
}
|
||||
|
||||
}
|
||||
72
vendor/topthink/framework/src/think/console/command/RunServer.php
vendored
Normal file
72
vendor/topthink/framework/src/think/console/command/RunServer.php
vendored
Normal file
@@ -0,0 +1,72 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2015 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: Slince <taosikai@yeah.net>
|
||||
// +----------------------------------------------------------------------
|
||||
declare (strict_types = 1);
|
||||
|
||||
namespace think\console\command;
|
||||
|
||||
use think\console\Command;
|
||||
use think\console\Input;
|
||||
use think\console\input\Option;
|
||||
use think\console\Output;
|
||||
|
||||
class RunServer extends Command
|
||||
{
|
||||
public function configure()
|
||||
{
|
||||
$this->setName('run')
|
||||
->addOption(
|
||||
'host',
|
||||
'H',
|
||||
Option::VALUE_OPTIONAL,
|
||||
'The host to server the application on',
|
||||
'0.0.0.0'
|
||||
)
|
||||
->addOption(
|
||||
'port',
|
||||
'p',
|
||||
Option::VALUE_OPTIONAL,
|
||||
'The port to server the application on',
|
||||
8000
|
||||
)
|
||||
->addOption(
|
||||
'root',
|
||||
'r',
|
||||
Option::VALUE_OPTIONAL,
|
||||
'The document root of the application',
|
||||
''
|
||||
)
|
||||
->setDescription('PHP Built-in Server for ThinkPHP');
|
||||
}
|
||||
|
||||
public function execute(Input $input, Output $output)
|
||||
{
|
||||
$host = $input->getOption('host');
|
||||
$port = $input->getOption('port');
|
||||
$root = $input->getOption('root');
|
||||
if (empty($root)) {
|
||||
$root = $this->app->getRootPath() . 'public';
|
||||
}
|
||||
|
||||
$command = sprintf(
|
||||
'"%s" -S %s:%d -t %s %s',
|
||||
PHP_BINARY,
|
||||
$host,
|
||||
$port,
|
||||
escapeshellarg($root),
|
||||
escapeshellarg($root . DIRECTORY_SEPARATOR . 'router.php')
|
||||
);
|
||||
|
||||
$output->writeln(sprintf('ThinkPHP Development server is started On <http://%s:%s/>', $host, $port));
|
||||
$output->writeln(sprintf('You can exit with <info>`CTRL-C`</info>'));
|
||||
$output->writeln(sprintf('Document root is: %s', $root));
|
||||
passthru($command);
|
||||
}
|
||||
}
|
||||
52
vendor/topthink/framework/src/think/console/command/ServiceDiscover.php
vendored
Normal file
52
vendor/topthink/framework/src/think/console/command/ServiceDiscover.php
vendored
Normal file
@@ -0,0 +1,52 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2023 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: yunwuxin <448901948@qq.com>
|
||||
// +----------------------------------------------------------------------
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace think\console\command;
|
||||
|
||||
use think\console\Command;
|
||||
use think\console\Input;
|
||||
use think\console\Output;
|
||||
|
||||
class ServiceDiscover extends Command
|
||||
{
|
||||
public function configure()
|
||||
{
|
||||
$this->setName('service:discover')
|
||||
->setDescription('Discover Services for ThinkPHP');
|
||||
}
|
||||
|
||||
public function execute(Input $input, Output $output)
|
||||
{
|
||||
if (is_file($path = $this->app->getRootPath() . 'vendor/composer/installed.json')) {
|
||||
$packages = json_decode(@file_get_contents($path), true);
|
||||
// Compatibility with Composer 2.0
|
||||
if (isset($packages['packages'])) {
|
||||
$packages = $packages['packages'];
|
||||
}
|
||||
|
||||
$services = [];
|
||||
foreach ($packages as $package) {
|
||||
if (!empty($package['extra']['think']['services'])) {
|
||||
$services = array_merge($services, (array) $package['extra']['think']['services']);
|
||||
}
|
||||
}
|
||||
|
||||
$header = '// This file is automatically generated at:' . date('Y-m-d H:i:s') . PHP_EOL . 'declare (strict_types = 1);' . PHP_EOL;
|
||||
|
||||
$content = '<?php ' . PHP_EOL . $header . "return " . var_export($services, true) . ';';
|
||||
|
||||
file_put_contents($this->app->getRootPath() . 'vendor/services.php', $content);
|
||||
|
||||
$output->writeln('<info>Succeed!</info>');
|
||||
}
|
||||
}
|
||||
}
|
||||
69
vendor/topthink/framework/src/think/console/command/VendorPublish.php
vendored
Normal file
69
vendor/topthink/framework/src/think/console/command/VendorPublish.php
vendored
Normal file
@@ -0,0 +1,69 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2023 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: yunwuxin <448901948@qq.com>
|
||||
// +----------------------------------------------------------------------
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace think\console\command;
|
||||
|
||||
use think\console\Command;
|
||||
use think\console\input\Option;
|
||||
|
||||
class VendorPublish extends Command
|
||||
{
|
||||
public function configure()
|
||||
{
|
||||
$this->setName('vendor:publish')
|
||||
->addOption('force', 'f', Option::VALUE_NONE, 'Overwrite any existing files')
|
||||
->setDescription('Publish any publishable assets from vendor packages');
|
||||
}
|
||||
|
||||
public function handle()
|
||||
{
|
||||
|
||||
$force = $this->input->getOption('force');
|
||||
|
||||
if (is_file($path = $this->app->getRootPath() . 'vendor/composer/installed.json')) {
|
||||
$packages = json_decode(@file_get_contents($path), true);
|
||||
// Compatibility with Composer 2.0
|
||||
if (isset($packages['packages'])) {
|
||||
$packages = $packages['packages'];
|
||||
}
|
||||
foreach ($packages as $package) {
|
||||
//配置
|
||||
$configDir = $this->app->getConfigPath();
|
||||
|
||||
if (!empty($package['extra']['think']['config'])) {
|
||||
|
||||
$installPath = $this->app->getRootPath() . 'vendor/' . $package['name'] . DIRECTORY_SEPARATOR;
|
||||
|
||||
foreach ((array) $package['extra']['think']['config'] as $name => $file) {
|
||||
|
||||
$target = $configDir . $name . '.php';
|
||||
$source = $installPath . $file;
|
||||
|
||||
if (is_file($target) && !$force) {
|
||||
$this->output->info("File {$target} exist!");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!is_file($source)) {
|
||||
$this->output->info("File {$source} not exist!");
|
||||
continue;
|
||||
}
|
||||
|
||||
copy($source, $target);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->output->writeln('<info>Succeed!</info>');
|
||||
}
|
||||
}
|
||||
}
|
||||
35
vendor/topthink/framework/src/think/console/command/Version.php
vendored
Normal file
35
vendor/topthink/framework/src/think/console/command/Version.php
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006-2016 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
declare (strict_types = 1);
|
||||
|
||||
namespace think\console\command;
|
||||
|
||||
use Composer\InstalledVersions;
|
||||
use think\console\Command;
|
||||
use think\console\Input;
|
||||
use think\console\Output;
|
||||
|
||||
class Version extends Command
|
||||
{
|
||||
protected function configure()
|
||||
{
|
||||
// 指令配置
|
||||
$this->setName('version')
|
||||
->setDescription('show thinkphp framework version');
|
||||
}
|
||||
|
||||
protected function execute(Input $input, Output $output)
|
||||
{
|
||||
$version = InstalledVersions::getPrettyVersion('topthink/framework');
|
||||
$output->writeln($version);
|
||||
}
|
||||
|
||||
}
|
||||
54
vendor/topthink/framework/src/think/console/command/make/Command.php
vendored
Normal file
54
vendor/topthink/framework/src/think/console/command/make/Command.php
vendored
Normal file
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2023 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace think\console\command\make;
|
||||
|
||||
use think\console\command\Make;
|
||||
use think\console\input\Argument;
|
||||
|
||||
class Command extends Make
|
||||
{
|
||||
protected $type = "Command";
|
||||
|
||||
protected function configure()
|
||||
{
|
||||
parent::configure();
|
||||
$this->setName('make:command')
|
||||
->addArgument('commandName', Argument::OPTIONAL, "The name of the command")
|
||||
->setDescription('Create a new command class');
|
||||
}
|
||||
|
||||
protected function buildClass(string $name): string
|
||||
{
|
||||
$commandName = $this->input->getArgument('commandName') ?: strtolower(basename($name));
|
||||
$namespace = trim(implode('\\', array_slice(explode('\\', $name), 0, -1)), '\\');
|
||||
|
||||
$class = str_replace($namespace . '\\', '', $name);
|
||||
$stub = file_get_contents($this->getStub());
|
||||
|
||||
return str_replace(['{%commandName%}', '{%className%}', '{%namespace%}', '{%app_namespace%}'], [
|
||||
$commandName,
|
||||
$class,
|
||||
$namespace,
|
||||
$this->app->getNamespace(),
|
||||
], $stub);
|
||||
}
|
||||
|
||||
protected function getStub(): string
|
||||
{
|
||||
return __DIR__ . DIRECTORY_SEPARATOR . 'stubs' . DIRECTORY_SEPARATOR . 'command.stub';
|
||||
}
|
||||
|
||||
protected function getNamespace(string $app): string
|
||||
{
|
||||
return parent::getNamespace($app) . '\\command';
|
||||
}
|
||||
}
|
||||
55
vendor/topthink/framework/src/think/console/command/make/Controller.php
vendored
Normal file
55
vendor/topthink/framework/src/think/console/command/make/Controller.php
vendored
Normal file
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2023 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace think\console\command\make;
|
||||
|
||||
use think\console\command\Make;
|
||||
use think\console\input\Option;
|
||||
|
||||
class Controller extends Make
|
||||
{
|
||||
|
||||
protected $type = "Controller";
|
||||
|
||||
protected function configure()
|
||||
{
|
||||
parent::configure();
|
||||
$this->setName('make:controller')
|
||||
->addOption('api', null, Option::VALUE_NONE, 'Generate an api controller class.')
|
||||
->addOption('plain', null, Option::VALUE_NONE, 'Generate an empty controller class.')
|
||||
->setDescription('Create a new resource controller class');
|
||||
}
|
||||
|
||||
protected function getStub(): string
|
||||
{
|
||||
$stubPath = __DIR__ . DIRECTORY_SEPARATOR . 'stubs' . DIRECTORY_SEPARATOR;
|
||||
|
||||
if ($this->input->getOption('api')) {
|
||||
return $stubPath . 'controller.api.stub';
|
||||
}
|
||||
|
||||
if ($this->input->getOption('plain')) {
|
||||
return $stubPath . 'controller.plain.stub';
|
||||
}
|
||||
|
||||
return $stubPath . 'controller.stub';
|
||||
}
|
||||
|
||||
protected function getClassName(string $name): string
|
||||
{
|
||||
return parent::getClassName($name) . ($this->app->config->get('route.controller_suffix') ? 'Controller' : '');
|
||||
}
|
||||
|
||||
protected function getNamespace(string $app): string
|
||||
{
|
||||
return parent::getNamespace($app) . '\\controller';
|
||||
}
|
||||
}
|
||||
35
vendor/topthink/framework/src/think/console/command/make/Event.php
vendored
Normal file
35
vendor/topthink/framework/src/think/console/command/make/Event.php
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2023 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
namespace think\console\command\make;
|
||||
|
||||
use think\console\command\Make;
|
||||
|
||||
class Event extends Make
|
||||
{
|
||||
protected $type = "Event";
|
||||
|
||||
protected function configure()
|
||||
{
|
||||
parent::configure();
|
||||
$this->setName('make:event')
|
||||
->setDescription('Create a new event class');
|
||||
}
|
||||
|
||||
protected function getStub(): string
|
||||
{
|
||||
return __DIR__ . DIRECTORY_SEPARATOR . 'stubs' . DIRECTORY_SEPARATOR . 'event.stub';
|
||||
}
|
||||
|
||||
protected function getNamespace(string $app): string
|
||||
{
|
||||
return parent::getNamespace($app) . '\\event';
|
||||
}
|
||||
}
|
||||
35
vendor/topthink/framework/src/think/console/command/make/Listener.php
vendored
Normal file
35
vendor/topthink/framework/src/think/console/command/make/Listener.php
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2023 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
namespace think\console\command\make;
|
||||
|
||||
use think\console\command\Make;
|
||||
|
||||
class Listener extends Make
|
||||
{
|
||||
protected $type = "Listener";
|
||||
|
||||
protected function configure()
|
||||
{
|
||||
parent::configure();
|
||||
$this->setName('make:listener')
|
||||
->setDescription('Create a new listener class');
|
||||
}
|
||||
|
||||
protected function getStub(): string
|
||||
{
|
||||
return __DIR__ . DIRECTORY_SEPARATOR . 'stubs' . DIRECTORY_SEPARATOR . 'listener.stub';
|
||||
}
|
||||
|
||||
protected function getNamespace(string $app): string
|
||||
{
|
||||
return parent::getNamespace($app) . '\\listener';
|
||||
}
|
||||
}
|
||||
36
vendor/topthink/framework/src/think/console/command/make/Middleware.php
vendored
Normal file
36
vendor/topthink/framework/src/think/console/command/make/Middleware.php
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2023 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace think\console\command\make;
|
||||
|
||||
use think\console\command\Make;
|
||||
|
||||
class Middleware extends Make
|
||||
{
|
||||
protected $type = "Middleware";
|
||||
|
||||
protected function configure()
|
||||
{
|
||||
parent::configure();
|
||||
$this->setName('make:middleware')
|
||||
->setDescription('Create a new middleware class');
|
||||
}
|
||||
|
||||
protected function getStub(): string
|
||||
{
|
||||
return __DIR__ . DIRECTORY_SEPARATOR . 'stubs' . DIRECTORY_SEPARATOR . 'middleware.stub';
|
||||
}
|
||||
|
||||
protected function getNamespace(string $app): string
|
||||
{
|
||||
return parent::getNamespace($app) . '\\middleware';
|
||||
}
|
||||
}
|
||||
36
vendor/topthink/framework/src/think/console/command/make/Model.php
vendored
Normal file
36
vendor/topthink/framework/src/think/console/command/make/Model.php
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2023 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace think\console\command\make;
|
||||
|
||||
use think\console\command\Make;
|
||||
|
||||
class Model extends Make
|
||||
{
|
||||
protected $type = "Model";
|
||||
|
||||
protected function configure()
|
||||
{
|
||||
parent::configure();
|
||||
$this->setName('make:model')
|
||||
->setDescription('Create a new model class');
|
||||
}
|
||||
|
||||
protected function getStub(): string
|
||||
{
|
||||
return __DIR__ . DIRECTORY_SEPARATOR . 'stubs' . DIRECTORY_SEPARATOR . 'model.stub';
|
||||
}
|
||||
|
||||
protected function getNamespace(string $app): string
|
||||
{
|
||||
return parent::getNamespace($app) . '\\model';
|
||||
}
|
||||
}
|
||||
36
vendor/topthink/framework/src/think/console/command/make/Service.php
vendored
Normal file
36
vendor/topthink/framework/src/think/console/command/make/Service.php
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2023 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace think\console\command\make;
|
||||
|
||||
use think\console\command\Make;
|
||||
|
||||
class Service extends Make
|
||||
{
|
||||
protected $type = "Service";
|
||||
|
||||
protected function configure()
|
||||
{
|
||||
parent::configure();
|
||||
$this->setName('make:service')
|
||||
->setDescription('Create a new Service class');
|
||||
}
|
||||
|
||||
protected function getStub(): string
|
||||
{
|
||||
return __DIR__ . DIRECTORY_SEPARATOR . 'stubs' . DIRECTORY_SEPARATOR . 'service.stub';
|
||||
}
|
||||
|
||||
protected function getNamespace(string $app): string
|
||||
{
|
||||
return parent::getNamespace($app) . '\\service';
|
||||
}
|
||||
}
|
||||
35
vendor/topthink/framework/src/think/console/command/make/Subscribe.php
vendored
Normal file
35
vendor/topthink/framework/src/think/console/command/make/Subscribe.php
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2023 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
namespace think\console\command\make;
|
||||
|
||||
use think\console\command\Make;
|
||||
|
||||
class Subscribe extends Make
|
||||
{
|
||||
protected $type = "Subscribe";
|
||||
|
||||
protected function configure()
|
||||
{
|
||||
parent::configure();
|
||||
$this->setName('make:subscribe')
|
||||
->setDescription('Create a new subscribe class');
|
||||
}
|
||||
|
||||
protected function getStub(): string
|
||||
{
|
||||
return __DIR__ . DIRECTORY_SEPARATOR . 'stubs' . DIRECTORY_SEPARATOR . 'subscribe.stub';
|
||||
}
|
||||
|
||||
protected function getNamespace(string $app): string
|
||||
{
|
||||
return parent::getNamespace($app) . '\\subscribe';
|
||||
}
|
||||
}
|
||||
38
vendor/topthink/framework/src/think/console/command/make/Validate.php
vendored
Normal file
38
vendor/topthink/framework/src/think/console/command/make/Validate.php
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2023 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace think\console\command\make;
|
||||
|
||||
use think\console\command\Make;
|
||||
|
||||
class Validate extends Make
|
||||
{
|
||||
protected $type = "Validate";
|
||||
|
||||
protected function configure()
|
||||
{
|
||||
parent::configure();
|
||||
$this->setName('make:validate')
|
||||
->setDescription('Create a validate class');
|
||||
}
|
||||
|
||||
protected function getStub(): string
|
||||
{
|
||||
$stubPath = __DIR__ . DIRECTORY_SEPARATOR . 'stubs' . DIRECTORY_SEPARATOR;
|
||||
|
||||
return $stubPath . 'validate.stub';
|
||||
}
|
||||
|
||||
protected function getNamespace(string $app): string
|
||||
{
|
||||
return parent::getNamespace($app) . '\\validate';
|
||||
}
|
||||
}
|
||||
26
vendor/topthink/framework/src/think/console/command/make/stubs/command.stub
vendored
Normal file
26
vendor/topthink/framework/src/think/console/command/make/stubs/command.stub
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
declare (strict_types = 1);
|
||||
|
||||
namespace {%namespace%};
|
||||
|
||||
use think\console\Command;
|
||||
use think\console\Input;
|
||||
use think\console\input\Argument;
|
||||
use think\console\input\Option;
|
||||
use think\console\Output;
|
||||
|
||||
class {%className%} extends Command
|
||||
{
|
||||
protected function configure()
|
||||
{
|
||||
// 指令配置
|
||||
$this->setName('{%commandName%}')
|
||||
->setDescription('the {%commandName%} command');
|
||||
}
|
||||
|
||||
protected function execute(Input $input, Output $output)
|
||||
{
|
||||
// 指令输出
|
||||
$output->writeln('{%commandName%}');
|
||||
}
|
||||
}
|
||||
64
vendor/topthink/framework/src/think/console/command/make/stubs/controller.api.stub
vendored
Normal file
64
vendor/topthink/framework/src/think/console/command/make/stubs/controller.api.stub
vendored
Normal file
@@ -0,0 +1,64 @@
|
||||
<?php
|
||||
declare (strict_types = 1);
|
||||
|
||||
namespace {%namespace%};
|
||||
|
||||
use think\Request;
|
||||
|
||||
class {%className%}
|
||||
{
|
||||
/**
|
||||
* 显示资源列表
|
||||
*
|
||||
* @return \think\Response
|
||||
*/
|
||||
public function index{%actionSuffix%}()
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存新建的资源
|
||||
*
|
||||
* @param \think\Request $request
|
||||
* @return \think\Response
|
||||
*/
|
||||
public function save{%actionSuffix%}(Request $request)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* 显示指定的资源
|
||||
*
|
||||
* @param int $id
|
||||
* @return \think\Response
|
||||
*/
|
||||
public function read{%actionSuffix%}($id)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存更新的资源
|
||||
*
|
||||
* @param \think\Request $request
|
||||
* @param int $id
|
||||
* @return \think\Response
|
||||
*/
|
||||
public function update{%actionSuffix%}(Request $request, $id)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除指定资源
|
||||
*
|
||||
* @param int $id
|
||||
* @return \think\Response
|
||||
*/
|
||||
public function delete{%actionSuffix%}($id)
|
||||
{
|
||||
//
|
||||
}
|
||||
}
|
||||
9
vendor/topthink/framework/src/think/console/command/make/stubs/controller.plain.stub
vendored
Normal file
9
vendor/topthink/framework/src/think/console/command/make/stubs/controller.plain.stub
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
declare (strict_types = 1);
|
||||
|
||||
namespace {%namespace%};
|
||||
|
||||
class {%className%}
|
||||
{
|
||||
//
|
||||
}
|
||||
85
vendor/topthink/framework/src/think/console/command/make/stubs/controller.stub
vendored
Normal file
85
vendor/topthink/framework/src/think/console/command/make/stubs/controller.stub
vendored
Normal file
@@ -0,0 +1,85 @@
|
||||
<?php
|
||||
declare (strict_types = 1);
|
||||
|
||||
namespace {%namespace%};
|
||||
|
||||
use think\Request;
|
||||
|
||||
class {%className%}
|
||||
{
|
||||
/**
|
||||
* 显示资源列表
|
||||
*
|
||||
* @return \think\Response
|
||||
*/
|
||||
public function index{%actionSuffix%}()
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* 显示创建资源表单页.
|
||||
*
|
||||
* @return \think\Response
|
||||
*/
|
||||
public function create{%actionSuffix%}()
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存新建的资源
|
||||
*
|
||||
* @param \think\Request $request
|
||||
* @return \think\Response
|
||||
*/
|
||||
public function save{%actionSuffix%}(Request $request)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* 显示指定的资源
|
||||
*
|
||||
* @param int $id
|
||||
* @return \think\Response
|
||||
*/
|
||||
public function read{%actionSuffix%}($id)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* 显示编辑资源表单页.
|
||||
*
|
||||
* @param int $id
|
||||
* @return \think\Response
|
||||
*/
|
||||
public function edit{%actionSuffix%}($id)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存更新的资源
|
||||
*
|
||||
* @param \think\Request $request
|
||||
* @param int $id
|
||||
* @return \think\Response
|
||||
*/
|
||||
public function update{%actionSuffix%}(Request $request, $id)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除指定资源
|
||||
*
|
||||
* @param int $id
|
||||
* @return \think\Response
|
||||
*/
|
||||
public function delete{%actionSuffix%}($id)
|
||||
{
|
||||
//
|
||||
}
|
||||
}
|
||||
8
vendor/topthink/framework/src/think/console/command/make/stubs/event.stub
vendored
Normal file
8
vendor/topthink/framework/src/think/console/command/make/stubs/event.stub
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
<?php
|
||||
declare (strict_types = 1);
|
||||
|
||||
namespace {%namespace%};
|
||||
|
||||
class {%className%}
|
||||
{
|
||||
}
|
||||
17
vendor/topthink/framework/src/think/console/command/make/stubs/listener.stub
vendored
Normal file
17
vendor/topthink/framework/src/think/console/command/make/stubs/listener.stub
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
declare (strict_types = 1);
|
||||
|
||||
namespace {%namespace%};
|
||||
|
||||
class {%className%}
|
||||
{
|
||||
/**
|
||||
* 事件监听处理
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle($event)
|
||||
{
|
||||
//
|
||||
}
|
||||
}
|
||||
19
vendor/topthink/framework/src/think/console/command/make/stubs/middleware.stub
vendored
Normal file
19
vendor/topthink/framework/src/think/console/command/make/stubs/middleware.stub
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
declare (strict_types = 1);
|
||||
|
||||
namespace {%namespace%};
|
||||
|
||||
class {%className%}
|
||||
{
|
||||
/**
|
||||
* 处理请求
|
||||
*
|
||||
* @param \think\Request $request
|
||||
* @param \Closure $next
|
||||
* @return Response
|
||||
*/
|
||||
public function handle($request, \Closure $next)
|
||||
{
|
||||
//
|
||||
}
|
||||
}
|
||||
14
vendor/topthink/framework/src/think/console/command/make/stubs/model.stub
vendored
Normal file
14
vendor/topthink/framework/src/think/console/command/make/stubs/model.stub
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
declare (strict_types = 1);
|
||||
|
||||
namespace {%namespace%};
|
||||
|
||||
use think\Model;
|
||||
|
||||
/**
|
||||
* @mixin \think\Model
|
||||
*/
|
||||
class {%className%} extends Model
|
||||
{
|
||||
//
|
||||
}
|
||||
27
vendor/topthink/framework/src/think/console/command/make/stubs/service.stub
vendored
Normal file
27
vendor/topthink/framework/src/think/console/command/make/stubs/service.stub
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
declare (strict_types = 1);
|
||||
|
||||
namespace {%namespace%};
|
||||
|
||||
class {%className%} extends \think\Service
|
||||
{
|
||||
/**
|
||||
* 注册服务
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function register()
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行服务
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function boot()
|
||||
{
|
||||
//
|
||||
}
|
||||
}
|
||||
8
vendor/topthink/framework/src/think/console/command/make/stubs/subscribe.stub
vendored
Normal file
8
vendor/topthink/framework/src/think/console/command/make/stubs/subscribe.stub
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
<?php
|
||||
declare (strict_types = 1);
|
||||
|
||||
namespace {%namespace%};
|
||||
|
||||
class {%className%}
|
||||
{
|
||||
}
|
||||
25
vendor/topthink/framework/src/think/console/command/make/stubs/validate.stub
vendored
Normal file
25
vendor/topthink/framework/src/think/console/command/make/stubs/validate.stub
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
declare (strict_types = 1);
|
||||
|
||||
namespace {%namespace%};
|
||||
|
||||
use think\Validate;
|
||||
|
||||
class {%className%} extends Validate
|
||||
{
|
||||
/**
|
||||
* 定义验证规则
|
||||
* 格式:'字段名' => ['规则1','规则2'...]
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $rule = [];
|
||||
|
||||
/**
|
||||
* 定义错误信息
|
||||
* 格式:'字段名.规则名' => '错误信息'
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $message = [];
|
||||
}
|
||||
66
vendor/topthink/framework/src/think/console/command/optimize/Route.php
vendored
Normal file
66
vendor/topthink/framework/src/think/console/command/optimize/Route.php
vendored
Normal file
@@ -0,0 +1,66 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006-2016 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: yunwuxin <448901948@qq.com>
|
||||
// +----------------------------------------------------------------------
|
||||
namespace think\console\command\optimize;
|
||||
|
||||
use think\console\Command;
|
||||
use think\console\Input;
|
||||
use think\console\input\Argument;
|
||||
use think\console\Output;
|
||||
use think\event\RouteLoaded;
|
||||
|
||||
class Route extends Command
|
||||
{
|
||||
protected function configure()
|
||||
{
|
||||
$this->setName('optimize:route')
|
||||
->addArgument('dir', Argument::OPTIONAL, 'dir name .')
|
||||
->setDescription('Build app route cache.');
|
||||
}
|
||||
|
||||
protected function execute(Input $input, Output $output)
|
||||
{
|
||||
$dir = $input->getArgument('dir') ?: '';
|
||||
|
||||
$path = $this->app->getRootPath() . 'runtime' . DIRECTORY_SEPARATOR . ($dir ? $dir . DIRECTORY_SEPARATOR : '');
|
||||
|
||||
$filename = $path . 'route.php';
|
||||
if (is_file($filename)) {
|
||||
unlink($filename);
|
||||
}
|
||||
|
||||
file_put_contents($filename, $this->buildRouteCache($dir));
|
||||
$output->writeln('<info>Succeed!</info>');
|
||||
}
|
||||
|
||||
protected function buildRouteCache(string $dir = null): string
|
||||
{
|
||||
$this->app->route->clear();
|
||||
$this->app->route->lazy(false);
|
||||
|
||||
// 路由检测
|
||||
$path = $this->app->getRootPath() . ($dir ? 'app' . DIRECTORY_SEPARATOR . $dir . DIRECTORY_SEPARATOR : '') . 'route' . DIRECTORY_SEPARATOR;
|
||||
|
||||
$files = is_dir($path) ? scandir($path) : [];
|
||||
|
||||
foreach ($files as $file) {
|
||||
if (str_contains($file, '.php')) {
|
||||
include $path . $file;
|
||||
}
|
||||
}
|
||||
|
||||
//触发路由载入完成事件
|
||||
$this->app->event->trigger(RouteLoaded::class);
|
||||
$rules = $this->app->route->getName();
|
||||
|
||||
return '<?php ' . PHP_EOL . 'return unserialize(\'' . serialize($rules) . '\');';
|
||||
}
|
||||
|
||||
}
|
||||
109
vendor/topthink/framework/src/think/console/command/optimize/Schema.php
vendored
Normal file
109
vendor/topthink/framework/src/think/console/command/optimize/Schema.php
vendored
Normal file
@@ -0,0 +1,109 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006-2016 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: yunwuxin <448901948@qq.com>
|
||||
// +----------------------------------------------------------------------
|
||||
namespace think\console\command\optimize;
|
||||
|
||||
use Exception;
|
||||
use think\console\Command;
|
||||
use think\console\Input;
|
||||
use think\console\input\Argument;
|
||||
use think\console\input\Option;
|
||||
use think\console\Output;
|
||||
use think\db\PDOConnection;
|
||||
|
||||
class Schema extends Command
|
||||
{
|
||||
protected function configure()
|
||||
{
|
||||
$this->setName('optimize:schema')
|
||||
->addArgument('dir', Argument::OPTIONAL, 'dir name .')
|
||||
->addOption('connection', null, Option::VALUE_REQUIRED, 'connection name .')
|
||||
->addOption('table', null, Option::VALUE_REQUIRED, 'table name .')
|
||||
->setDescription('Build database schema cache.');
|
||||
}
|
||||
|
||||
protected function execute(Input $input, Output $output)
|
||||
{
|
||||
$dir = $input->getArgument('dir') ?: '';
|
||||
|
||||
if ($input->hasOption('table')) {
|
||||
$connection = $this->app->db->connect($input->getOption('connection'));
|
||||
if (!$connection instanceof PDOConnection) {
|
||||
$output->error("only PDO connection support schema cache!");
|
||||
return;
|
||||
}
|
||||
$table = $input->getOption('table');
|
||||
if (!str_contains($table, '.')) {
|
||||
$dbName = $connection->getConfig('database');
|
||||
} else {
|
||||
[$dbName, $table] = explode('.', $table);
|
||||
}
|
||||
|
||||
if ($table == '*') {
|
||||
$table = $connection->getTables($dbName);
|
||||
}
|
||||
|
||||
$this->buildDataBaseSchema($connection, (array) $table, $dbName);
|
||||
} else {
|
||||
if ($dir) {
|
||||
$appPath = $this->app->getBasePath() . $dir . DIRECTORY_SEPARATOR;
|
||||
$namespace = 'app\\' . $dir;
|
||||
} else {
|
||||
$appPath = $this->app->getBasePath();
|
||||
$namespace = 'app';
|
||||
}
|
||||
|
||||
$path = $appPath . 'model';
|
||||
$list = is_dir($path) ? scandir($path) : [];
|
||||
|
||||
foreach ($list as $file) {
|
||||
if (str_starts_with($file, '.')) {
|
||||
continue;
|
||||
}
|
||||
$class = '\\' . $namespace . '\\model\\' . pathinfo($file, PATHINFO_FILENAME);
|
||||
|
||||
if (!class_exists($class)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->buildModelSchema($class);
|
||||
}
|
||||
}
|
||||
|
||||
$output->writeln('<info>Succeed!</info>');
|
||||
}
|
||||
|
||||
protected function buildModelSchema(string $class): void
|
||||
{
|
||||
$reflect = new \ReflectionClass($class);
|
||||
if (!$reflect->isAbstract() && $reflect->isSubclassOf('\think\Model')) {
|
||||
try {
|
||||
/** @var \think\Model $model */
|
||||
$model = new $class;
|
||||
$connection = $model->db()->getConnection();
|
||||
if ($connection instanceof PDOConnection) {
|
||||
$table = $model->getTable();
|
||||
//预读字段信息
|
||||
$connection->getSchemaInfo($table, true);
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected function buildDataBaseSchema(PDOConnection $connection, array $tables, string $dbName): void
|
||||
{
|
||||
foreach ($tables as $table) {
|
||||
//预读字段信息
|
||||
$connection->getSchemaInfo("{$dbName}.{$table}", true);
|
||||
}
|
||||
}
|
||||
}
|
||||
138
vendor/topthink/framework/src/think/console/input/Argument.php
vendored
Normal file
138
vendor/topthink/framework/src/think/console/input/Argument.php
vendored
Normal file
@@ -0,0 +1,138 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2015 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: yunwuxin <448901948@qq.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace think\console\input;
|
||||
|
||||
class Argument
|
||||
{
|
||||
// 必传参数
|
||||
const REQUIRED = 1;
|
||||
|
||||
// 可选参数
|
||||
const OPTIONAL = 2;
|
||||
|
||||
// 数组参数
|
||||
const IS_ARRAY = 4;
|
||||
|
||||
/**
|
||||
* 参数名
|
||||
* @var string
|
||||
*/
|
||||
private $name;
|
||||
|
||||
/**
|
||||
* 参数类型
|
||||
* @var int
|
||||
*/
|
||||
private $mode;
|
||||
|
||||
/**
|
||||
* 参数默认值
|
||||
* @var mixed
|
||||
*/
|
||||
private $default;
|
||||
|
||||
/**
|
||||
* 参数描述
|
||||
* @var string
|
||||
*/
|
||||
private $description;
|
||||
|
||||
/**
|
||||
* 构造方法
|
||||
* @param string $name 参数名
|
||||
* @param int $mode 参数类型: self::REQUIRED 或者 self::OPTIONAL
|
||||
* @param string $description 描述
|
||||
* @param mixed $default 默认值 (仅 self::OPTIONAL 类型有效)
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public function __construct(string $name, int $mode = null, string $description = '', $default = null)
|
||||
{
|
||||
if (null === $mode) {
|
||||
$mode = self::OPTIONAL;
|
||||
} elseif (!is_int($mode) || $mode > 7 || $mode < 1) {
|
||||
throw new \InvalidArgumentException(sprintf('Argument mode "%s" is not valid.', $mode));
|
||||
}
|
||||
|
||||
$this->name = $name;
|
||||
$this->mode = $mode;
|
||||
$this->description = $description;
|
||||
|
||||
$this->setDefault($default);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取参数名
|
||||
* @return string
|
||||
*/
|
||||
public function getName(): string
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否必须
|
||||
* @return bool
|
||||
*/
|
||||
public function isRequired(): bool
|
||||
{
|
||||
return self::REQUIRED === (self::REQUIRED & $this->mode);
|
||||
}
|
||||
|
||||
/**
|
||||
* 该参数是否接受数组
|
||||
* @return bool
|
||||
*/
|
||||
public function isArray(): bool
|
||||
{
|
||||
return self::IS_ARRAY === (self::IS_ARRAY & $this->mode);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置默认值
|
||||
* @param mixed $default 默认值
|
||||
* @throws \LogicException
|
||||
*/
|
||||
public function setDefault($default = null): void
|
||||
{
|
||||
if (self::REQUIRED === $this->mode && null !== $default) {
|
||||
throw new \LogicException('Cannot set a default value except for InputArgument::OPTIONAL mode.');
|
||||
}
|
||||
|
||||
if ($this->isArray()) {
|
||||
if (null === $default) {
|
||||
$default = [];
|
||||
} elseif (!is_array($default)) {
|
||||
throw new \LogicException('A default value for an array argument must be an array.');
|
||||
}
|
||||
}
|
||||
|
||||
$this->default = $default;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取默认值
|
||||
* @return mixed
|
||||
*/
|
||||
public function getDefault()
|
||||
{
|
||||
return $this->default;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取描述
|
||||
* @return string
|
||||
*/
|
||||
public function getDescription(): string
|
||||
{
|
||||
return $this->description;
|
||||
}
|
||||
}
|
||||
375
vendor/topthink/framework/src/think/console/input/Definition.php
vendored
Normal file
375
vendor/topthink/framework/src/think/console/input/Definition.php
vendored
Normal file
@@ -0,0 +1,375 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2015 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: yunwuxin <448901948@qq.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace think\console\input;
|
||||
|
||||
class Definition
|
||||
{
|
||||
|
||||
/**
|
||||
* @var Argument[]
|
||||
*/
|
||||
private $arguments;
|
||||
|
||||
private $requiredCount;
|
||||
private $hasAnArrayArgument = false;
|
||||
private $hasOptional;
|
||||
|
||||
/**
|
||||
* @var Option[]
|
||||
*/
|
||||
private $options;
|
||||
private $shortcuts;
|
||||
|
||||
/**
|
||||
* 构造方法
|
||||
* @param array $definition
|
||||
* @api
|
||||
*/
|
||||
public function __construct(array $definition = [])
|
||||
{
|
||||
$this->setDefinition($definition);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置指令的定义
|
||||
* @param array $definition 定义的数组
|
||||
*/
|
||||
public function setDefinition(array $definition): void
|
||||
{
|
||||
$arguments = [];
|
||||
$options = [];
|
||||
foreach ($definition as $item) {
|
||||
if ($item instanceof Option) {
|
||||
$options[] = $item;
|
||||
} else {
|
||||
$arguments[] = $item;
|
||||
}
|
||||
}
|
||||
|
||||
$this->setArguments($arguments);
|
||||
$this->setOptions($options);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置参数
|
||||
* @param Argument[] $arguments 参数数组
|
||||
*/
|
||||
public function setArguments(array $arguments = []): void
|
||||
{
|
||||
$this->arguments = [];
|
||||
$this->requiredCount = 0;
|
||||
$this->hasOptional = false;
|
||||
$this->hasAnArrayArgument = false;
|
||||
$this->addArguments($arguments);
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加参数
|
||||
* @param Argument[] $arguments 参数数组
|
||||
* @api
|
||||
*/
|
||||
public function addArguments(array $arguments = []): void
|
||||
{
|
||||
if (null !== $arguments) {
|
||||
foreach ($arguments as $argument) {
|
||||
$this->addArgument($argument);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加一个参数
|
||||
* @param Argument $argument 参数
|
||||
* @throws \LogicException
|
||||
*/
|
||||
public function addArgument(Argument $argument): void
|
||||
{
|
||||
if (isset($this->arguments[$argument->getName()])) {
|
||||
throw new \LogicException(sprintf('An argument with name "%s" already exists.', $argument->getName()));
|
||||
}
|
||||
|
||||
if ($this->hasAnArrayArgument) {
|
||||
throw new \LogicException('Cannot add an argument after an array argument.');
|
||||
}
|
||||
|
||||
if ($argument->isRequired() && $this->hasOptional) {
|
||||
throw new \LogicException('Cannot add a required argument after an optional one.');
|
||||
}
|
||||
|
||||
if ($argument->isArray()) {
|
||||
$this->hasAnArrayArgument = true;
|
||||
}
|
||||
|
||||
if ($argument->isRequired()) {
|
||||
++$this->requiredCount;
|
||||
} else {
|
||||
$this->hasOptional = true;
|
||||
}
|
||||
|
||||
$this->arguments[$argument->getName()] = $argument;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据名称或者位置获取参数
|
||||
* @param string|int $name 参数名或者位置
|
||||
* @return Argument 参数
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public function getArgument($name): Argument
|
||||
{
|
||||
if (!$this->hasArgument($name)) {
|
||||
throw new \InvalidArgumentException(sprintf('The "%s" argument does not exist.', $name));
|
||||
}
|
||||
|
||||
$arguments = is_int($name) ? array_values($this->arguments) : $this->arguments;
|
||||
|
||||
return $arguments[$name];
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据名称或位置检查是否具有某个参数
|
||||
* @param string|int $name 参数名或者位置
|
||||
* @return bool
|
||||
* @api
|
||||
*/
|
||||
public function hasArgument($name): bool
|
||||
{
|
||||
$arguments = is_int($name) ? array_values($this->arguments) : $this->arguments;
|
||||
|
||||
return isset($arguments[$name]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有的参数
|
||||
* @return Argument[] 参数数组
|
||||
*/
|
||||
public function getArguments(): array
|
||||
{
|
||||
return $this->arguments;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取参数数量
|
||||
* @return int
|
||||
*/
|
||||
public function getArgumentCount(): int
|
||||
{
|
||||
return $this->hasAnArrayArgument ? PHP_INT_MAX : count($this->arguments);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取必填的参数的数量
|
||||
* @return int
|
||||
*/
|
||||
public function getArgumentRequiredCount(): int
|
||||
{
|
||||
return $this->requiredCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取参数默认值
|
||||
* @return array
|
||||
*/
|
||||
public function getArgumentDefaults(): array
|
||||
{
|
||||
$values = [];
|
||||
foreach ($this->arguments as $argument) {
|
||||
$values[$argument->getName()] = $argument->getDefault();
|
||||
}
|
||||
|
||||
return $values;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置选项
|
||||
* @param Option[] $options 选项数组
|
||||
*/
|
||||
public function setOptions(array $options = []): void
|
||||
{
|
||||
$this->options = [];
|
||||
$this->shortcuts = [];
|
||||
$this->addOptions($options);
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加选项
|
||||
* @param Option[] $options 选项数组
|
||||
* @api
|
||||
*/
|
||||
public function addOptions(array $options = []): void
|
||||
{
|
||||
foreach ($options as $option) {
|
||||
$this->addOption($option);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加一个选项
|
||||
* @param Option $option 选项
|
||||
* @throws \LogicException
|
||||
* @api
|
||||
*/
|
||||
public function addOption(Option $option): void
|
||||
{
|
||||
if (isset($this->options[$option->getName()]) && !$option->equals($this->options[$option->getName()])) {
|
||||
throw new \LogicException(sprintf('An option named "%s" already exists.', $option->getName()));
|
||||
}
|
||||
|
||||
if ($option->getShortcut()) {
|
||||
foreach (explode('|', $option->getShortcut()) as $shortcut) {
|
||||
if (isset($this->shortcuts[$shortcut])
|
||||
&& !$option->equals($this->options[$this->shortcuts[$shortcut]])
|
||||
) {
|
||||
throw new \LogicException(sprintf('An option with shortcut "%s" already exists.', $shortcut));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->options[$option->getName()] = $option;
|
||||
if ($option->getShortcut()) {
|
||||
foreach (explode('|', $option->getShortcut()) as $shortcut) {
|
||||
$this->shortcuts[$shortcut] = $option->getName();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据名称获取选项
|
||||
* @param string $name 选项名
|
||||
* @return Option
|
||||
* @throws \InvalidArgumentException
|
||||
* @api
|
||||
*/
|
||||
public function getOption(string $name): Option
|
||||
{
|
||||
if (!$this->hasOption($name)) {
|
||||
throw new \InvalidArgumentException(sprintf('The "--%s" option does not exist.', $name));
|
||||
}
|
||||
|
||||
return $this->options[$name];
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据名称检查是否有这个选项
|
||||
* @param string $name 选项名
|
||||
* @return bool
|
||||
* @api
|
||||
*/
|
||||
public function hasOption(string $name): bool
|
||||
{
|
||||
return isset($this->options[$name]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有选项
|
||||
* @return Option[]
|
||||
* @api
|
||||
*/
|
||||
public function getOptions(): array
|
||||
{
|
||||
return $this->options;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据名称检查某个选项是否有短名称
|
||||
* @param string $name 短名称
|
||||
* @return bool
|
||||
*/
|
||||
public function hasShortcut(string $name): bool
|
||||
{
|
||||
return isset($this->shortcuts[$name]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据短名称获取选项
|
||||
* @param string $shortcut 短名称
|
||||
* @return Option
|
||||
*/
|
||||
public function getOptionForShortcut(string $shortcut): Option
|
||||
{
|
||||
return $this->getOption($this->shortcutToName($shortcut));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有选项的默认值
|
||||
* @return array
|
||||
*/
|
||||
public function getOptionDefaults(): array
|
||||
{
|
||||
$values = [];
|
||||
foreach ($this->options as $option) {
|
||||
$values[$option->getName()] = $option->getDefault();
|
||||
}
|
||||
|
||||
return $values;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据短名称获取选项名
|
||||
* @param string $shortcut 短名称
|
||||
* @return string
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
private function shortcutToName(string $shortcut): string
|
||||
{
|
||||
if (!isset($this->shortcuts[$shortcut])) {
|
||||
throw new \InvalidArgumentException(sprintf('The "-%s" option does not exist.', $shortcut));
|
||||
}
|
||||
|
||||
return $this->shortcuts[$shortcut];
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取该指令的介绍
|
||||
* @param bool $short 是否简洁介绍
|
||||
* @return string
|
||||
*/
|
||||
public function getSynopsis(bool $short = false): string
|
||||
{
|
||||
$elements = [];
|
||||
|
||||
if ($short && $this->getOptions()) {
|
||||
$elements[] = '[options]';
|
||||
} elseif (!$short) {
|
||||
foreach ($this->getOptions() as $option) {
|
||||
$value = '';
|
||||
if ($option->acceptValue()) {
|
||||
$value = sprintf(' %s%s%s', $option->isValueOptional() ? '[' : '', strtoupper($option->getName()), $option->isValueOptional() ? ']' : '');
|
||||
}
|
||||
|
||||
$shortcut = $option->getShortcut() ? sprintf('-%s|', $option->getShortcut()) : '';
|
||||
$elements[] = sprintf('[%s--%s%s]', $shortcut, $option->getName(), $value);
|
||||
}
|
||||
}
|
||||
|
||||
if (count($elements) && $this->getArguments()) {
|
||||
$elements[] = '[--]';
|
||||
}
|
||||
|
||||
foreach ($this->getArguments() as $argument) {
|
||||
$element = '<' . $argument->getName() . '>';
|
||||
if (!$argument->isRequired()) {
|
||||
$element = '[' . $element . ']';
|
||||
} elseif ($argument->isArray()) {
|
||||
$element .= ' (' . $element . ')';
|
||||
}
|
||||
|
||||
if ($argument->isArray()) {
|
||||
$element .= '...';
|
||||
}
|
||||
|
||||
$elements[] = $element;
|
||||
}
|
||||
|
||||
return implode(' ', $elements);
|
||||
}
|
||||
}
|
||||
221
vendor/topthink/framework/src/think/console/input/Option.php
vendored
Normal file
221
vendor/topthink/framework/src/think/console/input/Option.php
vendored
Normal file
@@ -0,0 +1,221 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2015 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: yunwuxin <448901948@qq.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace think\console\input;
|
||||
|
||||
/**
|
||||
* 命令行选项
|
||||
* @package think\console\input
|
||||
*/
|
||||
class Option
|
||||
{
|
||||
// 无需传值
|
||||
const VALUE_NONE = 1;
|
||||
// 必须传值
|
||||
const VALUE_REQUIRED = 2;
|
||||
// 可选传值
|
||||
const VALUE_OPTIONAL = 4;
|
||||
// 传数组值
|
||||
const VALUE_IS_ARRAY = 8;
|
||||
|
||||
/**
|
||||
* 选项名
|
||||
* @var string
|
||||
*/
|
||||
private $name = '';
|
||||
|
||||
/**
|
||||
* 选项短名称
|
||||
* @var string
|
||||
*/
|
||||
private $shortcut = '';
|
||||
|
||||
/**
|
||||
* 选项类型
|
||||
* @var int
|
||||
*/
|
||||
private $mode;
|
||||
|
||||
/**
|
||||
* 选项默认值
|
||||
* @var mixed
|
||||
*/
|
||||
private $default;
|
||||
|
||||
/**
|
||||
* 选项描述
|
||||
* @var string
|
||||
*/
|
||||
private $description = '';
|
||||
|
||||
/**
|
||||
* 构造方法
|
||||
* @param string $name 选项名
|
||||
* @param string|array $shortcut 短名称,多个用|隔开或者使用数组
|
||||
* @param int $mode 选项类型(可选类型为 self::VALUE_*)
|
||||
* @param string $description 描述
|
||||
* @param mixed $default 默认值 (类型为 self::VALUE_REQUIRED 或者 self::VALUE_NONE 的时候必须为null)
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public function __construct($name, $shortcut = null, $mode = null, $description = '', $default = null)
|
||||
{
|
||||
if (str_starts_with($name, '--')) {
|
||||
$name = substr($name, 2);
|
||||
}
|
||||
|
||||
if (empty($name)) {
|
||||
throw new \InvalidArgumentException('An option name cannot be empty.');
|
||||
}
|
||||
|
||||
if (empty($shortcut)) {
|
||||
$shortcut = '';
|
||||
}
|
||||
|
||||
if ('' !== $shortcut) {
|
||||
if (is_array($shortcut)) {
|
||||
$shortcut = implode('|', $shortcut);
|
||||
}
|
||||
$shortcuts = preg_split('{(\|)-?}', ltrim($shortcut, '-'));
|
||||
$shortcuts = array_filter($shortcuts);
|
||||
$shortcut = implode('|', $shortcuts);
|
||||
|
||||
if (empty($shortcut)) {
|
||||
throw new \InvalidArgumentException('An option shortcut cannot be empty.');
|
||||
}
|
||||
}
|
||||
|
||||
if (null === $mode) {
|
||||
$mode = self::VALUE_NONE;
|
||||
} elseif (!is_int($mode) || $mode > 15 || $mode < 1) {
|
||||
throw new \InvalidArgumentException(sprintf('Option mode "%s" is not valid.', $mode));
|
||||
}
|
||||
|
||||
$this->name = $name;
|
||||
$this->shortcut = $shortcut;
|
||||
$this->mode = $mode;
|
||||
$this->description = $description;
|
||||
|
||||
if ($this->isArray() && !$this->acceptValue()) {
|
||||
throw new \InvalidArgumentException('Impossible to have an option mode VALUE_IS_ARRAY if the option does not accept a value.');
|
||||
}
|
||||
|
||||
$this->setDefault($default);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取短名称
|
||||
* @return string
|
||||
*/
|
||||
public function getShortcut(): string
|
||||
{
|
||||
return $this->shortcut;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取选项名
|
||||
* @return string
|
||||
*/
|
||||
public function getName(): string
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否可以设置值
|
||||
* @return bool 类型不是 self::VALUE_NONE 的时候返回true,其他均返回false
|
||||
*/
|
||||
public function acceptValue(): bool
|
||||
{
|
||||
return $this->isValueRequired() || $this->isValueOptional();
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否必须
|
||||
* @return bool 类型是 self::VALUE_REQUIRED 的时候返回true,其他均返回false
|
||||
*/
|
||||
public function isValueRequired(): bool
|
||||
{
|
||||
return self::VALUE_REQUIRED === (self::VALUE_REQUIRED & $this->mode);
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否可选
|
||||
* @return bool 类型是 self::VALUE_OPTIONAL 的时候返回true,其他均返回false
|
||||
*/
|
||||
public function isValueOptional(): bool
|
||||
{
|
||||
return self::VALUE_OPTIONAL === (self::VALUE_OPTIONAL & $this->mode);
|
||||
}
|
||||
|
||||
/**
|
||||
* 选项值是否接受数组
|
||||
* @return bool 类型是 self::VALUE_IS_ARRAY 的时候返回true,其他均返回false
|
||||
*/
|
||||
public function isArray(): bool
|
||||
{
|
||||
return self::VALUE_IS_ARRAY === (self::VALUE_IS_ARRAY & $this->mode);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置默认值
|
||||
* @param mixed $default 默认值
|
||||
* @throws \LogicException
|
||||
*/
|
||||
public function setDefault($default = null)
|
||||
{
|
||||
if (self::VALUE_NONE === (self::VALUE_NONE & $this->mode) && null !== $default) {
|
||||
throw new \LogicException('Cannot set a default value when using InputOption::VALUE_NONE mode.');
|
||||
}
|
||||
|
||||
if ($this->isArray()) {
|
||||
if (null === $default) {
|
||||
$default = [];
|
||||
} elseif (!is_array($default)) {
|
||||
throw new \LogicException('A default value for an array option must be an array.');
|
||||
}
|
||||
}
|
||||
|
||||
$this->default = $this->acceptValue() ? $default : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取默认值
|
||||
* @return mixed
|
||||
*/
|
||||
public function getDefault()
|
||||
{
|
||||
return $this->default;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取描述文字
|
||||
* @return string
|
||||
*/
|
||||
public function getDescription(): string
|
||||
{
|
||||
return $this->description;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查所给选项是否是当前这个
|
||||
* @param Option $option
|
||||
* @return bool
|
||||
*/
|
||||
public function equals(Option $option): bool
|
||||
{
|
||||
return $option->getName() === $this->getName()
|
||||
&& $option->getShortcut() === $this->getShortcut()
|
||||
&& $option->getDefault() === $this->getDefault()
|
||||
&& $option->isArray() === $this->isArray()
|
||||
&& $option->isValueRequired() === $this->isValueRequired()
|
||||
&& $option->isValueOptional() === $this->isValueOptional();
|
||||
}
|
||||
}
|
||||
336
vendor/topthink/framework/src/think/console/output/Ask.php
vendored
Normal file
336
vendor/topthink/framework/src/think/console/output/Ask.php
vendored
Normal file
@@ -0,0 +1,336 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006-2016 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: yunwuxin <448901948@qq.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace think\console\output;
|
||||
|
||||
use think\console\Input;
|
||||
use think\console\Output;
|
||||
use think\console\output\question\Choice;
|
||||
use think\console\output\question\Confirmation;
|
||||
|
||||
class Ask
|
||||
{
|
||||
private static $stty;
|
||||
|
||||
private static $shell;
|
||||
|
||||
/** @var Input */
|
||||
protected $input;
|
||||
|
||||
/** @var Output */
|
||||
protected $output;
|
||||
|
||||
/** @var Question */
|
||||
protected $question;
|
||||
|
||||
public function __construct(Input $input, Output $output, Question $question)
|
||||
{
|
||||
$this->input = $input;
|
||||
$this->output = $output;
|
||||
$this->question = $question;
|
||||
}
|
||||
|
||||
public function run()
|
||||
{
|
||||
if (!$this->input->isInteractive()) {
|
||||
return $this->question->getDefault();
|
||||
}
|
||||
|
||||
if (!$this->question->getValidator()) {
|
||||
return $this->doAsk();
|
||||
}
|
||||
|
||||
$that = $this;
|
||||
|
||||
$interviewer = function () use ($that) {
|
||||
return $that->doAsk();
|
||||
};
|
||||
|
||||
return $this->validateAttempts($interviewer);
|
||||
}
|
||||
|
||||
protected function doAsk()
|
||||
{
|
||||
$this->writePrompt();
|
||||
|
||||
$inputStream = STDIN;
|
||||
$autocomplete = $this->question->getAutocompleterValues();
|
||||
|
||||
if (null === $autocomplete || !$this->hasSttyAvailable()) {
|
||||
$ret = false;
|
||||
if ($this->question->isHidden()) {
|
||||
try {
|
||||
$ret = trim($this->getHiddenResponse($inputStream));
|
||||
} catch (\RuntimeException $e) {
|
||||
if (!$this->question->isHiddenFallback()) {
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (false === $ret) {
|
||||
$ret = fgets($inputStream, 4096);
|
||||
if (false === $ret) {
|
||||
throw new \RuntimeException('Aborted');
|
||||
}
|
||||
$ret = trim($ret);
|
||||
}
|
||||
} else {
|
||||
$ret = trim($this->autocomplete($inputStream));
|
||||
}
|
||||
|
||||
$ret = strlen($ret) > 0 ? $ret : $this->question->getDefault();
|
||||
|
||||
if ($normalizer = $this->question->getNormalizer()) {
|
||||
return $normalizer($ret);
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
private function autocomplete($inputStream)
|
||||
{
|
||||
$autocomplete = $this->question->getAutocompleterValues();
|
||||
$ret = '';
|
||||
|
||||
$i = 0;
|
||||
$ofs = -1;
|
||||
$matches = $autocomplete;
|
||||
$numMatches = count($matches);
|
||||
|
||||
$sttyMode = shell_exec('stty -g');
|
||||
|
||||
shell_exec('stty -icanon -echo');
|
||||
|
||||
while (!feof($inputStream)) {
|
||||
$c = fread($inputStream, 1);
|
||||
|
||||
if ("\177" === $c) {
|
||||
if (0 === $numMatches && 0 !== $i) {
|
||||
--$i;
|
||||
$this->output->write("\033[1D");
|
||||
}
|
||||
|
||||
if ($i === 0) {
|
||||
$ofs = -1;
|
||||
$matches = $autocomplete;
|
||||
$numMatches = count($matches);
|
||||
} else {
|
||||
$numMatches = 0;
|
||||
}
|
||||
|
||||
$ret = substr($ret, 0, $i);
|
||||
} elseif ("\033" === $c) {
|
||||
$c .= fread($inputStream, 2);
|
||||
|
||||
if (isset($c[2]) && ('A' === $c[2] || 'B' === $c[2])) {
|
||||
if ('A' === $c[2] && -1 === $ofs) {
|
||||
$ofs = 0;
|
||||
}
|
||||
|
||||
if (0 === $numMatches) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$ofs += ('A' === $c[2]) ? -1 : 1;
|
||||
$ofs = ($numMatches + $ofs) % $numMatches;
|
||||
}
|
||||
} elseif (ord($c) < 32) {
|
||||
if ("\t" === $c || "\n" === $c) {
|
||||
if ($numMatches > 0 && -1 !== $ofs) {
|
||||
$ret = $matches[$ofs];
|
||||
$this->output->write(substr($ret, $i));
|
||||
$i = strlen($ret);
|
||||
}
|
||||
|
||||
if ("\n" === $c) {
|
||||
$this->output->write($c);
|
||||
break;
|
||||
}
|
||||
|
||||
$numMatches = 0;
|
||||
}
|
||||
|
||||
continue;
|
||||
} else {
|
||||
$this->output->write($c);
|
||||
$ret .= $c;
|
||||
++$i;
|
||||
|
||||
$numMatches = 0;
|
||||
$ofs = 0;
|
||||
|
||||
foreach ($autocomplete as $value) {
|
||||
if (str_starts_with($value, $ret) && $i !== strlen($value)) {
|
||||
$matches[$numMatches++] = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->output->write("\033[K");
|
||||
|
||||
if ($numMatches > 0 && -1 !== $ofs) {
|
||||
$this->output->write("\0337");
|
||||
$this->output->highlight(substr($matches[$ofs], $i));
|
||||
$this->output->write("\0338");
|
||||
}
|
||||
}
|
||||
|
||||
shell_exec(sprintf('stty %s', $sttyMode));
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
protected function getHiddenResponse($inputStream)
|
||||
{
|
||||
if ('\\' === DIRECTORY_SEPARATOR) {
|
||||
$exe = __DIR__ . '/../bin/hiddeninput.exe';
|
||||
|
||||
$value = rtrim(shell_exec($exe));
|
||||
$this->output->writeln('');
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
if ($this->hasSttyAvailable()) {
|
||||
$sttyMode = shell_exec('stty -g');
|
||||
|
||||
shell_exec('stty -echo');
|
||||
$value = fgets($inputStream, 4096);
|
||||
shell_exec(sprintf('stty %s', $sttyMode));
|
||||
|
||||
if (false === $value) {
|
||||
throw new \RuntimeException('Aborted');
|
||||
}
|
||||
|
||||
$value = trim($value);
|
||||
$this->output->writeln('');
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
if (false !== $shell = $this->getShell()) {
|
||||
$readCmd = $shell === 'csh' ? 'set mypassword = $<' : 'read -r mypassword';
|
||||
$command = sprintf("/usr/bin/env %s -c 'stty -echo; %s; stty echo; echo \$mypassword'", $shell, $readCmd);
|
||||
$value = rtrim(shell_exec($command));
|
||||
$this->output->writeln('');
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
throw new \RuntimeException('Unable to hide the response.');
|
||||
}
|
||||
|
||||
protected function validateAttempts($interviewer)
|
||||
{
|
||||
/** @var \Exception $error */
|
||||
$error = null;
|
||||
$attempts = $this->question->getMaxAttempts();
|
||||
while (null === $attempts || $attempts--) {
|
||||
if (null !== $error) {
|
||||
$this->output->error($error->getMessage());
|
||||
}
|
||||
|
||||
try {
|
||||
return call_user_func($this->question->getValidator(), $interviewer());
|
||||
} catch (\Exception $error) {
|
||||
}
|
||||
}
|
||||
|
||||
throw $error;
|
||||
}
|
||||
|
||||
/**
|
||||
* 显示问题的提示信息
|
||||
*/
|
||||
protected function writePrompt()
|
||||
{
|
||||
$text = $this->question->getQuestion();
|
||||
$default = $this->question->getDefault();
|
||||
|
||||
switch (true) {
|
||||
case null === $default:
|
||||
$text = sprintf(' <info>%s</info>:', $text);
|
||||
|
||||
break;
|
||||
|
||||
case $this->question instanceof Confirmation:
|
||||
$text = sprintf(' <info>%s (yes/no)</info> [<comment>%s</comment>]:', $text, $default ? 'yes' : 'no');
|
||||
|
||||
break;
|
||||
|
||||
case $this->question instanceof Choice && $this->question->isMultiselect():
|
||||
$choices = $this->question->getChoices();
|
||||
$default = explode(',', $default);
|
||||
|
||||
foreach ($default as $key => $value) {
|
||||
$default[$key] = $choices[trim($value)];
|
||||
}
|
||||
|
||||
$text = sprintf(' <info>%s</info> [<comment>%s</comment>]:', $text, implode(', ', $default));
|
||||
|
||||
break;
|
||||
|
||||
case $this->question instanceof Choice:
|
||||
$choices = $this->question->getChoices();
|
||||
$text = sprintf(' <info>%s</info> [<comment>%s</comment>]:', $text, $choices[$default]);
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
$text = sprintf(' <info>%s</info> [<comment>%s</comment>]:', $text, $default);
|
||||
}
|
||||
|
||||
$this->output->writeln($text);
|
||||
|
||||
if ($this->question instanceof Choice) {
|
||||
$width = max(array_map('strlen', array_keys($this->question->getChoices())));
|
||||
|
||||
foreach ($this->question->getChoices() as $key => $value) {
|
||||
$this->output->writeln(sprintf(" [<comment>%-{$width}s</comment>] %s", $key, $value));
|
||||
}
|
||||
}
|
||||
|
||||
$this->output->write(' > ');
|
||||
}
|
||||
|
||||
private function getShell()
|
||||
{
|
||||
if (null !== self::$shell) {
|
||||
return self::$shell;
|
||||
}
|
||||
|
||||
self::$shell = false;
|
||||
|
||||
if (file_exists('/usr/bin/env')) {
|
||||
$test = "/usr/bin/env %s -c 'echo OK' 2> /dev/null";
|
||||
foreach (['bash', 'zsh', 'ksh', 'csh'] as $sh) {
|
||||
if ('OK' === rtrim(shell_exec(sprintf($test, $sh)))) {
|
||||
self::$shell = $sh;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return self::$shell;
|
||||
}
|
||||
|
||||
private function hasSttyAvailable()
|
||||
{
|
||||
if (null !== self::$stty) {
|
||||
return self::$stty;
|
||||
}
|
||||
|
||||
exec('stty 2>&1', $output, $exitcode);
|
||||
|
||||
return self::$stty = $exitcode === 0;
|
||||
}
|
||||
}
|
||||
323
vendor/topthink/framework/src/think/console/output/Descriptor.php
vendored
Normal file
323
vendor/topthink/framework/src/think/console/output/Descriptor.php
vendored
Normal file
@@ -0,0 +1,323 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2015 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: yunwuxin <448901948@qq.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace think\console\output;
|
||||
|
||||
use think\Console;
|
||||
use think\console\Command;
|
||||
use think\console\input\Argument as InputArgument;
|
||||
use think\console\input\Definition as InputDefinition;
|
||||
use think\console\input\Option as InputOption;
|
||||
use think\console\Output;
|
||||
use think\console\output\descriptor\Console as ConsoleDescription;
|
||||
|
||||
class Descriptor
|
||||
{
|
||||
|
||||
/**
|
||||
* @var Output
|
||||
*/
|
||||
protected $output;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function describe(Output $output, $object, array $options = [])
|
||||
{
|
||||
$this->output = $output;
|
||||
|
||||
switch (true) {
|
||||
case $object instanceof InputArgument:
|
||||
$this->describeInputArgument($object, $options);
|
||||
break;
|
||||
case $object instanceof InputOption:
|
||||
$this->describeInputOption($object, $options);
|
||||
break;
|
||||
case $object instanceof InputDefinition:
|
||||
$this->describeInputDefinition($object, $options);
|
||||
break;
|
||||
case $object instanceof Command:
|
||||
$this->describeCommand($object, $options);
|
||||
break;
|
||||
case $object instanceof Console:
|
||||
$this->describeConsole($object, $options);
|
||||
break;
|
||||
default:
|
||||
throw new \InvalidArgumentException(sprintf('Object of type "%s" is not describable.', $object::class));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 输出内容
|
||||
* @param string $content
|
||||
* @param bool $decorated
|
||||
*/
|
||||
protected function write($content, $decorated = false)
|
||||
{
|
||||
$this->output->write($content, false, $decorated ? Output::OUTPUT_NORMAL : Output::OUTPUT_RAW);
|
||||
}
|
||||
|
||||
/**
|
||||
* 描述参数
|
||||
* @param InputArgument $argument
|
||||
* @param array $options
|
||||
* @return string|mixed
|
||||
*/
|
||||
protected function describeInputArgument(InputArgument $argument, array $options = [])
|
||||
{
|
||||
if (null !== $argument->getDefault()
|
||||
&& (!is_array($argument->getDefault())
|
||||
|| count($argument->getDefault()))
|
||||
) {
|
||||
$default = sprintf('<comment> [default: %s]</comment>', $this->formatDefaultValue($argument->getDefault()));
|
||||
} else {
|
||||
$default = '';
|
||||
}
|
||||
|
||||
$totalWidth = $options['total_width'] ?? strlen($argument->getName());
|
||||
$spacingWidth = $totalWidth - strlen($argument->getName()) + 2;
|
||||
|
||||
$this->writeText(sprintf(" <info>%s</info>%s%s%s", $argument->getName(), str_repeat(' ', $spacingWidth), // + 17 = 2 spaces + <info> + </info> + 2 spaces
|
||||
preg_replace('/\s*[\r\n]\s*/', PHP_EOL . str_repeat(' ', $totalWidth + 17), $argument->getDescription()), $default), $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* 描述选项
|
||||
* @param InputOption $option
|
||||
* @param array $options
|
||||
* @return string|mixed
|
||||
*/
|
||||
protected function describeInputOption(InputOption $option, array $options = [])
|
||||
{
|
||||
if ($option->acceptValue() && null !== $option->getDefault()
|
||||
&& (!is_array($option->getDefault())
|
||||
|| count($option->getDefault()))
|
||||
) {
|
||||
$default = sprintf('<comment> [default: %s]</comment>', $this->formatDefaultValue($option->getDefault()));
|
||||
} else {
|
||||
$default = '';
|
||||
}
|
||||
|
||||
$value = '';
|
||||
if ($option->acceptValue()) {
|
||||
$value = '=' . strtoupper($option->getName());
|
||||
|
||||
if ($option->isValueOptional()) {
|
||||
$value = '[' . $value . ']';
|
||||
}
|
||||
}
|
||||
|
||||
$totalWidth = $options['total_width'] ?? $this->calculateTotalWidthForOptions([$option]);
|
||||
$synopsis = sprintf('%s%s', $option->getShortcut() ? sprintf('-%s, ', $option->getShortcut()) : ' ', sprintf('--%s%s', $option->getName(), $value));
|
||||
|
||||
$spacingWidth = $totalWidth - strlen($synopsis) + 2;
|
||||
|
||||
$this->writeText(sprintf(" <info>%s</info>%s%s%s%s", $synopsis, str_repeat(' ', $spacingWidth), // + 17 = 2 spaces + <info> + </info> + 2 spaces
|
||||
preg_replace('/\s*[\r\n]\s*/', "\n" . str_repeat(' ', $totalWidth + 17), $option->getDescription()), $default, $option->isArray() ? '<comment> (multiple values allowed)</comment>' : ''), $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* 描述输入
|
||||
* @param InputDefinition $definition
|
||||
* @param array $options
|
||||
* @return string|mixed
|
||||
*/
|
||||
protected function describeInputDefinition(InputDefinition $definition, array $options = [])
|
||||
{
|
||||
$totalWidth = $this->calculateTotalWidthForOptions($definition->getOptions());
|
||||
foreach ($definition->getArguments() as $argument) {
|
||||
$totalWidth = max($totalWidth, strlen($argument->getName()));
|
||||
}
|
||||
|
||||
if ($definition->getArguments()) {
|
||||
$this->writeText('<comment>Arguments:</comment>', $options);
|
||||
$this->writeText("\n");
|
||||
foreach ($definition->getArguments() as $argument) {
|
||||
$this->describeInputArgument($argument, array_merge($options, ['total_width' => $totalWidth]));
|
||||
$this->writeText("\n");
|
||||
}
|
||||
}
|
||||
|
||||
if ($definition->getArguments() && $definition->getOptions()) {
|
||||
$this->writeText("\n");
|
||||
}
|
||||
|
||||
if ($definition->getOptions()) {
|
||||
$laterOptions = [];
|
||||
|
||||
$this->writeText('<comment>Options:</comment>', $options);
|
||||
foreach ($definition->getOptions() as $option) {
|
||||
if (strlen($option->getShortcut()) > 1) {
|
||||
$laterOptions[] = $option;
|
||||
continue;
|
||||
}
|
||||
$this->writeText("\n");
|
||||
$this->describeInputOption($option, array_merge($options, ['total_width' => $totalWidth]));
|
||||
}
|
||||
foreach ($laterOptions as $option) {
|
||||
$this->writeText("\n");
|
||||
$this->describeInputOption($option, array_merge($options, ['total_width' => $totalWidth]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 描述指令
|
||||
* @param Command $command
|
||||
* @param array $options
|
||||
* @return string|mixed
|
||||
*/
|
||||
protected function describeCommand(Command $command, array $options = [])
|
||||
{
|
||||
$command->getSynopsis(true);
|
||||
$command->getSynopsis(false);
|
||||
$command->mergeConsoleDefinition(false);
|
||||
|
||||
$this->writeText('<comment>Usage:</comment>', $options);
|
||||
foreach (array_merge([$command->getSynopsis(true)], $command->getAliases(), $command->getUsages()) as $usage) {
|
||||
$this->writeText("\n");
|
||||
$this->writeText(' ' . $usage, $options);
|
||||
}
|
||||
$this->writeText("\n");
|
||||
|
||||
$definition = $command->getNativeDefinition();
|
||||
if ($definition->getOptions() || $definition->getArguments()) {
|
||||
$this->writeText("\n");
|
||||
$this->describeInputDefinition($definition, $options);
|
||||
$this->writeText("\n");
|
||||
}
|
||||
|
||||
if ($help = $command->getProcessedHelp()) {
|
||||
$this->writeText("\n");
|
||||
$this->writeText('<comment>Help:</comment>', $options);
|
||||
$this->writeText("\n");
|
||||
$this->writeText(' ' . str_replace("\n", "\n ", $help), $options);
|
||||
$this->writeText("\n");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 描述控制台
|
||||
* @param Console $console
|
||||
* @param array $options
|
||||
* @return string|mixed
|
||||
*/
|
||||
protected function describeConsole(Console $console, array $options = [])
|
||||
{
|
||||
$describedNamespace = isset($options['namespace']) ? $options['namespace'] : null;
|
||||
$description = new ConsoleDescription($console, $describedNamespace);
|
||||
|
||||
if (isset($options['raw_text']) && $options['raw_text']) {
|
||||
$width = $this->getColumnWidth($description->getNamespaces());
|
||||
|
||||
foreach ($description->getCommands() as $command) {
|
||||
$this->writeText(sprintf("%-{$width}s %s", $command->getName(), $command->getDescription()), $options);
|
||||
$this->writeText("\n");
|
||||
}
|
||||
} else {
|
||||
if ('' != $help = $console->getHelp()) {
|
||||
$this->writeText("$help\n\n", $options);
|
||||
}
|
||||
|
||||
$this->writeText("<comment>Usage:</comment>\n", $options);
|
||||
$this->writeText(" command [options] [arguments]\n\n", $options);
|
||||
|
||||
$this->describeInputDefinition(new InputDefinition($console->getDefinition()->getOptions()), $options);
|
||||
|
||||
$this->writeText("\n");
|
||||
$this->writeText("\n");
|
||||
|
||||
$width = $this->getColumnWidth($description->getNamespaces());
|
||||
|
||||
if ($describedNamespace) {
|
||||
$this->writeText(sprintf('<comment>Available commands for the "%s" namespace:</comment>', $describedNamespace), $options);
|
||||
} else {
|
||||
$this->writeText('<comment>Available commands:</comment>', $options);
|
||||
}
|
||||
|
||||
// add commands by namespace
|
||||
foreach ($description->getNamespaces() as $namespace) {
|
||||
if (!$describedNamespace && ConsoleDescription::GLOBAL_NAMESPACE !== $namespace['id']) {
|
||||
$this->writeText("\n");
|
||||
$this->writeText(' <comment>' . $namespace['id'] . '</comment>', $options);
|
||||
}
|
||||
|
||||
foreach ($namespace['commands'] as $name) {
|
||||
$this->writeText("\n");
|
||||
$spacingWidth = $width - strlen($name);
|
||||
$this->writeText(sprintf(" <info>%s</info>%s%s", $name, str_repeat(' ', $spacingWidth), $description->getCommand($name)
|
||||
->getDescription()), $options);
|
||||
}
|
||||
}
|
||||
|
||||
$this->writeText("\n");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
private function writeText($content, array $options = [])
|
||||
{
|
||||
$this->write(isset($options['raw_text'])
|
||||
&& $options['raw_text'] ? strip_tags($content) : $content, isset($options['raw_output']) ? !$options['raw_output'] : true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化
|
||||
* @param mixed $default
|
||||
* @return string
|
||||
*/
|
||||
private function formatDefaultValue($default)
|
||||
{
|
||||
return json_encode($default, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Namespaces[] $namespaces
|
||||
* @return int
|
||||
*/
|
||||
private function getColumnWidth(array $namespaces)
|
||||
{
|
||||
$width = 0;
|
||||
foreach ($namespaces as $namespace) {
|
||||
foreach ($namespace['commands'] as $name) {
|
||||
if (strlen($name) > $width) {
|
||||
$width = strlen($name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $width + 2;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param InputOption[] $options
|
||||
* @return int
|
||||
*/
|
||||
private function calculateTotalWidthForOptions($options)
|
||||
{
|
||||
$totalWidth = 0;
|
||||
foreach ($options as $option) {
|
||||
$nameLength = 4 + strlen($option->getName()) + 2; // - + shortcut + , + whitespace + name + --
|
||||
|
||||
if ($option->acceptValue()) {
|
||||
$valueLength = 1 + strlen($option->getName()); // = + value
|
||||
$valueLength += $option->isValueOptional() ? 2 : 0; // [ + ]
|
||||
|
||||
$nameLength += $valueLength;
|
||||
}
|
||||
$totalWidth = max($totalWidth, $nameLength);
|
||||
}
|
||||
|
||||
return $totalWidth;
|
||||
}
|
||||
}
|
||||
198
vendor/topthink/framework/src/think/console/output/Formatter.php
vendored
Normal file
198
vendor/topthink/framework/src/think/console/output/Formatter.php
vendored
Normal file
@@ -0,0 +1,198 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2015 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: yunwuxin <448901948@qq.com>
|
||||
// +----------------------------------------------------------------------
|
||||
namespace think\console\output;
|
||||
|
||||
use think\console\output\formatter\Stack as StyleStack;
|
||||
use think\console\output\formatter\Style;
|
||||
|
||||
class Formatter
|
||||
{
|
||||
|
||||
private $decorated = false;
|
||||
private $styles = [];
|
||||
private $styleStack;
|
||||
|
||||
/**
|
||||
* 转义
|
||||
* @param string $text
|
||||
* @return string
|
||||
*/
|
||||
public static function escape($text)
|
||||
{
|
||||
return preg_replace('/([^\\\\]?)</is', '$1\\<', $text);
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化命令行输出格式
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->setStyle('error', new Style('white', 'red'));
|
||||
$this->setStyle('info', new Style('green'));
|
||||
$this->setStyle('comment', new Style('yellow'));
|
||||
$this->setStyle('question', new Style('black', 'cyan'));
|
||||
$this->setStyle('highlight', new Style('red'));
|
||||
$this->setStyle('warning', new Style('black', 'yellow'));
|
||||
|
||||
$this->styleStack = new StyleStack();
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置外观标识
|
||||
* @param bool $decorated 是否美化文字
|
||||
*/
|
||||
public function setDecorated($decorated)
|
||||
{
|
||||
$this->decorated = (bool) $decorated;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取外观标识
|
||||
* @return bool
|
||||
*/
|
||||
public function isDecorated()
|
||||
{
|
||||
return $this->decorated;
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加一个新样式
|
||||
* @param string $name 样式名
|
||||
* @param Style $style 样式实例
|
||||
*/
|
||||
public function setStyle($name, Style $style)
|
||||
{
|
||||
$this->styles[strtolower($name)] = $style;
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否有这个样式
|
||||
* @param string $name
|
||||
* @return bool
|
||||
*/
|
||||
public function hasStyle($name)
|
||||
{
|
||||
return isset($this->styles[strtolower($name)]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取样式
|
||||
* @param string $name
|
||||
* @return Style
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public function getStyle($name)
|
||||
{
|
||||
if (!$this->hasStyle($name)) {
|
||||
throw new \InvalidArgumentException(sprintf('Undefined style: %s', $name));
|
||||
}
|
||||
|
||||
return $this->styles[strtolower($name)];
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用所给的样式格式化文字
|
||||
* @param string $message 文字
|
||||
* @return string
|
||||
*/
|
||||
public function format($message)
|
||||
{
|
||||
$offset = 0;
|
||||
$output = '';
|
||||
$tagRegex = '[a-z][a-z0-9_=;-]*';
|
||||
preg_match_all("#<(($tagRegex) | /($tagRegex)?)>#isx", $message, $matches, PREG_OFFSET_CAPTURE);
|
||||
foreach ($matches[0] as $i => $match) {
|
||||
$pos = $match[1];
|
||||
$text = $match[0];
|
||||
|
||||
if (0 != $pos && '\\' == $message[$pos - 1]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$output .= $this->applyCurrentStyle(substr($message, $offset, $pos - $offset));
|
||||
$offset = $pos + strlen($text);
|
||||
|
||||
if ($open = '/' != $text[1]) {
|
||||
$tag = $matches[1][$i][0];
|
||||
} else {
|
||||
$tag = $matches[3][$i][0] ?? '';
|
||||
}
|
||||
|
||||
if (!$open && !$tag) {
|
||||
// </>
|
||||
$this->styleStack->pop();
|
||||
} elseif (false === $style = $this->createStyleFromString(strtolower($tag))) {
|
||||
$output .= $this->applyCurrentStyle($text);
|
||||
} elseif ($open) {
|
||||
$this->styleStack->push($style);
|
||||
} else {
|
||||
$this->styleStack->pop($style);
|
||||
}
|
||||
}
|
||||
|
||||
$output .= $this->applyCurrentStyle(substr($message, $offset));
|
||||
|
||||
return str_replace('\\<', '<', $output);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return StyleStack
|
||||
*/
|
||||
public function getStyleStack()
|
||||
{
|
||||
return $this->styleStack;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据字符串创建新的样式实例
|
||||
* @param string $string
|
||||
* @return Style|bool
|
||||
*/
|
||||
private function createStyleFromString($string)
|
||||
{
|
||||
if (isset($this->styles[$string])) {
|
||||
return $this->styles[$string];
|
||||
}
|
||||
|
||||
if (!preg_match_all('/([^=]+)=([^;]+)(;|$)/', strtolower($string), $matches, PREG_SET_ORDER)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$style = new Style();
|
||||
foreach ($matches as $match) {
|
||||
array_shift($match);
|
||||
|
||||
if ('fg' == $match[0]) {
|
||||
$style->setForeground($match[1]);
|
||||
} elseif ('bg' == $match[0]) {
|
||||
$style->setBackground($match[1]);
|
||||
} else {
|
||||
try {
|
||||
$style->setOption($match[1]);
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $style;
|
||||
}
|
||||
|
||||
/**
|
||||
* 从堆栈应用样式到文字
|
||||
* @param string $text 文字
|
||||
* @return string
|
||||
*/
|
||||
private function applyCurrentStyle($text)
|
||||
{
|
||||
return $this->isDecorated() && strlen($text) > 0 ? $this->styleStack->getCurrent()->apply($text) : $text;
|
||||
}
|
||||
}
|
||||
211
vendor/topthink/framework/src/think/console/output/Question.php
vendored
Normal file
211
vendor/topthink/framework/src/think/console/output/Question.php
vendored
Normal file
@@ -0,0 +1,211 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2015 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: yunwuxin <448901948@qq.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace think\console\output;
|
||||
|
||||
class Question
|
||||
{
|
||||
|
||||
private $question;
|
||||
private $attempts;
|
||||
private $hidden = false;
|
||||
private $hiddenFallback = true;
|
||||
private $autocompleterValues;
|
||||
private $validator;
|
||||
private $default;
|
||||
private $normalizer;
|
||||
|
||||
/**
|
||||
* 构造方法
|
||||
* @param string $question 问题
|
||||
* @param mixed $default 默认答案
|
||||
*/
|
||||
public function __construct($question, $default = null)
|
||||
{
|
||||
$this->question = $question;
|
||||
$this->default = $default;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取问题
|
||||
* @return string
|
||||
*/
|
||||
public function getQuestion()
|
||||
{
|
||||
return $this->question;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取默认答案
|
||||
* @return mixed
|
||||
*/
|
||||
public function getDefault()
|
||||
{
|
||||
return $this->default;
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否隐藏答案
|
||||
* @return bool
|
||||
*/
|
||||
public function isHidden()
|
||||
{
|
||||
return $this->hidden;
|
||||
}
|
||||
|
||||
/**
|
||||
* 隐藏答案
|
||||
* @param bool $hidden
|
||||
* @return Question
|
||||
*/
|
||||
public function setHidden($hidden)
|
||||
{
|
||||
if ($this->autocompleterValues) {
|
||||
throw new \LogicException('A hidden question cannot use the autocompleter.');
|
||||
}
|
||||
|
||||
$this->hidden = (bool) $hidden;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 不能被隐藏是否撤销
|
||||
* @return bool
|
||||
*/
|
||||
public function isHiddenFallback()
|
||||
{
|
||||
return $this->hiddenFallback;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置不能被隐藏的时候的操作
|
||||
* @param bool $fallback
|
||||
* @return Question
|
||||
*/
|
||||
public function setHiddenFallback($fallback)
|
||||
{
|
||||
$this->hiddenFallback = (bool) $fallback;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取自动完成
|
||||
* @return null|array|\Traversable
|
||||
*/
|
||||
public function getAutocompleterValues()
|
||||
{
|
||||
return $this->autocompleterValues;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置自动完成的值
|
||||
* @param null|array|\Traversable $values
|
||||
* @return Question
|
||||
* @throws \InvalidArgumentException
|
||||
* @throws \LogicException
|
||||
*/
|
||||
public function setAutocompleterValues($values)
|
||||
{
|
||||
if (is_array($values) && $this->isAssoc($values)) {
|
||||
$values = array_merge(array_keys($values), array_values($values));
|
||||
}
|
||||
|
||||
if (null !== $values && !is_array($values)) {
|
||||
if (!$values instanceof \Traversable || $values instanceof \Countable) {
|
||||
throw new \InvalidArgumentException('Autocompleter values can be either an array, `null` or an object implementing both `Countable` and `Traversable` interfaces.');
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->hidden) {
|
||||
throw new \LogicException('A hidden question cannot use the autocompleter.');
|
||||
}
|
||||
|
||||
$this->autocompleterValues = $values;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置答案的验证器
|
||||
* @param null|callable $validator
|
||||
* @return Question The current instance
|
||||
*/
|
||||
public function setValidator($validator)
|
||||
{
|
||||
$this->validator = $validator;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取验证器
|
||||
* @return null|callable
|
||||
*/
|
||||
public function getValidator()
|
||||
{
|
||||
return $this->validator;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置最大重试次数
|
||||
* @param null|int $attempts
|
||||
* @return Question
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public function setMaxAttempts($attempts)
|
||||
{
|
||||
if (null !== $attempts && $attempts < 1) {
|
||||
throw new \InvalidArgumentException('Maximum number of attempts must be a positive value.');
|
||||
}
|
||||
|
||||
$this->attempts = $attempts;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取最大重试次数
|
||||
* @return null|int
|
||||
*/
|
||||
public function getMaxAttempts()
|
||||
{
|
||||
return $this->attempts;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置响应的回调
|
||||
* @param string|\Closure $normalizer
|
||||
* @return Question
|
||||
*/
|
||||
public function setNormalizer($normalizer)
|
||||
{
|
||||
$this->normalizer = $normalizer;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取响应回调
|
||||
* The normalizer can ba a callable (a string), a closure or a class implementing __invoke.
|
||||
* @return string|\Closure
|
||||
*/
|
||||
public function getNormalizer()
|
||||
{
|
||||
return $this->normalizer;
|
||||
}
|
||||
|
||||
protected function isAssoc($array)
|
||||
{
|
||||
return (bool) count(array_filter(array_keys($array), 'is_string'));
|
||||
}
|
||||
}
|
||||
153
vendor/topthink/framework/src/think/console/output/descriptor/Console.php
vendored
Normal file
153
vendor/topthink/framework/src/think/console/output/descriptor/Console.php
vendored
Normal file
@@ -0,0 +1,153 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2015 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: yunwuxin <448901948@qq.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace think\console\output\descriptor;
|
||||
|
||||
use think\Console as ThinkConsole;
|
||||
use think\console\Command;
|
||||
|
||||
class Console
|
||||
{
|
||||
|
||||
const GLOBAL_NAMESPACE = '_global';
|
||||
|
||||
/**
|
||||
* @var ThinkConsole
|
||||
*/
|
||||
private $console;
|
||||
|
||||
/**
|
||||
* @var null|string
|
||||
*/
|
||||
private $namespace;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $namespaces;
|
||||
|
||||
/**
|
||||
* @var Command[]
|
||||
*/
|
||||
private $commands;
|
||||
|
||||
/**
|
||||
* @var Command[]
|
||||
*/
|
||||
private $aliases;
|
||||
|
||||
/**
|
||||
* 构造方法
|
||||
* @param ThinkConsole $console
|
||||
* @param string|null $namespace
|
||||
*/
|
||||
public function __construct(ThinkConsole $console, $namespace = null)
|
||||
{
|
||||
$this->console = $console;
|
||||
$this->namespace = $namespace;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getNamespaces(): array
|
||||
{
|
||||
if (null === $this->namespaces) {
|
||||
$this->inspectConsole();
|
||||
}
|
||||
|
||||
return $this->namespaces;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Command[]
|
||||
*/
|
||||
public function getCommands(): array
|
||||
{
|
||||
if (null === $this->commands) {
|
||||
$this->inspectConsole();
|
||||
}
|
||||
|
||||
return $this->commands;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @return Command
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public function getCommand(string $name): Command
|
||||
{
|
||||
if (!isset($this->commands[$name]) && !isset($this->aliases[$name])) {
|
||||
throw new \InvalidArgumentException(sprintf('Command %s does not exist.', $name));
|
||||
}
|
||||
|
||||
return $this->commands[$name] ?? $this->aliases[$name];
|
||||
}
|
||||
|
||||
private function inspectConsole(): void
|
||||
{
|
||||
$this->commands = [];
|
||||
$this->namespaces = [];
|
||||
|
||||
$all = $this->console->all($this->namespace ? $this->console->findNamespace($this->namespace) : null);
|
||||
foreach ($this->sortCommands($all) as $namespace => $commands) {
|
||||
$names = [];
|
||||
|
||||
/** @var Command $command */
|
||||
foreach ($commands as $name => $command) {
|
||||
if (is_string($command)) {
|
||||
$command = new $command();
|
||||
}
|
||||
|
||||
if (!$command->getName()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($command->getName() === $name) {
|
||||
$this->commands[$name] = $command;
|
||||
} else {
|
||||
$this->aliases[$name] = $command;
|
||||
}
|
||||
|
||||
$names[] = $name;
|
||||
}
|
||||
|
||||
$this->namespaces[$namespace] = ['id' => $namespace, 'commands' => $names];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $commands
|
||||
* @return array
|
||||
*/
|
||||
private function sortCommands(array $commands): array
|
||||
{
|
||||
$namespacedCommands = [];
|
||||
foreach ($commands as $name => $command) {
|
||||
$key = $this->console->extractNamespace($name, 1);
|
||||
if (!$key) {
|
||||
$key = self::GLOBAL_NAMESPACE;
|
||||
}
|
||||
|
||||
$namespacedCommands[$key][$name] = $command;
|
||||
}
|
||||
ksort($namespacedCommands);
|
||||
|
||||
foreach ($namespacedCommands as &$commandsSet) {
|
||||
ksort($commandsSet);
|
||||
}
|
||||
// unset reference to keep scope clear
|
||||
unset($commandsSet);
|
||||
|
||||
return $namespacedCommands;
|
||||
}
|
||||
}
|
||||
52
vendor/topthink/framework/src/think/console/output/driver/Buffer.php
vendored
Normal file
52
vendor/topthink/framework/src/think/console/output/driver/Buffer.php
vendored
Normal file
@@ -0,0 +1,52 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006-2016 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: yunwuxin <448901948@qq.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace think\console\output\driver;
|
||||
|
||||
use think\console\Output;
|
||||
|
||||
class Buffer
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $buffer = '';
|
||||
|
||||
public function __construct(Output $output)
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
public function fetch()
|
||||
{
|
||||
$content = $this->buffer;
|
||||
$this->buffer = '';
|
||||
return $content;
|
||||
}
|
||||
|
||||
public function write($messages, bool $newline = false, int $options = 0)
|
||||
{
|
||||
$messages = (array) $messages;
|
||||
|
||||
foreach ($messages as $message) {
|
||||
$this->buffer .= $message;
|
||||
}
|
||||
if ($newline) {
|
||||
$this->buffer .= "\n";
|
||||
}
|
||||
}
|
||||
|
||||
public function renderException(\Throwable $e)
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
}
|
||||
369
vendor/topthink/framework/src/think/console/output/driver/Console.php
vendored
Normal file
369
vendor/topthink/framework/src/think/console/output/driver/Console.php
vendored
Normal file
@@ -0,0 +1,369 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006-2016 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: yunwuxin <448901948@qq.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace think\console\output\driver;
|
||||
|
||||
use think\console\Output;
|
||||
use think\console\output\Formatter;
|
||||
|
||||
class Console
|
||||
{
|
||||
|
||||
/** @var Resource */
|
||||
private $stdout;
|
||||
|
||||
/** @var Formatter */
|
||||
private $formatter;
|
||||
|
||||
private $terminalDimensions;
|
||||
|
||||
/** @var Output */
|
||||
private $output;
|
||||
|
||||
public function __construct(Output $output)
|
||||
{
|
||||
$this->output = $output;
|
||||
$this->formatter = new Formatter();
|
||||
$this->stdout = $this->openOutputStream();
|
||||
$decorated = $this->hasColorSupport($this->stdout);
|
||||
$this->formatter->setDecorated($decorated);
|
||||
}
|
||||
|
||||
public function setDecorated($decorated)
|
||||
{
|
||||
$this->formatter->setDecorated($decorated);
|
||||
}
|
||||
|
||||
public function write($messages, bool $newline = false, int $type = 0, $stream = null)
|
||||
{
|
||||
if (Output::VERBOSITY_QUIET === $this->output->getVerbosity()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$messages = (array) $messages;
|
||||
|
||||
foreach ($messages as $message) {
|
||||
switch ($type) {
|
||||
case Output::OUTPUT_NORMAL:
|
||||
$message = $this->formatter->format($message);
|
||||
break;
|
||||
case Output::OUTPUT_RAW:
|
||||
break;
|
||||
case Output::OUTPUT_PLAIN:
|
||||
$message = strip_tags($this->formatter->format($message));
|
||||
break;
|
||||
default:
|
||||
throw new \InvalidArgumentException(sprintf('Unknown output type given (%s)', $type));
|
||||
}
|
||||
|
||||
$this->doWrite($message, $newline, $stream);
|
||||
}
|
||||
}
|
||||
|
||||
public function renderException(\Throwable $e)
|
||||
{
|
||||
$stderr = $this->openErrorStream();
|
||||
$decorated = $this->hasColorSupport($stderr);
|
||||
$this->formatter->setDecorated($decorated);
|
||||
|
||||
do {
|
||||
$title = sprintf(' [%s] ', $e::class);
|
||||
|
||||
$len = $this->stringWidth($title);
|
||||
|
||||
$width = $this->getTerminalWidth() ? $this->getTerminalWidth() - 1 : PHP_INT_MAX;
|
||||
|
||||
if (defined('HHVM_VERSION') && $width > 1 << 31) {
|
||||
$width = 1 << 31;
|
||||
}
|
||||
$lines = [];
|
||||
foreach (preg_split('/\r?\n/', $e->getMessage()) as $line) {
|
||||
foreach ($this->splitStringByWidth($line, $width - 4) as $line) {
|
||||
|
||||
$lineLength = $this->stringWidth(preg_replace('/\[[^m]*m/', '', $line)) + 4;
|
||||
$lines[] = [$line, $lineLength];
|
||||
|
||||
$len = max($lineLength, $len);
|
||||
}
|
||||
}
|
||||
|
||||
$messages = ['', ''];
|
||||
$messages[] = $emptyLine = sprintf('<error>%s</error>', str_repeat(' ', $len));
|
||||
$messages[] = sprintf('<error>%s%s</error>', $title, str_repeat(' ', max(0, $len - $this->stringWidth($title))));
|
||||
foreach ($lines as $line) {
|
||||
$messages[] = sprintf('<error> %s %s</error>', $line[0], str_repeat(' ', $len - $line[1]));
|
||||
}
|
||||
$messages[] = $emptyLine;
|
||||
$messages[] = '';
|
||||
$messages[] = '';
|
||||
|
||||
$this->write($messages, true, Output::OUTPUT_NORMAL, $stderr);
|
||||
|
||||
if (Output::VERBOSITY_VERBOSE <= $this->output->getVerbosity()) {
|
||||
$this->write('<comment>Exception trace:</comment>', true, Output::OUTPUT_NORMAL, $stderr);
|
||||
|
||||
// exception related properties
|
||||
$trace = $e->getTrace();
|
||||
array_unshift($trace, [
|
||||
'function' => '',
|
||||
'file' => $e->getFile() !== null ? $e->getFile() : 'n/a',
|
||||
'line' => $e->getLine() !== null ? $e->getLine() : 'n/a',
|
||||
'args' => [],
|
||||
]);
|
||||
|
||||
for ($i = 0, $count = count($trace); $i < $count; ++$i) {
|
||||
$class = isset($trace[$i]['class']) ? $trace[$i]['class'] : '';
|
||||
$type = isset($trace[$i]['type']) ? $trace[$i]['type'] : '';
|
||||
$function = $trace[$i]['function'];
|
||||
$file = isset($trace[$i]['file']) ? $trace[$i]['file'] : 'n/a';
|
||||
$line = isset($trace[$i]['line']) ? $trace[$i]['line'] : 'n/a';
|
||||
|
||||
$this->write(sprintf(' %s%s%s() at <info>%s:%s</info>', $class, $type, $function, $file, $line), true, Output::OUTPUT_NORMAL, $stderr);
|
||||
}
|
||||
|
||||
$this->write('', true, Output::OUTPUT_NORMAL, $stderr);
|
||||
$this->write('', true, Output::OUTPUT_NORMAL, $stderr);
|
||||
}
|
||||
} while ($e = $e->getPrevious());
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取终端宽度
|
||||
* @return int|null
|
||||
*/
|
||||
protected function getTerminalWidth()
|
||||
{
|
||||
$dimensions = $this->getTerminalDimensions();
|
||||
|
||||
return $dimensions[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取终端高度
|
||||
* @return int|null
|
||||
*/
|
||||
protected function getTerminalHeight()
|
||||
{
|
||||
$dimensions = $this->getTerminalDimensions();
|
||||
|
||||
return $dimensions[1];
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前终端的尺寸
|
||||
* @return array
|
||||
*/
|
||||
public function getTerminalDimensions(): array
|
||||
{
|
||||
if ($this->terminalDimensions) {
|
||||
return $this->terminalDimensions;
|
||||
}
|
||||
|
||||
if ('\\' === DIRECTORY_SEPARATOR) {
|
||||
if (preg_match('/^(\d+)x\d+ \(\d+x(\d+)\)$/', trim(getenv('ANSICON')), $matches)) {
|
||||
return [(int) $matches[1], (int) $matches[2]];
|
||||
}
|
||||
if (preg_match('/^(\d+)x(\d+)$/', $this->getMode(), $matches)) {
|
||||
return [(int) $matches[1], (int) $matches[2]];
|
||||
}
|
||||
}
|
||||
|
||||
if ($sttyString = $this->getSttyColumns()) {
|
||||
if (preg_match('/rows.(\d+);.columns.(\d+);/i', $sttyString, $matches)) {
|
||||
return [(int) $matches[2], (int) $matches[1]];
|
||||
}
|
||||
if (preg_match('/;.(\d+).rows;.(\d+).columns/i', $sttyString, $matches)) {
|
||||
return [(int) $matches[2], (int) $matches[1]];
|
||||
}
|
||||
}
|
||||
|
||||
return [null, null];
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取stty列数
|
||||
* @return string
|
||||
*/
|
||||
private function getSttyColumns()
|
||||
{
|
||||
if (!function_exists('proc_open')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$descriptorspec = [1 => ['pipe', 'w'], 2 => ['pipe', 'w']];
|
||||
$process = proc_open('stty -a | grep columns', $descriptorspec, $pipes, null, null, ['suppress_errors' => true]);
|
||||
if (is_resource($process)) {
|
||||
$info = stream_get_contents($pipes[1]);
|
||||
fclose($pipes[1]);
|
||||
fclose($pipes[2]);
|
||||
proc_close($process);
|
||||
|
||||
return $info;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取终端模式
|
||||
* @return string <width>x<height>
|
||||
*/
|
||||
private function getMode()
|
||||
{
|
||||
if (!function_exists('proc_open')) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$descriptorspec = [1 => ['pipe', 'w'], 2 => ['pipe', 'w']];
|
||||
$process = proc_open('mode CON', $descriptorspec, $pipes, null, null, ['suppress_errors' => true]);
|
||||
if (is_resource($process)) {
|
||||
$info = stream_get_contents($pipes[1]);
|
||||
fclose($pipes[1]);
|
||||
fclose($pipes[2]);
|
||||
proc_close($process);
|
||||
|
||||
if (preg_match('/--------+\r?\n.+?(\d+)\r?\n.+?(\d+)\r?\n/', $info, $matches)) {
|
||||
return $matches[2] . 'x' . $matches[1];
|
||||
}
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
private function stringWidth(string $string): int
|
||||
{
|
||||
if (!function_exists('mb_strwidth')) {
|
||||
return strlen($string);
|
||||
}
|
||||
|
||||
if (false === $encoding = mb_detect_encoding($string)) {
|
||||
return strlen($string);
|
||||
}
|
||||
|
||||
return mb_strwidth($string, $encoding);
|
||||
}
|
||||
|
||||
private function splitStringByWidth(string $string, int $width): array
|
||||
{
|
||||
if (!function_exists('mb_strwidth')) {
|
||||
return str_split($string, $width);
|
||||
}
|
||||
|
||||
if (false === $encoding = mb_detect_encoding($string)) {
|
||||
return str_split($string, $width);
|
||||
}
|
||||
|
||||
$utf8String = mb_convert_encoding($string, 'utf8', $encoding);
|
||||
$lines = [];
|
||||
$line = '';
|
||||
foreach (preg_split('//u', $utf8String) as $char) {
|
||||
if (mb_strwidth($line . $char, 'utf8') <= $width) {
|
||||
$line .= $char;
|
||||
continue;
|
||||
}
|
||||
$lines[] = str_pad($line, $width);
|
||||
$line = $char;
|
||||
}
|
||||
if (strlen($line)) {
|
||||
$lines[] = count($lines) ? str_pad($line, $width) : $line;
|
||||
}
|
||||
|
||||
mb_convert_variables($encoding, 'utf8', $lines);
|
||||
|
||||
return $lines;
|
||||
}
|
||||
|
||||
private function isRunningOS400(): bool
|
||||
{
|
||||
$checks = [
|
||||
function_exists('php_uname') ? php_uname('s') : '',
|
||||
getenv('OSTYPE'),
|
||||
PHP_OS,
|
||||
];
|
||||
return false !== stripos(implode(';', $checks), 'OS400');
|
||||
}
|
||||
|
||||
/**
|
||||
* 当前环境是否支持写入控制台输出到stdout.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function hasStdoutSupport(): bool
|
||||
{
|
||||
return false === $this->isRunningOS400();
|
||||
}
|
||||
|
||||
/**
|
||||
* 当前环境是否支持写入控制台输出到stderr.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function hasStderrSupport(): bool
|
||||
{
|
||||
return false === $this->isRunningOS400();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return resource
|
||||
*/
|
||||
private function openOutputStream()
|
||||
{
|
||||
if (!$this->hasStdoutSupport()) {
|
||||
return fopen('php://output', 'w');
|
||||
}
|
||||
return @fopen('php://stdout', 'w') ?: fopen('php://output', 'w');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return resource
|
||||
*/
|
||||
private function openErrorStream()
|
||||
{
|
||||
return fopen($this->hasStderrSupport() ? 'php://stderr' : 'php://output', 'w');
|
||||
}
|
||||
|
||||
/**
|
||||
* 将消息写入到输出。
|
||||
* @param string $message 消息
|
||||
* @param bool $newline 是否另起一行
|
||||
* @param null $stream
|
||||
*/
|
||||
protected function doWrite($message, $newline, $stream = null)
|
||||
{
|
||||
if (null === $stream) {
|
||||
$stream = $this->stdout;
|
||||
}
|
||||
if (false === @fwrite($stream, $message . ($newline ? PHP_EOL : ''))) {
|
||||
throw new \RuntimeException('Unable to write output.');
|
||||
}
|
||||
|
||||
fflush($stream);
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否支持着色
|
||||
* @param $stream
|
||||
* @return bool
|
||||
*/
|
||||
protected function hasColorSupport($stream): bool
|
||||
{
|
||||
if (DIRECTORY_SEPARATOR === '\\') {
|
||||
return
|
||||
'10.0.10586' === PHP_WINDOWS_VERSION_MAJOR . '.' . PHP_WINDOWS_VERSION_MINOR . '.' . PHP_WINDOWS_VERSION_BUILD
|
||||
|| false !== getenv('ANSICON')
|
||||
|| 'ON' === getenv('ConEmuANSI')
|
||||
|| 'xterm' === getenv('TERM');
|
||||
}
|
||||
|
||||
return function_exists('posix_isatty') && @posix_isatty($stream);
|
||||
}
|
||||
|
||||
}
|
||||
33
vendor/topthink/framework/src/think/console/output/driver/Nothing.php
vendored
Normal file
33
vendor/topthink/framework/src/think/console/output/driver/Nothing.php
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2015 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: yunwuxin <448901948@qq.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace think\console\output\driver;
|
||||
|
||||
use think\console\Output;
|
||||
|
||||
class Nothing
|
||||
{
|
||||
|
||||
public function __construct(Output $output)
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
public function write($messages, bool $newline = false, int $options = 0)
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
public function renderException(\Throwable $e)
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
116
vendor/topthink/framework/src/think/console/output/formatter/Stack.php
vendored
Normal file
116
vendor/topthink/framework/src/think/console/output/formatter/Stack.php
vendored
Normal file
@@ -0,0 +1,116 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2015 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: yunwuxin <448901948@qq.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace think\console\output\formatter;
|
||||
|
||||
class Stack
|
||||
{
|
||||
|
||||
/**
|
||||
* @var Style[]
|
||||
*/
|
||||
private $styles;
|
||||
|
||||
/**
|
||||
* @var Style
|
||||
*/
|
||||
private $emptyStyle;
|
||||
|
||||
/**
|
||||
* 构造方法
|
||||
* @param Style|null $emptyStyle
|
||||
*/
|
||||
public function __construct(Style $emptyStyle = null)
|
||||
{
|
||||
$this->emptyStyle = $emptyStyle ?: new Style();
|
||||
$this->reset();
|
||||
}
|
||||
|
||||
/**
|
||||
* 重置堆栈
|
||||
*/
|
||||
public function reset(): void
|
||||
{
|
||||
$this->styles = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* 推一个样式进入堆栈
|
||||
* @param Style $style
|
||||
*/
|
||||
public function push(Style $style): void
|
||||
{
|
||||
$this->styles[] = $style;
|
||||
}
|
||||
|
||||
/**
|
||||
* 从堆栈中弹出一个样式
|
||||
* @param Style|null $style
|
||||
* @return Style
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public function pop(Style $style = null): Style
|
||||
{
|
||||
if (empty($this->styles)) {
|
||||
return $this->emptyStyle;
|
||||
}
|
||||
|
||||
if (null === $style) {
|
||||
return array_pop($this->styles);
|
||||
}
|
||||
|
||||
/**
|
||||
* @var int $index
|
||||
* @var Style $stackedStyle
|
||||
*/
|
||||
foreach (array_reverse($this->styles, true) as $index => $stackedStyle) {
|
||||
if ($style->apply('') === $stackedStyle->apply('')) {
|
||||
$this->styles = array_slice($this->styles, 0, $index);
|
||||
|
||||
return $stackedStyle;
|
||||
}
|
||||
}
|
||||
|
||||
throw new \InvalidArgumentException('Incorrectly nested style tag found.');
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算堆栈的当前样式。
|
||||
* @return Style
|
||||
*/
|
||||
public function getCurrent(): Style
|
||||
{
|
||||
if (empty($this->styles)) {
|
||||
return $this->emptyStyle;
|
||||
}
|
||||
|
||||
return $this->styles[count($this->styles) - 1];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Style $emptyStyle
|
||||
* @return Stack
|
||||
*/
|
||||
public function setEmptyStyle(Style $emptyStyle)
|
||||
{
|
||||
$this->emptyStyle = $emptyStyle;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Style
|
||||
*/
|
||||
public function getEmptyStyle(): Style
|
||||
{
|
||||
return $this->emptyStyle;
|
||||
}
|
||||
}
|
||||
190
vendor/topthink/framework/src/think/console/output/formatter/Style.php
vendored
Normal file
190
vendor/topthink/framework/src/think/console/output/formatter/Style.php
vendored
Normal file
@@ -0,0 +1,190 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2015 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: yunwuxin <448901948@qq.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace think\console\output\formatter;
|
||||
|
||||
class Style
|
||||
{
|
||||
protected static $availableForegroundColors = [
|
||||
'black' => ['set' => 30, 'unset' => 39],
|
||||
'red' => ['set' => 31, 'unset' => 39],
|
||||
'green' => ['set' => 32, 'unset' => 39],
|
||||
'yellow' => ['set' => 33, 'unset' => 39],
|
||||
'blue' => ['set' => 34, 'unset' => 39],
|
||||
'magenta' => ['set' => 35, 'unset' => 39],
|
||||
'cyan' => ['set' => 36, 'unset' => 39],
|
||||
'white' => ['set' => 37, 'unset' => 39],
|
||||
];
|
||||
|
||||
protected static $availableBackgroundColors = [
|
||||
'black' => ['set' => 40, 'unset' => 49],
|
||||
'red' => ['set' => 41, 'unset' => 49],
|
||||
'green' => ['set' => 42, 'unset' => 49],
|
||||
'yellow' => ['set' => 43, 'unset' => 49],
|
||||
'blue' => ['set' => 44, 'unset' => 49],
|
||||
'magenta' => ['set' => 45, 'unset' => 49],
|
||||
'cyan' => ['set' => 46, 'unset' => 49],
|
||||
'white' => ['set' => 47, 'unset' => 49],
|
||||
];
|
||||
|
||||
protected static $availableOptions = [
|
||||
'bold' => ['set' => 1, 'unset' => 22],
|
||||
'underscore' => ['set' => 4, 'unset' => 24],
|
||||
'blink' => ['set' => 5, 'unset' => 25],
|
||||
'reverse' => ['set' => 7, 'unset' => 27],
|
||||
'conceal' => ['set' => 8, 'unset' => 28],
|
||||
];
|
||||
|
||||
private $foreground;
|
||||
private $background;
|
||||
private $options = [];
|
||||
|
||||
/**
|
||||
* 初始化输出的样式
|
||||
* @param string|null $foreground 字体颜色
|
||||
* @param string|null $background 背景色
|
||||
* @param array $options 格式
|
||||
* @api
|
||||
*/
|
||||
public function __construct($foreground = null, $background = null, array $options = [])
|
||||
{
|
||||
if (null !== $foreground) {
|
||||
$this->setForeground($foreground);
|
||||
}
|
||||
if (null !== $background) {
|
||||
$this->setBackground($background);
|
||||
}
|
||||
if (count($options)) {
|
||||
$this->setOptions($options);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置字体颜色
|
||||
* @param string|null $color 颜色名
|
||||
* @throws \InvalidArgumentException
|
||||
* @api
|
||||
*/
|
||||
public function setForeground($color = null)
|
||||
{
|
||||
if (null === $color) {
|
||||
$this->foreground = null;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isset(static::$availableForegroundColors[$color])) {
|
||||
throw new \InvalidArgumentException(sprintf('Invalid foreground color specified: "%s". Expected one of (%s)', $color, implode(', ', array_keys(static::$availableForegroundColors))));
|
||||
}
|
||||
|
||||
$this->foreground = static::$availableForegroundColors[$color];
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置背景色
|
||||
* @param string|null $color 颜色名
|
||||
* @throws \InvalidArgumentException
|
||||
* @api
|
||||
*/
|
||||
public function setBackground($color = null)
|
||||
{
|
||||
if (null === $color) {
|
||||
$this->background = null;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isset(static::$availableBackgroundColors[$color])) {
|
||||
throw new \InvalidArgumentException(sprintf('Invalid background color specified: "%s". Expected one of (%s)', $color, implode(', ', array_keys(static::$availableBackgroundColors))));
|
||||
}
|
||||
|
||||
$this->background = static::$availableBackgroundColors[$color];
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置字体格式
|
||||
* @param string $option 格式名
|
||||
* @throws \InvalidArgumentException When the option name isn't defined
|
||||
* @api
|
||||
*/
|
||||
public function setOption(string $option): void
|
||||
{
|
||||
if (!isset(static::$availableOptions[$option])) {
|
||||
throw new \InvalidArgumentException(sprintf('Invalid option specified: "%s". Expected one of (%s)', $option, implode(', ', array_keys(static::$availableOptions))));
|
||||
}
|
||||
|
||||
if (!in_array(static::$availableOptions[$option], $this->options)) {
|
||||
$this->options[] = static::$availableOptions[$option];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 重置字体格式
|
||||
* @param string $option 格式名
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public function unsetOption(string $option): void
|
||||
{
|
||||
if (!isset(static::$availableOptions[$option])) {
|
||||
throw new \InvalidArgumentException(sprintf('Invalid option specified: "%s". Expected one of (%s)', $option, implode(', ', array_keys(static::$availableOptions))));
|
||||
}
|
||||
|
||||
$pos = array_search(static::$availableOptions[$option], $this->options);
|
||||
if (false !== $pos) {
|
||||
unset($this->options[$pos]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量设置字体格式
|
||||
* @param array $options
|
||||
*/
|
||||
public function setOptions(array $options)
|
||||
{
|
||||
$this->options = [];
|
||||
|
||||
foreach ($options as $option) {
|
||||
$this->setOption($option);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 应用样式到文字
|
||||
* @param string $text 文字
|
||||
* @return string
|
||||
*/
|
||||
public function apply(string $text): string
|
||||
{
|
||||
$setCodes = [];
|
||||
$unsetCodes = [];
|
||||
|
||||
if (null !== $this->foreground) {
|
||||
$setCodes[] = $this->foreground['set'];
|
||||
$unsetCodes[] = $this->foreground['unset'];
|
||||
}
|
||||
if (null !== $this->background) {
|
||||
$setCodes[] = $this->background['set'];
|
||||
$unsetCodes[] = $this->background['unset'];
|
||||
}
|
||||
if (count($this->options)) {
|
||||
foreach ($this->options as $option) {
|
||||
$setCodes[] = $option['set'];
|
||||
$unsetCodes[] = $option['unset'];
|
||||
}
|
||||
}
|
||||
|
||||
if (0 === count($setCodes)) {
|
||||
return $text;
|
||||
}
|
||||
|
||||
return sprintf("\033[%sm%s\033[%sm", implode(';', $setCodes), $text, implode(';', $unsetCodes));
|
||||
}
|
||||
}
|
||||
163
vendor/topthink/framework/src/think/console/output/question/Choice.php
vendored
Normal file
163
vendor/topthink/framework/src/think/console/output/question/Choice.php
vendored
Normal file
@@ -0,0 +1,163 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2015 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: yunwuxin <448901948@qq.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace think\console\output\question;
|
||||
|
||||
use think\console\output\Question;
|
||||
|
||||
class Choice extends Question
|
||||
{
|
||||
|
||||
private $choices;
|
||||
private $multiselect = false;
|
||||
private $prompt = ' > ';
|
||||
private $errorMessage = 'Value "%s" is invalid';
|
||||
|
||||
/**
|
||||
* 构造方法
|
||||
* @param string $question 问题
|
||||
* @param array $choices 选项
|
||||
* @param mixed $default 默认答案
|
||||
*/
|
||||
public function __construct($question, array $choices, $default = null)
|
||||
{
|
||||
parent::__construct($question, $default);
|
||||
|
||||
$this->choices = $choices;
|
||||
$this->setValidator($this->getDefaultValidator());
|
||||
$this->setAutocompleterValues($choices);
|
||||
}
|
||||
|
||||
/**
|
||||
* 可选项
|
||||
* @return array
|
||||
*/
|
||||
public function getChoices(): array
|
||||
{
|
||||
return $this->choices;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置可否多选
|
||||
* @param bool $multiselect
|
||||
* @return self
|
||||
*/
|
||||
public function setMultiselect(bool $multiselect)
|
||||
{
|
||||
$this->multiselect = $multiselect;
|
||||
$this->setValidator($this->getDefaultValidator());
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function isMultiselect(): bool
|
||||
{
|
||||
return $this->multiselect;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取提示
|
||||
* @return string
|
||||
*/
|
||||
public function getPrompt(): string
|
||||
{
|
||||
return $this->prompt;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置提示
|
||||
* @param string $prompt
|
||||
* @return self
|
||||
*/
|
||||
public function setPrompt(string $prompt)
|
||||
{
|
||||
$this->prompt = $prompt;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置错误提示信息
|
||||
* @param string $errorMessage
|
||||
* @return self
|
||||
*/
|
||||
public function setErrorMessage(string $errorMessage)
|
||||
{
|
||||
$this->errorMessage = $errorMessage;
|
||||
$this->setValidator($this->getDefaultValidator());
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取默认的验证方法
|
||||
* @return callable
|
||||
*/
|
||||
private function getDefaultValidator()
|
||||
{
|
||||
$choices = $this->choices;
|
||||
$errorMessage = $this->errorMessage;
|
||||
$multiselect = $this->multiselect;
|
||||
$isAssoc = $this->isAssoc($choices);
|
||||
|
||||
return function ($selected) use ($choices, $errorMessage, $multiselect, $isAssoc) {
|
||||
// Collapse all spaces.
|
||||
$selectedChoices = str_replace(' ', '', $selected);
|
||||
|
||||
if ($multiselect) {
|
||||
// Check for a separated comma values
|
||||
if (!preg_match('/^[a-zA-Z0-9_-]+(?:,[a-zA-Z0-9_-]+)*$/', $selectedChoices, $matches)) {
|
||||
throw new \InvalidArgumentException(sprintf($errorMessage, $selected));
|
||||
}
|
||||
$selectedChoices = explode(',', $selectedChoices);
|
||||
} else {
|
||||
$selectedChoices = [$selected];
|
||||
}
|
||||
|
||||
$multiselectChoices = [];
|
||||
foreach ($selectedChoices as $value) {
|
||||
$results = [];
|
||||
foreach ($choices as $key => $choice) {
|
||||
if ($choice === $value) {
|
||||
$results[] = $key;
|
||||
}
|
||||
}
|
||||
|
||||
if (count($results) > 1) {
|
||||
throw new \InvalidArgumentException(sprintf('The provided answer is ambiguous. Value should be one of %s.', implode(' or ', $results)));
|
||||
}
|
||||
|
||||
$result = array_search($value, $choices);
|
||||
|
||||
if (!$isAssoc) {
|
||||
if (!empty($result)) {
|
||||
$result = $choices[$result];
|
||||
} elseif (isset($choices[$value])) {
|
||||
$result = $choices[$value];
|
||||
}
|
||||
} elseif (empty($result) && array_key_exists($value, $choices)) {
|
||||
$result = $value;
|
||||
}
|
||||
|
||||
if (false === $result) {
|
||||
throw new \InvalidArgumentException(sprintf($errorMessage, $value));
|
||||
}
|
||||
array_push($multiselectChoices, $result);
|
||||
}
|
||||
|
||||
if ($multiselect) {
|
||||
return $multiselectChoices;
|
||||
}
|
||||
|
||||
return current($multiselectChoices);
|
||||
};
|
||||
}
|
||||
}
|
||||
57
vendor/topthink/framework/src/think/console/output/question/Confirmation.php
vendored
Normal file
57
vendor/topthink/framework/src/think/console/output/question/Confirmation.php
vendored
Normal file
@@ -0,0 +1,57 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2015 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: yunwuxin <448901948@qq.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace think\console\output\question;
|
||||
|
||||
use think\console\output\Question;
|
||||
|
||||
class Confirmation extends Question
|
||||
{
|
||||
|
||||
private $trueAnswerRegex;
|
||||
|
||||
/**
|
||||
* 构造方法
|
||||
* @param string $question 问题
|
||||
* @param bool $default 默认答案
|
||||
* @param string $trueAnswerRegex 验证正则
|
||||
*/
|
||||
public function __construct(string $question, bool $default = true, string $trueAnswerRegex = '/^y/i')
|
||||
{
|
||||
parent::__construct($question, (bool) $default);
|
||||
|
||||
$this->trueAnswerRegex = $trueAnswerRegex;
|
||||
$this->setNormalizer($this->getDefaultNormalizer());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取默认的答案回调
|
||||
* @return callable
|
||||
*/
|
||||
private function getDefaultNormalizer()
|
||||
{
|
||||
$default = $this->getDefault();
|
||||
$regex = $this->trueAnswerRegex;
|
||||
|
||||
return function ($answer) use ($default, $regex) {
|
||||
if (is_bool($answer)) {
|
||||
return $answer;
|
||||
}
|
||||
|
||||
$answerIsTrue = (bool) preg_match($regex, $answer);
|
||||
if (false === $default) {
|
||||
return $answer && $answerIsTrue;
|
||||
}
|
||||
|
||||
return !$answer || $answerIsTrue;
|
||||
};
|
||||
}
|
||||
}
|
||||
71
vendor/topthink/framework/src/think/contract/CacheHandlerInterface.php
vendored
Normal file
71
vendor/topthink/framework/src/think/contract/CacheHandlerInterface.php
vendored
Normal file
@@ -0,0 +1,71 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2023 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
declare(strict_types = 1);
|
||||
|
||||
namespace think\contract;
|
||||
|
||||
use DateInterval;
|
||||
use DateTimeInterface;
|
||||
use Psr\SimpleCache\CacheInterface;
|
||||
use think\cache\TagSet;
|
||||
|
||||
/**
|
||||
* 缓存驱动接口
|
||||
*/
|
||||
interface CacheHandlerInterface extends CacheInterface
|
||||
{
|
||||
|
||||
/**
|
||||
* 自增缓存(针对数值缓存)
|
||||
* @param string $name 缓存变量名
|
||||
* @param int $step 步长
|
||||
* @return false|int
|
||||
*/
|
||||
public function inc($name, $step = 1);
|
||||
|
||||
/**
|
||||
* 自减缓存(针对数值缓存)
|
||||
* @param string $name 缓存变量名
|
||||
* @param int $step 步长
|
||||
* @return false|int
|
||||
*/
|
||||
public function dec($name, $step = 1);
|
||||
|
||||
/**
|
||||
* 读取缓存并删除
|
||||
* @param string $name 缓存变量名
|
||||
* @return mixed
|
||||
*/
|
||||
public function pull($name);
|
||||
|
||||
/**
|
||||
* 如果不存在则写入缓存
|
||||
* @param string $name 缓存变量名
|
||||
* @param mixed $value 存储数据
|
||||
* @param int|DateInterval|DateTimeInterface $expire 有效时间 0为永久
|
||||
* @return mixed
|
||||
*/
|
||||
public function remember($name, $value, $expire = null);
|
||||
|
||||
/**
|
||||
* 缓存标签
|
||||
* @param string|array $name 标签名
|
||||
* @return TagSet
|
||||
*/
|
||||
public function tag($name);
|
||||
|
||||
/**
|
||||
* 删除缓存标签
|
||||
* @param array $keys 缓存标识列表
|
||||
* @return void
|
||||
*/
|
||||
public function clearTag($keys);
|
||||
}
|
||||
28
vendor/topthink/framework/src/think/contract/LogHandlerInterface.php
vendored
Normal file
28
vendor/topthink/framework/src/think/contract/LogHandlerInterface.php
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006-2016 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
declare (strict_types = 1);
|
||||
|
||||
namespace think\contract;
|
||||
|
||||
/**
|
||||
* 日志驱动接口
|
||||
*/
|
||||
interface LogHandlerInterface
|
||||
{
|
||||
/**
|
||||
* 日志写入接口
|
||||
* @access public
|
||||
* @param array $log 日志信息
|
||||
* @return bool
|
||||
*/
|
||||
public function save(array $log): bool;
|
||||
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user