Compare commits
No commits in common. "main" and "5.1.5" have entirely different histories.
|
@ -1 +0,0 @@
|
|||
APP_DEBUG = true
[APP]
DEFAULT_TIMEZONE = Asia/Shanghai
[DATABASE]
TYPE = mysql
HOSTNAME = 127.0.0.1
DATABASE = test
USERNAME = username
PASSWORD = password
HOSTPORT = 3306
CHARSET = utf8
DEBUG = true
[LANG]
default_lang = zh-cn
|
|
@ -1,5 +1,5 @@
|
|||
/.idea
|
||||
/.vscode
|
||||
*.log
|
||||
.env
|
||||
/nbproject
|
||||
.idea
|
||||
composer.lock
|
||||
*.log
|
||||
nbproject
|
||||
.git
|
||||
|
|
155
README.md
155
README.md
|
@ -1,41 +1,144 @@
|
|||
ThinkPHP 6.0
|
||||
ThinkPHP 5.1
|
||||
===============
|
||||
|
||||
> 运行环境要求PHP7.1+。
|
||||
ThinkPHP5.1对底层架构做了进一步的改进,减少依赖,其主要特性包括:
|
||||
|
||||
## 主要新特性
|
||||
+ 采用容器统一管理对象
|
||||
+ 支持Facade
|
||||
+ 注解路由支持
|
||||
+ 路由跨域请求支持
|
||||
+ 配置和路由目录独立
|
||||
+ 取消系统常量
|
||||
+ 助手函数增强
|
||||
+ 类库别名机制
|
||||
+ 增加条件查询
|
||||
+ 改进查询机制
|
||||
+ 配置采用二级
|
||||
+ 依赖注入完善
|
||||
|
||||
* 采用`PHP7`强类型(严格模式)
|
||||
* 支持更多的`PSR`规范
|
||||
* 原生多应用支持
|
||||
* 更强大和易用的查询
|
||||
* 全新的事件系统
|
||||
* 模型事件和数据库事件统一纳入事件系统
|
||||
* 模板引擎分离出核心
|
||||
* 内部功能中间件化
|
||||
* SESSION/Cookie机制改进
|
||||
* 对Swoole以及协程支持改进
|
||||
* 对IDE更加友好
|
||||
* 统一和精简大量用法
|
||||
|
||||
## 安装
|
||||
> ThinkPHP5的运行环境要求PHP5.6以上。
|
||||
|
||||
|
||||
## 目录结构
|
||||
|
||||
初始的目录结构如下:
|
||||
|
||||
~~~
|
||||
composer create-project topthink/think tp 6.0.*-dev
|
||||
www WEB部署目录(或者子目录)
|
||||
├─application 应用目录
|
||||
│ ├─common 公共模块目录(可以更改)
|
||||
│ ├─module_name 模块目录
|
||||
│ │ ├─common.php 模块函数文件
|
||||
│ │ ├─controller 控制器目录
|
||||
│ │ ├─model 模型目录
|
||||
│ │ ├─view 视图目录
|
||||
│ │ └─ ... 更多类库目录
|
||||
│ │
|
||||
│ ├─command.php 命令行定义文件
|
||||
│ ├─common.php 公共函数文件
|
||||
│ └─tags.php 应用行为扩展定义文件
|
||||
│
|
||||
├─config 应用配置目录
|
||||
│ ├─module_name 模块配置目录
|
||||
│ │ ├─database.php 数据库配置
|
||||
│ │ ├─cache 缓存配置
|
||||
│ │ └─ ...
|
||||
│ │
|
||||
│ ├─app.php 应用配置
|
||||
│ ├─cache.php 缓存配置
|
||||
│ ├─cookie.php Cookie配置
|
||||
│ ├─database.php 数据库配置
|
||||
│ ├─log.php 日志配置
|
||||
│ ├─session.php Session配置
|
||||
│ ├─template.php 模板引擎配置
|
||||
│ └─trace.php Trace配置
|
||||
│
|
||||
├─route 路由定义目录
|
||||
│ ├─route.php 路由定义
|
||||
│ └─... 更多
|
||||
│
|
||||
├─public WEB目录(对外访问目录)
|
||||
│ ├─index.php 入口文件
|
||||
│ ├─router.php 快速测试文件
|
||||
│ └─.htaccess 用于apache的重写
|
||||
│
|
||||
├─thinkphp 框架系统目录
|
||||
│ ├─lang 语言文件目录
|
||||
│ ├─library 框架类库目录
|
||||
│ │ ├─think Think类库包目录
|
||||
│ │ └─traits 系统Trait目录
|
||||
│ │
|
||||
│ ├─tpl 系统模板目录
|
||||
│ ├─base.php 基础定义文件
|
||||
│ ├─console.php 控制台入口文件
|
||||
│ ├─convention.php 框架惯例配置文件
|
||||
│ ├─helper.php 助手函数文件
|
||||
│ ├─phpunit.xml phpunit配置文件
|
||||
│ └─start.php 框架入口文件
|
||||
│
|
||||
├─extend 扩展类库目录
|
||||
├─runtime 应用的运行时目录(可写,可定制)
|
||||
├─vendor 第三方类库目录(Composer依赖库)
|
||||
├─build.php 自动生成定义文件(参考)
|
||||
├─composer.json composer 定义文件
|
||||
├─LICENSE.txt 授权说明文件
|
||||
├─README.md README 文件
|
||||
├─think 命令行入口文件
|
||||
~~~
|
||||
|
||||
如果需要更新框架使用
|
||||
~~~
|
||||
composer update topthink/framework
|
||||
~~~
|
||||
> router.php用于php自带webserver支持,可用于快速测试
|
||||
> 切换到public目录后,启动命令:php -S localhost:8888 router.php
|
||||
> 上面的目录结构和名称是可以改变的,这取决于你的入口文件和配置参数。
|
||||
|
||||
## 文档
|
||||
## 升级指导
|
||||
|
||||
[完全开发手册](https://www.kancloud.cn/manual/thinkphp6_0/content)
|
||||
原有下面系统类库的命名空间需要调整:
|
||||
|
||||
* think\App => think\facade\App (或者 App )
|
||||
* think\Cache => think\facade\Cache (或者 Cache )
|
||||
* think\Config => think\facade\Config (或者 Config )
|
||||
* think\Cookie => think\facade\Cookie (或者 Cookie )
|
||||
* think\Debug => think\facade\Debug (或者 Debug )
|
||||
* think\Hook => think\facade\Hook (或者 Hook )
|
||||
* think\Lang => think\facade\Lang (或者 Lang )
|
||||
* think\Log => think\facade\Log (或者 Log )
|
||||
* think\Request => think\facade\Request (或者 Request )
|
||||
* think\Response => think\facade\Reponse (或者 Reponse )
|
||||
* think\Route => think\facade\Route (或者 Route )
|
||||
* think\Session => think\facade\Session (或者 Session )
|
||||
* think\Url => think\facade\Url (或者 Url )
|
||||
|
||||
原有的配置文件config.php 拆分为app.php cache.php 等独立配置文件 放入config目录。
|
||||
原有的路由定义文件route.php 移动到route目录
|
||||
|
||||
## 命名规范
|
||||
|
||||
`ThinkPHP5`遵循PSR-2命名规范和PSR-4自动加载规范,并且注意如下规范:
|
||||
|
||||
### 目录和文件
|
||||
|
||||
* 目录不强制规范,驼峰和小写+下划线模式均支持;
|
||||
* 类库、函数文件统一以`.php`为后缀;
|
||||
* 类的文件名均以命名空间定义,并且命名空间的路径和类库文件所在路径一致;
|
||||
* 类名和类文件名保持一致,统一采用驼峰法命名(首字母大写);
|
||||
|
||||
### 函数和类、属性命名
|
||||
* 类的命名采用驼峰法,并且首字母大写,例如 `User`、`UserType`,默认不需要添加后缀,例如`UserController`应该直接命名为`User`;
|
||||
* 函数的命名使用小写字母和下划线(小写字母开头)的方式,例如 `get_client_ip`;
|
||||
* 方法的命名使用驼峰法,并且首字母小写,例如 `getUserName`;
|
||||
* 属性的命名使用驼峰法,并且首字母小写,例如 `tableName`、`instance`;
|
||||
* 以双下划线“__”打头的函数或方法作为魔法方法,例如 `__call` 和 `__autoload`;
|
||||
|
||||
### 常量和配置
|
||||
* 常量以大写字母和下划线命名,例如 `APP_PATH`和 `THINK_PATH`;
|
||||
* 配置参数以小写字母和下划线命名,例如 `url_route_on` 和`url_convert`;
|
||||
|
||||
### 数据表和字段
|
||||
* 数据表和字段采用小写加下划线方式命名,并注意字段名不要以下划线开头,例如 `think_user` 表和 `user_name`字段,不建议使用驼峰和中文作为数据表字段命名。
|
||||
|
||||
## 参与开发
|
||||
|
||||
请参阅 [ThinkPHP 核心框架包](https://github.com/top-think/framework)。
|
||||
请参阅 [ThinkPHP5 核心框架包](https://github.com/top-think/framework)。
|
||||
|
||||
## 版权信息
|
||||
|
||||
|
@ -43,7 +146,7 @@ ThinkPHP遵循Apache2开源协议发布,并提供免费使用。
|
|||
|
||||
本项目包含的第三方源码和二进制文件之版权信息另行标注。
|
||||
|
||||
版权所有Copyright © 2006-2019 by ThinkPHP (http://thinkphp.cn)
|
||||
版权所有Copyright © 2006-2018 by ThinkPHP (http://thinkphp.cn)
|
||||
|
||||
All rights reserved。
|
||||
|
||||
|
|
|
@ -1,103 +0,0 @@
|
|||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2019 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 app;
|
||||
|
||||
use think\App;
|
||||
use think\exception\ValidateException;
|
||||
use think\Validate;
|
||||
|
||||
/**
|
||||
* 控制器基础类
|
||||
*/
|
||||
abstract class BaseController
|
||||
{
|
||||
/**
|
||||
* Request实例
|
||||
* @var \think\Request
|
||||
*/
|
||||
protected $request;
|
||||
|
||||
/**
|
||||
* 应用实例
|
||||
* @var \think\App
|
||||
*/
|
||||
protected $app;
|
||||
|
||||
/**
|
||||
* 是否批量验证
|
||||
* @var bool
|
||||
*/
|
||||
protected $batchValidate = false;
|
||||
|
||||
/**
|
||||
* 控制器中间件
|
||||
* @var array
|
||||
*/
|
||||
protected $middleware = [];
|
||||
|
||||
/**
|
||||
* 构造方法
|
||||
* @access public
|
||||
* @param App $app 应用对象
|
||||
*/
|
||||
public function __construct(App $app)
|
||||
{
|
||||
$this->app = $app;
|
||||
$this->request = $this->app->request;
|
||||
|
||||
// 控制器初始化
|
||||
$this->initialize();
|
||||
}
|
||||
|
||||
// 初始化
|
||||
protected function initialize()
|
||||
{}
|
||||
|
||||
/**
|
||||
* 验证数据
|
||||
* @access protected
|
||||
* @param array $data 数据
|
||||
* @param string|array $validate 验证器名或者验证规则数组
|
||||
* @param array $message 提示信息
|
||||
* @param bool $batch 是否批量验证
|
||||
* @return array|string|true
|
||||
* @throws ValidateException
|
||||
*/
|
||||
protected function validate(array $data, $validate, array $message = [], bool $batch = false)
|
||||
{
|
||||
if (is_array($validate)) {
|
||||
$v = new Validate();
|
||||
$v->rule($validate);
|
||||
} else {
|
||||
if (strpos($validate, '.')) {
|
||||
// 支持场景
|
||||
list($validate, $scene) = explode('.', $validate);
|
||||
}
|
||||
$class = false !== strpos($validate, '\\') ? $validate : $this->app->parseClass('validate', $validate);
|
||||
$v = new $class();
|
||||
if (!empty($scene)) {
|
||||
$v->scene($scene);
|
||||
}
|
||||
}
|
||||
|
||||
$v->message($message);
|
||||
|
||||
// 是否批量验证
|
||||
if ($batch || $this->batchValidate) {
|
||||
$v->batch(true);
|
||||
}
|
||||
|
||||
return $v->failException(true)->check($data);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,68 +0,0 @@
|
|||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2019 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace app;
|
||||
|
||||
use think\db\exception\DataNotFoundException;
|
||||
use think\db\exception\ModelNotFoundException;
|
||||
use think\exception\Handle;
|
||||
use think\exception\HttpException;
|
||||
use think\exception\HttpResponseException;
|
||||
use think\exception\ValidateException;
|
||||
use think\Response;
|
||||
use Throwable;
|
||||
|
||||
/**
|
||||
* 应用异常处理类
|
||||
*/
|
||||
class ExceptionHandle extends Handle
|
||||
{
|
||||
/**
|
||||
* 不需要记录信息(日志)的异常类列表
|
||||
* @var array
|
||||
*/
|
||||
protected $ignoreReport = [
|
||||
HttpException::class,
|
||||
HttpResponseException::class,
|
||||
ModelNotFoundException::class,
|
||||
DataNotFoundException::class,
|
||||
ValidateException::class,
|
||||
];
|
||||
|
||||
/**
|
||||
* 记录异常信息(包括日志或者其它方式记录)
|
||||
*
|
||||
* @access public
|
||||
* @param Throwable $exception
|
||||
* @return void
|
||||
*/
|
||||
public function report(Throwable $exception): void
|
||||
{
|
||||
// 使用内置的方式记录异常日志
|
||||
parent::report($exception);
|
||||
}
|
||||
|
||||
/**
|
||||
* Render an exception into an HTTP response.
|
||||
*
|
||||
* @access public
|
||||
* @param \think\Request $request
|
||||
* @param Throwable $e
|
||||
* @return Response
|
||||
*/
|
||||
public function render($request, Throwable $e): Response
|
||||
{
|
||||
// 添加自定义异常处理机制
|
||||
|
||||
// 其他错误交给系统处理
|
||||
return parent::render($request, $e);
|
||||
}
|
||||
}
|
|
@ -1,17 +0,0 @@
|
|||
<?php
|
||||
namespace app\controller;
|
||||
|
||||
use app\BaseController;
|
||||
|
||||
class Index extends BaseController
|
||||
{
|
||||
public function index()
|
||||
{
|
||||
return '<style type="text/css">*{ padding: 0; margin: 0; } div{ padding: 4px 48px;} a{color:#2E5CD5;cursor: pointer;text-decoration: none} a:hover{text-decoration:underline; } body{ background: #fff; font-family: "Century Gothic","Microsoft yahei"; color: #333;font-size:18px;} h1{ font-size: 100px; font-weight: normal; margin-bottom: 12px; } p{ line-height: 1.6em; font-size: 42px }</style><div style="padding: 24px 48px;"> <h1>:) </h1><p> ThinkPHP V6<br/><span style="font-size:30px">13载初心不改 - 你值得信赖的PHP框架</span></p></div><script type="text/javascript" src="https://tajs.qq.com/stats?sId=64890268" charset="UTF-8"></script><script type="text/javascript" src="https://e.topthink.com/Public/static/client.js"></script><think id="eab4b9f840753f8e7"></think>';
|
||||
}
|
||||
|
||||
public function hello($name = 'ThinkPHP6')
|
||||
{
|
||||
return 'hello,' . $name;
|
||||
}
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
<?php
|
||||
|
||||
return [
|
||||
// 全局请求缓存
|
||||
// \think\middleware\CheckRequestCache::class,
|
||||
// 多语言加载
|
||||
// \think\middleware\LoadLangPack::class,
|
||||
// Session初始化
|
||||
// \think\middleware\SessionInit::class,
|
||||
// 页面Trace调试
|
||||
// \think\middleware\TraceDebug::class,
|
||||
];
|
|
@ -1,19 +0,0 @@
|
|||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2019 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
use app\ExceptionHandle;
|
||||
use app\Request;
|
||||
|
||||
// 容器Provider定义文件
|
||||
return [
|
||||
'think\Request' => Request::class,
|
||||
'think\exception\Handle' => ExceptionHandle::class,
|
||||
];
|
|
@ -2,15 +2,11 @@
|
|||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2019 http://thinkphp.cn All rights reserved.
|
||||
// | 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\exception;
|
||||
|
||||
class FileException extends \RuntimeException
|
||||
{
|
||||
|
||||
}
|
||||
return [];
|
|
@ -0,0 +1,23 @@
|
|||
<?php
|
||||
|
||||
namespace app\index\behavior;
|
||||
|
||||
class Test
|
||||
{
|
||||
//这个是会执行的
|
||||
public function __construct() {
|
||||
echo '初始化<BR />';
|
||||
}
|
||||
|
||||
//若位置名称对应的方法不存在,则执行这个
|
||||
public function run($params)
|
||||
{
|
||||
echo 'run参数'.$params;
|
||||
}
|
||||
|
||||
//根据执行的位置名称,方法名 对应位置名称,若存在下划线将去掉下划线
|
||||
public function appInit($params)
|
||||
{
|
||||
echo 'appInit参数';
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
<?php
|
||||
namespace app\index\controller;
|
||||
|
||||
class Index
|
||||
{
|
||||
public function index()
|
||||
{
|
||||
return '<style type="text/css">*{ padding: 0; margin: 0; } div{ padding: 4px 48px;} a{color:#2E5CD5;cursor: pointer;text-decoration: none} a:hover{text-decoration:underline; } body{ background: #fff; font-family: "Century Gothic","Microsoft yahei"; color: #333;font-size:18px;} h1{ font-size: 100px; font-weight: normal; margin-bottom: 12px; } p{ line-height: 1.6em; font-size: 42px }</style><div style="padding: 24px 48px;"> <h1>:) 2018新年快乐</h1><p> ThinkPHP V5.1<br/><span style="font-size:30px">12载初心不改(2006-2018) - 你值得信赖的PHP框架</span></p></div><script type="text/javascript" src="https://tajs.qq.com/stats?sId=64890268" charset="UTF-8"></script><script type="text/javascript" src="https://e.topthink.com/Public/static/client.js"></script><think id="eab4b9f840753f8e7"></think>';
|
||||
}
|
||||
|
||||
public function hello($name = 'ThinkPHP5')
|
||||
{
|
||||
return 'hello,' . $name;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
<?php
|
||||
namespace app\news\controller;
|
||||
|
||||
class Index
|
||||
{
|
||||
public function index()
|
||||
{
|
||||
return 'news/INDEX';
|
||||
}
|
||||
|
||||
public function hello($name = 'ThinkPHP5')
|
||||
{
|
||||
return 'hello,' . $name;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
<?php
|
||||
namespace app\news\controller;
|
||||
|
||||
class Test
|
||||
{
|
||||
public function index()
|
||||
{
|
||||
return 'TestIndex';
|
||||
}
|
||||
|
||||
public function hello($name = 'ThinkPHP6')
|
||||
{
|
||||
return 'TestHello,' . $name;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
// 应用行为扩展定义文件
|
||||
return [
|
||||
// 应用初始化
|
||||
'app_init' => [
|
||||
// function($ddd){echo 'app_init闭包函数<BR />'.$ddd[0].'<BR />'.$ddd[1].'<BR />';},
|
||||
// 'app\\index\\behavior\\test'
|
||||
],
|
||||
// 应用开始
|
||||
'app_begin' => [],
|
||||
// 模块初始化
|
||||
'module_init' => [],
|
||||
// 操作开始执行
|
||||
'action_begin' => [],
|
||||
// 视图内容过滤
|
||||
'view_filter' => [],
|
||||
// 日志写入
|
||||
'log_write' => [],
|
||||
// 应用结束
|
||||
'app_end' => [],
|
||||
];
|
|
@ -9,18 +9,18 @@
|
|||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* php think build 自动生成应用的目录结构的定义示例
|
||||
*/
|
||||
return [
|
||||
// 需要自动创建的文件
|
||||
'__file__' => [],
|
||||
// 需要自动创建的目录
|
||||
'__dir__' => ['controller', 'model', 'view'],
|
||||
// 需要自动创建的控制器
|
||||
'controller' => ['Index'],
|
||||
// 需要自动创建的模型
|
||||
'model' => ['User'],
|
||||
// 需要自动创建的模板
|
||||
'view' => ['index/index'],
|
||||
// 生成应用公共文件
|
||||
'__file__' => ['common.php'],
|
||||
|
||||
// 定义demo模块的自动生成 (按照实际定义的文件名生成)
|
||||
'demo' => [
|
||||
'__file__' => ['common.php'],
|
||||
'__dir__' => ['behavior', 'controller', 'model', 'view'],
|
||||
'controller' => ['Index', 'Test', 'UserType'],
|
||||
'model' => ['User', 'UserType'],
|
||||
'view' => ['index/index'],
|
||||
],
|
||||
|
||||
// 其他更多的模块定义
|
||||
];
|
|
@ -16,28 +16,18 @@
|
|||
}
|
||||
],
|
||||
"require": {
|
||||
"php": ">=7.1.0",
|
||||
"topthink/framework": "6.0.*-dev",
|
||||
"topthink/think-view": "^1.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"symfony/var-dumper": "^4.2"
|
||||
"php": ">=5.6.0",
|
||||
"topthink/framework": "5.1.*"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"app\\": "app"
|
||||
},
|
||||
"psr-0": {
|
||||
"": "extend/"
|
||||
"app\\": "application"
|
||||
}
|
||||
},
|
||||
"extra": {
|
||||
"think-path": "thinkphp"
|
||||
},
|
||||
"config": {
|
||||
"preferred-install": "dist"
|
||||
},
|
||||
"scripts": {
|
||||
"post-autoload-dump": [
|
||||
"@php think service:discover",
|
||||
"@php think vendor:publish"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load Diff
137
config/app.php
137
config/app.php
|
@ -13,35 +13,126 @@
|
|||
// | 应用设置
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
use think\facade\Env;
|
||||
|
||||
return [
|
||||
// 应用名称
|
||||
'app_name' => '',
|
||||
// 应用地址
|
||||
'app_host' => Env::get('app.host', ''),
|
||||
// 应用的命名空间
|
||||
'app_namespace' => '',
|
||||
// 是否启用路由
|
||||
'with_route' => true,
|
||||
// 是否启用事件
|
||||
'with_event' => true,
|
||||
// 自动多应用模式
|
||||
'auto_multi_app' => false,
|
||||
// 应用映射(自动多应用模式有效)
|
||||
'app_map' => [],
|
||||
// 域名绑定(自动多应用模式有效)
|
||||
'domain_bind' => [],
|
||||
// 禁止URL访问的应用列表(自动多应用模式有效)
|
||||
'deny_app_list' => [],
|
||||
// 默认应用
|
||||
'default_app' => 'index',
|
||||
'app_host' => '',
|
||||
// 应用调试模式
|
||||
'app_debug' => false,
|
||||
// 应用Trace
|
||||
'app_trace' => false,
|
||||
// 应用模式状态
|
||||
'app_status' => '',
|
||||
// 是否支持多模块
|
||||
'app_multi_module' => true,
|
||||
// 入口自动绑定模块
|
||||
'auto_bind_module' => false,
|
||||
// 注册的根命名空间
|
||||
'root_namespace' => [],
|
||||
// 默认输出类型
|
||||
'default_return_type' => 'html',
|
||||
// 默认AJAX 数据返回格式,可选json xml ...
|
||||
'default_ajax_return' => 'json',
|
||||
// 默认JSONP格式返回的处理方法
|
||||
'default_jsonp_handler' => 'jsonpReturn',
|
||||
// 默认JSONP处理方法
|
||||
'var_jsonp_handler' => 'callback',
|
||||
// 默认时区
|
||||
'default_timezone' => 'Asia/Shanghai',
|
||||
'default_timezone' => 'PRC',
|
||||
// 是否开启多语言
|
||||
'lang_switch_on' => false,
|
||||
// 默认全局过滤方法 用逗号分隔多个
|
||||
'default_filter' => '',
|
||||
// 默认语言
|
||||
'default_lang' => 'zh-cn',
|
||||
// 应用类库后缀
|
||||
'class_suffix' => false,
|
||||
// 控制器类后缀
|
||||
'controller_suffix' => false,
|
||||
|
||||
// +----------------------------------------------------------------------
|
||||
// | 模块设置
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
// 默认模块名
|
||||
'default_module' => 'index',
|
||||
// 禁止访问模块
|
||||
'deny_module_list' => ['common'],
|
||||
// 默认控制器名
|
||||
'default_controller' => 'Index',
|
||||
// 默认操作名
|
||||
'default_action' => 'index',
|
||||
// 默认验证器
|
||||
'default_validate' => '',
|
||||
// 默认的空模块名
|
||||
'empty_module' => '',
|
||||
// 默认的空控制器名
|
||||
'empty_controller' => 'Error',
|
||||
// 操作方法前缀
|
||||
'use_action_prefix' => false,
|
||||
// 操作方法后缀
|
||||
'action_suffix' => '',
|
||||
// 自动搜索控制器
|
||||
'controller_auto_search' => false,
|
||||
|
||||
// +----------------------------------------------------------------------
|
||||
// | URL设置
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
// PATHINFO变量名 用于兼容模式
|
||||
'var_pathinfo' => 's',
|
||||
// 兼容PATH_INFO获取
|
||||
'pathinfo_fetch' => ['ORIG_PATH_INFO', 'REDIRECT_PATH_INFO', 'REDIRECT_URL'],
|
||||
// pathinfo分隔符
|
||||
'pathinfo_depr' => '/',
|
||||
// HTTPS代理标识
|
||||
'https_agent_name' => '',
|
||||
// URL伪静态后缀
|
||||
'url_html_suffix' => 'html',
|
||||
// URL普通方式参数 用于自动生成
|
||||
'url_common_param' => false,
|
||||
// URL参数方式 0 按名称成对解析 1 按顺序解析
|
||||
'url_param_type' => 0,
|
||||
// 是否开启路由延迟解析
|
||||
'url_lazy_route' => false,
|
||||
// 是否强制使用路由
|
||||
'url_route_must' => true,
|
||||
// 路由是否完全匹配
|
||||
'route_complete_match' => false,
|
||||
// 使用注解路由
|
||||
'route_annotation' => false,
|
||||
// 域名根,如thinkphp.cn
|
||||
'url_domain_root' => 'www.a.com',
|
||||
// 是否自动转换URL中的控制器和操作名
|
||||
'url_convert' => true,
|
||||
// 默认的访问控制器层
|
||||
'url_controller_layer' => 'controller',
|
||||
// 表单请求类型伪装变量
|
||||
'var_method' => '_method',
|
||||
// 表单ajax伪装变量
|
||||
'var_ajax' => '_ajax',
|
||||
// 表单pjax伪装变量
|
||||
'var_pjax' => '_pjax',
|
||||
// 是否开启请求缓存 true自动缓存 支持设置请求缓存规则
|
||||
'request_cache' => true,
|
||||
// 请求缓存有效期
|
||||
'request_cache_expire' => null,
|
||||
// 全局请求缓存排除规则
|
||||
'request_cache_except' => [],
|
||||
|
||||
// 默认跳转页面对应的模板文件
|
||||
'dispatch_success_tmpl' => Env::get('think_path') . 'tpl/dispatch_jump.tpl',
|
||||
'dispatch_error_tmpl' => Env::get('think_path') . 'tpl/dispatch_jump.tpl',
|
||||
|
||||
// 异常页面的模板文件
|
||||
'exception_tmpl' => app()->getThinkPath() . 'tpl/think_exception.tpl',
|
||||
'exception_tmpl' => Env::get('think_path') . 'tpl/think_exception.tpl',
|
||||
|
||||
// 错误显示信息,非调试模式有效
|
||||
'error_message' => '页面错误!请稍后再试~',
|
||||
'error_message' => '页面错误!请稍后再试~',
|
||||
// 显示错误信息
|
||||
'show_error_msg' => false,
|
||||
'show_error_msg' => false,
|
||||
// 异常处理handle类 留空使用 \think\exception\Handle
|
||||
'exception_handle' => '',
|
||||
|
||||
];
|
||||
|
|
|
@ -8,32 +8,18 @@
|
|||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
use think\facade\Env;
|
||||
|
||||
// +----------------------------------------------------------------------
|
||||
// | 缓存设置
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
return [
|
||||
// 默认缓存驱动
|
||||
'default' => Env::get('cache.driver', 'file'),
|
||||
|
||||
// 缓存连接方式配置
|
||||
'stores' => [
|
||||
'file' => [
|
||||
// 驱动方式
|
||||
'type' => 'File',
|
||||
// 缓存保存目录
|
||||
'path' => app()->getRuntimePath() . 'cache',
|
||||
// 缓存前缀
|
||||
'prefix' => '',
|
||||
// 缓存有效期 0表示永久缓存
|
||||
'expire' => 0,
|
||||
// 缓存标签前缀
|
||||
'tag_prefix' => 'tag:',
|
||||
// 序列化机制 例如 ['serialize', 'unserialize']
|
||||
'serialize' => [],
|
||||
],
|
||||
// 更多的缓存连接
|
||||
],
|
||||
// 驱动方式
|
||||
'type' => 'File',
|
||||
// 缓存保存目录
|
||||
'path' => '',
|
||||
// 缓存前缀
|
||||
'prefix' => '',
|
||||
// 缓存有效期 0表示永久缓存
|
||||
'expire' => 0,
|
||||
];
|
||||
|
|
|
@ -13,6 +13,8 @@
|
|||
// | Cookie设置
|
||||
// +----------------------------------------------------------------------
|
||||
return [
|
||||
// cookie 名称前缀
|
||||
'prefix' => '',
|
||||
// cookie 保存时间
|
||||
'expire' => 0,
|
||||
// cookie 保存路径
|
||||
|
@ -22,7 +24,7 @@ return [
|
|||
// cookie 启用安全传输
|
||||
'secure' => false,
|
||||
// httponly设置
|
||||
'httponly' => false,
|
||||
'httponly' => '',
|
||||
// 是否使用 setcookie
|
||||
'setcookie' => true,
|
||||
];
|
||||
|
|
|
@ -9,62 +9,47 @@
|
|||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
use think\facade\Env;
|
||||
|
||||
return [
|
||||
// 默认使用的数据库连接配置
|
||||
'default' => Env::get('database.driver', 'mysql'),
|
||||
|
||||
// 自定义时间查询规则
|
||||
'time_query_rule' => [],
|
||||
|
||||
// 数据库类型
|
||||
'type' => 'mysql',
|
||||
// 服务器地址
|
||||
'hostname' => '127.0.0.1',
|
||||
// 数据库名
|
||||
'database' => '',
|
||||
// 用户名
|
||||
'username' => 'root',
|
||||
// 密码
|
||||
'password' => '',
|
||||
// 端口
|
||||
'hostport' => '',
|
||||
// 连接dsn
|
||||
'dsn' => '',
|
||||
// 数据库连接参数
|
||||
'params' => [],
|
||||
// 数据库编码默认采用utf8
|
||||
'charset' => 'utf8',
|
||||
// 数据库表前缀
|
||||
'prefix' => '',
|
||||
// 数据库调试模式
|
||||
'debug' => true,
|
||||
// 数据库部署方式:0 集中式(单一服务器),1 分布式(主从服务器)
|
||||
'deploy' => 0,
|
||||
// 数据库读写是否分离 主从式有效
|
||||
'rw_separate' => false,
|
||||
// 读写分离后 主服务器数量
|
||||
'master_num' => 1,
|
||||
// 指定从服务器序号
|
||||
'slave_no' => '',
|
||||
// 是否严格检查字段是否存在
|
||||
'fields_strict' => true,
|
||||
// 数据集返回类型
|
||||
'resultset_type' => 'array',
|
||||
// 自动写入时间戳字段
|
||||
// true为自动识别类型 false关闭
|
||||
// 字符串则明确指定时间字段类型 支持 int timestamp datetime date
|
||||
'auto_timestamp' => true,
|
||||
|
||||
'auto_timestamp' => false,
|
||||
// 时间字段取出后的默认时间格式
|
||||
'datetime_format' => 'Y-m-d H:i:s',
|
||||
|
||||
// 数据库连接配置信息
|
||||
'connections' => [
|
||||
'mysql' => [
|
||||
// 数据库类型
|
||||
'type' => Env::get('database.type', 'mysql'),
|
||||
// 服务器地址
|
||||
'hostname' => Env::get('database.hostname', '127.0.0.1'),
|
||||
// 数据库名
|
||||
'database' => Env::get('database.database', ''),
|
||||
// 用户名
|
||||
'username' => Env::get('database.username', 'root'),
|
||||
// 密码
|
||||
'password' => Env::get('database.password', ''),
|
||||
// 端口
|
||||
'hostport' => Env::get('database.hostport', '3306'),
|
||||
// 数据库连接参数
|
||||
'params' => [],
|
||||
// 数据库编码默认采用utf8
|
||||
'charset' => Env::get('database.charset', 'utf8'),
|
||||
// 数据库表前缀
|
||||
'prefix' => Env::get('database.prefix', ''),
|
||||
// 数据库调试模式
|
||||
'debug' => Env::get('database.debug', true),
|
||||
// 数据库部署方式:0 集中式(单一服务器),1 分布式(主从服务器)
|
||||
'deploy' => 0,
|
||||
// 数据库读写是否分离 主从式有效
|
||||
'rw_separate' => false,
|
||||
// 读写分离后 主服务器数量
|
||||
'master_num' => 1,
|
||||
// 指定从服务器序号
|
||||
'slave_no' => '',
|
||||
// 是否严格检查字段是否存在
|
||||
'fields_strict' => true,
|
||||
// 是否需要进行SQL性能分析
|
||||
'sql_explain' => false,
|
||||
// 是否需要断线重连
|
||||
'break_reconnect' => false,
|
||||
],
|
||||
|
||||
// 更多的数据库配置信息
|
||||
],
|
||||
// 是否需要进行SQL性能分析
|
||||
'sql_explain' => false,
|
||||
// Query类
|
||||
'query' => '\\think\\db\\Query',
|
||||
];
|
||||
|
|
|
@ -1,20 +0,0 @@
|
|||
<?php
|
||||
|
||||
use think\facade\Env;
|
||||
|
||||
return [
|
||||
'default' => Env::get('filesystem.driver', 'local'),
|
||||
'disks' => [
|
||||
'local' => [
|
||||
'type' => 'local',
|
||||
'root' => app()->getRuntimePath() . 'storage',
|
||||
],
|
||||
'public' => [
|
||||
'type' => 'local',
|
||||
'root' => app()->getRootPath() . 'public/storage',
|
||||
'url' => '/storage',
|
||||
'visibility' => 'public',
|
||||
],
|
||||
// 更多的磁盘配置信息
|
||||
],
|
||||
];
|
|
@ -1,37 +0,0 @@
|
|||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
// +----------------------------------------------------------------------
|
||||
// | 多语言设置
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
use think\facade\Env;
|
||||
|
||||
return [
|
||||
// 默认语言
|
||||
'default_lang' => Env::get('lang.default_lang', 'zh-cn'),
|
||||
// 允许的语言列表
|
||||
'allow_lang_list' => [],
|
||||
// 多语言自动侦测变量名
|
||||
'detect_var' => 'lang',
|
||||
// 是否使用Cookie记录
|
||||
'use_cookie' => true,
|
||||
// 多语言cookie变量
|
||||
'cookie_var' => 'think_lang',
|
||||
// 扩展语言包
|
||||
'extend_list' => [],
|
||||
// Accept-Language转义为对应语言包名称
|
||||
'accept_language' => [
|
||||
'zh-hans-cn' => 'zh-cn',
|
||||
],
|
||||
// 是否支持语言分组
|
||||
'allow_group' => false,
|
||||
];
|
|
@ -8,48 +8,15 @@
|
|||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
use think\facade\Env;
|
||||
|
||||
// +----------------------------------------------------------------------
|
||||
// | 日志设置
|
||||
// +----------------------------------------------------------------------
|
||||
return [
|
||||
// 默认日志记录通道
|
||||
'default' => Env::get('log.channel', 'file'),
|
||||
// 日志记录方式,内置 file socket 支持扩展
|
||||
'type' => 'File',
|
||||
// 日志保存目录
|
||||
'path' => '',
|
||||
// 日志记录级别
|
||||
'level' => [],
|
||||
// 日志类型记录的通道 ['error'=>'email',...]
|
||||
'type_channel' => [],
|
||||
// 关闭全局日志写入
|
||||
'close' => false,
|
||||
// 全局日志处理 支持闭包
|
||||
'processor' => null,
|
||||
|
||||
// 日志通道列表
|
||||
'channels' => [
|
||||
'file' => [
|
||||
// 日志记录方式
|
||||
'type' => 'File',
|
||||
// 日志保存目录
|
||||
'path' => app()->getRuntimePath() . 'log',
|
||||
// 单文件日志写入
|
||||
'single' => false,
|
||||
// 独立日志级别
|
||||
'apart_level' => [],
|
||||
// 最大日志文件数量
|
||||
'max_files' => 0,
|
||||
// 使用JSON格式记录
|
||||
'json' => false,
|
||||
// 日志处理
|
||||
'processor' => null,
|
||||
// 关闭通道日志写入
|
||||
'close' => false,
|
||||
// 日志输出格式化
|
||||
'format' => '[%s][%s] %s',
|
||||
// 是否实时写入
|
||||
'realtime_write' => false,
|
||||
],
|
||||
// 其它日志通道配置
|
||||
],
|
||||
|
||||
'level' => [],
|
||||
];
|
||||
|
|
|
@ -1,63 +0,0 @@
|
|||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
// +----------------------------------------------------------------------
|
||||
// | 应用设置
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
return [
|
||||
// pathinfo分隔符
|
||||
'pathinfo_depr' => '/',
|
||||
// URL伪静态后缀
|
||||
'url_html_suffix' => 'html',
|
||||
// URL普通方式参数 用于自动生成
|
||||
'url_common_param' => true,
|
||||
// 是否开启路由延迟解析
|
||||
'url_lazy_route' => false,
|
||||
// 是否强制使用路由
|
||||
'url_route_must' => false,
|
||||
// 合并路由规则
|
||||
'route_rule_merge' => false,
|
||||
// 路由是否完全匹配
|
||||
'route_complete_match' => false,
|
||||
// 是否开启路由缓存
|
||||
'route_check_cache' => false,
|
||||
// 路由缓存连接参数
|
||||
'route_cache_option' => [],
|
||||
// 路由缓存Key
|
||||
'route_check_cache_key' => '',
|
||||
// 访问控制器层名称
|
||||
'controller_layer' => 'controller',
|
||||
// 空控制器名
|
||||
'empty_controller' => 'Error',
|
||||
// 是否使用控制器后缀
|
||||
'controller_suffix' => false,
|
||||
// 默认的路由变量规则
|
||||
'default_route_pattern' => '[\w\.]+',
|
||||
// 是否自动转换URL中的控制器和操作名
|
||||
'url_convert' => true,
|
||||
// 是否开启请求缓存 true自动缓存 支持设置请求缓存规则
|
||||
'request_cache' => false,
|
||||
// 请求缓存有效期
|
||||
'request_cache_expire' => null,
|
||||
// 全局请求缓存排除规则
|
||||
'request_cache_except' => [],
|
||||
// 默认控制器名
|
||||
'default_controller' => 'Index',
|
||||
// 默认操作名
|
||||
'default_action' => 'index',
|
||||
// 操作方法后缀
|
||||
'action_suffix' => '',
|
||||
// 默认JSONP格式返回的处理方法
|
||||
'default_jsonp_handler' => 'jsonpReturn',
|
||||
// 默认JSONP处理方法
|
||||
'var_jsonp_handler' => 'callback',
|
||||
];
|
|
@ -14,14 +14,13 @@
|
|||
// +----------------------------------------------------------------------
|
||||
|
||||
return [
|
||||
// session name
|
||||
'name' => '',
|
||||
'id' => '',
|
||||
// SESSION_ID的提交变量,解决flash上传跨域
|
||||
'var_session_id' => '',
|
||||
// 驱动方式 支持file redis memcache memcached
|
||||
'type' => 'file',
|
||||
// 过期时间
|
||||
'expire' => 0,
|
||||
// 前缀
|
||||
'prefix' => '',
|
||||
// SESSION 前缀
|
||||
'prefix' => 'think',
|
||||
// 驱动方式 支持redis memcache memcached
|
||||
'type' => '',
|
||||
// 是否自动开启 SESSION
|
||||
'auto_start' => true,
|
||||
];
|
||||
|
|
|
@ -1,13 +1,21 @@
|
|||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
// +----------------------------------------------------------------------
|
||||
// | 模板设置
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
return [
|
||||
// 模板引擎类型使用Think
|
||||
// 模板引擎类型 支持 php think 支持扩展
|
||||
'type' => 'Think',
|
||||
// 默认模板渲染规则 1 解析为小写+下划线 2 全部转换小写 3 保持操作方法
|
||||
'auto_rule' => 1,
|
||||
// 模板路径
|
||||
'view_path' => '',
|
||||
// 模板后缀
|
||||
|
|
|
@ -10,11 +10,9 @@
|
|||
// +----------------------------------------------------------------------
|
||||
|
||||
// +----------------------------------------------------------------------
|
||||
// | Trace设置 开启调试模式后有效
|
||||
// | Trace设置 开启 app_trace 后 有效
|
||||
// +----------------------------------------------------------------------
|
||||
return [
|
||||
// 内置Html 支持扩展
|
||||
'type' => 'Html',
|
||||
// 读取的日志通道名
|
||||
'channel' => '',
|
||||
// 内置Html Console 支持扩展
|
||||
'type' => 'Html',
|
||||
];
|
||||
|
|
|
@ -12,13 +12,75 @@
|
|||
// [ 应用入口文件 ]
|
||||
namespace think;
|
||||
|
||||
require __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
// 执行HTTP应用并响应
|
||||
$http = (new App())->http;
|
||||
|
||||
$response = $http->run();
|
||||
|
||||
$response->send();
|
||||
|
||||
$http->end($response);
|
||||
|
||||
|
||||
|
||||
function langt($str = '',$lang = 'en'){
|
||||
// $lang 要自动获取当前语言,并不需要靠赋值来区分语言
|
||||
if($lang == 'cn') return $str;
|
||||
$langarr = array(
|
||||
'en' => array(
|
||||
'Name of the merchant'=>'商户名称',
|
||||
'Detailed address'=>'详细地址',
|
||||
'Distribution area'=>'经销区域',
|
||||
'Latitude and longitude orientation'=>'经纬度定位',
|
||||
'Latitude and longitude orientation'=>'经纬度定位',
|
||||
),
|
||||
'tc' => array(
|
||||
'Name of the merchant'=>'商戶名稱',
|
||||
'Detailed address'=>'詳細地址',
|
||||
'Distribution area'=>'經銷區域',
|
||||
'Latitude and longitude orientation'=>'經緯度定位6',
|
||||
)
|
||||
);
|
||||
|
||||
$langkey = (string) array_search($str,$langarr['en']);
|
||||
if($lang == 'en') return $langkey?:$str;
|
||||
return isset($langarr[$lang][$langkey])?$langarr[$lang][$langkey]:$str;
|
||||
}
|
||||
/**
|
||||
* 输出字符串或数组
|
||||
* @param string/array $vars 输出字符串或数组
|
||||
* @param string $label 提示标题
|
||||
* @param string $return 是否有返回值
|
||||
*/
|
||||
function dump($vars, $return = false, $label = ''){
|
||||
if (ini_get('html_errors')){
|
||||
$content = "<pre>\n";
|
||||
if ($label != '') {
|
||||
$content .= "<strong>{$label} :</strong>\n";
|
||||
}
|
||||
$content .= htmlspecialchars(print_r($vars, true), ENT_COMPAT, 'ISO-8859-1');
|
||||
$content .= "\n</pre>\n";
|
||||
} else {
|
||||
$content = $label . " :\n" . print_r($vars, true);
|
||||
}
|
||||
echo $content;
|
||||
if ($return) exit;
|
||||
return null;
|
||||
|
||||
for ($i=0;$i<100;$i++){
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
// 加载基础文件
|
||||
require __DIR__ . '/../thinkphp/base.php';
|
||||
|
||||
// 支持事先使用静态方法设置Request对象和Config对象
|
||||
|
||||
// Container::get('app') 返回thinkphp/libray/think/app的实例
|
||||
// run() thinkphp/libray/think/app 对应用进行各种配置和初始化
|
||||
// send() think\Response 内
|
||||
// 执行应用并响应
|
||||
|
||||
Container::get('app')->run()->send();
|
||||
|
||||
//Loader::dinfo();
|
||||
|
|
|
@ -8,10 +8,15 @@
|
|||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
use think\facade\Route;
|
||||
|
||||
Route::get('think', function () {
|
||||
return 'hello,ThinkPHP6!';
|
||||
});
|
||||
//Route::get('think', function () {
|
||||
// return 'hello,ThinkPHP5!';
|
||||
//});
|
||||
|
||||
Route::get('hello/:name', 'index/hello');
|
||||
|
||||
Route::get('news', 'news/test/hello');
|
||||
|
||||
return [
|
||||
|
||||
];
|
|
@ -9,19 +9,14 @@
|
|||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
// 事件定义文件
|
||||
Route::get('think', function () {
|
||||
return 'hello,ThinkPHP5!';
|
||||
});
|
||||
|
||||
//Route::get('hello/:name', 'index/hello');
|
||||
//
|
||||
//Route::get('news', 'news/test/hello');
|
||||
|
||||
return [
|
||||
'bind' => [
|
||||
],
|
||||
|
||||
'listen' => [
|
||||
'AppInit' => [],
|
||||
'HttpRun' => [],
|
||||
'HttpEnd' => [],
|
||||
'LogLevel' => [],
|
||||
'LogWrite' => [],
|
||||
],
|
||||
|
||||
'subscribe' => [
|
||||
],
|
||||
|
||||
];
|
|
@ -2,16 +2,15 @@
|
|||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2019 http://thinkphp.cn All rights reserved.
|
||||
// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace app;
|
||||
|
||||
class Request extends \think\Request
|
||||
{
|
||||
|
||||
}
|
||||
return [
|
||||
'test' => [
|
||||
'news/test/index',[]
|
||||
]
|
||||
];
|
7
think
7
think
|
@ -13,7 +13,10 @@
|
|||
namespace think;
|
||||
|
||||
// 加载基础文件
|
||||
require __DIR__ . '/vendor/autoload.php';
|
||||
require __DIR__ . '/thinkphp/base.php';
|
||||
|
||||
// 应用初始化
|
||||
(new App())->console->run();
|
||||
Container::get('app')->path(__DIR__ . '/application/')->initialize();
|
||||
|
||||
// 控制台初始化
|
||||
Console::init();
|
|
@ -0,0 +1,3 @@
|
|||
/composer.lock
|
||||
.idea
|
||||
.DS_Store
|
|
@ -0,0 +1 @@
|
|||
deny from all
|
|
@ -0,0 +1,61 @@
|
|||
ThinkPHP 5.1
|
||||
===============
|
||||
|
||||
[![StyleCI](https://styleci.io/repos/48530411/shield?style=flat&branch=master)](https://styleci.io/repos/48530411)
|
||||
[![Build Status](https://travis-ci.org/top-think/framework.svg?branch=master)](https://travis-ci.org/top-think/framework)
|
||||
[![codecov.io](http://codecov.io/github/top-think/framework/coverage.svg?branch=master)](http://codecov.io/github/github/top-think/framework?branch=master)
|
||||
[![Total Downloads](https://poser.pugx.org/topthink/framework/downloads)](https://packagist.org/packages/topthink/framework)
|
||||
[![Latest Stable Version](https://poser.pugx.org/topthink/framework/v/stable)](https://packagist.org/packages/topthink/framework)
|
||||
[![Latest Unstable Version](https://poser.pugx.org/topthink/framework/v/unstable)](https://packagist.org/packages/topthink/framework)
|
||||
[![License](https://poser.pugx.org/topthink/framework/license)](https://packagist.org/packages/topthink/framework)
|
||||
|
||||
ThinkPHP5.1对底层架构做了进一步的改进,减少依赖,其主要特性包括:
|
||||
|
||||
+ 采用容器统一管理对象
|
||||
+ 支持Facade
|
||||
+ 更易用的路由
|
||||
+ 注解路由支持
|
||||
+ 路由跨域请求支持
|
||||
+ 验证类增强
|
||||
+ 配置和路由目录独立
|
||||
+ 取消系统常量
|
||||
+ 类库别名机制
|
||||
+ 模型和数据库增强
|
||||
+ 依赖注入完善
|
||||
+ 支持PSR-3日志规范
|
||||
|
||||
### 废除的功能:
|
||||
|
||||
+ 聚合模型
|
||||
+ 内置控制器扩展类
|
||||
+ 模型自动验证
|
||||
|
||||
> ThinkPHP5的运行环境要求PHP5.6以上。
|
||||
|
||||
|
||||
## 在线手册
|
||||
|
||||
+ [完全开发手册](https://www.kancloud.cn/manual/thinkphp5_1)
|
||||
+ [升级指导](https://www.kancloud.cn/manual/thinkphp5_1/354155)
|
||||
|
||||
## 命名规范
|
||||
|
||||
`ThinkPHP5`遵循PSR-2命名规范和PSR-4自动加载规范。
|
||||
|
||||
## 参与开发
|
||||
|
||||
请参阅 [ThinkPHP5 核心框架包](https://github.com/top-think/framework)。
|
||||
|
||||
## 版权信息
|
||||
|
||||
ThinkPHP遵循Apache2开源协议发布,并提供免费使用。
|
||||
|
||||
本项目包含的第三方源码和二进制文件之版权信息另行标注。
|
||||
|
||||
版权所有Copyright © 2006-2018 by ThinkPHP (http://thinkphp.cn)
|
||||
|
||||
All rights reserved。
|
||||
|
||||
ThinkPHP® 商标和著作权所有者为上海顶想信息科技有限公司。
|
||||
|
||||
更多细节参阅 [LICENSE.txt](LICENSE.txt)
|
|
@ -0,0 +1,108 @@
|
|||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
namespace think;
|
||||
|
||||
// 载入Loader类
|
||||
require __DIR__ . '/library/think/Loader.php';
|
||||
|
||||
// 注册自动加载
|
||||
Loader::register();
|
||||
|
||||
//// 注册错误和异常处理机制
|
||||
//Error::register();
|
||||
//
|
||||
//// 实现日志接口
|
||||
//if (interface_exists('Psr\Log\LoggerInterface')) {
|
||||
// interface LoggerInterface extends \Psr\Log\LoggerInterface
|
||||
// {}
|
||||
//} else {
|
||||
// interface LoggerInterface
|
||||
// {}
|
||||
//}
|
||||
|
||||
|
||||
//通过 Container::getInstance()->bind() 先将核心类库实例化后注册到容器内
|
||||
//再通过 Facade::bind() 将核心类转成静态代理,
|
||||
//最后使用 Loader::addClassAlias() 给静态代理注册类别名,方便直接静态调用
|
||||
|
||||
// 注册核心类到容器
|
||||
Container::getInstance()->bind([
|
||||
'app' => App::class,
|
||||
'build' => Build::class,
|
||||
'cache' => Cache::class,
|
||||
'config' => Config::class,
|
||||
'cookie' => Cookie::class,
|
||||
'debug' => Debug::class,
|
||||
'env' => Env::class,
|
||||
'hook' => Hook::class,
|
||||
'lang' => Lang::class,
|
||||
'log' => Log::class,
|
||||
'request' => Request::class,
|
||||
'response' => Response::class,
|
||||
'route' => Route::class,
|
||||
'session' => Session::class,
|
||||
'url' => Url::class,
|
||||
'validate' => Validate::class,
|
||||
'view' => View::class,
|
||||
'middlewareDispatcher' => http\middleware\Dispatcher::class,
|
||||
// 接口依赖注入
|
||||
'think\LoggerInterface' => Log::class,
|
||||
]);
|
||||
|
||||
// 注册核心类的静态代理
|
||||
Facade::bind([
|
||||
facade\App::class => App::class,
|
||||
facade\Build::class => Build::class,
|
||||
facade\Cache::class => Cache::class,
|
||||
facade\Config::class => Config::class,
|
||||
facade\Cookie::class => Cookie::class,
|
||||
facade\Debug::class => Debug::class,
|
||||
facade\Env::class => Env::class,
|
||||
facade\Hook::class => Hook::class,
|
||||
facade\Lang::class => Lang::class,
|
||||
facade\Log::class => Log::class,
|
||||
facade\Request::class => Request::class,
|
||||
facade\Response::class => Response::class,
|
||||
facade\Route::class => Route::class,
|
||||
facade\Session::class => Session::class,
|
||||
facade\Url::class => Url::class,
|
||||
facade\Validate::class => Validate::class,
|
||||
facade\View::class => View::class,
|
||||
]);
|
||||
|
||||
// 注册类库别名
|
||||
Loader::addClassAlias([
|
||||
'App' => facade\App::class,
|
||||
'Build' => facade\Build::class,
|
||||
'Cache' => facade\Cache::class,
|
||||
'Config' => facade\Config::class,
|
||||
'Cookie' => facade\Cookie::class,
|
||||
'Db' => Db::class,
|
||||
'Debug' => facade\Debug::class,
|
||||
'Env' => facade\Env::class,
|
||||
'Facade' => Facade::class,
|
||||
'Hook' => facade\Hook::class,
|
||||
'Lang' => facade\Lang::class,
|
||||
'Log' => facade\Log::class,
|
||||
'Request' => facade\Request::class,
|
||||
'Response' => facade\Response::class,
|
||||
'Route' => facade\Route::class,
|
||||
'Session' => facade\Session::class,
|
||||
'Url' => facade\Url::class,
|
||||
'Validate' => facade\Validate::class,
|
||||
'View' => facade\View::class,
|
||||
]);
|
||||
|
||||
// 加载惯例配置文件
|
||||
facade\Config::set(__include_file(__DIR__ . '/convention.php'));
|
||||
|
||||
// 加载composer autofile文件
|
||||
Loader::loadComposerAutoloadFiles();
|
|
@ -0,0 +1,35 @@
|
|||
{
|
||||
"name": "topthink/framework",
|
||||
"description": "the new thinkphp framework",
|
||||
"type": "think-framework",
|
||||
"keywords": [
|
||||
"framework",
|
||||
"thinkphp",
|
||||
"ORM"
|
||||
],
|
||||
"homepage": "http://thinkphp.cn/",
|
||||
"license": "Apache-2.0",
|
||||
"authors": [
|
||||
{
|
||||
"name": "liu21st",
|
||||
"email": "liu21st@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "yunwuxin",
|
||||
"email": "448901948@qq.com"
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": ">=5.6.0",
|
||||
"topthink/think-installer": "~1.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^5.0|^6.0",
|
||||
"johnkary/phpunit-speedtrap": "^1.0",
|
||||
"mikey179/vfsStream": "~1.6",
|
||||
"phploc/phploc": "2.*",
|
||||
"sebastian/phpcpd": "2.*",
|
||||
"squizlabs/php_codesniffer": "2.*",
|
||||
"phpdocumentor/reflection-docblock": "^2.0"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,292 @@
|
|||
<?php
|
||||
|
||||
return [
|
||||
// +----------------------------------------------------------------------
|
||||
// | 应用设置
|
||||
// +----------------------------------------------------------------------
|
||||
'app' => [
|
||||
// 应用名称
|
||||
'app_name' => '',
|
||||
// 应用地址
|
||||
'app_host' => '',
|
||||
// 应用调试模式
|
||||
'app_debug' => false,
|
||||
// 应用Trace
|
||||
'app_trace' => false,
|
||||
// 应用模式状态
|
||||
'app_status' => '',
|
||||
// 是否支持多模块
|
||||
'app_multi_module' => true,
|
||||
// 入口自动绑定模块
|
||||
'auto_bind_module' => false,
|
||||
// 注册的根命名空间
|
||||
'root_namespace' => [],
|
||||
// 默认输出类型
|
||||
'default_return_type' => 'html',
|
||||
// 默认AJAX 数据返回格式,可选json xml ...
|
||||
'default_ajax_return' => 'json',
|
||||
// 默认JSONP格式返回的处理方法
|
||||
'default_jsonp_handler' => 'jsonpReturn',
|
||||
// 默认JSONP处理方法
|
||||
'var_jsonp_handler' => 'callback',
|
||||
// 默认时区
|
||||
'default_timezone' => 'PRC',
|
||||
// 是否开启多语言
|
||||
'lang_switch_on' => false,
|
||||
// 默认全局过滤方法 用逗号分隔多个
|
||||
'default_filter' => '',
|
||||
// 默认语言
|
||||
'default_lang' => 'zh-cn',
|
||||
// 应用类库后缀
|
||||
'class_suffix' => false,
|
||||
// 控制器类后缀
|
||||
'controller_suffix' => false,
|
||||
|
||||
// +----------------------------------------------------------------------
|
||||
// | 模块设置
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
// 默认模块名
|
||||
'default_module' => 'index',
|
||||
// 禁止访问模块
|
||||
'deny_module_list' => ['common'],
|
||||
// 默认控制器名
|
||||
'default_controller' => 'Index',
|
||||
// 默认操作名
|
||||
'default_action' => 'index',
|
||||
// 默认验证器
|
||||
'default_validate' => '',
|
||||
// 默认的空模块名
|
||||
'empty_module' => '',
|
||||
// 默认的空控制器名
|
||||
'empty_controller' => 'Error',
|
||||
// 操作方法前缀
|
||||
'use_action_prefix' => false,
|
||||
// 操作方法后缀
|
||||
'action_suffix' => '',
|
||||
// 自动搜索控制器
|
||||
'controller_auto_search' => false,
|
||||
|
||||
// +----------------------------------------------------------------------
|
||||
// | URL设置
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
// PATHINFO变量名 用于兼容模式
|
||||
'var_pathinfo' => 's',
|
||||
// 兼容PATH_INFO获取
|
||||
'pathinfo_fetch' => ['ORIG_PATH_INFO', 'REDIRECT_PATH_INFO', 'REDIRECT_URL'],
|
||||
// pathinfo分隔符
|
||||
'pathinfo_depr' => '/',
|
||||
// HTTPS代理标识
|
||||
'https_agent_name' => '',
|
||||
// URL伪静态后缀
|
||||
'url_html_suffix' => 'html',
|
||||
// URL普通方式参数 用于自动生成
|
||||
'url_common_param' => false,
|
||||
// URL参数方式 0 按名称成对解析 1 按顺序解析
|
||||
'url_param_type' => 0,
|
||||
// 是否开启路由延迟解析
|
||||
'url_lazy_route' => false,
|
||||
// 是否强制使用路由
|
||||
'url_route_must' => false,
|
||||
// 路由是否完全匹配
|
||||
'route_complete_match' => false,
|
||||
// 使用注解路由
|
||||
'route_annotation' => false,
|
||||
// 域名根,如thinkphp.cn
|
||||
'url_domain_root' => '',
|
||||
// 是否自动转换URL中的控制器和操作名
|
||||
'url_convert' => true,
|
||||
// 默认的访问控制器层
|
||||
'url_controller_layer' => 'controller',
|
||||
// 表单请求类型伪装变量
|
||||
'var_method' => '_method',
|
||||
// 表单ajax伪装变量
|
||||
'var_ajax' => '_ajax',
|
||||
// 表单pjax伪装变量
|
||||
'var_pjax' => '_pjax',
|
||||
// 是否开启请求缓存 true自动缓存 支持设置请求缓存规则
|
||||
'request_cache' => false,
|
||||
// 请求缓存有效期
|
||||
'request_cache_expire' => null,
|
||||
// 全局请求缓存排除规则
|
||||
'request_cache_except' => [],
|
||||
|
||||
// 默认跳转页面对应的模板文件
|
||||
'dispatch_success_tmpl' => __DIR__ . '/tpl/dispatch_jump.tpl',
|
||||
'dispatch_error_tmpl' => __DIR__ . '/tpl/dispatch_jump.tpl',
|
||||
|
||||
// +----------------------------------------------------------------------
|
||||
// | 异常及错误设置
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
// 异常页面的模板文件
|
||||
'exception_tmpl' => __DIR__ . '/tpl/think_exception.tpl',
|
||||
|
||||
// 错误显示信息,非调试模式有效
|
||||
'error_message' => '页面错误!请稍后再试~',
|
||||
// 显示错误信息
|
||||
'show_error_msg' => false,
|
||||
// 异常处理handle类 留空使用 \think\exception\Handle
|
||||
'exception_handle' => '',
|
||||
],
|
||||
|
||||
// +----------------------------------------------------------------------
|
||||
// | 模板设置
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
'template' => [
|
||||
// 模板引擎类型 支持 php think 支持扩展
|
||||
'type' => 'Think',
|
||||
// 视图基础目录,配置目录为所有模块的视图起始目录
|
||||
'view_base' => '',
|
||||
// 当前模板的视图目录 留空为自动获取
|
||||
'view_path' => '',
|
||||
// 模板后缀
|
||||
'view_suffix' => 'html',
|
||||
// 模板文件名分隔符
|
||||
'view_depr' => DIRECTORY_SEPARATOR,
|
||||
// 模板引擎普通标签开始标记
|
||||
'tpl_begin' => '{',
|
||||
// 模板引擎普通标签结束标记
|
||||
'tpl_end' => '}',
|
||||
// 标签库标签开始标记
|
||||
'taglib_begin' => '{',
|
||||
// 标签库标签结束标记
|
||||
'taglib_end' => '}',
|
||||
],
|
||||
|
||||
// +----------------------------------------------------------------------
|
||||
// | 日志设置
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
'log' => [
|
||||
// 日志记录方式,内置 file socket 支持扩展
|
||||
'type' => 'File',
|
||||
// 日志保存目录
|
||||
//'path' => LOG_PATH,
|
||||
// 日志记录级别
|
||||
'level' => [],
|
||||
// 是否记录trace信息到日志
|
||||
'record_trace' => false,
|
||||
],
|
||||
|
||||
// +----------------------------------------------------------------------
|
||||
// | Trace设置 开启 app_trace 后 有效
|
||||
// +----------------------------------------------------------------------
|
||||
'trace' => [
|
||||
// 内置Html Console 支持扩展
|
||||
'type' => 'Html',
|
||||
'file' => __DIR__ . '/tpl/page_trace.tpl',
|
||||
],
|
||||
|
||||
// +----------------------------------------------------------------------
|
||||
// | 缓存设置
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
'cache' => [
|
||||
// 驱动方式
|
||||
'type' => 'File',
|
||||
// 缓存保存目录
|
||||
//'path' => CACHE_PATH,
|
||||
// 缓存前缀
|
||||
'prefix' => '',
|
||||
// 缓存有效期 0表示永久缓存
|
||||
'expire' => 0,
|
||||
],
|
||||
|
||||
// +----------------------------------------------------------------------
|
||||
// | 会话设置
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
'session' => [
|
||||
'id' => '',
|
||||
// SESSION_ID的提交变量,解决flash上传跨域
|
||||
'var_session_id' => '',
|
||||
// SESSION 前缀
|
||||
'prefix' => 'think',
|
||||
// 驱动方式 支持redis memcache memcached
|
||||
'type' => '',
|
||||
// 是否自动开启 SESSION
|
||||
'auto_start' => true,
|
||||
'httponly' => true,
|
||||
'secure' => false,
|
||||
],
|
||||
|
||||
// +----------------------------------------------------------------------
|
||||
// | Cookie设置
|
||||
// +----------------------------------------------------------------------
|
||||
'cookie' => [
|
||||
// cookie 名称前缀
|
||||
'prefix' => '',
|
||||
// cookie 保存时间
|
||||
'expire' => 0,
|
||||
// cookie 保存路径
|
||||
'path' => '/',
|
||||
// cookie 有效域名
|
||||
'domain' => '',
|
||||
// cookie 启用安全传输
|
||||
'secure' => false,
|
||||
// httponly设置
|
||||
'httponly' => '',
|
||||
// 是否使用 setcookie
|
||||
'setcookie' => true,
|
||||
],
|
||||
|
||||
// +----------------------------------------------------------------------
|
||||
// | 数据库设置
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
'database' => [
|
||||
// 数据库类型
|
||||
'type' => 'mysql',
|
||||
// 数据库连接DSN配置
|
||||
'dsn' => '',
|
||||
// 服务器地址
|
||||
'hostname' => '127.0.0.1',
|
||||
// 数据库名
|
||||
'database' => '',
|
||||
// 数据库用户名
|
||||
'username' => 'root',
|
||||
// 数据库密码
|
||||
'password' => '',
|
||||
// 数据库连接端口
|
||||
'hostport' => '',
|
||||
// 数据库连接参数
|
||||
'params' => [],
|
||||
// 数据库编码默认采用utf8
|
||||
'charset' => 'utf8',
|
||||
// 数据库表前缀
|
||||
'prefix' => '',
|
||||
// 数据库调试模式
|
||||
'debug' => false,
|
||||
// 数据库部署方式:0 集中式(单一服务器),1 分布式(主从服务器)
|
||||
'deploy' => 0,
|
||||
// 数据库读写是否分离 主从式有效
|
||||
'rw_separate' => false,
|
||||
// 读写分离后 主服务器数量
|
||||
'master_num' => 1,
|
||||
// 指定从服务器序号
|
||||
'slave_no' => '',
|
||||
// 是否严格检查字段是否存在
|
||||
'fields_strict' => true,
|
||||
// 数据集返回类型
|
||||
'resultset_type' => 'array',
|
||||
// 自动写入时间戳字段
|
||||
'auto_timestamp' => false,
|
||||
// 时间字段取出后的默认时间格式
|
||||
'datetime_format' => 'Y-m-d H:i:s',
|
||||
// 是否需要进行SQL性能分析
|
||||
'sql_explain' => false,
|
||||
// 查询对象
|
||||
'query' => '\\think\\db\\Query',
|
||||
],
|
||||
|
||||
//分页配置
|
||||
'paginate' => [
|
||||
'type' => 'bootstrap',
|
||||
'var_page' => 'page',
|
||||
'list_rows' => 15,
|
||||
],
|
||||
|
||||
];
|
|
@ -0,0 +1,691 @@
|
|||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
//------------------------
|
||||
// ThinkPHP 助手函数
|
||||
//-------------------------
|
||||
|
||||
use think\Container;
|
||||
use think\Db;
|
||||
use think\exception\HttpException;
|
||||
use think\exception\HttpResponseException;
|
||||
use think\facade\Cache;
|
||||
use think\facade\Config;
|
||||
use think\facade\Cookie;
|
||||
use think\facade\Debug;
|
||||
use think\facade\Env;
|
||||
use think\facade\Hook;
|
||||
use think\facade\Lang;
|
||||
use think\facade\Log;
|
||||
use think\facade\Request;
|
||||
use think\facade\Route;
|
||||
use think\facade\Session;
|
||||
use think\facade\Url;
|
||||
use think\Response;
|
||||
use think\route\RuleItem;
|
||||
|
||||
if (!function_exists('abort')) {
|
||||
/**
|
||||
* 抛出HTTP异常
|
||||
* @param integer|Response $code 状态码 或者 Response对象实例
|
||||
* @param string $message 错误信息
|
||||
* @param array $header 参数
|
||||
*/
|
||||
function abort($code, $message = null, $header = [])
|
||||
{
|
||||
if ($code instanceof Response) {
|
||||
throw new HttpResponseException($code);
|
||||
} else {
|
||||
throw new HttpException($code, $message, null, $header);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('action')) {
|
||||
/**
|
||||
* 调用模块的操作方法 参数格式 [模块/控制器/]操作
|
||||
* @param string $url 调用地址
|
||||
* @param string|array $vars 调用参数 支持字符串和数组
|
||||
* @param string $layer 要调用的控制层名称
|
||||
* @param bool $appendSuffix 是否添加类名后缀
|
||||
* @return mixed
|
||||
*/
|
||||
function action($url, $vars = [], $layer = 'controller', $appendSuffix = false)
|
||||
{
|
||||
return app()->action($url, $vars, $layer, $appendSuffix);
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('app')) {
|
||||
/**
|
||||
* 快速获取容器中的实例 支持依赖注入
|
||||
* @param string $name 类名或标识 默认获取当前应用实例
|
||||
* @param array $args 参数
|
||||
* @param bool $newInstance 是否每次创建新的实例
|
||||
* @return object
|
||||
*/
|
||||
function app($name = 'think\App', $args = [], $newInstance = false)
|
||||
{
|
||||
return Container::get($name, $args, $newInstance);
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('behavior')) {
|
||||
/**
|
||||
* 执行某个行为(run方法) 支持依赖注入
|
||||
* @param mixed $behavior 行为类名或者别名
|
||||
* @param mixed $args 参数
|
||||
* @return mixed
|
||||
*/
|
||||
function behavior($behavior, $args = null)
|
||||
{
|
||||
return Hook::exec($behavior, $args);
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('bind')) {
|
||||
/**
|
||||
* 绑定一个类到容器
|
||||
* @access public
|
||||
* @param string $abstract 类标识、接口
|
||||
* @param mixed $concrete 要绑定的类、闭包或者实例
|
||||
* @return Container
|
||||
*/
|
||||
function bind($abstract, $concrete = null)
|
||||
{
|
||||
return Container::getInstance()->bind($abstract, $concrete);
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('cache')) {
|
||||
/**
|
||||
* 缓存管理
|
||||
* @param mixed $name 缓存名称,如果为数组表示进行缓存设置
|
||||
* @param mixed $value 缓存值
|
||||
* @param mixed $options 缓存参数
|
||||
* @param string $tag 缓存标签
|
||||
* @return mixed
|
||||
*/
|
||||
function cache($name, $value = '', $options = null, $tag = null)
|
||||
{
|
||||
if (is_array($options)) {
|
||||
// 缓存操作的同时初始化
|
||||
Cache::connect($options);
|
||||
} elseif (is_array($name)) {
|
||||
// 缓存初始化
|
||||
return Cache::connect($name);
|
||||
}
|
||||
|
||||
if ('' === $value) {
|
||||
// 获取缓存
|
||||
return 0 === strpos($name, '?') ? Cache::has(substr($name, 1)) : Cache::get($name);
|
||||
} elseif (is_null($value)) {
|
||||
// 删除缓存
|
||||
return Cache::rm($name);
|
||||
} else {
|
||||
// 缓存数据
|
||||
if (is_array($options)) {
|
||||
$expire = isset($options['expire']) ? $options['expire'] : null; //修复查询缓存无法设置过期时间
|
||||
} else {
|
||||
$expire = is_numeric($options) ? $options : null; //默认快捷缓存设置过期时间
|
||||
}
|
||||
|
||||
if (is_null($tag)) {
|
||||
return Cache::set($name, $value, $expire);
|
||||
} else {
|
||||
return Cache::tag($tag)->set($name, $value, $expire);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('call')) {
|
||||
/**
|
||||
* 调用反射执行callable 支持依赖注入
|
||||
* @param mixed $callable 支持闭包等callable写法
|
||||
* @param array $args 参数
|
||||
* @return mixed
|
||||
*/
|
||||
function call($callable, $args = [])
|
||||
{
|
||||
return Container::getInstance()->invoke($callable, $args);
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('class_basename')) {
|
||||
/**
|
||||
* 获取类名(不包含命名空间)
|
||||
*
|
||||
* @param string|object $class
|
||||
* @return string
|
||||
*/
|
||||
function class_basename($class)
|
||||
{
|
||||
$class = is_object($class) ? get_class($class) : $class;
|
||||
return basename(str_replace('\\', '/', $class));
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('class_uses_recursive')) {
|
||||
/**
|
||||
*获取一个类里所有用到的trait,包括父类的
|
||||
*
|
||||
* @param $class
|
||||
* @return array
|
||||
*/
|
||||
function class_uses_recursive($class)
|
||||
{
|
||||
if (is_object($class)) {
|
||||
$class = get_class($class);
|
||||
}
|
||||
|
||||
$results = [];
|
||||
$classes = array_merge([$class => $class], class_parents($class));
|
||||
foreach ($classes as $class) {
|
||||
$results += trait_uses_recursive($class);
|
||||
}
|
||||
|
||||
return array_unique($results);
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('config')) {
|
||||
/**
|
||||
* 获取和设置配置参数
|
||||
* @param string|array $name 参数名
|
||||
* @param mixed $value 参数值
|
||||
* @return mixed
|
||||
*/
|
||||
function config($name = '', $value = null)
|
||||
{
|
||||
if (is_null($value) && is_string($name)) {
|
||||
if ('.' == substr($name, -1)) {
|
||||
return Config::pull(substr($name, 0, -1));
|
||||
}
|
||||
|
||||
return 0 === strpos($name, '?') ? Config::has(substr($name, 1)) : Config::get($name);
|
||||
} else {
|
||||
return Config::set($name, $value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('container')) {
|
||||
/**
|
||||
* 获取容器对象实例
|
||||
* @return Container
|
||||
*/
|
||||
function container()
|
||||
{
|
||||
return Container::getInstance();
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('controller')) {
|
||||
/**
|
||||
* 实例化控制器 格式:[模块/]控制器
|
||||
* @param string $name 资源地址
|
||||
* @param string $layer 控制层名称
|
||||
* @param bool $appendSuffix 是否添加类名后缀
|
||||
* @return \think\Controller
|
||||
*/
|
||||
function controller($name, $layer = 'controller', $appendSuffix = false)
|
||||
{
|
||||
return app()->controller($name, $layer, $appendSuffix);
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('cookie')) {
|
||||
/**
|
||||
* Cookie管理
|
||||
* @param string|array $name cookie名称,如果为数组表示进行cookie设置
|
||||
* @param mixed $value cookie值
|
||||
* @param mixed $option 参数
|
||||
* @return mixed
|
||||
*/
|
||||
function cookie($name, $value = '', $option = null)
|
||||
{
|
||||
if (is_array($name)) {
|
||||
// 初始化
|
||||
Cookie::init($name);
|
||||
} elseif (is_null($name)) {
|
||||
// 清除
|
||||
Cookie::clear($value);
|
||||
} elseif ('' === $value) {
|
||||
// 获取
|
||||
return 0 === strpos($name, '?') ? Cookie::has(substr($name, 1), $option) : Cookie::get($name);
|
||||
} elseif (is_null($value)) {
|
||||
// 删除
|
||||
return Cookie::delete($name);
|
||||
} else {
|
||||
// 设置
|
||||
return Cookie::set($name, $value, $option);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('db')) {
|
||||
/**
|
||||
* 实例化数据库类
|
||||
* @param string $name 操作的数据表名称(不含前缀)
|
||||
* @param array|string $config 数据库配置参数
|
||||
* @param bool $force 是否强制重新连接
|
||||
* @return \think\db\Query
|
||||
*/
|
||||
function db($name = '', $config = [], $force = true)
|
||||
{
|
||||
return Db::connect($config, $force)->name($name);
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('debug')) {
|
||||
/**
|
||||
* 记录时间(微秒)和内存使用情况
|
||||
* @param string $start 开始标签
|
||||
* @param string $end 结束标签
|
||||
* @param integer|string $dec 小数位 如果是m 表示统计内存占用
|
||||
* @return mixed
|
||||
*/
|
||||
function debug($start, $end = '', $dec = 6)
|
||||
{
|
||||
if ('' == $end) {
|
||||
Debug::remark($start);
|
||||
} else {
|
||||
return 'm' == $dec ? Debug::getRangeMem($start, $end) : Debug::getRangeTime($start, $end, $dec);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('dump')) {
|
||||
/**
|
||||
* 浏览器友好的变量输出
|
||||
* @param mixed $var 变量
|
||||
* @param boolean $echo 是否输出 默认为true 如果为false 则返回输出字符串
|
||||
* @param string $label 标签 默认为空
|
||||
* @return void|string
|
||||
*/
|
||||
function dump($var, $echo = true, $label = null)
|
||||
{
|
||||
return Debug::dump($var, $echo, $label);
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('env')) {
|
||||
/**
|
||||
* 获取环境变量值
|
||||
* @access public
|
||||
* @param string $name 环境变量名(支持二级 .号分割)
|
||||
* @param string $default 默认值
|
||||
* @return mixed
|
||||
*/
|
||||
function env($name = null, $default = null)
|
||||
{
|
||||
return Env::get($name, $default);
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('exception')) {
|
||||
/**
|
||||
* 抛出异常处理
|
||||
*
|
||||
* @param string $msg 异常消息
|
||||
* @param integer $code 异常代码 默认为0
|
||||
* @param string $exception 异常类
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
function exception($msg, $code = 0, $exception = '')
|
||||
{
|
||||
$e = $exception ?: '\think\Exception';
|
||||
throw new $e($msg, $code);
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('halt')) {
|
||||
/**
|
||||
* 调试变量并且中断输出
|
||||
* @param mixed $var 调试变量或者信息
|
||||
*/
|
||||
function halt($var)
|
||||
{
|
||||
dump($var);
|
||||
|
||||
throw new HttpResponseException(new Response);
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('input')) {
|
||||
/**
|
||||
* 获取输入数据 支持默认值和过滤
|
||||
* @param string $key 获取的变量名
|
||||
* @param mixed $default 默认值
|
||||
* @param string $filter 过滤方法
|
||||
* @return mixed
|
||||
*/
|
||||
function input($key = '', $default = null, $filter = null)
|
||||
{
|
||||
if (0 === strpos($key, '?')) {
|
||||
$key = substr($key, 1);
|
||||
$has = true;
|
||||
}
|
||||
|
||||
if ($pos = strpos($key, '.')) {
|
||||
// 指定参数来源
|
||||
$method = substr($key, 0, $pos);
|
||||
if (in_array($method, ['get', 'post', 'put', 'patch', 'delete', 'route', 'param', 'request', 'session', 'cookie', 'server', 'env', 'path', 'file'])) {
|
||||
$key = substr($key, $pos + 1);
|
||||
} else {
|
||||
$method = 'param';
|
||||
}
|
||||
} else {
|
||||
// 默认为自动判断
|
||||
$method = 'param';
|
||||
}
|
||||
|
||||
if (isset($has)) {
|
||||
return request()->has($key, $method, $default);
|
||||
} else {
|
||||
return request()->$method($key, $default, $filter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('json')) {
|
||||
/**
|
||||
* 获取\think\response\Json对象实例
|
||||
* @param mixed $data 返回的数据
|
||||
* @param integer $code 状态码
|
||||
* @param array $header 头部
|
||||
* @param array $options 参数
|
||||
* @return \think\response\Json
|
||||
*/
|
||||
function json($data = [], $code = 200, $header = [], $options = [])
|
||||
{
|
||||
return Response::create($data, 'json', $code, $header, $options);
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('jsonp')) {
|
||||
/**
|
||||
* 获取\think\response\Jsonp对象实例
|
||||
* @param mixed $data 返回的数据
|
||||
* @param integer $code 状态码
|
||||
* @param array $header 头部
|
||||
* @param array $options 参数
|
||||
* @return \think\response\Jsonp
|
||||
*/
|
||||
function jsonp($data = [], $code = 200, $header = [], $options = [])
|
||||
{
|
||||
return Response::create($data, 'jsonp', $code, $header, $options);
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('lang')) {
|
||||
/**
|
||||
* 获取语言变量值
|
||||
* @param string $name 语言变量名
|
||||
* @param array $vars 动态变量值
|
||||
* @param string $lang 语言
|
||||
* @return mixed
|
||||
*/
|
||||
function lang($name, $vars = [], $lang = '')
|
||||
{
|
||||
return Lang::get($name, $vars, $lang);
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('model')) {
|
||||
/**
|
||||
* 实例化Model
|
||||
* @param string $name Model名称
|
||||
* @param string $layer 业务层名称
|
||||
* @param bool $appendSuffix 是否添加类名后缀
|
||||
* @return \think\Model
|
||||
*/
|
||||
function model($name = '', $layer = 'model', $appendSuffix = false)
|
||||
{
|
||||
return app()->model($name, $layer, $appendSuffix);
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('parse_name')) {
|
||||
/**
|
||||
* 字符串命名风格转换
|
||||
* type 0 将Java风格转换为C的风格 1 将C风格转换为Java的风格
|
||||
* @param string $name 字符串
|
||||
* @param integer $type 转换类型
|
||||
* @param bool $ucfirst 首字母是否大写(驼峰规则)
|
||||
* @return string
|
||||
*/
|
||||
function parse_name($name, $type = 0, $ucfirst = true)
|
||||
{
|
||||
if ($type) {
|
||||
$name = preg_replace_callback('/_([a-zA-Z])/', function ($match) {
|
||||
return strtoupper($match[1]);
|
||||
}, $name);
|
||||
|
||||
return $ucfirst ? ucfirst($name) : lcfirst($name);
|
||||
} else {
|
||||
return strtolower(trim(preg_replace("/[A-Z]/", "_\\0", $name), "_"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('redirect')) {
|
||||
/**
|
||||
* 获取\think\response\Redirect对象实例
|
||||
* @param mixed $url 重定向地址 支持Url::build方法的地址
|
||||
* @param array|integer $params 额外参数
|
||||
* @param integer $code 状态码
|
||||
* @return \think\response\Redirect
|
||||
*/
|
||||
function redirect($url = [], $params = [], $code = 302)
|
||||
{
|
||||
if (is_integer($params)) {
|
||||
$code = $params;
|
||||
$params = [];
|
||||
}
|
||||
|
||||
return Response::create($url, 'redirect', $code)->params($params);
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('request')) {
|
||||
/**
|
||||
* 获取当前Request对象实例
|
||||
* @return Request
|
||||
*/
|
||||
function 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')
|
||||
{
|
||||
return Response::create($data, $type, $code, $header);
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('route')) {
|
||||
/**
|
||||
* 路由注册
|
||||
* @param string $rule 路由规则
|
||||
* @param mixed $route 路由地址
|
||||
* @param array $option 路由参数
|
||||
* @param array $pattern 变量规则
|
||||
* @return RuleItem
|
||||
*/
|
||||
function route($rule, $route, $option = [], $pattern = [])
|
||||
{
|
||||
return Route::rule($rule, $route, '*', $option, $pattern);
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('session')) {
|
||||
/**
|
||||
* Session管理
|
||||
* @param string|array $name session名称,如果为数组表示进行session设置
|
||||
* @param mixed $value session值
|
||||
* @param string $prefix 前缀
|
||||
* @return mixed
|
||||
*/
|
||||
function session($name, $value = '', $prefix = null)
|
||||
{
|
||||
if (is_array($name)) {
|
||||
// 初始化
|
||||
Session::init($name);
|
||||
} elseif (is_null($name)) {
|
||||
// 清除
|
||||
Session::clear($value);
|
||||
} elseif ('' === $value) {
|
||||
// 判断或获取
|
||||
return 0 === strpos($name, '?') ? Session::has(substr($name, 1), $prefix) : Session::get($name, $prefix);
|
||||
} elseif (is_null($value)) {
|
||||
// 删除
|
||||
return Session::delete($name, $prefix);
|
||||
} else {
|
||||
// 设置
|
||||
return Session::set($name, $value, $prefix);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('token')) {
|
||||
/**
|
||||
* 生成表单令牌
|
||||
* @param string $name 令牌名称
|
||||
* @param mixed $type 令牌生成方法
|
||||
* @return string
|
||||
*/
|
||||
function token($name = '__token__', $type = 'md5')
|
||||
{
|
||||
$token = Request::token($name, $type);
|
||||
|
||||
return '<input type="hidden" name="' . $name . '" value="' . $token . '" />';
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('trace')) {
|
||||
/**
|
||||
* 记录日志信息
|
||||
* @param mixed $log log信息 支持字符串和数组
|
||||
* @param string $level 日志级别
|
||||
* @return array|void
|
||||
*/
|
||||
function trace($log = '[think]', $level = 'log')
|
||||
{
|
||||
if ('[think]' === $log) {
|
||||
return Log::getLog();
|
||||
} else {
|
||||
Log::record($log, $level);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('trait_uses_recursive')) {
|
||||
/**
|
||||
* 获取一个trait里所有引用到的trait
|
||||
*
|
||||
* @param string $trait
|
||||
* @return array
|
||||
*/
|
||||
function trait_uses_recursive($trait)
|
||||
{
|
||||
$traits = class_uses($trait);
|
||||
foreach ($traits as $trait) {
|
||||
$traits += trait_uses_recursive($trait);
|
||||
}
|
||||
|
||||
return $traits;
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('url')) {
|
||||
/**
|
||||
* Url生成
|
||||
* @param string $url 路由地址
|
||||
* @param string|array $vars 变量
|
||||
* @param bool|string $suffix 生成的URL后缀
|
||||
* @param bool|string $domain 域名
|
||||
* @return string
|
||||
*/
|
||||
function url($url = '', $vars = '', $suffix = true, $domain = false)
|
||||
{
|
||||
return Url::build($url, $vars, $suffix, $domain);
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('validate')) {
|
||||
/**
|
||||
* 实例化验证器
|
||||
* @param string $name 验证器名称
|
||||
* @param string $layer 业务层名称
|
||||
* @param bool $appendSuffix 是否添加类名后缀
|
||||
* @return \think\Validate
|
||||
*/
|
||||
function validate($name = '', $layer = 'validate', $appendSuffix = false)
|
||||
{
|
||||
return app()->validate($name, $layer, $appendSuffix);
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('view')) {
|
||||
/**
|
||||
* 渲染模板输出
|
||||
* @param string $template 模板文件
|
||||
* @param array $vars 模板变量
|
||||
* @param integer $code 状态码
|
||||
* @param callable $filer 内容过滤
|
||||
* @return \think\response\View
|
||||
*/
|
||||
function view($template = '', $vars = [], $code = 200, $filter = null)
|
||||
{
|
||||
return Response::create($template, 'view', $code)->assign($vars)->filter($filter);
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('widget')) {
|
||||
/**
|
||||
* 渲染输出Widget
|
||||
* @param string $name Widget名称
|
||||
* @param array $data 传入的参数
|
||||
* @return mixed
|
||||
*/
|
||||
function widget($name, $data = [])
|
||||
{
|
||||
return app()->action($name, $data, 'widget');
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('xml')) {
|
||||
/**
|
||||
* 获取\think\response\Xml对象实例
|
||||
* @param mixed $data 返回的数据
|
||||
* @param integer $code 状态码
|
||||
* @param array $header 头部
|
||||
* @param array $options 参数
|
||||
* @return \think\response\Xml
|
||||
*/
|
||||
function xml($data = [], $code = 200, $header = [], $options = [])
|
||||
{
|
||||
return Response::create($data, 'xml', $code, $header, $options);
|
||||
}
|
||||
}
|
|
@ -2,7 +2,7 @@
|
|||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2019 http://thinkphp.cn All rights reserved.
|
||||
// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
|
@ -24,8 +24,7 @@ return [
|
|||
'dispatch type not support' => '不支持的调度类型',
|
||||
'method param miss' => '方法参数错误',
|
||||
'method not exists' => '方法不存在',
|
||||
'function not exists' => '函数不存在',
|
||||
'app not exists' => '应用不存在',
|
||||
'module not exists' => '模块不存在',
|
||||
'controller not exists' => '控制器不存在',
|
||||
'class not exists' => '类不存在',
|
||||
'property not exists' => '类的属性不存在',
|
||||
|
@ -33,20 +32,15 @@ return [
|
|||
'illegal controller name' => '非法的控制器名称',
|
||||
'illegal action name' => '非法的操作名称',
|
||||
'url suffix deny' => '禁止的URL后缀访问',
|
||||
'Undefined cache config' => '缓存配置未定义',
|
||||
'Route Not Found' => '当前访问路由未定义或不匹配',
|
||||
'Undefined db config' => '数据库配置未定义',
|
||||
'Undefined log config' => '日志配置未定义',
|
||||
'Route Not Found' => '当前访问路由未定义',
|
||||
'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运行',
|
||||
|
@ -72,9 +66,6 @@ return [
|
|||
'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' => '未知上传错误!',
|
||||
|
@ -92,8 +83,6 @@ return [
|
|||
'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必须',
|
||||
|
@ -143,6 +132,4 @@ return [
|
|||
'invalid Request method' => '无效的请求类型',
|
||||
'invalid token' => '令牌数据无效',
|
||||
'not conform to the rules' => '规则错误',
|
||||
|
||||
'record has update' => '记录已经被更新了',
|
||||
];
|
|
@ -0,0 +1,946 @@
|
|||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace think;
|
||||
|
||||
use think\exception\ClassNotFoundException;
|
||||
use think\exception\HttpResponseException;
|
||||
use think\route\Dispatch;
|
||||
|
||||
/**
|
||||
* App 应用管理
|
||||
*/
|
||||
class App implements \ArrayAccess
|
||||
{
|
||||
const VERSION = '5.1.5';
|
||||
|
||||
/**
|
||||
* 当前模块路径
|
||||
* @var string
|
||||
*/
|
||||
protected $modulePath;
|
||||
|
||||
/**
|
||||
* 应用调试模式
|
||||
* @var bool
|
||||
*/
|
||||
protected $debug = true;
|
||||
|
||||
/**
|
||||
* 应用开始时间
|
||||
* @var float
|
||||
*/
|
||||
protected $beginTime;
|
||||
|
||||
/**
|
||||
* 应用内存初始占用
|
||||
* @var integer
|
||||
*/
|
||||
protected $beginMem;
|
||||
|
||||
/**
|
||||
* 应用类库命名空间
|
||||
* @var string
|
||||
*/
|
||||
protected $namespace = 'app';
|
||||
|
||||
/**
|
||||
* 应用类库后缀
|
||||
* @var bool
|
||||
*/
|
||||
protected $suffix = false;
|
||||
|
||||
/**
|
||||
* 严格路由检测
|
||||
* @var bool
|
||||
*/
|
||||
protected $routeMust;
|
||||
|
||||
/**
|
||||
* 应用类库目录
|
||||
* @var string
|
||||
*/
|
||||
protected $appPath;
|
||||
|
||||
/**
|
||||
* 框架目录
|
||||
* @var string
|
||||
*/
|
||||
protected $thinkPath;
|
||||
|
||||
/**
|
||||
* 应用根目录
|
||||
* @var string
|
||||
*/
|
||||
protected $rootPath;
|
||||
|
||||
/**
|
||||
* 运行时目录
|
||||
* @var string
|
||||
*/
|
||||
protected $runtimePath;
|
||||
|
||||
/**
|
||||
* 配置目录
|
||||
* @var string
|
||||
*/
|
||||
protected $configPath;
|
||||
|
||||
/**
|
||||
* 路由目录
|
||||
* @var string
|
||||
*/
|
||||
protected $routePath;
|
||||
|
||||
/**
|
||||
* 配置后缀
|
||||
* @var string
|
||||
*/
|
||||
protected $configExt;
|
||||
|
||||
/**
|
||||
* 应用调度实例
|
||||
* @var Dispatch
|
||||
*/
|
||||
protected $dispatch;
|
||||
|
||||
/**
|
||||
* 容器对象实例
|
||||
* @var Container
|
||||
*/
|
||||
protected $container;
|
||||
|
||||
/**
|
||||
* 绑定模块(控制器)
|
||||
* @var string
|
||||
*/
|
||||
protected $bind;
|
||||
|
||||
public function __construct($appPath = '')
|
||||
{
|
||||
$this->appPath = $appPath ?: realpath(dirname($_SERVER['SCRIPT_FILENAME']) . '/../application') . '/';
|
||||
$this->container = Container::getInstance();
|
||||
}
|
||||
|
||||
/**
|
||||
* 绑定模块或者控制器
|
||||
* @access public
|
||||
* @param string $bind
|
||||
* @return $this
|
||||
*/
|
||||
public function bind($bind)
|
||||
{
|
||||
$this->bind = $bind;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置应用类库目录
|
||||
* @access public
|
||||
* @param string $path 路径
|
||||
* @return $this
|
||||
*/
|
||||
public function path($path)
|
||||
{
|
||||
$this->appPath = $path;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化应用
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function initialize()
|
||||
{
|
||||
//返回当前 Unix 时间戳的微秒数
|
||||
$this->beginTime = microtime(true);
|
||||
|
||||
//返回分配给 PHP 的内存量
|
||||
$this->beginMem = memory_get_usage();
|
||||
|
||||
//函数返回路径中的目录部分
|
||||
// dirname(__DIR__) D:\wamp\www\tp5\thinkphp\library
|
||||
// dirname(dirname(__DIR__)) D:\wamp\www\tp5\thinkphp
|
||||
$this->thinkPath = dirname(dirname(__DIR__)) . '/'; // D:\wamp\www\tp5\thinkphp/
|
||||
|
||||
//realpath() 函数返回绝对路径。
|
||||
// $this->appPath D:\wamp\www\tp5\application/
|
||||
$this->rootPath = dirname(realpath($this->appPath)) . '/'; // D:\wamp\www\tp5/
|
||||
$this->runtimePath = $this->rootPath . 'runtime/'; // D:\wamp\www\tp5/runtime/
|
||||
$this->routePath = $this->rootPath . 'route/'; // D:\wamp\www\tp5/route/
|
||||
$this->configPath = $this->rootPath . 'config/'; // D:\wamp\www\tp5/config/
|
||||
|
||||
// 设置路径环境变量
|
||||
//$this->env think\Env
|
||||
$this->env->set([
|
||||
'think_path' => $this->thinkPath, // D:\wamp\www\tp5\thinkphp/
|
||||
'root_path' => $this->rootPath, // D:\wamp\www\tp5/
|
||||
'app_path' => $this->appPath, // D:\wamp\www\tp5\application/ 应用所在的文件夹
|
||||
'config_path' => $this->configPath, // D:\wamp\www\tp5/config/
|
||||
'route_path' => $this->routePath, // D:\wamp\www\tp5/route/
|
||||
'runtime_path' => $this->runtimePath, // D:\wamp\www\tp5/runtime/
|
||||
'extend_path' => $this->rootPath . 'extend/', // D:\wamp\www\tp5/extend/
|
||||
'vendor_path' => $this->rootPath . 'vendor/', // D:\wamp\www\tp5/vendor/
|
||||
]);
|
||||
|
||||
// 加载环境变量配置文件
|
||||
// is_file() 函数检查指定的文件名是否存在 文件存在则返回 true。
|
||||
if (is_file($this->rootPath . '.env')) {
|
||||
// 获取.env的配置信息 内容格式为.ini语法
|
||||
$this->env->load($this->rootPath . '.env');
|
||||
}
|
||||
|
||||
$this->namespace = $this->env->get('app_namespace', $this->namespace); //返回app // $this->namespace
|
||||
|
||||
$this->env->set('app_namespace', $this->namespace);
|
||||
|
||||
// 注册应用命名空间 $this->appPath [指定应用所在的文件夹 D:\wamp\www\tp5\application/]
|
||||
Loader::addNamespace($this->namespace, $this->appPath);
|
||||
|
||||
// 配置后缀
|
||||
$this->configExt = $this->env->get('config_ext', '.php');
|
||||
|
||||
// 初始化应用
|
||||
$this->init();
|
||||
|
||||
// 开启类名后缀 实际是查看config 内 app内的 class_suffix 值,默认为false
|
||||
$this->suffix = $this->config('app.class_suffix');
|
||||
|
||||
// 应用调试模式
|
||||
// 如果app_debug 没有设置 则启用 $this->config('app.app_debug')的值 默认为false
|
||||
$this->debug = $this->env->get('app_debug', $this->config('app.app_debug'));
|
||||
//获取的值设置为 app_debug 的值给予下次调用
|
||||
$this->env->set('app_debug', $this->debug);
|
||||
|
||||
if (!$this->debug) {
|
||||
// 非调试模式 关闭(Off)错误
|
||||
ini_set('display_errors', 'Off');
|
||||
} elseif (PHP_SAPI != 'cli') {
|
||||
//开启调试后切非cli格式 执行
|
||||
//重新申请一块比较大的buffer
|
||||
if (ob_get_level() > 0) {
|
||||
$output = ob_get_clean();
|
||||
}
|
||||
ob_start();
|
||||
if (!empty($output)) {
|
||||
echo $output;
|
||||
}
|
||||
}
|
||||
|
||||
// 注册根命名空间
|
||||
// root_namespace 默认为 空数组
|
||||
if (!empty($this->config('app.root_namespace'))) {
|
||||
//等于非空数组时执行
|
||||
Loader::addNamespace($this->config('app.root_namespace'));
|
||||
}
|
||||
|
||||
// 注册类库别名
|
||||
// alias 主页为空
|
||||
Loader::addClassAlias($this->config->pull('alias'));
|
||||
|
||||
// 设置系统时区
|
||||
date_default_timezone_set($this->config('app.default_timezone'));
|
||||
|
||||
// 监听app_init
|
||||
$this->hook->listen('app_init',['ceshi','TESTT']);
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化应用或模块
|
||||
* @access public
|
||||
* @param string $module 模块名
|
||||
* @return void
|
||||
*/
|
||||
public function init($module = '')
|
||||
{
|
||||
// 定位模块目录文件名,指定当前模块的文件夹名称
|
||||
$module = $module ? $module . DIRECTORY_SEPARATOR : '';
|
||||
|
||||
//指定当前模块的文件夹目录
|
||||
$path = $this->appPath . $module;
|
||||
|
||||
// 加载初始化文件
|
||||
// 检测init.php 是否存在
|
||||
if (is_file($path . 'init.php')) {
|
||||
include $path . 'init.php';
|
||||
//检测根目录下的是否存在 D:\wamp\www\tp5/runtime/
|
||||
} elseif (is_file($this->runtimePath . $module . 'init.php')) {
|
||||
include $this->runtimePath . $module . 'init.php';
|
||||
} else {
|
||||
// 加载行为扩展文件
|
||||
if (is_file($path . 'tags.php')) {
|
||||
// $this->hook think\Hook
|
||||
// 注册钩子
|
||||
$this->hook->import(include $path . 'tags.php');
|
||||
}
|
||||
|
||||
// 加载application下的 common.php 公共文件
|
||||
if (is_file($path . 'common.php')) {
|
||||
include $path . 'common.php';
|
||||
}
|
||||
|
||||
//$module 等于空 加载系统助手函数
|
||||
if ('' == $module) {
|
||||
// 加载系统助手函数 D:\wamp\www\tp5\thinkphp/
|
||||
include $this->thinkPath . 'helper.php';
|
||||
}
|
||||
|
||||
// 注册服务的容器对象实例
|
||||
if (is_file($path . 'provider.php')) {
|
||||
$this->container->bind(include $path . 'provider.php');
|
||||
}
|
||||
|
||||
// 自动读取配置文件
|
||||
//模块下的配置文件夹不存在就加载 D:\wamp\www\tp5/config/ 内的
|
||||
if (is_dir($path . 'config')) {
|
||||
$dir = $path . 'config';
|
||||
} elseif (is_dir($this->configPath . $module)) {
|
||||
$dir = $this->configPath . $module;
|
||||
}
|
||||
|
||||
// scandir($dir) 列出 $dir 目录中的文件和目录
|
||||
$files = isset($dir) ? scandir($dir) : [];
|
||||
|
||||
//循环去掉一切不需要的值
|
||||
foreach ($files as $file) {
|
||||
if ('.' . pathinfo($file, PATHINFO_EXTENSION) === $this->configExt) {
|
||||
$filename = $dir . DIRECTORY_SEPARATOR . $file;
|
||||
//加载所有的配置文件
|
||||
// $this->config think\Config
|
||||
$this->config->load($filename, pathinfo($file, PATHINFO_FILENAME));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// $this->request think\Request
|
||||
// 全局过滤方法 default_filter 实际是 app 键值内的 default_filter 值
|
||||
$this->request->filter($this->config('app.default_filter'));
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行应用程序
|
||||
* @access public
|
||||
* @return Response
|
||||
* @throws Exception
|
||||
*/
|
||||
public function run()
|
||||
{
|
||||
// 初始化应用,初步完成注释
|
||||
$this->initialize();
|
||||
|
||||
try {
|
||||
if ($this->bind) {
|
||||
// 模块/控制器绑定
|
||||
// $this->route think\Route
|
||||
$this->route->bind($this->bind);
|
||||
} elseif ($this->config('app.auto_bind_module')) {
|
||||
// 入口自动绑定模块 app.auto_bind_module 默认是false
|
||||
// 入口自动绑定
|
||||
$name = pathinfo($this->request->baseFile(), PATHINFO_FILENAME);
|
||||
if ($name && 'index' != $name && is_dir($this->appPath . $name)) {
|
||||
$this->route->bind($name);
|
||||
}
|
||||
}
|
||||
|
||||
// 读取默认语言
|
||||
// app.default_lang 默认为 zh-cn
|
||||
// $this->lang think\Lang
|
||||
// 设置当前的语言
|
||||
$this->lang->range($this->config('app.default_lang'));
|
||||
//判断是否开启了多语言,默认是false
|
||||
if ($this->config('app.lang_switch_on')) {
|
||||
// 开启多语言机制 检测当前语言
|
||||
$this->lang->detect();
|
||||
}
|
||||
|
||||
// $this->request think\Request
|
||||
// $this->lang->range() 获取当前的语言
|
||||
// 设置当前的语言
|
||||
$this->request->langset($this->lang->range());
|
||||
|
||||
// 加载系统语言包
|
||||
$this->lang->load([
|
||||
$this->thinkPath . 'lang/' . $this->request->langset() . '.php',
|
||||
$this->appPath . 'lang/' . $this->request->langset() . '.php',
|
||||
]);
|
||||
|
||||
// 监听app_dispatch
|
||||
$this->hook->listen('app_dispatch');
|
||||
|
||||
// 获取应用调度信息
|
||||
$dispatch = $this->dispatch;
|
||||
if (empty($dispatch)) {
|
||||
//$dispatch 为空时执行
|
||||
// 进行URL路由检测
|
||||
// 主页返回的 think\route\dispatch\Url 实例
|
||||
// 在这里也或许会返回404
|
||||
$dispatch = $this->routeCheck();
|
||||
}
|
||||
|
||||
// 记录当前调度信息 设置或者获取当前请求的调度信息
|
||||
$this->request->dispatch($dispatch);
|
||||
|
||||
// 记录路由和请求信息
|
||||
if ($this->debug) {
|
||||
$this->log('[ ROUTE ] ' . var_export($this->request->routeInfo(), true));
|
||||
$this->log('[ HEADER ] ' . var_export($this->request->header(), true));
|
||||
$this->log('[ PARAM ] ' . var_export($this->request->param(), true));
|
||||
}
|
||||
|
||||
// 监听app_begin
|
||||
$this->hook->listen('app_begin');
|
||||
|
||||
// 请求缓存检查
|
||||
$this->request->cache(
|
||||
$this->config('app.request_cache'),
|
||||
$this->config('app.request_cache_expire'),
|
||||
$this->config('app.request_cache_except')
|
||||
);
|
||||
|
||||
// 执行调度
|
||||
// think\route\dispatch\Url 内的 run()
|
||||
$data = $dispatch->run();
|
||||
var_dump($data);
|
||||
|
||||
// EXIT;
|
||||
|
||||
} catch (HttpResponseException $exception) {
|
||||
$data = $exception->getResponse();
|
||||
}
|
||||
|
||||
$this->middlewareDispatcher->add(function (Request $request, $next) use ($data) {
|
||||
// 输出数据到客户端
|
||||
if ($data instanceof Response) {
|
||||
$response = $data;
|
||||
} elseif (!is_null($data)) {
|
||||
// 默认自动识别响应输出类型
|
||||
$isAjax = $request->isAjax();
|
||||
$type = $isAjax ? $this->config('app.default_ajax_return') : $this->config('app.default_return_type');
|
||||
|
||||
$response = Response::create($data, $type);
|
||||
} else {
|
||||
$response = Response::create();
|
||||
}
|
||||
return $response;
|
||||
});
|
||||
|
||||
$response = $this->middlewareDispatcher->dispatch($this->request);
|
||||
|
||||
// 监听app_end
|
||||
$this->hook->listen('app_end', $response);
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置当前请求的调度信息
|
||||
* @access public
|
||||
* @param Dispatch $dispatch 调度信息
|
||||
* @return $this
|
||||
*/
|
||||
public function dispatch(Dispatch $dispatch)
|
||||
{
|
||||
$this->dispatch = $dispatch;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 记录调试信息
|
||||
* @access public
|
||||
* @param mixed $msg 调试信息
|
||||
* @param string $type 信息类型
|
||||
* @return void
|
||||
*/
|
||||
public function log($log, $type = 'info')
|
||||
{
|
||||
$this->debug && $this->log->record($log, $type);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取配置参数 为空则获取所有配置
|
||||
* @access public
|
||||
* @param string $name 配置参数名(支持二级配置 .号分割)
|
||||
* @return mixed
|
||||
*/
|
||||
public function config($name = '')
|
||||
{
|
||||
return $this->config->get($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* URL路由检测(根据PATH_INFO)
|
||||
* @access public
|
||||
* @return Dispatch
|
||||
*/
|
||||
public function routeCheck()
|
||||
{
|
||||
// 获取当前请求URL的pathinfo信息(不含URL后缀 如:.html)
|
||||
$path = $this->request->path();
|
||||
// pathinfo_depr 为 pathinfo分隔符,默认为'/'
|
||||
$depr = $this->config('app.pathinfo_depr');
|
||||
|
||||
// 路由检测
|
||||
$files = scandir($this->routePath); // D:\wamp\www\tp5/route/
|
||||
foreach ($files as $file) {
|
||||
if (strpos($file, '.php')) {
|
||||
$filename = $this->routePath . $file;
|
||||
var_dump($filename);
|
||||
// 导入路由配置
|
||||
$rules = include $filename;
|
||||
// is_array() 检测变量是否是数组
|
||||
if (is_array($rules)) {
|
||||
$this->route->import($rules);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
$this->route->routeinfo();
|
||||
// exit;
|
||||
|
||||
// app.route_annotation 使用注解路由 默认false
|
||||
// 这个模式可以放弃使用
|
||||
if ($this->config('app.route_annotation')) {
|
||||
// 自动生成路由定义
|
||||
if ($this->debug) {
|
||||
$this->build->buildRoute($this->config('app.controller_suffix'));
|
||||
}
|
||||
|
||||
$filename = $this->runtimePath . 'build_route.php';
|
||||
|
||||
if (is_file($filename)) {
|
||||
include $filename;
|
||||
}
|
||||
}
|
||||
|
||||
// 是否强制路由模式
|
||||
// 等于false 则使用
|
||||
// $this->routeMust 默认为空 is_null($this->routeMust) 为 true
|
||||
// $this->routeMust 默认为空
|
||||
// app.url_route_must 是否强制使用路由 默认为false
|
||||
$must = !is_null($this->routeMust) ? $this->routeMust : $this->config('app.url_route_must');
|
||||
// $must 值为false
|
||||
|
||||
// 路由检测 返回一个Dispatch对象
|
||||
|
||||
// $path 请求URL 不含后缀(.HTML) 不含域名
|
||||
// URL分隔符 默认为/
|
||||
// $must 是否强制路由模式 默认值为false
|
||||
// app.rote_complete_match 路由是否完全匹配 默认为false
|
||||
return $this->route->check($path, $depr, $must, $this->config('app.route_complete_match'));
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置应用的路由检测机制
|
||||
* @access public
|
||||
* @param bool $must 是否强制检测路由
|
||||
* @return $this
|
||||
*/
|
||||
public function routeMust($must = false)
|
||||
{
|
||||
$this->routeMust = $must;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析模块和类名
|
||||
* @access protected
|
||||
* @param string $name 资源地址
|
||||
* @param string $layer 验证层名称
|
||||
* @param bool $appendSuffix 是否添加类名后缀
|
||||
* @return array
|
||||
*/
|
||||
protected function parseModuleAndClass($name, $layer, $appendSuffix)
|
||||
{
|
||||
if (false !== strpos($name, '\\')) {
|
||||
$class = $name;
|
||||
$module = $this->request->module();
|
||||
} else {
|
||||
if (strpos($name, '/')) {
|
||||
list($module, $name) = explode('/', $name, 2);
|
||||
} else {
|
||||
$module = $this->request->module();
|
||||
}
|
||||
|
||||
$class = $this->parseClass($module, $layer, $name, $appendSuffix);
|
||||
}
|
||||
|
||||
return [$module, $class];
|
||||
}
|
||||
|
||||
/**
|
||||
* 实例化应用类库
|
||||
* @access public
|
||||
* @param string $name 类名称
|
||||
* @param string $layer 业务层名称
|
||||
* @param bool $appendSuffix 是否添加类名后缀
|
||||
* @param string $common 公共模块名
|
||||
* @return object
|
||||
* @throws ClassNotFoundException
|
||||
*/
|
||||
public function create($name, $layer, $appendSuffix = false, $common = 'common')
|
||||
{
|
||||
$guid = $name . $layer;
|
||||
|
||||
if ($this->__isset($guid)) {
|
||||
return $this->__get($guid);
|
||||
}
|
||||
|
||||
list($module, $class) = $this->parseModuleAndClass($name, $layer, $appendSuffix);
|
||||
|
||||
if (class_exists($class)) {
|
||||
$object = $this->__get($class);
|
||||
} else {
|
||||
$class = str_replace('\\' . $module . '\\', '\\' . $common . '\\', $class);
|
||||
if (class_exists($class)) {
|
||||
$object = $this->__get($class);
|
||||
} else {
|
||||
throw new ClassNotFoundException('class not exists:' . $class, $class);
|
||||
}
|
||||
}
|
||||
|
||||
$this->__set($guid, $class);
|
||||
|
||||
return $object;
|
||||
}
|
||||
|
||||
/**
|
||||
* 实例化(分层)模型
|
||||
* @access public
|
||||
* @param string $name Model名称
|
||||
* @param string $layer 业务层名称
|
||||
* @param bool $appendSuffix 是否添加类名后缀
|
||||
* @param string $common 公共模块名
|
||||
* @return Model
|
||||
* @throws ClassNotFoundException
|
||||
*/
|
||||
public function model($name = '', $layer = 'model', $appendSuffix = false, $common = 'common')
|
||||
{
|
||||
return $this->create($name, $layer, $appendSuffix, $common);
|
||||
}
|
||||
|
||||
/**
|
||||
* 实例化(分层)控制器 格式:[模块名/]控制器名
|
||||
* @access public
|
||||
* @param string $name 资源地址
|
||||
* @param string $layer 控制层名称
|
||||
* @param bool $appendSuffix 是否添加类名后缀
|
||||
* @param string $empty 空控制器名称
|
||||
* @return object
|
||||
* @throws ClassNotFoundException
|
||||
*/
|
||||
public function controller($name, $layer = 'controller', $appendSuffix = false, $empty = '')
|
||||
{
|
||||
list($module, $class) = $this->parseModuleAndClass($name, $layer, $appendSuffix);
|
||||
|
||||
if (class_exists($class)) {
|
||||
return $this->__get($class);
|
||||
} elseif ($empty && class_exists($emptyClass = $this->parseClass($module, $layer, $empty, $appendSuffix))) {
|
||||
return $this->__get($emptyClass);
|
||||
} else {
|
||||
throw new ClassNotFoundException('class not exists:' . $class, $class);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 实例化验证类 格式:[模块名/]验证器名
|
||||
* @access public
|
||||
* @param string $name 资源地址
|
||||
* @param string $layer 验证层名称
|
||||
* @param bool $appendSuffix 是否添加类名后缀
|
||||
* @param string $common 公共模块名
|
||||
* @return Validate
|
||||
* @throws ClassNotFoundException
|
||||
*/
|
||||
public function validate($name = '', $layer = 'validate', $appendSuffix = false, $common = 'common')
|
||||
{
|
||||
$name = $name ?: $this->config('default_validate');
|
||||
|
||||
if (empty($name)) {
|
||||
return new Validate;
|
||||
}
|
||||
|
||||
return $this->create($name, $layer, $appendSuffix, $common);
|
||||
}
|
||||
|
||||
/**
|
||||
* 数据库初始化
|
||||
* @access public
|
||||
* @param mixed $config 数据库配置
|
||||
* @param bool|string $name 连接标识 true 强制重新连接
|
||||
* @return \think\db\Query
|
||||
*/
|
||||
public function db($config = [], $name = false)
|
||||
{
|
||||
return Db::connect($config, $name);
|
||||
}
|
||||
|
||||
/**
|
||||
* 远程调用模块的操作方法 参数格式 [模块/控制器/]操作
|
||||
* @access public
|
||||
* @param string $url 调用地址
|
||||
* @param string|array $vars 调用参数 支持字符串和数组
|
||||
* @param string $layer 要调用的控制层名称
|
||||
* @param bool $appendSuffix 是否添加类名后缀
|
||||
* @return mixed
|
||||
* @throws ClassNotFoundException
|
||||
*/
|
||||
public function action($url, $vars = [], $layer = 'controller', $appendSuffix = false)
|
||||
{
|
||||
$info = pathinfo($url);
|
||||
$action = $info['basename'];
|
||||
$module = '.' != $info['dirname'] ? $info['dirname'] : $this->request->controller();
|
||||
$class = $this->controller($module, $layer, $appendSuffix);
|
||||
|
||||
if (is_scalar($vars)) {
|
||||
if (strpos($vars, '=')) {
|
||||
parse_str($vars, $vars);
|
||||
} else {
|
||||
$vars = [$vars];
|
||||
}
|
||||
}
|
||||
|
||||
return $this->container->invokeMethod([$class, $action . $this->config('action_suffix')], $vars);
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析应用类的类名
|
||||
* @access public
|
||||
* @param string $module 模块名
|
||||
* @param string $layer 层名 controller model ...
|
||||
* @param string $name 类名
|
||||
* @param bool $appendSuffix
|
||||
* @return string
|
||||
*/
|
||||
public function parseClass($module, $layer, $name, $appendSuffix = false)
|
||||
{
|
||||
$name = str_replace(['/', '.'], '\\', $name);
|
||||
$array = explode('\\', $name);
|
||||
$class = Loader::parseName(array_pop($array), 1) . ($this->suffix || $appendSuffix ? ucfirst($layer) : '');
|
||||
$path = $array ? implode('\\', $array) . '\\' : '';
|
||||
|
||||
return $this->namespace . '\\' . ($module ? $module . '\\' : '') . $layer . '\\' . $path . $class;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取框架版本
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function version()
|
||||
{
|
||||
return static::VERSION;
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否为调试模式
|
||||
* @access public
|
||||
* @return bool
|
||||
*/
|
||||
public function isDebug()
|
||||
{
|
||||
return $this->debug;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取模块路径
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function getModulePath()
|
||||
{
|
||||
return $this->modulePath;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置模块路径
|
||||
* @access public
|
||||
* @param string $path 路径
|
||||
* @return void
|
||||
*/
|
||||
public function setModulePath($path)
|
||||
{
|
||||
$this->modulePath = $path;
|
||||
$this->env->set('module_path', $path);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取应用根目录
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function getRootPath()
|
||||
{
|
||||
return $this->rootPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取应用类库目录
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function getAppPath()
|
||||
{
|
||||
return $this->appPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取应用运行时目录
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function getRuntimePath()
|
||||
{
|
||||
return $this->runtimePath;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取核心框架目录
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function getThinkPath()
|
||||
{
|
||||
return $this->thinkPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取路由目录
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function getRoutePath()
|
||||
{
|
||||
return $this->routePath;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取应用配置目录
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function getConfigPath()
|
||||
{
|
||||
return $this->configPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取配置后缀
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function getConfigExt()
|
||||
{
|
||||
return $this->configExt;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取应用类库命名空间
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function getNamespace()
|
||||
{
|
||||
return $this->namespace;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置应用类库命名空间
|
||||
* @access public
|
||||
* @param string $namespace 命名空间名称
|
||||
* @return $this
|
||||
*/
|
||||
public function setNamespace($namespace)
|
||||
{
|
||||
$this->namespace = $namespace;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否启用类库后缀
|
||||
* @access public
|
||||
* @return bool
|
||||
*/
|
||||
public function getSuffix()
|
||||
{
|
||||
return $this->suffix;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取应用开启时间
|
||||
* @access public
|
||||
* @return float
|
||||
*/
|
||||
public function getBeginTime()
|
||||
{
|
||||
return $this->beginTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取应用初始内存占用
|
||||
* @access public
|
||||
* @return integer
|
||||
*/
|
||||
public function getBeginMem()
|
||||
{
|
||||
return $this->beginMem;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取容器实例
|
||||
* @access public
|
||||
* @return Container
|
||||
*/
|
||||
public function container()
|
||||
{
|
||||
return $this->container;
|
||||
}
|
||||
|
||||
public function __set($name, $value)
|
||||
{
|
||||
$this->container->bind($name, $value);
|
||||
}
|
||||
|
||||
public function __get($name)
|
||||
{
|
||||
return $this->container->make($name);
|
||||
}
|
||||
|
||||
public function __isset($name)
|
||||
{
|
||||
return $this->container->bound($name);
|
||||
}
|
||||
|
||||
public function __unset($name)
|
||||
{
|
||||
$this->container->__unset($name);
|
||||
}
|
||||
|
||||
public function offsetExists($key)
|
||||
{
|
||||
return $this->__isset($key);
|
||||
}
|
||||
|
||||
public function offsetGet($key)
|
||||
{
|
||||
return $this->__get($key);
|
||||
}
|
||||
|
||||
public function offsetSet($key, $value)
|
||||
{
|
||||
$this->__set($key, $value);
|
||||
}
|
||||
|
||||
public function offsetUnset($key)
|
||||
{
|
||||
$this->__unset($key);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,376 @@
|
|||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace think;
|
||||
|
||||
class Build
|
||||
{
|
||||
/**
|
||||
* 应用对象
|
||||
* @var App
|
||||
*/
|
||||
protected $app;
|
||||
|
||||
/**
|
||||
* 应用目录
|
||||
* @var string
|
||||
*/
|
||||
protected $basePath;
|
||||
|
||||
public function __construct(App $app)
|
||||
{
|
||||
$this->app = $app;
|
||||
$this->basePath = $this->app->getAppPath();
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据传入的build资料创建目录和文件
|
||||
* @access public
|
||||
* @param array $build build列表
|
||||
* @param string $namespace 应用类库命名空间
|
||||
* @param bool $suffix 类库后缀
|
||||
* @return void
|
||||
*/
|
||||
public function run(array $build = [], $namespace = 'app', $suffix = false)
|
||||
{
|
||||
// 锁定
|
||||
$lockfile = $this->basePath . 'build.lock';
|
||||
|
||||
if (is_writable($lockfile)) {
|
||||
return;
|
||||
} elseif (!touch($lockfile)) {
|
||||
throw new Exception('应用目录[' . $this->basePath . ']不可写,目录无法自动生成!<BR>请手动生成项目目录~', 10006);
|
||||
}
|
||||
|
||||
foreach ($build as $module => $list) {
|
||||
if ('__dir__' == $module) {
|
||||
// 创建目录列表
|
||||
$this->buildDir($list);
|
||||
} elseif ('__file__' == $module) {
|
||||
// 创建文件列表
|
||||
$this->buildFile($list);
|
||||
} else {
|
||||
// 创建模块
|
||||
$this->module($module, $list, $namespace, $suffix);
|
||||
}
|
||||
}
|
||||
|
||||
// 解除锁定
|
||||
unlink($lockfile);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建目录
|
||||
* @access protected
|
||||
* @param array $list 目录列表
|
||||
* @return void
|
||||
*/
|
||||
protected function buildDir($list)
|
||||
{
|
||||
foreach ($list as $dir) {
|
||||
$this->checkDirBuild($this->basePath . $dir);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建文件
|
||||
* @access protected
|
||||
* @param array $list 文件列表
|
||||
* @return void
|
||||
*/
|
||||
protected function buildFile($list)
|
||||
{
|
||||
foreach ($list as $file) {
|
||||
if (!is_dir($this->basePath . dirname($file))) {
|
||||
// 创建目录
|
||||
mkdir($this->basePath . dirname($file), 0755, true);
|
||||
}
|
||||
|
||||
if (!is_file($this->basePath . $file)) {
|
||||
file_put_contents($this->basePath . $file, 'php' == pathinfo($file, PATHINFO_EXTENSION) ? "<?php\n" : '');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建模块
|
||||
* @access public
|
||||
* @param string $module 模块名
|
||||
* @param array $list build列表
|
||||
* @param string $namespace 应用类库命名空间
|
||||
* @param bool $suffix 类库后缀
|
||||
* @return void
|
||||
*/
|
||||
public function module($module = '', $list = [], $namespace = 'app', $suffix = false)
|
||||
{
|
||||
$module = $module ? $module : '';
|
||||
|
||||
if (!is_dir($this->basePath . $module)) {
|
||||
// 创建模块目录
|
||||
mkdir($this->basePath . $module);
|
||||
}
|
||||
|
||||
if (basename($this->app->getRuntimePath()) != $module) {
|
||||
// 创建配置文件和公共文件
|
||||
$this->buildCommon($module);
|
||||
// 创建模块的默认页面
|
||||
$this->buildHello($module, $namespace, $suffix);
|
||||
}
|
||||
|
||||
if (empty($list)) {
|
||||
// 创建默认的模块目录和文件
|
||||
$list = [
|
||||
'__file__' => ['common.php'],
|
||||
'__dir__' => ['controller', 'model', 'view', 'config'],
|
||||
];
|
||||
}
|
||||
|
||||
// 创建子目录和文件
|
||||
foreach ($list as $path => $file) {
|
||||
$modulePath = $this->basePath . $module . '/';
|
||||
if ('__dir__' == $path) {
|
||||
// 生成子目录
|
||||
foreach ($file as $dir) {
|
||||
$this->checkDirBuild($modulePath . $dir);
|
||||
}
|
||||
} elseif ('__file__' == $path) {
|
||||
// 生成(空白)文件
|
||||
foreach ($file as $name) {
|
||||
if (!is_file($modulePath . $name)) {
|
||||
file_put_contents($modulePath . $name, 'php' == pathinfo($name, PATHINFO_EXTENSION) ? "<?php\n" : '');
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 生成相关MVC文件
|
||||
foreach ($file as $val) {
|
||||
$val = trim($val);
|
||||
$filename = $modulePath . $path . DIRECTORY_SEPARATOR . $val . ($suffix ? ucfirst($path) : '') . '.php';
|
||||
$space = $namespace . '\\' . ($module ? $module . '\\' : '') . $path;
|
||||
$class = $val . ($suffix ? ucfirst($path) : '');
|
||||
switch ($path) {
|
||||
case 'controller': // 控制器
|
||||
$content = "<?php\nnamespace {$space};\n\nclass {$class}\n{\n\n}";
|
||||
break;
|
||||
case 'model': // 模型
|
||||
$content = "<?php\nnamespace {$space};\n\nuse think\Model;\n\nclass {$class} extends Model\n{\n\n}";
|
||||
break;
|
||||
case 'view': // 视图
|
||||
$filename = $modulePath . $path . DIRECTORY_SEPARATOR . $val . '.html';
|
||||
$this->checkDirBuild(dirname($filename));
|
||||
$content = '';
|
||||
break;
|
||||
default:
|
||||
// 其他文件
|
||||
$content = "<?php\nnamespace {$space};\n\nclass {$class}\n{\n\n}";
|
||||
}
|
||||
|
||||
if (!is_file($filename)) {
|
||||
file_put_contents($filename, $content);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据注释自动生成路由规则
|
||||
* @access public
|
||||
* @param bool $suffix 类库后缀
|
||||
* @param string $layer 控制器层目录名
|
||||
* @return string
|
||||
*/
|
||||
public function buildRoute($alias = false, $layer = '')
|
||||
{
|
||||
var_dump($this->app);
|
||||
exit;
|
||||
$namespace = $this->app->getNameSpace();
|
||||
$modules = glob($this->basePath . '*', GLOB_ONLYDIR);
|
||||
$content = '<?php ' . PHP_EOL . '//根据 Annotation 自动生成的路由规则';
|
||||
|
||||
if (!$layer) {
|
||||
$layer = $this->app->config('app.url_controller_layer');
|
||||
}
|
||||
|
||||
foreach ($modules as $module) {
|
||||
$module = basename($module);
|
||||
|
||||
if (in_array($module, $this->app->config('app.deny_module_list'))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$controllers = glob($this->basePath . $module . '/' . $layer . '/*.php');
|
||||
|
||||
foreach ($controllers as $controller) {
|
||||
$content .= $this->getControllerRoute($namespace, $module, basename($controller, '.php'), $alias, $layer);
|
||||
}
|
||||
}
|
||||
|
||||
$filename = $this->app->getRuntimePath() . 'build_route.php';
|
||||
file_put_contents($filename, $content);
|
||||
|
||||
return $filename;
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成控制器类的路由规则
|
||||
* @access protected
|
||||
* @param string $namespace 应用命名空间
|
||||
* @param string $module 模块
|
||||
* @param string $controller 控制器名
|
||||
* @param bool $suffix 类库后缀
|
||||
* @param string $layer 控制器层目录名
|
||||
* @return string
|
||||
*/
|
||||
protected function getControllerRoute($namespace, $module, $controller, $alias = false, $layer = '')
|
||||
{
|
||||
$class = new \ReflectionClass($namespace . '\\' . $module . '\\' . $layer . '\\' . $controller);
|
||||
$content = '';
|
||||
$comment = $class->getDocComment();
|
||||
|
||||
if ($alias) {
|
||||
$controller = substr($controller, 0, -10);
|
||||
}
|
||||
|
||||
if (false !== strpos($comment, '@route(')) {
|
||||
$comment = $this->parseRouteComment($comment);
|
||||
$route = $module . '/' . $controller;
|
||||
$comment = preg_replace('/route\(\s?([\'\"][\-\_\/\:\<\>\?\$\[\]\w]+[\'\"])\s?\)/is', 'Route::resourece(\1,\'' . $route . '\')', $comment);
|
||||
$content .= PHP_EOL . $comment;
|
||||
} elseif (false !== strpos($comment, '@alias(')) {
|
||||
$comment = $this->parseRouteComment($comment, '@alias(');
|
||||
$route = $module . '/' . $controller;
|
||||
$comment = preg_replace('/alias\(\s?([\'\"][\-\_\/\w]+[\'\"])\s?\)/is', 'Route::alias(\1,\'' . $route . '\')', $comment);
|
||||
$content .= PHP_EOL . $comment;
|
||||
}
|
||||
|
||||
$methods = $class->getMethods(\ReflectionMethod::IS_PUBLIC);
|
||||
|
||||
foreach ($methods as $method) {
|
||||
$comment = $this->getMethodRouteComment($module, $controller, $method);
|
||||
if ($comment) {
|
||||
$content .= PHP_EOL . $comment;
|
||||
}
|
||||
}
|
||||
|
||||
return $content;
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析路由注释
|
||||
* @access protected
|
||||
* @param string $comment
|
||||
* @param string $tag
|
||||
* @return string
|
||||
*/
|
||||
protected function parseRouteComment($comment, $tag = '@route(')
|
||||
{
|
||||
$comment = substr($comment, 3, -2);
|
||||
$comment = explode(PHP_EOL, substr(strstr(trim($comment), $tag), 1));
|
||||
$comment = array_map(function ($item) {return trim(trim($item), ' \t*');}, $comment);
|
||||
|
||||
if (count($comment) > 1) {
|
||||
$key = array_search('', $comment);
|
||||
$comment = array_slice($comment, 0, false === $key ? 1 : $key);
|
||||
}
|
||||
|
||||
$comment = implode(PHP_EOL . "\t", $comment) . ';';
|
||||
|
||||
if (strpos($comment, '{')) {
|
||||
$comment = preg_replace_callback('/\{\s?.*?\s?\}/s', function ($matches) {
|
||||
return false !== strpos($matches[0], '"') ? '[' . substr(var_export(json_decode($matches[0], true), true), 7, -1) . ']' : $matches[0];
|
||||
}, $comment);
|
||||
}
|
||||
return $comment;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取方法的路由注释
|
||||
* @access protected
|
||||
* @param string $module 模块
|
||||
* @param string $controller 控制器名
|
||||
* @param \ReflectMethod $reflectMethod
|
||||
* @return string|void
|
||||
*/
|
||||
protected function getMethodRouteComment($module, $controller, $reflectMethod)
|
||||
{
|
||||
$comment = $reflectMethod->getDocComment();
|
||||
|
||||
if (false !== strpos($comment, '@route(')) {
|
||||
$comment = $this->parseRouteComment($comment);
|
||||
$action = $reflectMethod->getName();
|
||||
|
||||
if ($suffix = $this->app->config('app.action_suffix')) {
|
||||
$action = substr($action, 0, -strlen($suffix));
|
||||
}
|
||||
|
||||
$route = $module . '/' . $controller . '/' . $action;
|
||||
$comment = preg_replace('/route\s?\(\s?([\'\"][\-\_\/\:\<\>\?\$\[\]\w]+[\'\"])\s?\,?\s?[\'\"]?(\w+?)[\'\"]?\s?\)/is', 'Route::\2(\1,\'' . $route . '\')', $comment);
|
||||
$comment = preg_replace('/route\s?\(\s?([\'\"][\-\_\/\:\<\>\?\$\[\]\w]+[\'\"])\s?\)/is', 'Route::rule(\1,\'' . $route . '\')', $comment);
|
||||
|
||||
return $comment;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建模块的欢迎页面
|
||||
* @access protected
|
||||
* @param string $module 模块名
|
||||
* @param string $namespace 应用类库命名空间
|
||||
* @param bool $suffix 类库后缀
|
||||
* @return void
|
||||
*/
|
||||
protected function buildHello($module, $namespace, $suffix = false)
|
||||
{
|
||||
$filename = $this->basePath . ($module ? $module . DIRECTORY_SEPARATOR : '') . 'controller' . DIRECTORY_SEPARATOR . 'Index' . ($suffix ? 'Controller' : '') . '.php';
|
||||
if (!is_file($filename)) {
|
||||
$content = file_get_contents($this->app->getThinkPath() . 'tpl' . DIRECTORY_SEPARATOR . 'default_index.tpl');
|
||||
$content = str_replace(['{$app}', '{$module}', '{layer}', '{$suffix}'], [$namespace, $module ? $module . '\\' : '', 'controller', $suffix ? 'Controller' : ''], $content);
|
||||
$this->checkDirBuild(dirname($filename));
|
||||
|
||||
file_put_contents($filename, $content);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建模块的公共文件
|
||||
* @access protected
|
||||
* @param string $module 模块名
|
||||
* @return void
|
||||
*/
|
||||
protected function buildCommon($module)
|
||||
{
|
||||
$filename = $this->app->getConfigPath() . ($module ? $module . DIRECTORY_SEPARATOR : '') . 'app.php';
|
||||
$this->checkDirBuild(dirname($filename));
|
||||
|
||||
if (!is_file($filename)) {
|
||||
file_put_contents($filename, "<?php\n//配置文件\nreturn [\n\n];");
|
||||
}
|
||||
|
||||
$filename = $this->basePath . ($module ? $module . DIRECTORY_SEPARATOR : '') . 'common.php';
|
||||
|
||||
if (!is_file($filename)) {
|
||||
file_put_contents($filename, "<?php\n");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建目录
|
||||
* @access protected
|
||||
* @param string $dirname 目录名称
|
||||
* @return void
|
||||
*/
|
||||
protected function checkDirBuild($dirname)
|
||||
{
|
||||
if (!is_dir($dirname)) {
|
||||
mkdir($dirname, 0755, true);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,117 @@
|
|||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace think;
|
||||
|
||||
use think\cache\Driver;
|
||||
|
||||
class Cache
|
||||
{
|
||||
/**
|
||||
* 缓存实例
|
||||
* @var array
|
||||
*/
|
||||
protected $instance = [];
|
||||
|
||||
/**
|
||||
* 应用对象
|
||||
* @var App
|
||||
*/
|
||||
protected $app;
|
||||
|
||||
/**
|
||||
* 操作句柄
|
||||
* @var object
|
||||
*/
|
||||
protected $handler;
|
||||
|
||||
public function __construct(App $app)
|
||||
{
|
||||
$this->app = $app;
|
||||
}
|
||||
|
||||
/**
|
||||
* 连接缓存
|
||||
* @access public
|
||||
* @param array $options 配置数组
|
||||
* @param bool|string $name 缓存连接标识 true 强制重新连接
|
||||
* @return Driver
|
||||
*/
|
||||
public function connect(array $options = [], $name = false)
|
||||
{
|
||||
$type = !empty($options['type']) ? $options['type'] : 'File';
|
||||
|
||||
if (false === $name) {
|
||||
$name = md5(serialize($options));
|
||||
}
|
||||
|
||||
if (true === $name || !isset($this->instance[$name])) {
|
||||
$class = false !== strpos($type, '\\') ? $type : '\\think\\cache\\driver\\' . ucwords($type);
|
||||
|
||||
// 记录初始化信息
|
||||
$this->app->log('[ CACHE ] INIT ' . $type);
|
||||
|
||||
if (true === $name) {
|
||||
$name = md5(serialize($options));
|
||||
}
|
||||
|
||||
$this->instance[$name] = new $class($options);
|
||||
}
|
||||
|
||||
return $this->instance[$name];
|
||||
}
|
||||
|
||||
/**
|
||||
* 自动初始化缓存
|
||||
* @access public
|
||||
* @param array $options 配置数组
|
||||
* @return Driver
|
||||
*/
|
||||
public function init(array $options = [])
|
||||
{
|
||||
if (is_null($this->handler)) {
|
||||
// 自动初始化缓存
|
||||
$config = $this->app['config'];
|
||||
|
||||
if (empty($options) && 'complex' == $config->get('cache.type')) {
|
||||
$default = $config->get('cache.default');
|
||||
$options = $config->get('cache.' . $default['type']) ?: $default;
|
||||
} elseif (empty($options)) {
|
||||
$options = $config->pull('cache');
|
||||
}
|
||||
|
||||
$this->handler = $this->connect($options);
|
||||
}
|
||||
|
||||
return $this->handler;
|
||||
}
|
||||
|
||||
/**
|
||||
* 切换缓存类型 需要配置 cache.type 为 complex
|
||||
* @access public
|
||||
* @param string $name 缓存标识
|
||||
* @return Driver
|
||||
*/
|
||||
public function store($name = '')
|
||||
{
|
||||
if ('' !== $name && 'complex' == $this->app['config']->get('cache.type')) {
|
||||
return $this->connect($this->app['config']->get('cache.' . $name), strtolower($name));
|
||||
}
|
||||
|
||||
return $this->init();
|
||||
}
|
||||
|
||||
public function __call($method, $args)
|
||||
{
|
||||
return call_user_func_array([$this->init(), $method], $args);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,388 @@
|
|||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: zhangyajun <448901948@qq.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace think;
|
||||
|
||||
use ArrayAccess;
|
||||
use ArrayIterator;
|
||||
use Countable;
|
||||
use IteratorAggregate;
|
||||
use JsonSerializable;
|
||||
|
||||
class Collection implements ArrayAccess, Countable, IteratorAggregate, JsonSerializable
|
||||
{
|
||||
/**
|
||||
* 数据集数据
|
||||
* @var array
|
||||
*/
|
||||
protected $items = [];
|
||||
|
||||
public function __construct($items = [])
|
||||
{
|
||||
$this->items = $this->convertToArray($items);
|
||||
}
|
||||
|
||||
public static function make($items = [])
|
||||
{
|
||||
return new static($items);
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否为空
|
||||
* @access public
|
||||
* @return bool
|
||||
*/
|
||||
public function isEmpty()
|
||||
{
|
||||
return empty($this->items);
|
||||
}
|
||||
|
||||
public function toArray()
|
||||
{
|
||||
return array_map(function ($value) {
|
||||
return ($value instanceof Model || $value instanceof self) ? $value->toArray() : $value;
|
||||
}, $this->items);
|
||||
}
|
||||
|
||||
public function all()
|
||||
{
|
||||
return $this->items;
|
||||
}
|
||||
|
||||
/**
|
||||
* 合并数组
|
||||
*
|
||||
* @access public
|
||||
* @param mixed $items
|
||||
* @return static
|
||||
*/
|
||||
public function merge($items)
|
||||
{
|
||||
return new static(array_merge($this->items, $this->convertToArray($items)));
|
||||
}
|
||||
|
||||
/**
|
||||
* 比较数组,返回差集
|
||||
*
|
||||
* @access public
|
||||
* @param mixed $items
|
||||
* @return static
|
||||
*/
|
||||
public function diff($items)
|
||||
{
|
||||
return new static(array_diff($this->items, $this->convertToArray($items)));
|
||||
}
|
||||
|
||||
/**
|
||||
* 交换数组中的键和值
|
||||
*
|
||||
* @access public
|
||||
* @return static
|
||||
*/
|
||||
public function flip()
|
||||
{
|
||||
return new static(array_flip($this->items));
|
||||
}
|
||||
|
||||
/**
|
||||
* 比较数组,返回交集
|
||||
*
|
||||
* @access public
|
||||
* @param mixed $items
|
||||
* @return static
|
||||
*/
|
||||
public function intersect($items)
|
||||
{
|
||||
return new static(array_intersect($this->items, $this->convertToArray($items)));
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回数组中所有的键名
|
||||
*
|
||||
* @access public
|
||||
* @return static
|
||||
*/
|
||||
public function keys()
|
||||
{
|
||||
return new static(array_keys($this->items));
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除数组的最后一个元素(出栈)
|
||||
*
|
||||
* @access public
|
||||
* @return mixed
|
||||
*/
|
||||
public function pop()
|
||||
{
|
||||
return array_pop($this->items);
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过使用用户自定义函数,以字符串返回数组
|
||||
*
|
||||
* @access public
|
||||
* @param callable $callback
|
||||
* @param mixed $initial
|
||||
* @return mixed
|
||||
*/
|
||||
public function reduce(callable $callback, $initial = null)
|
||||
{
|
||||
return array_reduce($this->items, $callback, $initial);
|
||||
}
|
||||
|
||||
/**
|
||||
* 以相反的顺序返回数组。
|
||||
*
|
||||
* @access public
|
||||
* @return static
|
||||
*/
|
||||
public function reverse()
|
||||
{
|
||||
return new static(array_reverse($this->items));
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除数组中首个元素,并返回被删除元素的值
|
||||
*
|
||||
* @access public
|
||||
* @return mixed
|
||||
*/
|
||||
public function shift()
|
||||
{
|
||||
return array_shift($this->items);
|
||||
}
|
||||
|
||||
/**
|
||||
* 在数组结尾插入一个元素
|
||||
* @access public
|
||||
* @param mixed $value
|
||||
* @param mixed $key
|
||||
* @return void
|
||||
*/
|
||||
public function push($value, $key = null)
|
||||
{
|
||||
if (is_null($key)) {
|
||||
$this->items[] = $value;
|
||||
} else {
|
||||
$this->items[$key] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 把一个数组分割为新的数组块.
|
||||
*
|
||||
* @access public
|
||||
* @param int $size
|
||||
* @param bool $preserveKeys
|
||||
* @return static
|
||||
*/
|
||||
public function chunk($size, $preserveKeys = false)
|
||||
{
|
||||
$chunks = [];
|
||||
|
||||
foreach (array_chunk($this->items, $size, $preserveKeys) as $chunk) {
|
||||
$chunks[] = new static($chunk);
|
||||
}
|
||||
|
||||
return new static($chunks);
|
||||
}
|
||||
|
||||
/**
|
||||
* 在数组开头插入一个元素
|
||||
* @access public
|
||||
* @param mixed $value
|
||||
* @param mixed $key
|
||||
* @return void
|
||||
*/
|
||||
public function unshift($value, $key = null)
|
||||
{
|
||||
if (is_null($key)) {
|
||||
array_unshift($this->items, $value);
|
||||
} else {
|
||||
$this->items = [$key => $value] + $this->items;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 给每个元素执行个回调
|
||||
*
|
||||
* @access public
|
||||
* @param callable $callback
|
||||
* @return $this
|
||||
*/
|
||||
public function each(callable $callback)
|
||||
{
|
||||
foreach ($this->items as $key => $item) {
|
||||
$result = $callback($item, $key);
|
||||
|
||||
if (false === $result) {
|
||||
break;
|
||||
} elseif (!is_object($item)) {
|
||||
$this->items[$key] = $result;
|
||||
}
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 用回调函数过滤数组中的元素
|
||||
* @access public
|
||||
* @param callable|null $callback
|
||||
* @return static
|
||||
*/
|
||||
public function filter(callable $callback = null)
|
||||
{
|
||||
if ($callback) {
|
||||
return new static(array_filter($this->items, $callback));
|
||||
}
|
||||
|
||||
return new static(array_filter($this->items));
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回数据中指定的一列
|
||||
* @access public
|
||||
* @param mixed $columnKey 键名
|
||||
* @param mixed $indexKey 作为索引值的列
|
||||
* @return array
|
||||
*/
|
||||
public function column($columnKey, $indexKey = null)
|
||||
{
|
||||
return array_column($this->items, $columnKey, $indexKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* 对数组排序
|
||||
*
|
||||
* @access public
|
||||
* @param callable|null $callback
|
||||
* @return static
|
||||
*/
|
||||
public function sort(callable $callback = null)
|
||||
{
|
||||
$items = $this->items;
|
||||
|
||||
$callback = $callback ?: function ($a, $b) {
|
||||
return $a == $b ? 0 : (($a < $b) ? -1 : 1);
|
||||
|
||||
};
|
||||
|
||||
uasort($items, $callback);
|
||||
|
||||
return new static($items);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将数组打乱
|
||||
*
|
||||
* @access public
|
||||
* @return static
|
||||
*/
|
||||
public function shuffle()
|
||||
{
|
||||
$items = $this->items;
|
||||
|
||||
shuffle($items);
|
||||
|
||||
return new static($items);
|
||||
}
|
||||
|
||||
/**
|
||||
* 截取数组
|
||||
*
|
||||
* @access public
|
||||
* @param int $offset
|
||||
* @param int $length
|
||||
* @param bool $preserveKeys
|
||||
* @return static
|
||||
*/
|
||||
public function slice($offset, $length = null, $preserveKeys = false)
|
||||
{
|
||||
return new static(array_slice($this->items, $offset, $length, $preserveKeys));
|
||||
}
|
||||
|
||||
// ArrayAccess
|
||||
public function offsetExists($offset)
|
||||
{
|
||||
return array_key_exists($offset, $this->items);
|
||||
}
|
||||
|
||||
public function offsetGet($offset)
|
||||
{
|
||||
return $this->items[$offset];
|
||||
}
|
||||
|
||||
public function offsetSet($offset, $value)
|
||||
{
|
||||
if (is_null($offset)) {
|
||||
$this->items[] = $value;
|
||||
} else {
|
||||
$this->items[$offset] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
public function offsetUnset($offset)
|
||||
{
|
||||
unset($this->items[$offset]);
|
||||
}
|
||||
|
||||
//Countable
|
||||
public function count()
|
||||
{
|
||||
return count($this->items);
|
||||
}
|
||||
|
||||
//IteratorAggregate
|
||||
public function getIterator()
|
||||
{
|
||||
return new ArrayIterator($this->items);
|
||||
}
|
||||
|
||||
//JsonSerializable
|
||||
public function jsonSerialize()
|
||||
{
|
||||
return $this->toArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换当前数据集为JSON字符串
|
||||
* @access public
|
||||
* @param integer $options json参数
|
||||
* @return string
|
||||
*/
|
||||
public function toJson($options = JSON_UNESCAPED_UNICODE)
|
||||
{
|
||||
return json_encode($this->toArray(), $options);
|
||||
}
|
||||
|
||||
public function __toString()
|
||||
{
|
||||
return $this->toJson();
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换成数组
|
||||
*
|
||||
* @access public
|
||||
* @param mixed $items
|
||||
* @return array
|
||||
*/
|
||||
protected function convertToArray($items)
|
||||
{
|
||||
if ($items instanceof self) {
|
||||
return $items->all();
|
||||
}
|
||||
|
||||
return (array) $items;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,330 @@
|
|||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace think;
|
||||
|
||||
class Config implements \ArrayAccess
|
||||
{
|
||||
/**
|
||||
* 配置参数
|
||||
* @var array
|
||||
*/
|
||||
private $config = [];
|
||||
|
||||
/**
|
||||
* 缓存前缀
|
||||
* @var string
|
||||
*/
|
||||
private $prefix = 'app';
|
||||
|
||||
/**
|
||||
* 设置配置参数默认前缀
|
||||
* @access public
|
||||
* @param string $prefix 前缀
|
||||
* @return void
|
||||
*/
|
||||
public function setDefaultPrefix($prefix)
|
||||
{
|
||||
$this->prefix = $prefix;
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析配置文件或内容
|
||||
* @access public
|
||||
* @param string $config 配置文件路径或内容
|
||||
* @param string $type 配置解析类型
|
||||
* @param string $name 配置名(如设置即表示二级配置)
|
||||
* @return mixed
|
||||
*/
|
||||
public function parse($config, $type = '', $name = '')
|
||||
{
|
||||
if (empty($type)) {
|
||||
$type = pathinfo($config, PATHINFO_EXTENSION);
|
||||
}
|
||||
|
||||
$class = false !== strpos($type, '\\') ? $type : '\\think\\config\\driver\\' . ucwords($type);
|
||||
|
||||
return $this->set((new $class())->parse($config), $name);
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载配置文件(多种格式)
|
||||
* @access public
|
||||
* @param string $file 配置文件名
|
||||
* @param string $name 一级配置名
|
||||
* @return mixed
|
||||
*/
|
||||
public function load($file, $name = '')
|
||||
{
|
||||
//检测文件是否存在
|
||||
if (is_file($file)) {
|
||||
//$name 所有字符转换为小写
|
||||
$name = strtolower($name);
|
||||
//获取文件的后缀格式
|
||||
$type = pathinfo($file, PATHINFO_EXTENSION);
|
||||
if ('php' == $type) {
|
||||
// 后缀为 php格式,返回配置信息数组的值
|
||||
return $this->set(include $file, $name);
|
||||
} elseif ('yaml' == $type && function_exists('yaml_parse_file')) {
|
||||
// yaml 后缀格式 并检测环境是否支持 yaml_parse_file 函数
|
||||
return $this->set(yaml_parse_file($file), $name);
|
||||
} else {
|
||||
// 除以上两种格式以外的
|
||||
return $this->parse($file, $type, $name);
|
||||
}
|
||||
} else {
|
||||
// 文件不存在直接返回配置信息数组
|
||||
return $this->config;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 自动加载配置文件(PHP格式)
|
||||
* @access public
|
||||
* @param string $name 配置名
|
||||
* @return void
|
||||
*/
|
||||
protected function autoLoad($name)
|
||||
{
|
||||
// 如果尚未载入 则动态加载配置文件
|
||||
$module = Container::get('request')->module();
|
||||
$module = $module ? $module . '/' : '';
|
||||
$app = Container::get('app');
|
||||
$path = $app->getAppPath() . $module;
|
||||
|
||||
if (is_dir($path . 'config')) {
|
||||
$file = $path . 'config/' . $name . $app->getConfigExt();
|
||||
} elseif (is_dir($app->getConfigPath() . $module)) {
|
||||
$file = $app->getConfigPath() . $module . $name . $app->getConfigExt();
|
||||
}
|
||||
|
||||
if (isset($file) && is_file($file)) {
|
||||
$this->load($file, $name);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检测配置是否存在
|
||||
* @access public
|
||||
* @param string $name 配置参数名(支持多级配置 .号分割)
|
||||
* @return bool
|
||||
*/
|
||||
public function has($name)
|
||||
{
|
||||
if (!strpos($name, '.')) {
|
||||
$name = $this->prefix . '.' . $name;
|
||||
}
|
||||
|
||||
return $this->get($name) ? true : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取一级配置
|
||||
* @access public
|
||||
* @param string $name 一级配置名
|
||||
* @return array
|
||||
*/
|
||||
public function pull($name)
|
||||
{
|
||||
$name = strtolower($name);
|
||||
|
||||
if (!isset($this->config[$name])) {
|
||||
// 如果尚未载入 则动态加载配置文件
|
||||
$this->autoLoad($name);
|
||||
}
|
||||
|
||||
return isset($this->config[$name]) ? $this->config[$name] : [];
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取配置参数 为空则获取所有配置
|
||||
* @access public
|
||||
* @param string $name 配置参数名(支持多级配置 .号分割)
|
||||
* @return mixed
|
||||
*/
|
||||
public function get($name = null)
|
||||
{
|
||||
// 无参数时获取所有
|
||||
if (empty($name)) {
|
||||
return $this->config;
|
||||
}
|
||||
|
||||
//点在字符串中第一次出现的位置
|
||||
if (!strpos($name, '.')) {
|
||||
$name = $this->prefix . '.' . $name;
|
||||
} elseif ('.' == substr($name, -1)) {
|
||||
return $this->pull(substr($name, 0, -1));
|
||||
}
|
||||
|
||||
$name = explode('.', $name);
|
||||
$name[0] = strtolower($name[0]);
|
||||
$config = $this->config;
|
||||
|
||||
if (!isset($config[$name[0]])) {
|
||||
// 如果尚未载入 则动态加载配置文件
|
||||
$this->autoLoad($name[0]);
|
||||
}
|
||||
|
||||
// 按.拆分成多维数组进行判断
|
||||
foreach ($name as $val) {
|
||||
if (isset($config[$val])) {
|
||||
$config = $config[$val];
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
return $config;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置配置参数 name为数组则为批量设置
|
||||
* @access public
|
||||
* @param string|array $name 配置参数名(支持三级配置 .号分割)
|
||||
* @param mixed $value 配置值
|
||||
* @return mixed
|
||||
*/
|
||||
public function set($name, $value = null)
|
||||
{
|
||||
|
||||
// PHP 后缀时 $value 标识为文件名 $name 文件内容(数组)
|
||||
// 检测$name 是否是字符串 是为true
|
||||
// php 时一般$name 为数组 非字符串
|
||||
if (is_string($name)) {
|
||||
if (!strpos($name, '.')) {
|
||||
$name = $this->prefix . '.' . $name;
|
||||
}
|
||||
|
||||
$name = explode('.', $name, 3);
|
||||
|
||||
if (count($name) == 2) {
|
||||
$this->config[strtolower($name[0])][$name[1]] = $value;
|
||||
} else {
|
||||
$this->config[strtolower($name[0])][$name[1]][$name[2]] = $value;
|
||||
}
|
||||
|
||||
return $value;
|
||||
} elseif (is_array($name)) {
|
||||
// 为数组时执行 批量设置
|
||||
// 检测¥value 是否为空或者null 不为空才执行如下
|
||||
if (!empty($value)) {
|
||||
//检测 是否已经存在
|
||||
if (isset($this->config[$value])) {
|
||||
//存在则合并成新的
|
||||
$result = array_merge($this->config[$value], $name);
|
||||
} else {
|
||||
//不存在则赋值
|
||||
$result = $name;
|
||||
}
|
||||
//最终根据¥value值为键值
|
||||
$this->config[$value] = $result;
|
||||
} else {
|
||||
// empty($value) 为空时执行 数组合并
|
||||
$result = $this->config = array_merge($this->config, $name);
|
||||
}
|
||||
} else {
|
||||
// 为空直接返回 已有配置
|
||||
$result = $this->config;
|
||||
}
|
||||
//并且返回当前的值
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除配置
|
||||
* @access public
|
||||
* @param string $name 配置参数名(支持三级配置 .号分割)
|
||||
* @return void
|
||||
*/
|
||||
public function remove($name)
|
||||
{
|
||||
if (!strpos($name, '.')) {
|
||||
$name = $this->prefix . '.' . $name;
|
||||
}
|
||||
|
||||
$name = explode('.', $name, 3);
|
||||
|
||||
if (count($name) == 2) {
|
||||
unset($this->config[strtolower($name[0])][$name[1]]);
|
||||
} else {
|
||||
unset($this->config[strtolower($name[0])][$name[1]][$name[2]]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 重置配置参数
|
||||
* @access public
|
||||
* @param string $prefix 配置前缀名
|
||||
* @return void
|
||||
*/
|
||||
public function reset($prefix = '')
|
||||
{
|
||||
if ('' === $prefix) {
|
||||
$this->config = [];
|
||||
} else {
|
||||
$this->config[$prefix] = [];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置配置
|
||||
* @access public
|
||||
* @param string $name 参数名
|
||||
* @param mixed $value 值
|
||||
*/
|
||||
public function __set($name, $value)
|
||||
{
|
||||
return $this->set($name, $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取配置参数
|
||||
* @access public
|
||||
* @param string $name 参数名
|
||||
* @return mixed
|
||||
*/
|
||||
public function __get($name)
|
||||
{
|
||||
return $this->get($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* 检测是否存在参数
|
||||
* @access public
|
||||
* @param string $name 参数名
|
||||
* @return bool
|
||||
*/
|
||||
public function __isset($name)
|
||||
{
|
||||
return $this->has($name);
|
||||
}
|
||||
|
||||
// ArrayAccess
|
||||
public function offsetSet($name, $value)
|
||||
{
|
||||
$this->set($name, $value);
|
||||
}
|
||||
|
||||
public function offsetExists($name)
|
||||
{
|
||||
return $this->has($name);
|
||||
}
|
||||
|
||||
public function offsetUnset($name)
|
||||
{
|
||||
$this->remove($name);
|
||||
}
|
||||
|
||||
public function offsetGet($name)
|
||||
{
|
||||
return $this->get($name);
|
||||
}
|
||||
}
|
|
@ -6,35 +6,11 @@
|
|||
// +----------------------------------------------------------------------
|
||||
// | 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\Build;
|
||||
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;
|
||||
|
@ -42,146 +18,100 @@ use think\console\input\Option as InputOption;
|
|||
use think\console\Output;
|
||||
use think\console\output\driver\Buffer;
|
||||
|
||||
/**
|
||||
* 控制台应用管理类
|
||||
*/
|
||||
class Console
|
||||
{
|
||||
|
||||
protected $app;
|
||||
private $name;
|
||||
private $version;
|
||||
|
||||
/** @var Command[] */
|
||||
protected $commands = [];
|
||||
private $commands = [];
|
||||
|
||||
protected $wantHelps = false;
|
||||
private $wantHelps = false;
|
||||
|
||||
protected $catchExceptions = true;
|
||||
protected $autoExit = true;
|
||||
protected $definition;
|
||||
protected $defaultCommand = 'list';
|
||||
private $catchExceptions = true;
|
||||
private $autoExit = true;
|
||||
private $definition;
|
||||
private $defaultCommand;
|
||||
|
||||
protected $defaultCommands = [
|
||||
'help' => Help::class,
|
||||
'list' => Lists::class,
|
||||
'build' => Build::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:schema' => Schema::class,
|
||||
'optimize:route' => Route::class,
|
||||
'run' => RunServer::class,
|
||||
'version' => Version::class,
|
||||
'route:list' => RouteList::class,
|
||||
'service:discover' => ServiceDiscover::class,
|
||||
'vendor:publish' => VendorPublish::class,
|
||||
private static $defaultCommands = [
|
||||
"think\\console\\command\\Help",
|
||||
"think\\console\\command\\Lists",
|
||||
"think\\console\\command\\Build",
|
||||
"think\\console\\command\\Clear",
|
||||
"think\\console\\command\\make\\Controller",
|
||||
"think\\console\\command\\make\\Model",
|
||||
"think\\console\\command\\optimize\\Autoload",
|
||||
"think\\console\\command\\optimize\\Config",
|
||||
"think\\console\\command\\optimize\\Schema",
|
||||
"think\\console\\command\\optimize\\Route",
|
||||
"think\\console\\command\\RunServer",
|
||||
];
|
||||
|
||||
/**
|
||||
* 启动器
|
||||
* @var array
|
||||
*/
|
||||
protected static $startCallbacks = [];
|
||||
|
||||
public function __construct(App $app)
|
||||
public function __construct($name = 'UNKNOWN', $version = 'UNKNOWN')
|
||||
{
|
||||
$this->app = $app;
|
||||
$this->name = $name;
|
||||
$this->version = $version;
|
||||
|
||||
if (!$this->app->initialized()) {
|
||||
$this->app->initialize();
|
||||
}
|
||||
$this->defaultCommand = 'list';
|
||||
$this->definition = $this->getDefaultInputDefinition();
|
||||
|
||||
$user = $this->app->config->get('console.user');
|
||||
|
||||
if ($user) {
|
||||
$this->setUser($user);
|
||||
}
|
||||
|
||||
$this->definition = $this->getDefaultInputDefinition();
|
||||
|
||||
//加载指令
|
||||
$this->loadCommands();
|
||||
|
||||
$this->start();
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加初始化器
|
||||
* @param Closure $callback
|
||||
*/
|
||||
public static function starting(Closure $callback): void
|
||||
{
|
||||
static::$startCallbacks[] = $callback;
|
||||
}
|
||||
|
||||
/**
|
||||
* 清空启动器
|
||||
*/
|
||||
public static function flushStartCallbacks(): void
|
||||
{
|
||||
static::$startCallbacks = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* 启动
|
||||
*/
|
||||
protected function start(): void
|
||||
{
|
||||
foreach (static::$startCallbacks as $callback) {
|
||||
$callback($this);
|
||||
foreach ($this->getDefaultCommands() as $command) {
|
||||
$this->add($command);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置执行用户
|
||||
* @param $user
|
||||
*/
|
||||
protected function setUser(string $user): void
|
||||
public static function init($run = true)
|
||||
{
|
||||
if (extension_loaded('posix')) {
|
||||
$user = posix_getpwnam($user);
|
||||
static $console;
|
||||
|
||||
if (!empty($user)) {
|
||||
posix_setuid($user['uid']);
|
||||
posix_setgid($user['gid']);
|
||||
if (!$console) {
|
||||
// 实例化console
|
||||
$console = new self('Think Console', '0.1');
|
||||
|
||||
// 读取指令集
|
||||
$file = Container::get('env')->get('app_path') . 'command.php';
|
||||
|
||||
if (is_file($file)) {
|
||||
$commands = include $file;
|
||||
|
||||
if (is_array($commands)) {
|
||||
foreach ($commands as $command) {
|
||||
if (class_exists($command) && is_subclass_of($command, "\\think\\console\\Command")) {
|
||||
// 注册指令
|
||||
$console->add(new $command());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载指令
|
||||
* @access protected
|
||||
*/
|
||||
protected function loadCommands(): void
|
||||
{
|
||||
$commands = $this->app->config->get('console.commands', []);
|
||||
$commands = array_merge($this->defaultCommands, $commands);
|
||||
|
||||
$this->addCommands($commands);
|
||||
if ($run) {
|
||||
// 运行
|
||||
return $console->run();
|
||||
} else {
|
||||
return $console;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @access public
|
||||
* @param string $command
|
||||
* @param array $parameters
|
||||
* @param string $driver
|
||||
* @param string $command
|
||||
* @param array $parameters
|
||||
* @param string $driver
|
||||
* @return Output|Buffer
|
||||
*/
|
||||
public function call(string $command, array $parameters = [], string $driver = 'buffer')
|
||||
public static function call($command, array $parameters = [], $driver = 'buffer')
|
||||
{
|
||||
$console = self::init(false);
|
||||
|
||||
array_unshift($parameters, $command);
|
||||
|
||||
$input = new Input($parameters);
|
||||
$output = new Output($driver);
|
||||
|
||||
$this->setCatchExceptions(false);
|
||||
$this->find($command)->run($input, $output);
|
||||
$console->setCatchExceptions(false);
|
||||
$console->find($command)->run($input, $output);
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
@ -234,8 +164,8 @@ class Console
|
|||
/**
|
||||
* 执行指令
|
||||
* @access public
|
||||
* @param Input $input
|
||||
* @param Output $output
|
||||
* @param Input $input
|
||||
* @param Output $output
|
||||
* @return int
|
||||
*/
|
||||
public function doRun(Input $input, Output $output)
|
||||
|
@ -264,17 +194,17 @@ class Console
|
|||
|
||||
$command = $this->find($name);
|
||||
|
||||
$this->app->log->info('run: php think ' . $input);
|
||||
$exitCode = $this->doRunCommand($command, $input, $output);
|
||||
|
||||
return $this->doRunCommand($command, $input, $output);
|
||||
return $exitCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置输入参数定义
|
||||
* @access public
|
||||
* @param InputDefinition $definition
|
||||
* @param InputDefinition $definition
|
||||
*/
|
||||
public function setDefinition(InputDefinition $definition): void
|
||||
public function setDefinition(InputDefinition $definition)
|
||||
{
|
||||
$this->definition = $definition;
|
||||
}
|
||||
|
@ -284,7 +214,7 @@ class Console
|
|||
* @access public
|
||||
* @return InputDefinition The InputDefinition instance
|
||||
*/
|
||||
public function getDefinition(): InputDefinition
|
||||
public function getDefinition()
|
||||
{
|
||||
return $this->definition;
|
||||
}
|
||||
|
@ -294,7 +224,7 @@ class Console
|
|||
* @access public
|
||||
* @return string A help message.
|
||||
*/
|
||||
public function getHelp(): string
|
||||
public function getHelp()
|
||||
{
|
||||
return $this->getLongVersion();
|
||||
}
|
||||
|
@ -302,23 +232,64 @@ class Console
|
|||
/**
|
||||
* 是否捕获异常
|
||||
* @access public
|
||||
* @param bool $boolean
|
||||
* @param bool $boolean
|
||||
* @api
|
||||
*/
|
||||
public function setCatchExceptions(bool $boolean): void
|
||||
public function setCatchExceptions($boolean)
|
||||
{
|
||||
$this->catchExceptions = $boolean;
|
||||
$this->catchExceptions = (bool) $boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否自动退出
|
||||
* @access public
|
||||
* @param bool $boolean
|
||||
* @param bool $boolean
|
||||
* @api
|
||||
*/
|
||||
public function setAutoExit(bool $boolean): void
|
||||
public function setAutoExit($boolean)
|
||||
{
|
||||
$this->autoExit = $boolean;
|
||||
$this->autoExit = (bool) $boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取名称
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置名称
|
||||
* @access public
|
||||
* @param string $name
|
||||
*/
|
||||
public function setName($name)
|
||||
{
|
||||
$this->name = $name;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取版本
|
||||
* @access public
|
||||
* @return string
|
||||
* @api
|
||||
*/
|
||||
public function getVersion()
|
||||
{
|
||||
return $this->version;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置版本
|
||||
* @access public
|
||||
* @param string $version
|
||||
*/
|
||||
public function setVersion($version)
|
||||
{
|
||||
$this->version = $version;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -326,48 +297,46 @@ class Console
|
|||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function getLongVersion(): string
|
||||
public function getLongVersion()
|
||||
{
|
||||
if ($this->app->version()) {
|
||||
return sprintf('version <comment>%s</comment>', $this->app->version());
|
||||
if ('UNKNOWN' !== $this->getName() && 'UNKNOWN' !== $this->getVersion()) {
|
||||
return sprintf('<info>%s</info> version <comment>%s</comment>', $this->getName(), $this->getVersion());
|
||||
}
|
||||
|
||||
return '<info>Console Tool</info>';
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加指令集
|
||||
* 注册一个指令
|
||||
* @access public
|
||||
* @param array $commands
|
||||
* @param string $name
|
||||
* @return Command
|
||||
*/
|
||||
public function addCommands(array $commands): void
|
||||
public function register($name)
|
||||
{
|
||||
foreach ($commands as $key => $command) {
|
||||
if (is_subclass_of($command, Command::class)) {
|
||||
// 注册指令
|
||||
$this->addCommand($command, is_numeric($key) ? '' : $key);
|
||||
}
|
||||
return $this->add(new Command($name));
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加指令
|
||||
* @access public
|
||||
* @param Command[] $commands
|
||||
*/
|
||||
public function addCommands(array $commands)
|
||||
{
|
||||
foreach ($commands as $command) {
|
||||
$this->add($command);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加一个指令
|
||||
* @access public
|
||||
* @param string|Command $command 指令对象或者指令类名
|
||||
* @param string $name 指令名 留空则自动获取
|
||||
* @return Command|void
|
||||
* @param Command $command
|
||||
* @return Command
|
||||
*/
|
||||
public function addCommand($command, string $name = '')
|
||||
public function add(Command $command)
|
||||
{
|
||||
if ($name) {
|
||||
$this->commands[$name] = $command;
|
||||
return;
|
||||
}
|
||||
|
||||
if (is_string($command)) {
|
||||
$command = $this->app->invokeClass($command);
|
||||
}
|
||||
|
||||
$command->setConsole($this);
|
||||
|
||||
if (!$command->isEnabled()) {
|
||||
|
@ -375,10 +344,8 @@ class Console
|
|||
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.', get_class($command)));
|
||||
throw new \LogicException(sprintf('Command class "%s" is not correctly initialized. You probably forgot to call the parent constructor.', get_class($command)));
|
||||
}
|
||||
|
||||
$this->commands[$command->getName()] = $command;
|
||||
|
@ -393,30 +360,23 @@ class Console
|
|||
/**
|
||||
* 获取指令
|
||||
* @access public
|
||||
* @param string $name 指令名称
|
||||
* @param string $name 指令名称
|
||||
* @return Command
|
||||
* @throws InvalidArgumentException
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public function getCommand(string $name): Command
|
||||
public function get($name)
|
||||
{
|
||||
if (!isset($this->commands[$name])) {
|
||||
throw new InvalidArgumentException(sprintf('The command "%s" does not exist.', $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 = $this->get('help');
|
||||
$helpCommand->setCommand($command);
|
||||
|
||||
return $helpCommand;
|
||||
|
@ -428,10 +388,10 @@ class Console
|
|||
/**
|
||||
* 某个指令是否存在
|
||||
* @access public
|
||||
* @param string $name 指令名称
|
||||
* @param string $name 指令名称
|
||||
* @return bool
|
||||
*/
|
||||
public function hasCommand(string $name): bool
|
||||
public function has($name)
|
||||
{
|
||||
return isset($this->commands[$name]);
|
||||
}
|
||||
|
@ -441,18 +401,14 @@ class Console
|
|||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function getNamespaces(): array
|
||||
public function getNamespaces()
|
||||
{
|
||||
$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 ($this->commands as $command) {
|
||||
$namespaces = array_merge($namespaces, $this->extractAllNamespaces($command->getName()));
|
||||
|
||||
foreach ($command->getAliases() as $alias) {
|
||||
$namespaces = array_merge($namespaces, $this->extractAllNamespaces($alias));
|
||||
}
|
||||
foreach ($command->getAliases() as $alias) {
|
||||
$namespaces = array_merge($namespaces, $this->extractAllNamespaces($alias));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -462,11 +418,11 @@ class Console
|
|||
/**
|
||||
* 查找注册命名空间中的名称或缩写。
|
||||
* @access public
|
||||
* @param string $namespace
|
||||
* @param string $namespace
|
||||
* @return string
|
||||
* @throws InvalidArgumentException
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public function findNamespace(string $namespace): string
|
||||
public function findNamespace($namespace)
|
||||
{
|
||||
$allNamespaces = $this->getNamespaces();
|
||||
$expr = preg_replace_callback('{([^:]+|)}', function ($matches) {
|
||||
|
@ -487,12 +443,12 @@ class Console
|
|||
$message .= implode("\n ", $alternatives);
|
||||
}
|
||||
|
||||
throw new InvalidArgumentException($message);
|
||||
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))));
|
||||
throw new \InvalidArgumentException(sprintf('The namespace "%s" is ambiguous (%s).', $namespace, $this->getAbbreviationSuggestions(array_values($namespaces))));
|
||||
}
|
||||
|
||||
return $exact ? $namespace : reset($namespaces);
|
||||
|
@ -501,11 +457,11 @@ class Console
|
|||
/**
|
||||
* 查找指令
|
||||
* @access public
|
||||
* @param string $name 名称或者别名
|
||||
* @param string $name 名称或者别名
|
||||
* @return Command
|
||||
* @throws InvalidArgumentException
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public function find(string $name): Command
|
||||
public function find($name)
|
||||
{
|
||||
$allCommands = array_keys($this->commands);
|
||||
|
||||
|
@ -531,27 +487,37 @@ class Console
|
|||
$message .= implode("\n ", $alternatives);
|
||||
}
|
||||
|
||||
throw new InvalidArgumentException($message);
|
||||
throw new \InvalidArgumentException($message);
|
||||
}
|
||||
|
||||
if (count($commands) > 1) {
|
||||
$commandList = $this->commands;
|
||||
|
||||
$commands = array_filter($commands, function ($nameOrAlias) use ($commandList, $commands) {
|
||||
$commandName = $commandList[$nameOrAlias]->getName();
|
||||
|
||||
return $commandName === $nameOrAlias || !in_array($commandName, $commands);
|
||||
});
|
||||
}
|
||||
|
||||
$exact = in_array($name, $commands, true);
|
||||
if (count($commands) > 1 && !$exact) {
|
||||
$suggestions = $this->getAbbreviationSuggestions(array_values($commands));
|
||||
|
||||
throw new InvalidArgumentException(sprintf('Command "%s" is ambiguous (%s).', $name, $suggestions));
|
||||
throw new \InvalidArgumentException(sprintf('Command "%s" is ambiguous (%s).', $name, $suggestions));
|
||||
}
|
||||
|
||||
return $this->getCommand($exact ? $name : reset($commands));
|
||||
return $this->get($exact ? $name : reset($commands));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有的指令
|
||||
* @access public
|
||||
* @param string $namespace 命名空间
|
||||
* @param string $namespace 命名空间
|
||||
* @return Command[]
|
||||
* @api
|
||||
*/
|
||||
public function all(string $namespace = null): array
|
||||
public function all($namespace = null)
|
||||
{
|
||||
if (null === $namespace) {
|
||||
return $this->commands;
|
||||
|
@ -567,13 +533,32 @@ class Console
|
|||
return $commands;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取可能的指令名
|
||||
* @access public
|
||||
* @param array $names
|
||||
* @return array
|
||||
*/
|
||||
public static function getAbbreviations($names)
|
||||
{
|
||||
$abbrevs = [];
|
||||
foreach ($names as $name) {
|
||||
for ($len = strlen($name); $len > 0; --$len) {
|
||||
$abbrev = substr($name, 0, $len);
|
||||
$abbrevs[$abbrev][] = $name;
|
||||
}
|
||||
}
|
||||
|
||||
return $abbrevs;
|
||||
}
|
||||
|
||||
/**
|
||||
* 配置基于用户的参数和选项的输入和输出实例。
|
||||
* @access protected
|
||||
* @param Input $input 输入实例
|
||||
* @param Output $output 输出实例
|
||||
* @param Input $input 输入实例
|
||||
* @param Output $output 输出实例
|
||||
*/
|
||||
protected function configureIO(Input $input, Output $output): void
|
||||
protected function configureIO(Input $input, Output $output)
|
||||
{
|
||||
if (true === $input->hasParameterOption(['--ansi'])) {
|
||||
$output->setDecorated(true);
|
||||
|
@ -587,21 +572,23 @@ class Console
|
|||
|
||||
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);
|
||||
} else {
|
||||
if ($input->hasParameterOption('-vvv') || $input->hasParameterOption('--verbose=3') || $input->getParameterOption('--verbose') === 3) {
|
||||
$output->setVerbosity(Output::VERBOSITY_DEBUG);
|
||||
} elseif ($input->hasParameterOption('-vv') || $input->hasParameterOption('--verbose=2') || $input->getParameterOption('--verbose') === 2) {
|
||||
$output->setVerbosity(Output::VERBOSITY_VERY_VERBOSE);
|
||||
} elseif ($input->hasParameterOption('-v') || $input->hasParameterOption('--verbose=1') || $input->hasParameterOption('--verbose') || $input->getParameterOption('--verbose')) {
|
||||
$output->setVerbosity(Output::VERBOSITY_VERBOSE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行指令
|
||||
* @access protected
|
||||
* @param Command $command 指令实例
|
||||
* @param Input $input 输入实例
|
||||
* @param Output $output 输出实例
|
||||
* @param Command $command 指令实例
|
||||
* @param Input $input 输入实例
|
||||
* @param Output $output 输出实例
|
||||
* @return int
|
||||
* @throws \Exception
|
||||
*/
|
||||
|
@ -613,12 +600,12 @@ class Console
|
|||
/**
|
||||
* 获取指令的基础名称
|
||||
* @access protected
|
||||
* @param Input $input
|
||||
* @param Input $input
|
||||
* @return string
|
||||
*/
|
||||
protected function getCommandName(Input $input): string
|
||||
protected function getCommandName(Input $input)
|
||||
{
|
||||
return $input->getFirstArgument() ?: '';
|
||||
return $input->getFirstArgument();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -626,7 +613,7 @@ class Console
|
|||
* @access protected
|
||||
* @return InputDefinition
|
||||
*/
|
||||
protected function getDefaultInputDefinition(): InputDefinition
|
||||
protected function getDefaultInputDefinition()
|
||||
{
|
||||
return new InputDefinition([
|
||||
new InputArgument('command', InputArgument::REQUIRED, 'The command to execute'),
|
||||
|
@ -640,13 +627,36 @@ class Console
|
|||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置默认命令
|
||||
* @access protected
|
||||
* @return Command[] An array of default Command instances
|
||||
*/
|
||||
protected function getDefaultCommands()
|
||||
{
|
||||
$defaultCommands = [];
|
||||
|
||||
foreach (self::$defaultCommands as $classname) {
|
||||
if (class_exists($classname) && is_subclass_of($classname, "think\\console\\Command")) {
|
||||
$defaultCommands[] = new $classname();
|
||||
}
|
||||
}
|
||||
|
||||
return $defaultCommands;
|
||||
}
|
||||
|
||||
public static function addDefaultCommands(array $classnames)
|
||||
{
|
||||
self::$defaultCommands = array_merge(self::$defaultCommands, $classnames);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取可能的建议
|
||||
* @access private
|
||||
* @param array $abbrevs
|
||||
* @param array $abbrevs
|
||||
* @return string
|
||||
*/
|
||||
private function getAbbreviationSuggestions(array $abbrevs): string
|
||||
private function getAbbreviationSuggestions($abbrevs)
|
||||
{
|
||||
return sprintf('%s, %s%s', $abbrevs[0], $abbrevs[1], count($abbrevs) > 2 ? sprintf(' and %d more', count($abbrevs) - 2) : '');
|
||||
}
|
||||
|
@ -654,26 +664,26 @@ class Console
|
|||
/**
|
||||
* 返回命名空间部分
|
||||
* @access public
|
||||
* @param string $name 指令
|
||||
* @param int $limit 部分的命名空间的最大数量
|
||||
* @param string $name 指令
|
||||
* @param string $limit 部分的命名空间的最大数量
|
||||
* @return string
|
||||
*/
|
||||
public function extractNamespace(string $name, int $limit = 0): string
|
||||
public function extractNamespace($name, $limit = null)
|
||||
{
|
||||
$parts = explode(':', $name);
|
||||
array_pop($parts);
|
||||
|
||||
return implode(':', 0 === $limit ? $parts : array_slice($parts, 0, $limit));
|
||||
return implode(':', null === $limit ? $parts : array_slice($parts, 0, $limit));
|
||||
}
|
||||
|
||||
/**
|
||||
* 查找可替代的建议
|
||||
* @access private
|
||||
* @param string $name
|
||||
* @param array|\Traversable $collection
|
||||
* @param string $name
|
||||
* @param array|\Traversable $collection
|
||||
* @return array
|
||||
*/
|
||||
private function findAlternatives(string $name, $collection): array
|
||||
private function findAlternatives($name, $collection)
|
||||
{
|
||||
$threshold = 1e3;
|
||||
$alternatives = [];
|
||||
|
@ -717,13 +727,23 @@ class Console
|
|||
return array_keys($alternatives);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置默认的指令
|
||||
* @access public
|
||||
* @param string $commandName The Command name
|
||||
*/
|
||||
public function setDefaultCommand($commandName)
|
||||
{
|
||||
$this->defaultCommand = $commandName;
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回所有的命名空间
|
||||
* @access private
|
||||
* @param string $name
|
||||
* @param string $name
|
||||
* @return array
|
||||
*/
|
||||
private function extractAllNamespaces(string $name): array
|
||||
private function extractAllNamespaces($name)
|
||||
{
|
||||
$parts = explode(':', $name, -1);
|
||||
$namespaces = [];
|
|
@ -0,0 +1,320 @@
|
|||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace think;
|
||||
|
||||
use Closure;
|
||||
use InvalidArgumentException;
|
||||
use ReflectionClass;
|
||||
use ReflectionFunction;
|
||||
use ReflectionMethod;
|
||||
|
||||
class Container
|
||||
{
|
||||
/**
|
||||
* 容器对象实例
|
||||
* @var Container
|
||||
*/
|
||||
protected static $instance;
|
||||
|
||||
/**
|
||||
* 容器中的对象实例
|
||||
* @var array
|
||||
*/
|
||||
protected $instances = [];
|
||||
|
||||
/**
|
||||
* 容器绑定标识
|
||||
* @var array
|
||||
*/
|
||||
protected $bind = [];
|
||||
|
||||
/**
|
||||
* 获取当前容器的实例(单例)
|
||||
* @access public
|
||||
* @return static
|
||||
*/
|
||||
public static function getInstance()
|
||||
{
|
||||
if (is_null(static::$instance)) {
|
||||
static::$instance = new static;
|
||||
}
|
||||
|
||||
return static::$instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取容器中的对象实例
|
||||
* @access public
|
||||
* @param string $abstract 类名或者标识
|
||||
* @param array|true $vars 变量
|
||||
* @param bool $newInstance 是否每次创建新的实例
|
||||
* @return object
|
||||
*/
|
||||
public static function get($abstract, $vars = [], $newInstance = false)
|
||||
{
|
||||
return static::getInstance()->make($abstract, $vars, $newInstance);
|
||||
}
|
||||
|
||||
/**
|
||||
* 绑定一个类、闭包、实例、接口实现到容器
|
||||
* @access public
|
||||
* @param string $abstract 类标识、接口
|
||||
* @param mixed $concrete 要绑定的类、闭包或者实例
|
||||
* @return Container
|
||||
*/
|
||||
public static function set($abstract, $concrete = null)
|
||||
{
|
||||
return static::getInstance()->bind($abstract, $concrete);
|
||||
}
|
||||
|
||||
/**
|
||||
* 绑定一个类、闭包、实例、接口实现到容器
|
||||
* @access public
|
||||
* @param string|array $abstract 类标识、接口
|
||||
* @param mixed $concrete 要绑定的类、闭包或者实例
|
||||
* @return $this
|
||||
*/
|
||||
public function bind($abstract, $concrete = null)
|
||||
{
|
||||
if (is_array($abstract)) {
|
||||
$this->bind = array_merge($this->bind, $abstract);
|
||||
} elseif ($concrete instanceof Closure) {
|
||||
$this->bind[$abstract] = $concrete;
|
||||
} elseif (is_object($concrete)) {
|
||||
$this->instances[$abstract] = $concrete;
|
||||
} else {
|
||||
$this->bind[$abstract] = $concrete;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 绑定一个类实例当容器
|
||||
* @access public
|
||||
* @param string $abstract 类名或者标识
|
||||
* @param object $instance 类的实例
|
||||
* @return $this
|
||||
*/
|
||||
public function instance($abstract, $instance)
|
||||
{
|
||||
if (isset($this->bind[$abstract])) {
|
||||
$abstract = $this->bind[$abstract];
|
||||
}
|
||||
|
||||
$this->instances[$abstract] = $instance;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断容器中是否存在类及标识
|
||||
* @access public
|
||||
* @param string $abstract 类名或者标识
|
||||
* @return bool
|
||||
*/
|
||||
public function bound($abstract)
|
||||
{
|
||||
return isset($this->bind[$abstract]) || isset($this->instances[$abstract]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断容器中是否存在类及标识
|
||||
* @access public
|
||||
* @param string $name 类名或者标识
|
||||
* @return bool
|
||||
*/
|
||||
public function has($name)
|
||||
{
|
||||
return $this->bound($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建类的实例
|
||||
* @access public
|
||||
* @param string $abstract 类名或者标识
|
||||
* @param array|true $args 变量
|
||||
* @param bool $newInstance 是否每次创建新的实例
|
||||
* @return object
|
||||
*/
|
||||
public function make($abstract, $vars = [], $newInstance = false)
|
||||
{
|
||||
if (true === $vars) {
|
||||
// 总是创建新的实例化对象
|
||||
$newInstance = true;
|
||||
$vars = [];
|
||||
}
|
||||
|
||||
if (isset($this->instances[$abstract]) && !$newInstance) {
|
||||
$object = $this->instances[$abstract];
|
||||
} else {
|
||||
if (isset($this->bind[$abstract])) {
|
||||
$concrete = $this->bind[$abstract];
|
||||
|
||||
if ($concrete instanceof Closure) {
|
||||
$object = $this->invokeFunction($concrete, $vars);
|
||||
} else {
|
||||
$object = $this->make($concrete, $vars, $newInstance);
|
||||
}
|
||||
} else {
|
||||
$object = $this->invokeClass($abstract, $vars);
|
||||
}
|
||||
|
||||
if (!$newInstance) {
|
||||
$this->instances[$abstract] = $object;
|
||||
}
|
||||
}
|
||||
|
||||
return $object;
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行函数或者闭包方法 支持参数调用
|
||||
* @access public
|
||||
* @param string|array|\Closure $function 函数或者闭包
|
||||
* @param array $vars 变量
|
||||
* @return mixed
|
||||
*/
|
||||
public function invokeFunction($function, $vars = [])
|
||||
{
|
||||
//$vars 带入的参数
|
||||
$reflect = new ReflectionFunction($function);
|
||||
//整理参数
|
||||
$args = $this->bindParams($reflect, $vars);
|
||||
// 调用(执行)反射的方法并将其参数作为数组传递
|
||||
return $reflect->invokeArgs($args);
|
||||
}
|
||||
|
||||
/**
|
||||
* 调用反射执行类的方法 支持参数绑定
|
||||
* @access public
|
||||
* @param string|array $method 方法
|
||||
* @param array $vars 变量
|
||||
* @return mixed
|
||||
*/
|
||||
public function invokeMethod($method, $vars = [])
|
||||
{
|
||||
if (is_array($method)) {
|
||||
//检测变量是否是一个对象
|
||||
//检测第一个值是否为实例化对象,是则采用,不是则获取生成实例化对象
|
||||
$class = is_object($method[0]) ? $method[0] : $this->invokeClass($method[0]);
|
||||
$reflect = new ReflectionMethod($class, $method[1]);
|
||||
} else {
|
||||
// 静态方法
|
||||
$reflect = new ReflectionMethod($method);
|
||||
}
|
||||
//整理参数
|
||||
$args = $this->bindParams($reflect, $vars);
|
||||
// 调用(执行)反射的方法并将其参数作为数组传递
|
||||
return $reflect->invokeArgs(isset($class) ? $class : null, $args);
|
||||
}
|
||||
|
||||
/**
|
||||
* 调用反射执行callable 支持参数绑定
|
||||
* @access public
|
||||
* @param mixed $callable
|
||||
* @param array $vars 变量
|
||||
* @return mixed
|
||||
*/
|
||||
public function invoke($callable, $vars = [])
|
||||
{
|
||||
// $callable 数组或者字符串,匿名函数,或者类命名空间 或者静态调用方法
|
||||
// $vars 传递的参数
|
||||
//是否为闭包,闭包则执行函数,否则执行类方法
|
||||
if ($callable instanceof Closure) {
|
||||
//执行闭包函数
|
||||
$result = $this->invokeFunction($callable, $vars);
|
||||
|
||||
} else {
|
||||
//执行类 方法操作
|
||||
$result = $this->invokeMethod($callable, $vars);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 调用反射执行类的实例化 支持依赖注入
|
||||
* @access public
|
||||
* @param string $class 类名
|
||||
* @param array $vars 变量
|
||||
* @return mixed
|
||||
*/
|
||||
public function invokeClass($class, $vars = [])
|
||||
{
|
||||
//给定命名空间或者类名,返回对应的实例对象
|
||||
// $vars 实例时需要传递的值
|
||||
$reflect = new ReflectionClass($class);
|
||||
// 获取类的构造函数,返回类命名空间以及构造函数
|
||||
$constructor = $reflect->getConstructor();
|
||||
|
||||
if ($constructor) {
|
||||
//处理传递的参数
|
||||
$args = $this->bindParams($constructor, $vars);
|
||||
} else {
|
||||
$args = [];
|
||||
}
|
||||
|
||||
//返回创建的新实例 从给出的参数创建一个新的类实例
|
||||
return $reflect->newInstanceArgs($args);
|
||||
}
|
||||
|
||||
/**
|
||||
* 绑定参数
|
||||
* @access protected
|
||||
* @param \ReflectionMethod|\ReflectionFunction $reflect 反射类
|
||||
* @param array $vars 变量
|
||||
* @return array
|
||||
*/
|
||||
protected function bindParams($reflect, $vars = [])
|
||||
{
|
||||
$args = [];
|
||||
|
||||
// $reflect 代表ReflectionFunction 或者 ReflectionMethod 实例
|
||||
// getNumberOfParameters() 获取的是函数或者方法需要的参数个数 如:function($1,$2,$3)
|
||||
if ($reflect->getNumberOfParameters() > 0) {
|
||||
// 判断数组类型 数字数组时按顺序绑定参数
|
||||
// 将数组的内部指针指向第一个单元
|
||||
reset($vars);
|
||||
$type = key($vars) === 0 ? 1 : 0;
|
||||
|
||||
//获取函数或者方法内 参数额变量名
|
||||
$params = $reflect->getParameters();
|
||||
|
||||
foreach ($params as $param) {
|
||||
//变量名称
|
||||
$name = $param->getName();
|
||||
//所属类
|
||||
$class = $param->getClass();
|
||||
|
||||
//判断类是否有值
|
||||
if ($class) {
|
||||
//获取类的命名空间名称
|
||||
$className = $class->getName();
|
||||
$args[] = $this->make($className);
|
||||
} elseif (1 == $type && !empty($vars)) {
|
||||
//删除数组中的第一个元素
|
||||
$args[] = array_shift($vars);
|
||||
} elseif (0 == $type && isset($vars[$name])) {
|
||||
$args[] = $vars[$name];
|
||||
} elseif ($param->isDefaultValueAvailable()) {
|
||||
$args[] = $param->getDefaultValue();
|
||||
} else {
|
||||
throw new InvalidArgumentException('method param miss:' . $name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $args;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,242 @@
|
|||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace think;
|
||||
|
||||
use think\exception\ValidateException;
|
||||
use traits\controller\Jump;
|
||||
|
||||
class Controller
|
||||
{
|
||||
use Jump;
|
||||
|
||||
/**
|
||||
* 视图类实例
|
||||
* @var \think\View
|
||||
*/
|
||||
protected $view;
|
||||
|
||||
/**
|
||||
* Request实例
|
||||
* @var \think\Request
|
||||
*/
|
||||
protected $request;
|
||||
|
||||
/**
|
||||
* 应用实例
|
||||
* @var \think\App
|
||||
*/
|
||||
protected $app;
|
||||
|
||||
/**
|
||||
* 验证失败是否抛出异常
|
||||
* @var bool
|
||||
*/
|
||||
protected $failException = false;
|
||||
|
||||
/**
|
||||
* 是否批量验证
|
||||
* @var bool
|
||||
*/
|
||||
protected $batchValidate = false;
|
||||
|
||||
/**
|
||||
* 前置操作方法列表
|
||||
* @var array $beforeActionList
|
||||
*/
|
||||
protected $beforeActionList = [];
|
||||
|
||||
/**
|
||||
* 构造方法
|
||||
* @access public
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->request = Container::get('request');
|
||||
$this->app = Container::get('app');
|
||||
$this->view = Container::get('view')->init(
|
||||
$this->app['config']->pull('template')
|
||||
);
|
||||
|
||||
// 控制器初始化
|
||||
$this->initialize();
|
||||
|
||||
// 前置操作方法
|
||||
if ($this->beforeActionList) {
|
||||
foreach ($this->beforeActionList as $method => $options) {
|
||||
is_numeric($method) ?
|
||||
$this->beforeAction($options) :
|
||||
$this->beforeAction($method, $options);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 初始化
|
||||
protected function initialize()
|
||||
{}
|
||||
|
||||
/**
|
||||
* 前置操作
|
||||
* @access protected
|
||||
* @param string $method 前置操作方法名
|
||||
* @param array $options 调用参数 ['only'=>[...]] 或者['except'=>[...]]
|
||||
*/
|
||||
protected function beforeAction($method, $options = [])
|
||||
{
|
||||
if (isset($options['only'])) {
|
||||
if (is_string($options['only'])) {
|
||||
$options['only'] = explode(',', $options['only']);
|
||||
}
|
||||
if (!in_array($this->request->action(), $options['only'])) {
|
||||
return;
|
||||
}
|
||||
} elseif (isset($options['except'])) {
|
||||
if (is_string($options['except'])) {
|
||||
$options['except'] = explode(',', $options['except']);
|
||||
}
|
||||
if (in_array($this->request->action(), $options['except'])) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
call_user_func([$this, $method]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载模板输出
|
||||
* @access protected
|
||||
* @param string $template 模板文件名
|
||||
* @param array $vars 模板输出变量
|
||||
* @param array $config 模板参数
|
||||
* @return mixed
|
||||
*/
|
||||
protected function fetch($template = '', $vars = [], $config = [])
|
||||
{
|
||||
return $this->view->fetch($template, $vars, $config);
|
||||
}
|
||||
|
||||
/**
|
||||
* 渲染内容输出
|
||||
* @access protected
|
||||
* @param string $content 模板内容
|
||||
* @param array $vars 模板输出变量
|
||||
* @param array $config 模板参数
|
||||
* @return mixed
|
||||
*/
|
||||
protected function display($content = '', $vars = [], $config = [])
|
||||
{
|
||||
return $this->view->display($content, $vars, $config);
|
||||
}
|
||||
|
||||
/**
|
||||
* 模板变量赋值
|
||||
* @access protected
|
||||
* @param mixed $name 要显示的模板变量
|
||||
* @param mixed $value 变量的值
|
||||
* @return $this
|
||||
*/
|
||||
protected function assign($name, $value = '')
|
||||
{
|
||||
$this->view->assign($name, $value);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 视图过滤
|
||||
* @access protected
|
||||
* @param Callable $filter 过滤方法或闭包
|
||||
* @return $this
|
||||
*/
|
||||
protected function filter($filter)
|
||||
{
|
||||
$this->view->filter($filter);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化模板引擎
|
||||
* @access protected
|
||||
* @param array|string $engine 引擎参数
|
||||
* @return $this
|
||||
*/
|
||||
protected function engine($engine)
|
||||
{
|
||||
$this->view->engine($engine);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置验证失败后是否抛出异常
|
||||
* @access protected
|
||||
* @param bool $fail 是否抛出异常
|
||||
* @return $this
|
||||
*/
|
||||
protected function validateFailException($fail = true)
|
||||
{
|
||||
$this->failException = $fail;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证数据
|
||||
* @access protected
|
||||
* @param array $data 数据
|
||||
* @param string|array $validate 验证器名或者验证规则数组
|
||||
* @param array $message 提示信息
|
||||
* @param bool $batch 是否批量验证
|
||||
* @param mixed $callback 回调方法(闭包)
|
||||
* @return array|string|true
|
||||
* @throws ValidateException
|
||||
*/
|
||||
protected function validate($data, $validate, $message = [], $batch = false, $callback = null)
|
||||
{
|
||||
if (is_array($validate)) {
|
||||
$v = $this->app->validate();
|
||||
$v->rule($validate);
|
||||
} else {
|
||||
if (strpos($validate, '.')) {
|
||||
// 支持场景
|
||||
list($validate, $scene) = explode('.', $validate);
|
||||
}
|
||||
$v = $this->app->validate($validate);
|
||||
if (!empty($scene)) {
|
||||
$v->scene($scene);
|
||||
}
|
||||
}
|
||||
|
||||
// 是否批量验证
|
||||
if ($batch || $this->batchValidate) {
|
||||
$v->batch(true);
|
||||
}
|
||||
|
||||
if (is_array($message)) {
|
||||
$v->message($message);
|
||||
}
|
||||
|
||||
if ($callback && is_callable($callback)) {
|
||||
call_user_func_array($callback, [$v, &$data]);
|
||||
}
|
||||
|
||||
if (!$v->check($data)) {
|
||||
if ($this->failException) {
|
||||
throw new ValidateException($v->getError());
|
||||
} else {
|
||||
return $v->getError();
|
||||
}
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,262 @@
|
|||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace think;
|
||||
|
||||
class Cookie
|
||||
{
|
||||
/**
|
||||
* 配置参数
|
||||
* @var array
|
||||
*/
|
||||
protected $config = [
|
||||
// cookie 名称前缀
|
||||
'prefix' => '',
|
||||
// cookie 保存时间
|
||||
'expire' => 0,
|
||||
// cookie 保存路径
|
||||
'path' => '/',
|
||||
// cookie 有效域名
|
||||
'domain' => '',
|
||||
// cookie 启用安全传输
|
||||
'secure' => false,
|
||||
// httponly设置
|
||||
'httponly' => false,
|
||||
// 是否使用 setcookie
|
||||
'setcookie' => true,
|
||||
];
|
||||
|
||||
/**
|
||||
* 是否初始化
|
||||
* @var bool
|
||||
*/
|
||||
protected $init;
|
||||
|
||||
/**
|
||||
* Cookie初始化
|
||||
* @access public
|
||||
* @param array $config
|
||||
* @return void
|
||||
*/
|
||||
public function init(array $config = [])
|
||||
{
|
||||
if (empty($config)) {
|
||||
$config = Container::get('config')->pull('cookie');
|
||||
}
|
||||
|
||||
$this->config = array_merge($this->config, array_change_key_case($config));
|
||||
|
||||
if (!empty($this->config['httponly'])) {
|
||||
ini_set('session.cookie_httponly', 1);
|
||||
}
|
||||
|
||||
$this->init = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置或者获取cookie作用域(前缀)
|
||||
* @access public
|
||||
* @param string $prefix
|
||||
* @return string|void
|
||||
*/
|
||||
public function prefix($prefix = '')
|
||||
{
|
||||
if (empty($prefix)) {
|
||||
return $this->config['prefix'];
|
||||
}
|
||||
|
||||
$this->config['prefix'] = $prefix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cookie 设置、获取、删除
|
||||
*
|
||||
* @access public
|
||||
* @param string $name cookie名称
|
||||
* @param mixed $value cookie值
|
||||
* @param mixed $option 可选参数 可能会是 null|integer|string
|
||||
* @return void
|
||||
*/
|
||||
public function set($name, $value = '', $option = null)
|
||||
{
|
||||
!isset($this->init) && $this->init();
|
||||
|
||||
// 参数设置(会覆盖黙认设置)
|
||||
if (!is_null($option)) {
|
||||
if (is_numeric($option)) {
|
||||
$option = ['expire' => $option];
|
||||
} elseif (is_string($option)) {
|
||||
parse_str($option, $option);
|
||||
}
|
||||
|
||||
$config = array_merge($this->config, array_change_key_case($option));
|
||||
} else {
|
||||
$config = $this->config;
|
||||
}
|
||||
|
||||
$name = $config['prefix'] . $name;
|
||||
|
||||
// 设置cookie
|
||||
if (is_array($value)) {
|
||||
array_walk_recursive($value, [$this, 'jsonFormatProtect'], 'encode');
|
||||
$value = 'think:' . json_encode($value);
|
||||
}
|
||||
|
||||
$expire = !empty($config['expire']) ? $_SERVER['REQUEST_TIME'] + intval($config['expire']) : 0;
|
||||
|
||||
if ($config['setcookie']) {
|
||||
setcookie($name, $value, $expire, $config['path'], $config['domain'], $config['secure'], $config['httponly']);
|
||||
}
|
||||
|
||||
$_COOKIE[$name] = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* 永久保存Cookie数据
|
||||
* @access public
|
||||
* @param string $name cookie名称
|
||||
* @param mixed $value cookie值
|
||||
* @param mixed $option 可选参数 可能会是 null|integer|string
|
||||
* @return void
|
||||
*/
|
||||
public function forever($name, $value = '', $option = null)
|
||||
{
|
||||
if (is_null($option) || is_numeric($option)) {
|
||||
$option = [];
|
||||
}
|
||||
|
||||
$option['expire'] = 315360000;
|
||||
|
||||
$this->set($name, $value, $option);
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断Cookie数据
|
||||
* @access public
|
||||
* @param string $name cookie名称
|
||||
* @param string|null $prefix cookie前缀
|
||||
* @return bool
|
||||
*/
|
||||
public function has($name, $prefix = null)
|
||||
{
|
||||
!isset($this->init) && $this->init();
|
||||
|
||||
$prefix = !is_null($prefix) ? $prefix : $this->config['prefix'];
|
||||
$name = $prefix . $name;
|
||||
|
||||
return isset($_COOKIE[$name]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Cookie获取
|
||||
* @access public
|
||||
* @param string $name cookie名称 留空获取全部
|
||||
* @param string|null $prefix cookie前缀
|
||||
* @return mixed
|
||||
*/
|
||||
public function get($name = '', $prefix = null)
|
||||
{
|
||||
!isset($this->init) && $this->init();
|
||||
|
||||
$prefix = !is_null($prefix) ? $prefix : $this->config['prefix'];
|
||||
$key = $prefix . $name;
|
||||
|
||||
if ('' == $name) {
|
||||
if ($prefix) {
|
||||
$value = [];
|
||||
foreach ($_COOKIE as $k => $val) {
|
||||
if (0 === strpos($k, $prefix)) {
|
||||
$value[$k] = $val;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$value = $_COOKIE;
|
||||
}
|
||||
} elseif (isset($_COOKIE[$key])) {
|
||||
$value = $_COOKIE[$key];
|
||||
|
||||
if (0 === strpos($value, 'think:')) {
|
||||
$value = substr($value, 6);
|
||||
$value = json_decode($value, true);
|
||||
array_walk_recursive($value, [$this, 'jsonFormatProtect'], 'decode');
|
||||
}
|
||||
} else {
|
||||
$value = null;
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cookie删除
|
||||
* @access public
|
||||
* @param string $name cookie名称
|
||||
* @param string|null $prefix cookie前缀
|
||||
* @return void
|
||||
*/
|
||||
public function delete($name, $prefix = null)
|
||||
{
|
||||
!isset($this->init) && $this->init();
|
||||
|
||||
$config = $this->config;
|
||||
$prefix = !is_null($prefix) ? $prefix : $config['prefix'];
|
||||
$name = $prefix . $name;
|
||||
|
||||
if ($config['setcookie']) {
|
||||
setcookie($name, '', $_SERVER['REQUEST_TIME'] - 3600, $config['path'], $config['domain'], $config['secure'], $config['httponly']);
|
||||
}
|
||||
|
||||
// 删除指定cookie
|
||||
unset($_COOKIE[$name]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Cookie清空
|
||||
* @access public
|
||||
* @param string|null $prefix cookie前缀
|
||||
* @return void
|
||||
*/
|
||||
public function clear($prefix = null)
|
||||
{
|
||||
// 清除指定前缀的所有cookie
|
||||
if (empty($_COOKIE)) {
|
||||
return;
|
||||
}
|
||||
|
||||
!isset($this->init) && $this->init();
|
||||
|
||||
// 要删除的cookie前缀,不指定则删除config设置的指定前缀
|
||||
$config = $this->config;
|
||||
$prefix = !is_null($prefix) ? $prefix : $config['prefix'];
|
||||
|
||||
if ($prefix) {
|
||||
// 如果前缀为空字符串将不作处理直接返回
|
||||
foreach ($_COOKIE as $key => $val) {
|
||||
if (0 === strpos($key, $prefix)) {
|
||||
if ($config['setcookie']) {
|
||||
setcookie($key, '', $_SERVER['REQUEST_TIME'] - 3600, $config['path'], $config['domain'], $config['secure'], $config['httponly']);
|
||||
}
|
||||
unset($_COOKIE[$key]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
private function jsonFormatProtect(&$val, $key, $type = 'encode')
|
||||
{
|
||||
if (!empty($val) && true !== $val) {
|
||||
$val = 'decode' == $type ? urldecode($val) : urlencode($val);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace think;
|
||||
|
||||
/**
|
||||
* Class Db
|
||||
* @package think
|
||||
* @method \think\db\Query table(string $table) static 指定数据表(含前缀)
|
||||
* @method \think\db\Query name(string $name) static 指定数据表(不含前缀)
|
||||
* @method \think\db\Query where(mixed $field, string $op = null, mixed $condition = null) static 查询条件
|
||||
* @method \think\db\Query join(mixed $join, mixed $condition = null, string $type = 'INNER') static JOIN查询
|
||||
* @method \think\db\Query view(mixed $join, mixed $field = null, mixed $on = null, string $type = 'INNER') static 视图查询
|
||||
* @method \think\db\Query union(mixed $union, boolean $all = false) static UNION查询
|
||||
* @method \think\db\Query limit(mixed $offset, integer $length = null) static 查询LIMIT
|
||||
* @method \think\db\Query order(mixed $field, string $order = null) static 查询ORDER
|
||||
* @method \think\db\Query cache(mixed $key = null , integer $expire = null) static 设置查询缓存
|
||||
* @method mixed value(string $field) static 获取某个字段的值
|
||||
* @method array column(string $field, string $key = '') static 获取某个列的值
|
||||
* @method mixed find(mixed $data = null) static 查询单个记录
|
||||
* @method mixed select(mixed $data = null) static 查询多个记录
|
||||
* @method integer insert(array $data, boolean $replace = false, boolean $getLastInsID = false, string $sequence = null) static 插入一条记录
|
||||
* @method integer insertGetId(array $data, boolean $replace = false, string $sequence = null) static 插入一条记录并返回自增ID
|
||||
* @method integer insertAll(array $dataSet) static 插入多条记录
|
||||
* @method integer update(array $data) static 更新记录
|
||||
* @method integer delete(mixed $data = null) static 删除记录
|
||||
* @method boolean chunk(integer $count, callable $callback, string $column = null) static 分块获取数据
|
||||
* @method \Generator cursor(mixed $data = null) static 使用游标查找记录
|
||||
* @method mixed query(string $sql, array $bind = [], boolean $master = false, bool $pdo = false) static SQL查询
|
||||
* @method integer execute(string $sql, array $bind = [], boolean $fetch = false, boolean $getLastInsID = false, string $sequence = null) static SQL执行
|
||||
* @method \think\Paginator paginate(integer $listRows = 15, mixed $simple = null, array $config = []) static 分页查询
|
||||
* @method mixed transaction(callable $callback) static 执行数据库事务
|
||||
* @method void startTrans() static 启动事务
|
||||
* @method void commit() static 用于非自动提交状态下面的查询提交
|
||||
* @method void rollback() static 事务回滚
|
||||
* @method boolean batchQuery(array $sqlArray) static 批处理执行SQL语句
|
||||
* @method string getLastInsID($sequence = null) static 获取最近插入的ID
|
||||
*/
|
||||
class Db
|
||||
{
|
||||
/**
|
||||
* 查询次数
|
||||
* @var integer
|
||||
*/
|
||||
public static $queryTimes = 0;
|
||||
|
||||
/**
|
||||
* 执行次数
|
||||
* @var integer
|
||||
*/
|
||||
public static $executeTimes = 0;
|
||||
|
||||
public static function __callStatic($method, $args)
|
||||
{
|
||||
$class = Container::get('config')->get('database.query') ?: '\\think\\db\\Query';
|
||||
|
||||
$query = new $class();
|
||||
|
||||
return call_user_func_array([$query, $method], $args);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,259 @@
|
|||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace think;
|
||||
|
||||
use think\exception\ClassNotFoundException;
|
||||
use think\model\Collection as ModelCollection;
|
||||
use think\response\Redirect;
|
||||
|
||||
class Debug
|
||||
{
|
||||
/**
|
||||
* 区间时间信息
|
||||
* @var array
|
||||
*/
|
||||
protected $info = [];
|
||||
|
||||
/**
|
||||
* 区间内存信息
|
||||
* @var array
|
||||
*/
|
||||
protected $mem = [];
|
||||
|
||||
/**
|
||||
* 应用对象
|
||||
* @var App
|
||||
*/
|
||||
protected $app;
|
||||
|
||||
public function __construct(App $app)
|
||||
{
|
||||
$this->app = $app;
|
||||
}
|
||||
|
||||
/**
|
||||
* 记录时间(微秒)和内存使用情况
|
||||
* @access public
|
||||
* @param string $name 标记位置
|
||||
* @param mixed $value 标记值 留空则取当前 time 表示仅记录时间 否则同时记录时间和内存
|
||||
* @return void
|
||||
*/
|
||||
public function remark($name, $value = '')
|
||||
{
|
||||
// 记录时间和内存使用
|
||||
$this->info[$name] = is_float($value) ? $value : microtime(true);
|
||||
|
||||
if ('time' != $value) {
|
||||
$this->mem['mem'][$name] = is_float($value) ? $value : memory_get_usage();
|
||||
$this->mem['peak'][$name] = memory_get_peak_usage();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 统计某个区间的时间(微秒)使用情况
|
||||
* @access public
|
||||
* @param string $start 开始标签
|
||||
* @param string $end 结束标签
|
||||
* @param integer|string $dec 小数位
|
||||
* @return integer
|
||||
*/
|
||||
public function getRangeTime($start, $end, $dec = 6)
|
||||
{
|
||||
if (!isset($this->info[$end])) {
|
||||
$this->info[$end] = microtime(true);
|
||||
}
|
||||
|
||||
return number_format(($this->info[$end] - $this->info[$start]), $dec);
|
||||
}
|
||||
|
||||
/**
|
||||
* 统计从开始到统计时的时间(微秒)使用情况
|
||||
* @access public
|
||||
* @param integer|string $dec 小数位
|
||||
* @return integer
|
||||
*/
|
||||
public function getUseTime($dec = 6)
|
||||
{
|
||||
return number_format((microtime(true) - $this->app->getBeginTime()), $dec);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前访问的吞吐率情况
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function getThroughputRate()
|
||||
{
|
||||
return number_format(1 / $this->getUseTime(), 2) . 'req/s';
|
||||
}
|
||||
|
||||
/**
|
||||
* 记录区间的内存使用情况
|
||||
* @access public
|
||||
* @param string $start 开始标签
|
||||
* @param string $end 结束标签
|
||||
* @param integer|string $dec 小数位
|
||||
* @return string
|
||||
*/
|
||||
public function getRangeMem($start, $end, $dec = 2)
|
||||
{
|
||||
if (!isset($this->mem['mem'][$end])) {
|
||||
$this->mem['mem'][$end] = memory_get_usage();
|
||||
}
|
||||
|
||||
$size = $this->mem['mem'][$end] - $this->mem['mem'][$start];
|
||||
$a = ['B', 'KB', 'MB', 'GB', 'TB'];
|
||||
$pos = 0;
|
||||
|
||||
while ($size >= 1024) {
|
||||
$size /= 1024;
|
||||
$pos++;
|
||||
}
|
||||
|
||||
return round($size, $dec) . " " . $a[$pos];
|
||||
}
|
||||
|
||||
/**
|
||||
* 统计从开始到统计时的内存使用情况
|
||||
* @access public
|
||||
* @param integer|string $dec 小数位
|
||||
* @return string
|
||||
*/
|
||||
public function getUseMem($dec = 2)
|
||||
{
|
||||
$size = memory_get_usage() - $this->app->getBeginMem();
|
||||
$a = ['B', 'KB', 'MB', 'GB', 'TB'];
|
||||
$pos = 0;
|
||||
|
||||
while ($size >= 1024) {
|
||||
$size /= 1024;
|
||||
$pos++;
|
||||
}
|
||||
|
||||
return round($size, $dec) . " " . $a[$pos];
|
||||
}
|
||||
|
||||
/**
|
||||
* 统计区间的内存峰值情况
|
||||
* @access public
|
||||
* @param string $start 开始标签
|
||||
* @param string $end 结束标签
|
||||
* @param integer|string $dec 小数位
|
||||
* @return string
|
||||
*/
|
||||
public function getMemPeak($start, $end, $dec = 2)
|
||||
{
|
||||
if (!isset($this->mem['peak'][$end])) {
|
||||
$this->mem['peak'][$end] = memory_get_peak_usage();
|
||||
}
|
||||
|
||||
$size = $this->mem['peak'][$end] - $this->mem['peak'][$start];
|
||||
$a = ['B', 'KB', 'MB', 'GB', 'TB'];
|
||||
$pos = 0;
|
||||
|
||||
while ($size >= 1024) {
|
||||
$size /= 1024;
|
||||
$pos++;
|
||||
}
|
||||
|
||||
return round($size, $dec) . " " . $a[$pos];
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文件加载信息
|
||||
* @access public
|
||||
* @param bool $detail 是否显示详细
|
||||
* @return integer|array
|
||||
*/
|
||||
public function getFile($detail = false)
|
||||
{
|
||||
if ($detail) {
|
||||
$files = get_included_files();
|
||||
$info = [];
|
||||
|
||||
foreach ($files as $key => $file) {
|
||||
$info[] = $file . ' ( ' . number_format(filesize($file) / 1024, 2) . ' KB )';
|
||||
}
|
||||
|
||||
return $info;
|
||||
}
|
||||
|
||||
return count(get_included_files());
|
||||
}
|
||||
|
||||
/**
|
||||
* 浏览器友好的变量输出
|
||||
* @access public
|
||||
* @param mixed $var 变量
|
||||
* @param boolean $echo 是否输出 默认为true 如果为false 则返回输出字符串
|
||||
* @param string $label 标签 默认为空
|
||||
* @param integer $flags htmlspecialchars flags
|
||||
* @return void|string
|
||||
*/
|
||||
public function dump($var, $echo = true, $label = null, $flags = ENT_SUBSTITUTE)
|
||||
{
|
||||
$label = (null === $label) ? '' : rtrim($label) . ':';
|
||||
if ($var instanceof Model || $var instanceof ModelCollection) {
|
||||
$var = $var->toArray();
|
||||
}
|
||||
|
||||
ob_start();
|
||||
var_dump($var);
|
||||
|
||||
$output = ob_get_clean();
|
||||
$output = preg_replace('/\]\=\>\n(\s+)/m', '] => ', $output);
|
||||
|
||||
if (PHP_SAPI == 'cli') {
|
||||
$output = PHP_EOL . $label . $output . PHP_EOL;
|
||||
} else {
|
||||
if (!extension_loaded('xdebug')) {
|
||||
$output = htmlspecialchars($output, $flags);
|
||||
}
|
||||
$output = '<pre>' . $label . $output . '</pre>';
|
||||
}
|
||||
if ($echo) {
|
||||
echo($output);
|
||||
return;
|
||||
} else {
|
||||
return $output;
|
||||
}
|
||||
}
|
||||
|
||||
public function inject(Response $response, &$content)
|
||||
{
|
||||
$config = $this->app['config']->pull('trace');
|
||||
$type = isset($config['type']) ? $config['type'] : 'Html';
|
||||
$class = false !== strpos($type, '\\') ? $type : '\\think\\debug\\' . ucwords($type);
|
||||
unset($config['type']);
|
||||
|
||||
if (class_exists($class)) {
|
||||
$trace = new $class($config);
|
||||
} else {
|
||||
throw new ClassNotFoundException('class not exists:' . $class, $class);
|
||||
}
|
||||
|
||||
if ($response instanceof Redirect) {
|
||||
//TODO 记录
|
||||
} else {
|
||||
$output = $trace->output($response, $this->app['log']->getLog());
|
||||
if (is_string($output)) {
|
||||
// trace调试信息注入
|
||||
$pos = strripos($content, '</body>');
|
||||
if (false !== $pos) {
|
||||
$content = substr($content, 0, $pos) . $output . substr($content, $pos);
|
||||
} else {
|
||||
$content = $content . $output;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,108 @@
|
|||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace think;
|
||||
|
||||
class Env
|
||||
{
|
||||
/**
|
||||
* 环境变量数据
|
||||
* @var array
|
||||
*/
|
||||
protected $data = [];
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->data = $_ENV;
|
||||
}
|
||||
|
||||
/**
|
||||
* 读取环境变量定义文件
|
||||
* @access public
|
||||
* @param string $file 环境变量定义文件
|
||||
* @return void
|
||||
*/
|
||||
public function load($file)
|
||||
{
|
||||
$env = parse_ini_file($file, true);
|
||||
$this->set($env);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取环境变量值
|
||||
* @access public
|
||||
* @param string $name 环境变量名
|
||||
* @param mixed $default 默认值
|
||||
* @return mixed
|
||||
*/
|
||||
public function get($name = null, $default = null)
|
||||
{
|
||||
if (is_null($name)) {
|
||||
return $this->data;
|
||||
}
|
||||
//替换字符内的.为_ 然后将字符串转为大写
|
||||
$name = strtoupper(str_replace('.', '_', $name));
|
||||
|
||||
if (isset($this->data[$name])) {
|
||||
return $this->data[$name];
|
||||
}
|
||||
|
||||
return $this->getEnv($name, $default);
|
||||
}
|
||||
|
||||
protected function getEnv($name, $default = null)
|
||||
{
|
||||
$result = getenv('PHP_' . $name);
|
||||
|
||||
if (false !== $result) {
|
||||
if ('false' === $result) {
|
||||
$result = false;
|
||||
} elseif ('true' === $result) {
|
||||
$result = true;
|
||||
}
|
||||
|
||||
if (!isset($this->data[$name])) {
|
||||
$this->data[$name] = $result;
|
||||
}
|
||||
|
||||
return $result;
|
||||
} else {
|
||||
return $default;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置环境变量值
|
||||
* @access public
|
||||
* @param string|array $env 环境变量
|
||||
* @param mixed $value 值
|
||||
* @return void
|
||||
*/
|
||||
public function set($env, $value = null)
|
||||
{
|
||||
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) {
|
||||
$this->data[$key . '_' . strtoupper($k)] = $v;
|
||||
}
|
||||
} else {
|
||||
$this->data[$key] = $val;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$name = strtoupper(str_replace('.', '_', $env));
|
||||
|
||||
$this->data[$name] = $value;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,128 @@
|
|||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: 麦当苗儿 <zuojiazi@vip.qq.com> <http://zjzit.cn>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace think;
|
||||
|
||||
use think\console\Output as ConsoleOutput;
|
||||
use think\exception\ErrorException;
|
||||
use think\exception\Handle;
|
||||
use think\exception\ThrowableError;
|
||||
|
||||
class Error
|
||||
{
|
||||
/**
|
||||
* 注册异常处理
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public static function register()
|
||||
{
|
||||
error_reporting(E_ALL);
|
||||
set_error_handler([__CLASS__, 'appError']);
|
||||
set_exception_handler([__CLASS__, 'appException']);
|
||||
register_shutdown_function([__CLASS__, 'appShutdown']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Exception Handler
|
||||
* @access public
|
||||
* @param \Exception|\Throwable $e
|
||||
*/
|
||||
public static function appException($e)
|
||||
{
|
||||
if (!$e instanceof \Exception) {
|
||||
$e = new ThrowableError($e);
|
||||
}
|
||||
|
||||
self::getExceptionHandler()->report($e);
|
||||
|
||||
if (PHP_SAPI == 'cli') {
|
||||
self::getExceptionHandler()->renderForConsole(new ConsoleOutput, $e);
|
||||
} else {
|
||||
self::getExceptionHandler()->render($e)->send();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Error Handler
|
||||
* @access public
|
||||
* @param integer $errno 错误编号
|
||||
* @param integer $errstr 详细错误信息
|
||||
* @param string $errfile 出错的文件
|
||||
* @param integer $errline 出错行号
|
||||
* @throws ErrorException
|
||||
*/
|
||||
public static function appError($errno, $errstr, $errfile = '', $errline = 0)
|
||||
{
|
||||
$exception = new ErrorException($errno, $errstr, $errfile, $errline);
|
||||
if (error_reporting() & $errno) {
|
||||
// 将错误信息托管至 think\exception\ErrorException
|
||||
throw $exception;
|
||||
} else {
|
||||
self::getExceptionHandler()->report($exception);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Shutdown Handler
|
||||
* @access public
|
||||
*/
|
||||
public static function appShutdown()
|
||||
{
|
||||
if (!is_null($error = error_get_last()) && self::isFatal($error['type'])) {
|
||||
// 将错误信息托管至think\ErrorException
|
||||
$exception = new ErrorException($error['type'], $error['message'], $error['file'], $error['line']);
|
||||
|
||||
self::appException($exception);
|
||||
}
|
||||
|
||||
// 写入日志
|
||||
Container::get('log')->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* 确定错误类型是否致命
|
||||
*
|
||||
* @access protected
|
||||
* @param int $type
|
||||
* @return bool
|
||||
*/
|
||||
protected static function isFatal($type)
|
||||
{
|
||||
return in_array($type, [E_ERROR, E_CORE_ERROR, E_COMPILE_ERROR, E_PARSE]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an instance of the exception handler.
|
||||
*
|
||||
* @access public
|
||||
* @return Handle
|
||||
*/
|
||||
public static function getExceptionHandler()
|
||||
{
|
||||
static $handle;
|
||||
|
||||
if (!$handle) {
|
||||
// 异常处理handle
|
||||
$class = Container::get('config')->get('exception_handle');
|
||||
if ($class && is_string($class) && class_exists($class) && is_subclass_of($class, "\\think\\exception\\Handle")) {
|
||||
$handle = new $class;
|
||||
} else {
|
||||
$handle = new Handle;
|
||||
if ($class instanceof \Closure) {
|
||||
$handle->setRender($class);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $handle;
|
||||
}
|
||||
}
|
|
@ -2,21 +2,18 @@
|
|||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2019 http://thinkphp.cn All rights reserved.
|
||||
// | Copyright (c) 2006~2018 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;
|
||||
|
||||
/**
|
||||
* 异常基础类
|
||||
*/
|
||||
class Exception extends \Exception
|
||||
{
|
||||
|
||||
/**
|
||||
* 保存异常页面显示的额外Debug数据
|
||||
* @var array
|
||||
|
@ -40,7 +37,7 @@ class Exception extends \Exception
|
|||
* @param string $label 数据分类,用于异常页面显示
|
||||
* @param array $data 需要显示的数据,必须为关联数组
|
||||
*/
|
||||
final protected function setData(string $label, array $data)
|
||||
final protected function setData($label, array $data)
|
||||
{
|
||||
$this->data[$label] = $data;
|
||||
}
|
|
@ -2,42 +2,68 @@
|
|||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2019 http://thinkphp.cn All rights reserved.
|
||||
// | Copyright (c) 2006~2018 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 array
|
||||
*/
|
||||
protected static $bind = [];
|
||||
|
||||
/**
|
||||
* 始终创建新的对象实例
|
||||
* @var bool
|
||||
*/
|
||||
protected static $alwaysNewInstance;
|
||||
|
||||
/**
|
||||
* 绑定类的静态代理
|
||||
* @static
|
||||
* @access public
|
||||
* @param string|array $name 类标识
|
||||
* @param string $class 类名
|
||||
* @return object
|
||||
*/
|
||||
public static function bind($name, $class = null)
|
||||
{
|
||||
if (__CLASS__ != static::class) {
|
||||
return self::__callStatic('bind', func_get_args());
|
||||
}
|
||||
|
||||
if (is_array($name)) {
|
||||
self::$bind = array_merge(self::$bind, $name);
|
||||
} else {
|
||||
self::$bind[$name] = $class;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建Facade实例
|
||||
* @static
|
||||
* @access protected
|
||||
* @param string $class 类名或标识
|
||||
* @param array $args 变量
|
||||
* @param bool $newInstance 是否每次创建新的实例
|
||||
* @param string $class 类名或标识
|
||||
* @param array $args 变量
|
||||
* @param bool $newInstance 是否每次创建新的实例
|
||||
* @return object
|
||||
*/
|
||||
protected static function createFacade(string $class = '', array $args = [], bool $newInstance = false)
|
||||
protected static function createFacade($class = '', $args = [], $newInstance = false)
|
||||
{
|
||||
$class = $class ?: static::class;
|
||||
|
||||
$class = $class ?: static::class;
|
||||
$facadeClass = static::getFacadeClass();
|
||||
|
||||
if ($facadeClass) {
|
||||
$class = $facadeClass;
|
||||
} elseif (isset(self::$bind[$class])) {
|
||||
$class = self::$bind[$class];
|
||||
}
|
||||
|
||||
if (static::$alwaysNewInstance) {
|
||||
|
@ -62,20 +88,18 @@ class Facade
|
|||
*/
|
||||
public static function instance(...$args)
|
||||
{
|
||||
if (__CLASS__ != static::class) {
|
||||
return self::createFacade('', $args);
|
||||
}
|
||||
return self::createFacade('', $args);
|
||||
}
|
||||
|
||||
/**
|
||||
* 调用类的实例
|
||||
* @access public
|
||||
* @param string $class 类名或者标识
|
||||
* @param array|true $args 变量
|
||||
* @param bool $newInstance 是否每次创建新的实例
|
||||
* @param string $class 类名或者标识
|
||||
* @param array|true $args 变量
|
||||
* @param bool $newInstance 是否每次创建新的实例
|
||||
* @return object
|
||||
*/
|
||||
public static function make(string $class, $args = [], $newInstance = false)
|
||||
public static function make($class, $args = [], $newInstance = false)
|
||||
{
|
||||
if (__CLASS__ != static::class) {
|
||||
return self::__callStatic('make', func_get_args());
|
|
@ -0,0 +1,494 @@
|
|||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace think;
|
||||
|
||||
use SplFileObject;
|
||||
|
||||
class File extends SplFileObject
|
||||
{
|
||||
/**
|
||||
* 错误信息
|
||||
* @var string
|
||||
*/
|
||||
private $error = '';
|
||||
|
||||
/**
|
||||
* 当前完整文件名
|
||||
* @var string
|
||||
*/
|
||||
protected $filename;
|
||||
|
||||
/**
|
||||
* 上传文件名
|
||||
* @var string
|
||||
*/
|
||||
protected $saveName;
|
||||
|
||||
/**
|
||||
* 上传文件命名规则
|
||||
* @var string
|
||||
*/
|
||||
protected $rule = 'date';
|
||||
|
||||
/**
|
||||
* 上传文件验证规则
|
||||
* @var array
|
||||
*/
|
||||
protected $validate = [];
|
||||
|
||||
/**
|
||||
* 是否单元测试
|
||||
* @var bool
|
||||
*/
|
||||
protected $isTest;
|
||||
|
||||
/**
|
||||
* 上传文件信息
|
||||
* @var array
|
||||
*/
|
||||
protected $info = [];
|
||||
|
||||
/**
|
||||
* 文件hash规则
|
||||
* @var array
|
||||
*/
|
||||
protected $hash = [];
|
||||
|
||||
public function __construct($filename, $mode = 'r')
|
||||
{
|
||||
parent::__construct($filename, $mode);
|
||||
|
||||
$this->filename = $this->getRealPath() ?: $this->getPathname();
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否测试
|
||||
* @access public
|
||||
* @param bool $test 是否测试
|
||||
* @return $this
|
||||
*/
|
||||
public function isTest($test = false)
|
||||
{
|
||||
$this->isTest = $test;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置上传信息
|
||||
* @access public
|
||||
* @param array $info 上传文件信息
|
||||
* @return $this
|
||||
*/
|
||||
public function setUploadInfo($info)
|
||||
{
|
||||
$this->info = $info;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取上传文件的信息
|
||||
* @access public
|
||||
* @param string $name
|
||||
* @return array|string
|
||||
*/
|
||||
public function getInfo($name = '')
|
||||
{
|
||||
return isset($this->info[$name]) ? $this->info[$name] : $this->info;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取上传文件的文件名
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function getSaveName()
|
||||
{
|
||||
return $this->saveName;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置上传文件的保存文件名
|
||||
* @access public
|
||||
* @param string $saveName
|
||||
* @return $this
|
||||
*/
|
||||
public function setSaveName($saveName)
|
||||
{
|
||||
$this->saveName = $saveName;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文件的哈希散列值
|
||||
* @access public
|
||||
* @param string $type
|
||||
* @return string
|
||||
*/
|
||||
public function hash($type = 'sha1')
|
||||
{
|
||||
if (!isset($this->hash[$type])) {
|
||||
$this->hash[$type] = hash_file($type, $this->filename);
|
||||
}
|
||||
|
||||
return $this->hash[$type];
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查目录是否可写
|
||||
* @access public
|
||||
* @param string $path 目录
|
||||
* @return boolean
|
||||
*/
|
||||
protected function checkPath($path)
|
||||
{
|
||||
if (is_dir($path)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (mkdir($path, 0755, true)) {
|
||||
return true;
|
||||
} else {
|
||||
$this->error = ['directory {:path} creation failed', ['path' => $path]];
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文件类型信息
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function getMime()
|
||||
{
|
||||
$finfo = finfo_open(FILEINFO_MIME_TYPE);
|
||||
|
||||
return finfo_file($finfo, $this->filename);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置文件的命名规则
|
||||
* @access public
|
||||
* @param string $rule 文件命名规则
|
||||
* @return $this
|
||||
*/
|
||||
public function rule($rule)
|
||||
{
|
||||
$this->rule = $rule;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置上传文件的验证规则
|
||||
* @access public
|
||||
* @param array $rule 验证规则
|
||||
* @return $this
|
||||
*/
|
||||
public function validate($rule = [])
|
||||
{
|
||||
$this->validate = $rule;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检测是否合法的上传文件
|
||||
* @access public
|
||||
* @return bool
|
||||
*/
|
||||
public function isValid()
|
||||
{
|
||||
if ($this->isTest) {
|
||||
return is_file($this->filename);
|
||||
}
|
||||
|
||||
return is_uploaded_file($this->filename);
|
||||
}
|
||||
|
||||
/**
|
||||
* 检测上传文件
|
||||
* @access public
|
||||
* @param array $rule 验证规则
|
||||
* @return bool
|
||||
*/
|
||||
public function check($rule = [])
|
||||
{
|
||||
$rule = $rule ?: $this->validate;
|
||||
|
||||
/* 检查文件大小 */
|
||||
if (isset($rule['size']) && !$this->checkSize($rule['size'])) {
|
||||
$this->error = 'filesize not match';
|
||||
return false;
|
||||
}
|
||||
|
||||
/* 检查文件Mime类型 */
|
||||
if (isset($rule['type']) && !$this->checkMime($rule['type'])) {
|
||||
$this->error = 'mimetype to upload is not allowed';
|
||||
return false;
|
||||
}
|
||||
|
||||
/* 检查文件后缀 */
|
||||
if (isset($rule['ext']) && !$this->checkExt($rule['ext'])) {
|
||||
$this->error = 'extensions to upload is not allowed';
|
||||
return false;
|
||||
}
|
||||
|
||||
/* 检查图像文件 */
|
||||
if (!$this->checkImg()) {
|
||||
$this->error = 'illegal image files';
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检测上传文件后缀
|
||||
* @access public
|
||||
* @param array|string $ext 允许后缀
|
||||
* @return bool
|
||||
*/
|
||||
public function checkExt($ext)
|
||||
{
|
||||
if (is_string($ext)) {
|
||||
$ext = explode(',', $ext);
|
||||
}
|
||||
|
||||
$extension = strtolower(pathinfo($this->getInfo('name'), PATHINFO_EXTENSION));
|
||||
|
||||
if (!in_array($extension, $ext)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检测图像文件
|
||||
* @access public
|
||||
* @return bool
|
||||
*/
|
||||
public function checkImg()
|
||||
{
|
||||
$extension = strtolower(pathinfo($this->getInfo('name'), PATHINFO_EXTENSION));
|
||||
|
||||
/* 对图像文件进行严格检测 */
|
||||
if (in_array($extension, ['gif', 'jpg', 'jpeg', 'bmp', 'png', 'swf']) && !in_array($this->getImageType($this->filename), [1, 2, 3, 4, 6, 13])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// 判断图像类型
|
||||
protected function getImageType($image)
|
||||
{
|
||||
if (function_exists('exif_imagetype')) {
|
||||
return exif_imagetype($image);
|
||||
} else {
|
||||
try {
|
||||
$info = getimagesize($image);
|
||||
return $info ? $info[2] : false;
|
||||
} catch (\Exception $e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检测上传文件大小
|
||||
* @access public
|
||||
* @param integer $size 最大大小
|
||||
* @return bool
|
||||
*/
|
||||
public function checkSize($size)
|
||||
{
|
||||
if ($this->getSize() > $size) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检测上传文件类型
|
||||
* @access public
|
||||
* @param array|string $mime 允许类型
|
||||
* @return bool
|
||||
*/
|
||||
public function checkMime($mime)
|
||||
{
|
||||
if (is_string($mime)) {
|
||||
$mime = explode(',', $mime);
|
||||
}
|
||||
|
||||
if (!in_array(strtolower($this->getMime()), $mime)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 移动文件
|
||||
* @access public
|
||||
* @param string $path 保存路径
|
||||
* @param string|bool $savename 保存的文件名 默认自动生成
|
||||
* @param boolean $replace 同名文件是否覆盖
|
||||
* @return false|File false-失败 否则返回File实例
|
||||
*/
|
||||
public function move($path, $savename = true, $replace = true)
|
||||
{
|
||||
// 文件上传失败,捕获错误代码
|
||||
if (!empty($this->info['error'])) {
|
||||
$this->error($this->info['error']);
|
||||
return false;
|
||||
}
|
||||
|
||||
// 检测合法性
|
||||
if (!$this->isValid()) {
|
||||
$this->error = 'upload illegal files';
|
||||
return false;
|
||||
}
|
||||
|
||||
// 验证上传
|
||||
if (!$this->check()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$path = rtrim($path, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR;
|
||||
// 文件保存命名规则
|
||||
$saveName = $this->buildSaveName($savename);
|
||||
$filename = $path . $saveName;
|
||||
|
||||
// 检测目录
|
||||
if (false === $this->checkPath(dirname($filename))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* 不覆盖同名文件 */
|
||||
if (!$replace && is_file($filename)) {
|
||||
$this->error = ['has the same filename: {:filename}', ['filename' => $filename]];
|
||||
return false;
|
||||
}
|
||||
|
||||
/* 移动文件 */
|
||||
if ($this->isTest) {
|
||||
rename($this->filename, $filename);
|
||||
} elseif (!move_uploaded_file($this->filename, $filename)) {
|
||||
$this->error = 'upload write error';
|
||||
return false;
|
||||
}
|
||||
|
||||
// 返回 File对象实例
|
||||
$file = new self($filename);
|
||||
$file->setSaveName($saveName);
|
||||
$file->setUploadInfo($this->info);
|
||||
|
||||
return $file;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取保存文件名
|
||||
* @access public
|
||||
* @param string|bool $savename 保存的文件名 默认自动生成
|
||||
* @return string
|
||||
*/
|
||||
protected function buildSaveName($savename)
|
||||
{
|
||||
if (true === $savename) {
|
||||
// 自动生成文件名
|
||||
if ($this->rule instanceof \Closure) {
|
||||
$savename = call_user_func_array($this->rule, [$this]);
|
||||
} else {
|
||||
switch ($this->rule) {
|
||||
case 'date':
|
||||
$savename = date('Ymd') . '/' . md5(microtime(true));
|
||||
break;
|
||||
default:
|
||||
if (in_array($this->rule, hash_algos())) {
|
||||
$hash = $this->hash($this->rule);
|
||||
$savename = substr($hash, 0, 2) . '/' . substr($hash, 2);
|
||||
} elseif (is_callable($this->rule)) {
|
||||
$savename = call_user_func($this->rule);
|
||||
} else {
|
||||
$savename = date('Ymd') . '/' . md5(microtime(true));
|
||||
}
|
||||
}
|
||||
}
|
||||
} elseif ('' === $savename || false === $savename) {
|
||||
$savename = $this->getInfo('name');
|
||||
}
|
||||
|
||||
if (!strpos($savename, '.')) {
|
||||
$savename .= '.' . pathinfo($this->getInfo('name'), PATHINFO_EXTENSION);
|
||||
}
|
||||
|
||||
return $savename;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取错误代码信息
|
||||
* @access public
|
||||
* @param int $errorNo 错误号
|
||||
*/
|
||||
private function error($errorNo)
|
||||
{
|
||||
switch ($errorNo) {
|
||||
case 1:
|
||||
case 2:
|
||||
$this->error = 'upload File size exceeds the maximum value';
|
||||
break;
|
||||
case 3:
|
||||
$this->error = 'only the portion of file is uploaded';
|
||||
break;
|
||||
case 4:
|
||||
$this->error = 'no file to uploaded';
|
||||
break;
|
||||
case 6:
|
||||
$this->error = 'upload temp dir not found';
|
||||
break;
|
||||
case 7:
|
||||
$this->error = 'file write error';
|
||||
break;
|
||||
default:
|
||||
$this->error = 'unknown upload error';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取错误信息(支持多语言)
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function getError()
|
||||
{
|
||||
$lang = Container::get('lang');
|
||||
|
||||
if (is_array($this->error)) {
|
||||
list($msg, $vars) = $this->error;
|
||||
} else {
|
||||
$msg = $this->error;
|
||||
$vars = [];
|
||||
}
|
||||
|
||||
return $lang->has($msg) ? $lang->get($msg, $vars) : $msg;
|
||||
}
|
||||
|
||||
public function __call($method, $args)
|
||||
{
|
||||
return $this->hash($method);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,250 @@
|
|||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace think;
|
||||
|
||||
class Hook
|
||||
{
|
||||
/**
|
||||
* 钩子行为定义
|
||||
* @var array
|
||||
*/
|
||||
private $tags = [];
|
||||
|
||||
/**
|
||||
* 绑定行为列表
|
||||
* @var array
|
||||
*/
|
||||
protected $bind = [];
|
||||
|
||||
/**
|
||||
* 入口方法名称
|
||||
* @var string
|
||||
*/
|
||||
private static $portal = 'run';
|
||||
|
||||
/**
|
||||
* 指定入口方法名称
|
||||
* @access public
|
||||
* @param string $name 方法名
|
||||
* @return $this
|
||||
*/
|
||||
public function portal($name)
|
||||
{
|
||||
self::$portal = $name;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 指定行为标识 便于调用
|
||||
* @access public
|
||||
* @param string|array $name 行为标识
|
||||
* @param mixed $behavior 行为
|
||||
* @return $this
|
||||
*/
|
||||
public function alias($name, $behavior = null)
|
||||
{
|
||||
if (is_array($name)) {
|
||||
$this->bind = array_merge($this->bind, $name);
|
||||
} else {
|
||||
$this->bind[$name] = $behavior;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 动态添加行为扩展到某个标签
|
||||
* @access public
|
||||
* @param string $tag 标签名称
|
||||
* @param mixed $behavior 行为名称
|
||||
* @param bool $first 是否放到开头执行
|
||||
* @return void
|
||||
*/
|
||||
public function add($tag, $behavior, $first = false)
|
||||
{
|
||||
// isset($this->tags[$tag]) 为空 后面执行 $this->tags[$tag] = [];
|
||||
// 值为空或者不存在则赋值为数组
|
||||
isset($this->tags[$tag]) || $this->tags[$tag] = [];
|
||||
// is_callable 检测参数是否为合法的可调用结构 可调用则返回 TRUE
|
||||
// $behavior 是数组且不可调用时执行
|
||||
if (is_array($behavior) && !is_callable($behavior)) {
|
||||
// 检查键名内是否包含 _overlay 不包含时执行
|
||||
if (!array_key_exists('_overlay', $behavior)) {
|
||||
//执行合并
|
||||
$this->tags[$tag] = array_merge($this->tags[$tag], $behavior);
|
||||
} else {
|
||||
//包含时执行注销
|
||||
unset($behavior['_overlay']);
|
||||
$this->tags[$tag] = $behavior;
|
||||
}
|
||||
//开头执行
|
||||
} elseif ($first) {
|
||||
//$behavior 插入到 $this->tags 数组内
|
||||
array_unshift($this->tags[$tag], $behavior);
|
||||
} else {
|
||||
$this->tags[$tag][] = $behavior;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量导入插件
|
||||
* @access public
|
||||
* @param array $tags 插件信息
|
||||
* @param bool $recursive 是否递归合并
|
||||
* @return void
|
||||
*/
|
||||
public function import(array $tags, $recursive = true)
|
||||
{
|
||||
if ($recursive) {
|
||||
foreach ($tags as $tag => $behavior) {
|
||||
//将插件信息添加
|
||||
$this->add($tag, $behavior);
|
||||
}
|
||||
} else {
|
||||
//数组合并
|
||||
$this->tags = $tags + $this->tags;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取插件信息
|
||||
* @access public
|
||||
* @param string $tag 插件位置 留空获取全部
|
||||
* @return array
|
||||
*/
|
||||
public function get($tag = '')
|
||||
{
|
||||
if (empty($tag)) {
|
||||
//获取全部的插件信息
|
||||
return $this->tags;
|
||||
} else {
|
||||
return array_key_exists($tag, $this->tags) ? $this->tags[$tag] : [];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 监听标签的行为
|
||||
* @access public
|
||||
* @param string $tag 标签名称
|
||||
* @param mixed $params 传入参数
|
||||
* @param bool $once 只获取一个有效返回值
|
||||
* @return mixed
|
||||
*/
|
||||
public function listen($tag, $params = null, $once = false)
|
||||
{
|
||||
// $results 用来存放返回的值
|
||||
$results = [];
|
||||
//获取这个钩子需要执行的所有代码
|
||||
$tags = $this->get($tag);
|
||||
|
||||
//若数组内有值,则循环
|
||||
foreach ($tags as $key => $name) {
|
||||
//根据值执行代码并获取返回值
|
||||
// $name 可理解为 需要执行的代码,或者类空间名,或者理解为执行方法
|
||||
// $tag 可理解为钩子名称
|
||||
// $params 需要传递的参数
|
||||
$results[$key] = $this->execTag($name, $tag, $params);
|
||||
if (false === $results[$key]) {
|
||||
// 如果返回false 则中断行为执行
|
||||
break;
|
||||
} elseif (!is_null($results[$key]) && $once) {
|
||||
//返回值 是 null 则返回 TRUE,
|
||||
//返回值 不为空,则只要一个有效值时跳出
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $once ? end($results) : $results;
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行行为
|
||||
* @access public
|
||||
* @param mixed $class 行为
|
||||
* @param mixed $params 参数
|
||||
* @return mixed
|
||||
*/
|
||||
public function exec($class, $params = null)
|
||||
{
|
||||
if ($class instanceof \Closure || is_array($class)) {
|
||||
$method = $class;
|
||||
} else {
|
||||
if (isset($this->bind[$class])) {
|
||||
$class = $this->bind[$class];
|
||||
}
|
||||
$method = [$class, self::$portal];
|
||||
}
|
||||
|
||||
return Container::getInstance()->invoke($method, [$params]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行某个标签的行为
|
||||
* @access protected
|
||||
* @param mixed $class 要执行的行为
|
||||
* @param string $tag 方法名(标签名)
|
||||
* @param mixed $params 参数
|
||||
* @return mixed
|
||||
*/
|
||||
protected function execTag($class, $tag = '', $params = null)
|
||||
{
|
||||
//返回app的实例化
|
||||
$app = Container::get('app');
|
||||
//是否为调试模式,开启调试模式则进行赋值
|
||||
$app->isDebug() && $app['debug']->remark('behavior_start', 'time');
|
||||
|
||||
// 字符串命名风格转换
|
||||
// 0 将Java风格转换为C的风格 1 将C风格转换为Java的风格,去掉下划线
|
||||
// $tag 可理解为钩子名称
|
||||
$method = Loader::parseName($tag, 1, false);
|
||||
|
||||
// instanceof 判断一个对象是否是某个类的实例
|
||||
if ($class instanceof \Closure) {
|
||||
// 闭包调用
|
||||
$call = $class;
|
||||
$class = 'Closure'; //调试才使用此值
|
||||
} elseif (strpos($class, '::')) {
|
||||
// 静态调用
|
||||
// strpos 在字符串中第一次出现的位置
|
||||
$call = $class;
|
||||
} else {
|
||||
// 动态调用
|
||||
//根据$class 获取此类的实例化
|
||||
$obj = Container::get($class); //会导致先初始化一次,应该缓存一下
|
||||
|
||||
//is_callable 检测回调函数 可调用则返回 TRUE
|
||||
if (!is_callable([$obj, $method])) {
|
||||
// 不可回调 赋默认值
|
||||
$method = self::$portal; // 默认值run() 方法
|
||||
}
|
||||
|
||||
$call = [$class, $method]; // 类或者空间名称 执行方法
|
||||
$class = $class . '->' . $method; //只针对调试使用,拼接成 空间名称执行的例子
|
||||
|
||||
}
|
||||
|
||||
//以上代码主要获取 $call--正常要的参数 和 $class--调试时才需要的参数
|
||||
// Container::getInstance() 获取的实例 think\Container,执行 container 内的 invoke()方法
|
||||
$result = Container::getInstance()->invoke($call, [$params]);
|
||||
|
||||
//调试模式
|
||||
if ($app->isDebug()) {
|
||||
$debug = $app['debug'];
|
||||
$debug->remark('behavior_end', 'time');
|
||||
$app->log('[ BEHAVIOR ] Run ' . $class . ' @' . $tag . ' [ RunTime:' . $debug->getRangeTime('behavior_start', 'behavior_end') . 's ]');
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,265 @@
|
|||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace think;
|
||||
|
||||
class Lang
|
||||
{
|
||||
/**
|
||||
* 多语言信息
|
||||
* @var array
|
||||
*/
|
||||
private $lang = [];
|
||||
|
||||
/**
|
||||
* 当前语言
|
||||
* @var string
|
||||
*/
|
||||
private $range = 'zh-cn';
|
||||
|
||||
/**
|
||||
* 多语言自动侦测变量名
|
||||
* @var string
|
||||
*/
|
||||
protected $langDetectVar = 'lang';
|
||||
|
||||
/**
|
||||
* 多语言cookie变量
|
||||
* @var string
|
||||
*/
|
||||
protected $langCookieVar = 'think_var';
|
||||
|
||||
/**
|
||||
* 允许的多语言列表
|
||||
* @var array
|
||||
*/
|
||||
protected $allowLangList = [];
|
||||
|
||||
/**
|
||||
* Accept-Language转义为对应语言包名称 系统默认配置
|
||||
* @var string
|
||||
*/
|
||||
protected $acceptLanguage = [
|
||||
'zh-hans-cn' => 'zh-cn',
|
||||
];
|
||||
|
||||
// 设定当前的语言
|
||||
public function range($range = '')
|
||||
{
|
||||
if ('' == $range) {
|
||||
return $this->range;
|
||||
} else {
|
||||
$this->range = $range;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置语言定义(不区分大小写)
|
||||
* @access public
|
||||
* @param string|array $name 语言变量
|
||||
* @param string $value 语言值
|
||||
* @param string $range 语言作用域
|
||||
* @return mixed
|
||||
*/
|
||||
public function set($name, $value = null, $range = '')
|
||||
{
|
||||
$range = $range ?: $this->range;
|
||||
// 批量定义
|
||||
if (!isset($this->lang[$range])) {
|
||||
$this->lang[$range] = [];
|
||||
}
|
||||
|
||||
if (is_array($name)) {
|
||||
return $this->lang[$range] = array_change_key_case($name) + $this->lang[$range];
|
||||
} else {
|
||||
return $this->lang[$range][strtolower($name)] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载语言定义(不区分大小写)
|
||||
* @access public
|
||||
* @param string|array $file 语言文件
|
||||
* @param string $range 语言作用域
|
||||
* @return array
|
||||
*/
|
||||
public function load($file, $range = '')
|
||||
{
|
||||
$range = $range ?: $this->range;
|
||||
if (!isset($this->lang[$range])) {
|
||||
$this->lang[$range] = [];
|
||||
}
|
||||
|
||||
// 批量定义
|
||||
if (is_string($file)) {
|
||||
$file = [$file];
|
||||
}
|
||||
|
||||
$lang = [];
|
||||
|
||||
foreach ($file as $_file) {
|
||||
if (is_file($_file)) {
|
||||
// 记录加载信息
|
||||
Container::get('app')->log('[ LANG ] ' . $_file);
|
||||
$_lang = include $_file;
|
||||
if (is_array($_lang)) {
|
||||
$lang = array_change_key_case($_lang) + $lang;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($lang)) {
|
||||
$this->lang[$range] = $lang + $this->lang[$range];
|
||||
}
|
||||
|
||||
return $this->lang[$range];
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取语言定义(不区分大小写)
|
||||
* @access public
|
||||
* @param string|null $name 语言变量
|
||||
* @param string $range 语言作用域
|
||||
* @return bool
|
||||
*/
|
||||
public function has($name, $range = '')
|
||||
{
|
||||
$range = $range ?: $this->range;
|
||||
|
||||
return isset($this->lang[$range][strtolower($name)]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取语言定义(不区分大小写)
|
||||
* @access public
|
||||
* @param string|null $name 语言变量
|
||||
* @param array $vars 变量替换
|
||||
* @param string $range 语言作用域
|
||||
* @return mixed
|
||||
*/
|
||||
public function get($name = null, $vars = [], $range = '')
|
||||
{
|
||||
$range = $range ?: $this->range;
|
||||
|
||||
// 空参数返回所有定义
|
||||
if (empty($name)) {
|
||||
return $this->lang[$range];
|
||||
}
|
||||
|
||||
$key = strtolower($name);
|
||||
$value = isset($this->lang[$range][$key]) ? $this->lang[$range][$key] : $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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 自动侦测设置获取语言选择
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function detect()
|
||||
{
|
||||
// 自动侦测设置获取语言选择
|
||||
$langSet = '';
|
||||
|
||||
if (isset($_GET[$this->langDetectVar])) {
|
||||
// url中设置了语言变量
|
||||
$langSet = strtolower($_GET[$this->langDetectVar]);
|
||||
} elseif (isset($_COOKIE[$this->langCookieVar])) {
|
||||
// Cookie中设置了语言变量
|
||||
$langSet = strtolower($_COOKIE[$this->langCookieVar]);
|
||||
} elseif (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {
|
||||
// 自动侦测浏览器语言
|
||||
preg_match('/^([a-z\d\-]+)/i', $_SERVER['HTTP_ACCEPT_LANGUAGE'], $matches);
|
||||
$langSet = strtolower($matches[1]);
|
||||
$acceptLangs = Container::get('config')->get('header_accept_lang');
|
||||
if (isset($acceptLangs[$langSet])) {
|
||||
$langSet = $acceptLangs[$langSet];
|
||||
} elseif (isset($this->acceptLanguage[$langSet])) {
|
||||
$langSet = $this->acceptLanguage[$langSet];
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($this->allowLangList) || in_array($langSet, $this->allowLangList)) {
|
||||
// 合法的语言
|
||||
$this->range = $langSet ?: $this->range;
|
||||
}
|
||||
|
||||
return $this->range;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置当前语言到Cookie
|
||||
* @access public
|
||||
* @param string $lang 语言
|
||||
* @return void
|
||||
*/
|
||||
public function saveToCookie($lang = null)
|
||||
{
|
||||
$range = $lang ?: $this->range;
|
||||
|
||||
$_COOKIE[$this->langCookieVar] = $range;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置语言自动侦测的变量
|
||||
* @access public
|
||||
* @param string $var 变量名称
|
||||
* @return void
|
||||
*/
|
||||
public function setLangDetectVar($var)
|
||||
{
|
||||
$this->langDetectVar = $var;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置语言的cookie保存变量
|
||||
* @access public
|
||||
* @param string $var 变量名称
|
||||
* @return void
|
||||
*/
|
||||
public function setLangCookieVar($var)
|
||||
{
|
||||
$this->langCookieVar = $var;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置允许的语言列表
|
||||
* @access public
|
||||
* @param array $list 语言列表
|
||||
* @return void
|
||||
*/
|
||||
public function setAllowLangList($list)
|
||||
{
|
||||
$this->allowLangList = $list;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,428 @@
|
|||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace think;
|
||||
|
||||
class Loader
|
||||
{
|
||||
/**
|
||||
* 类名映射信息
|
||||
* @var array
|
||||
*/
|
||||
protected static $map = [];
|
||||
|
||||
/**
|
||||
* 类库别名
|
||||
* @var array
|
||||
*/
|
||||
protected static $classAlias = [];
|
||||
|
||||
/**
|
||||
* PSR-4
|
||||
* @var array
|
||||
*/
|
||||
private static $prefixLengthsPsr4 = [];
|
||||
private static $prefixDirsPsr4 = [];
|
||||
private static $fallbackDirsPsr4 = [];
|
||||
|
||||
/**
|
||||
* PSR-0
|
||||
* @var array
|
||||
*/
|
||||
private static $prefixesPsr0 = [];
|
||||
private static $fallbackDirsPsr0 = [];
|
||||
|
||||
/**
|
||||
* 自动加载的文件列表
|
||||
* @var array
|
||||
*/
|
||||
private static $autoloadFiles = [];
|
||||
|
||||
/**
|
||||
* Composer安装路径
|
||||
* @var string
|
||||
*/
|
||||
private static $composerPath;
|
||||
|
||||
public static function dinfo(){
|
||||
var_dump('---------------map 类名映射信息-------------------');
|
||||
var_dump(self::$map);
|
||||
var_dump('---------------classAlias 类库别名-------------------');
|
||||
var_dump(self::$classAlias);
|
||||
var_dump('---------------prefixLengthsPsr4-------------------');
|
||||
var_dump(self::$prefixLengthsPsr4);
|
||||
var_dump('---------------prefixDirsPsr4-------------------');
|
||||
var_dump(self::$prefixDirsPsr4);
|
||||
var_dump('---------------fallbackDirsPsr4-------------------');
|
||||
var_dump(self::$fallbackDirsPsr4);
|
||||
var_dump('---------------prefixesPsr0-------------------');
|
||||
var_dump(self::$prefixesPsr0);
|
||||
var_dump('---------------fallbackDirsPsr0-------------------');
|
||||
var_dump(self::$fallbackDirsPsr0);
|
||||
var_dump('---------------autoloadFiles 自动加载的文件列表-------------------');
|
||||
var_dump(self::$autoloadFiles);
|
||||
var_dump('---------------composerPath-------------------');
|
||||
var_dump(self::$composerPath);
|
||||
}
|
||||
|
||||
// 注册自动加载机制
|
||||
public static function register($autoload = '')
|
||||
{
|
||||
// 注册系统自动加载
|
||||
spl_autoload_register($autoload ?: 'think\\Loader::autoload', true, true);
|
||||
|
||||
// 注册命名空间定义
|
||||
self::addNamespace([
|
||||
//核心目录
|
||||
'think' => __DIR__ . '/',
|
||||
//复用目录
|
||||
'traits' => __DIR__ . '/../traits/',
|
||||
]);
|
||||
|
||||
// 获取程序根目录
|
||||
// $_SERVER['SCRIPT_FILENAME'] 当前执行脚本的绝对路径,并非当前文件的绝对路径
|
||||
$path = dirname($_SERVER['SCRIPT_FILENAME']);
|
||||
// is_file() 函数检查指定的文件名是否是正常的文件
|
||||
// realpath() 函数返回绝对路径。
|
||||
if (is_file('./think')) {
|
||||
$rootPath = realpath($path) . '/';
|
||||
} else {
|
||||
$rootPath = realpath($path . '/../') . '/';
|
||||
}
|
||||
// $rootPath 程序所在根目录
|
||||
|
||||
// 加载类库映射文件
|
||||
if (is_file($rootPath . 'runtime/classmap.php')) {
|
||||
self::addClassMap(__include_file($rootPath . 'runtime/classmap.php'));
|
||||
}
|
||||
|
||||
// Composer安装路径
|
||||
self::$composerPath = $rootPath . 'vendor/composer/';
|
||||
|
||||
// Composer自动加载支持
|
||||
if (is_dir(self::$composerPath)) {
|
||||
self::registerComposerLoader(self::$composerPath);
|
||||
}
|
||||
|
||||
// 自动加载extend目录
|
||||
self::addAutoLoadDir($rootPath . 'extend');
|
||||
}
|
||||
|
||||
// 自动加载
|
||||
public static function autoload($class)
|
||||
{
|
||||
if (isset(self::$classAlias[$class])) {
|
||||
return class_alias(self::$classAlias[$class], $class);
|
||||
}
|
||||
|
||||
if ($file = self::findFile($class)) {
|
||||
|
||||
// Win环境严格区分大小写
|
||||
if (strpos(PHP_OS, 'WIN') !== false && pathinfo($file, PATHINFO_FILENAME) != pathinfo(realpath($file), PATHINFO_FILENAME)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
__include_file($file);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 查找文件
|
||||
* @access private
|
||||
* @param string $class
|
||||
* @return string|false
|
||||
*/
|
||||
private static function findFile($class)
|
||||
{
|
||||
if (!empty(self::$map[$class])) {
|
||||
// 类库映射
|
||||
return self::$map[$class];
|
||||
}
|
||||
|
||||
// 查找 PSR-4
|
||||
// 将$class 字符串中的字符 内的\\ 替换成系统默认的文件目录,再拼接上文件后缀
|
||||
$logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . '.php';
|
||||
// var_dump($logicalPathPsr4);
|
||||
$first = $class[0];
|
||||
// var_dump($first);
|
||||
if (isset(self::$prefixLengthsPsr4[$first])) {
|
||||
foreach (self::$prefixLengthsPsr4[$first] as $prefix => $length) {
|
||||
// strpos() 字符串中第一次出现的位置
|
||||
if (0 === strpos($class, $prefix)) {
|
||||
foreach (self::$prefixDirsPsr4[$prefix] as $dir) {
|
||||
|
||||
// var_dump(substr($logicalPathPsr4, $length));
|
||||
|
||||
// substr() 从字符串中返回
|
||||
if (is_file($file = $dir . DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $length))) {
|
||||
// echo $file.'<br />';
|
||||
return $file;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 查找 PSR-4 fallback dirs
|
||||
foreach (self::$fallbackDirsPsr4 as $dir) {
|
||||
if (is_file($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) {
|
||||
echo $file.'---------------<br />';
|
||||
return $file;
|
||||
}
|
||||
}
|
||||
|
||||
// // 查找 PSR-0
|
||||
// if (false !== $pos = strrpos($class, '\\')) {
|
||||
// // namespaced class name
|
||||
// $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1)
|
||||
// . strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR);
|
||||
// } else {
|
||||
// // PEAR-like class name
|
||||
// $logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . '.php';
|
||||
// }
|
||||
//
|
||||
// if (isset(self::$prefixesPsr0[$first])) {
|
||||
// foreach (self::$prefixesPsr0[$first] as $prefix => $dirs) {
|
||||
// if (0 === strpos($class, $prefix)) {
|
||||
// foreach ($dirs as $dir) {
|
||||
// if (is_file($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
|
||||
// return $file;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// // 查找 PSR-0 fallback dirs
|
||||
// foreach (self::$fallbackDirsPsr0 as $dir) {
|
||||
// if (is_file($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
|
||||
// return $file;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// return self::$map[$class] = false;
|
||||
}
|
||||
|
||||
// 注册classmap
|
||||
public static function addClassMap($class, $map = '')
|
||||
{
|
||||
if (is_array($class)) {
|
||||
self::$map = array_merge(self::$map, $class);
|
||||
} else {
|
||||
self::$map[$class] = $map;
|
||||
}
|
||||
}
|
||||
|
||||
// 注册命名空间
|
||||
public static function addNamespace($namespace, $path = '')
|
||||
{
|
||||
// 检测是否为数组
|
||||
if (is_array($namespace)) {
|
||||
foreach ($namespace as $prefix => $paths) {
|
||||
self::addPsr4($prefix . '\\', rtrim($paths, DIRECTORY_SEPARATOR), true);
|
||||
// 会增加一次IF判断
|
||||
// self::addNamespace($prefix, $paths);
|
||||
}
|
||||
} else {
|
||||
// 非数组则执行这个
|
||||
self::addPsr4($namespace . '\\', rtrim($path, DIRECTORY_SEPARATOR), true);
|
||||
}
|
||||
}
|
||||
|
||||
// 添加Ps0空间
|
||||
private static function addPsr0($prefix, $paths, $prepend = false)
|
||||
{
|
||||
if (!$prefix) {
|
||||
if ($prepend) {
|
||||
self::$fallbackDirsPsr0 = array_merge(
|
||||
(array) $paths,
|
||||
self::$fallbackDirsPsr0
|
||||
);
|
||||
} else {
|
||||
self::$fallbackDirsPsr0 = array_merge(
|
||||
self::$fallbackDirsPsr0,
|
||||
(array) $paths
|
||||
);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$first = $prefix[0];
|
||||
if (!isset(self::$prefixesPsr0[$first][$prefix])) {
|
||||
self::$prefixesPsr0[$first][$prefix] = (array) $paths;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ($prepend) {
|
||||
self::$prefixesPsr0[$first][$prefix] = array_merge(
|
||||
(array) $paths,
|
||||
self::$prefixesPsr0[$first][$prefix]
|
||||
);
|
||||
} else {
|
||||
self::$prefixesPsr0[$first][$prefix] = array_merge(
|
||||
self::$prefixesPsr0[$first][$prefix],
|
||||
(array) $paths
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// 添加Psr4空间
|
||||
// $prefix 别名
|
||||
// $paths 路径
|
||||
private static function addPsr4($prefix, $paths, $prepend = false)
|
||||
{
|
||||
if (!$prefix) {
|
||||
// 无值 则执行
|
||||
// 为根命名空间注册目录。 Register directories for the root namespace.
|
||||
// array_merge() 数组元素有相同的键名,则最后的元素会覆盖其他元素
|
||||
if ($prepend) {
|
||||
// 为真执行,数组合并
|
||||
self::$fallbackDirsPsr4 = array_merge(
|
||||
(array) $paths,
|
||||
self::$fallbackDirsPsr4
|
||||
);
|
||||
} else {
|
||||
self::$fallbackDirsPsr4 = array_merge(
|
||||
self::$fallbackDirsPsr4,
|
||||
(array) $paths
|
||||
);
|
||||
}
|
||||
} elseif (!isset(self::$prefixDirsPsr4[$prefix])) {
|
||||
// isset() 检测变量是否已设置 存在并且值不是 NULL 则返回 TRUE
|
||||
// self::$prefixDirsPsr4[$prefix] 为空执行
|
||||
// 为新名称空间注册目录。 Register directories for a new namespace.
|
||||
// 计算字符长度
|
||||
$length = strlen($prefix);
|
||||
if ('\\' !== $prefix[$length - 1]) {
|
||||
// 判断最后以为是否为\ 符号,若不是则报错
|
||||
// 在非空的PSR - 4字头端必须用命名空间separator
|
||||
throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
|
||||
}
|
||||
// 取$prefix 第一个字符做键值,$prefix 最后将$prefix的长度赋值
|
||||
self::$prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
|
||||
// $prefix 作为键值,将 $paths 转成数组做值
|
||||
self::$prefixDirsPsr4[$prefix] = (array) $paths;
|
||||
} elseif ($prepend) {
|
||||
// 以上条件都不满足条件,判断为真 则执行
|
||||
// 在目录已经注册的命名空间。 Prepend directories for an already registered namespace.
|
||||
self::$prefixDirsPsr4[$prefix] = array_merge(
|
||||
(array) $paths,
|
||||
self::$prefixDirsPsr4[$prefix]
|
||||
);
|
||||
} else {
|
||||
// 为已注册的命名空间追加目录。 Append directories for an already registered namespace.
|
||||
self::$prefixDirsPsr4[$prefix] = array_merge(
|
||||
self::$prefixDirsPsr4[$prefix],
|
||||
(array) $paths
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// 注册自动加载类库目录
|
||||
public static function addAutoLoadDir($path)
|
||||
{
|
||||
self::$fallbackDirsPsr4[] = $path;
|
||||
}
|
||||
|
||||
// 注册类别名
|
||||
public static function addClassAlias($alias, $class = null)
|
||||
{
|
||||
if (is_array($alias)) {
|
||||
self::$classAlias = array_merge(self::$classAlias, $alias);
|
||||
} else {
|
||||
self::$classAlias[$alias] = $class;
|
||||
}
|
||||
}
|
||||
|
||||
// 注册composer自动加载
|
||||
public static function registerComposerLoader($composerPath)
|
||||
{
|
||||
if (is_file($composerPath . 'autoload_namespaces.php')) {
|
||||
$map = require $composerPath . 'autoload_namespaces.php';
|
||||
foreach ($map as $namespace => $path) {
|
||||
self::addPsr0($namespace, $path);
|
||||
}
|
||||
}
|
||||
|
||||
if (is_file($composerPath . 'autoload_psr4.php')) {
|
||||
$map = require $composerPath . 'autoload_psr4.php';
|
||||
foreach ($map as $namespace => $path) {
|
||||
self::addPsr4($namespace, $path);
|
||||
}
|
||||
}
|
||||
|
||||
if (is_file($composerPath . 'autoload_classmap.php')) {
|
||||
$classMap = require $composerPath . 'autoload_classmap.php';
|
||||
if ($classMap) {
|
||||
self::addClassMap($classMap);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 加载composer autofile文件
|
||||
public static function loadComposerAutoloadFiles()
|
||||
{
|
||||
if (is_file(self::$composerPath . 'autoload_files.php')) {
|
||||
$includeFiles = require self::$composerPath . 'autoload_files.php';
|
||||
foreach ($includeFiles as $fileIdentifier => $file) {
|
||||
if (empty(self::$autoloadFiles[$fileIdentifier])) {
|
||||
__require_file($file);
|
||||
self::$autoloadFiles[$fileIdentifier] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 字符串命名风格转换
|
||||
* type 0 将Java风格转换为C的风格 1 将C风格转换为Java的风格
|
||||
* @access public
|
||||
* @param string $name 字符串
|
||||
* @param integer $type 转换类型
|
||||
* @param bool $ucfirst 首字母是否大写(驼峰规则)
|
||||
* @return string
|
||||
*/
|
||||
public static function parseName($name, $type = 0, $ucfirst = true)
|
||||
{
|
||||
if ($type) {
|
||||
//strtoupper 把所有字符转换为大写
|
||||
$name = preg_replace_callback('/_([a-zA-Z])/', function ($match) {
|
||||
return strtoupper($match[1]);
|
||||
}, $name);
|
||||
// ucfirst() 首字符转换为大写
|
||||
// lcfirst() 首字符转换为小写
|
||||
return $ucfirst ? ucfirst($name) : lcfirst($name);
|
||||
} else {
|
||||
// strtolower 所有字符转成小写
|
||||
return strtolower(trim(preg_replace("/[A-Z]/", "_\\0", $name), "_"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 作用范围隔离
|
||||
*
|
||||
* @param $file
|
||||
* @return mixed
|
||||
*/
|
||||
function __include_file($file)
|
||||
{
|
||||
return include $file;
|
||||
}
|
||||
|
||||
function __require_file($file)
|
||||
{
|
||||
return require $file;
|
||||
}
|
|
@ -0,0 +1,372 @@
|
|||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace think;
|
||||
|
||||
use think\exception\ClassNotFoundException;
|
||||
|
||||
class Log implements LoggerInterface
|
||||
{
|
||||
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';
|
||||
|
||||
/**
|
||||
* 日志信息
|
||||
* @var array
|
||||
*/
|
||||
protected $log = [];
|
||||
|
||||
/**
|
||||
* 配置参数
|
||||
* @var array
|
||||
*/
|
||||
protected $config = [];
|
||||
|
||||
/**
|
||||
* 日志写入驱动
|
||||
* @var object
|
||||
*/
|
||||
protected $driver;
|
||||
|
||||
/**
|
||||
* 日志授权key
|
||||
* @var string
|
||||
*/
|
||||
protected $key;
|
||||
|
||||
/**
|
||||
* 应用对象
|
||||
* @var App
|
||||
*/
|
||||
protected $app;
|
||||
|
||||
public function __construct(App $app)
|
||||
{
|
||||
$this->app = $app;
|
||||
}
|
||||
|
||||
/**
|
||||
* 日志初始化
|
||||
* @access public
|
||||
* @param array $config
|
||||
* @return $this
|
||||
*/
|
||||
public function init($config = [])
|
||||
{
|
||||
$type = isset($config['type']) ? $config['type'] : 'File';
|
||||
$class = false !== strpos($type, '\\') ? $type : '\\think\\log\\driver\\' . ucwords($type);
|
||||
|
||||
$this->config = $config;
|
||||
|
||||
unset($config['type']);
|
||||
|
||||
if (class_exists($class)) {
|
||||
$this->driver = new $class($config);
|
||||
} else {
|
||||
throw new ClassNotFoundException('class not exists:' . $class, $class);
|
||||
}
|
||||
|
||||
// 记录初始化信息
|
||||
$this->app->isDebug() && $this->record('[ LOG ] INIT ' . $type);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取日志信息
|
||||
* @access public
|
||||
* @param string $type 信息类型
|
||||
* @return array
|
||||
*/
|
||||
public function getLog($type = '')
|
||||
{
|
||||
return $type ? $this->log[$type] : $this->log;
|
||||
}
|
||||
|
||||
/**
|
||||
* 记录日志信息
|
||||
* @access public
|
||||
* @param mixed $msg 日志信息
|
||||
* @param string $type 日志级别
|
||||
* @param array $context 替换内容
|
||||
* @return $this
|
||||
*/
|
||||
public function record($msg, $type = 'info', array $context = [])
|
||||
{
|
||||
if (is_string($msg)) {
|
||||
$replace = [];
|
||||
foreach ($context as $key => $val) {
|
||||
$replace['{' . $key . '}'] = $val;
|
||||
}
|
||||
|
||||
$msg = strtr($msg, $replace);
|
||||
}
|
||||
|
||||
$this->log[$type][] = $msg;
|
||||
|
||||
if (PHP_SAPI == 'cli') {
|
||||
// 命令行日志实时写入
|
||||
$this->save();
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 清空日志信息
|
||||
* @access public
|
||||
* @return $this
|
||||
*/
|
||||
public function clear()
|
||||
{
|
||||
$this->log = [];
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 当前日志记录的授权key
|
||||
* @access public
|
||||
* @param string $key 授权key
|
||||
* @return $this
|
||||
*/
|
||||
public function key($key)
|
||||
{
|
||||
$this->key = $key;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查日志写入权限
|
||||
* @access public
|
||||
* @param array $config 当前日志配置参数
|
||||
* @return bool
|
||||
*/
|
||||
public function check($config)
|
||||
{
|
||||
if ($this->key && !empty($config['allow_key']) && !in_array($this->key, $config['allow_key'])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存调试信息
|
||||
* @access public
|
||||
* @return bool
|
||||
*/
|
||||
public function save()
|
||||
{
|
||||
if (!empty($this->log)) {
|
||||
if (is_null($this->driver)) {
|
||||
$this->init($this->app['config']->pull('log'));
|
||||
}
|
||||
|
||||
if (!$this->check($this->config)) {
|
||||
// 检测日志写入权限
|
||||
return false;
|
||||
}
|
||||
|
||||
if (empty($this->config['level'])) {
|
||||
// 获取全部日志
|
||||
$log = $this->log;
|
||||
if (!$this->app->isDebug() && isset($log['debug'])) {
|
||||
unset($log['debug']);
|
||||
}
|
||||
} else {
|
||||
// 记录允许级别
|
||||
$log = [];
|
||||
foreach ($this->config['level'] as $level) {
|
||||
if (isset($this->log[$level])) {
|
||||
$log[$level] = $this->log[$level];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$result = $this->driver->save($log);
|
||||
if ($result) {
|
||||
$this->log = [];
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 实时写入日志信息 并支持行为
|
||||
* @access public
|
||||
* @param mixed $msg 调试信息
|
||||
* @param string $type 日志级别
|
||||
* @param bool $force 是否强制写入
|
||||
* @return bool
|
||||
*/
|
||||
public function write($msg, $type = 'info', $force = false)
|
||||
{
|
||||
// 封装日志信息
|
||||
$log = $this->log;
|
||||
|
||||
if (true === $force || empty($this->config['level'])) {
|
||||
$log[$type][] = $msg;
|
||||
} elseif (in_array($type, $this->config['level'])) {
|
||||
$log[$type][] = $msg;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 监听log_write
|
||||
$this->app['hook']->listen('log_write', $log);
|
||||
|
||||
if (is_null($this->driver)) {
|
||||
$this->init($this->app['config']->pull('log'));
|
||||
}
|
||||
|
||||
// 写入日志
|
||||
$result = $this->driver->save($log);
|
||||
|
||||
if ($result) {
|
||||
$this->log = [];
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 记录日志信息
|
||||
* @access public
|
||||
* @param string $level 日志级别
|
||||
* @param mixed $message 日志信息
|
||||
* @param array $context 替换内容
|
||||
* @return void
|
||||
*/
|
||||
public function log($level, $message, array $context = [])
|
||||
{
|
||||
$this->record($message, $level, $context);
|
||||
}
|
||||
|
||||
/**
|
||||
* 记录emergency信息
|
||||
* @access public
|
||||
* @param mixed $message 日志信息
|
||||
* @param array $context 替换内容
|
||||
* @return void
|
||||
*/
|
||||
public function emergency($message, array $context = [])
|
||||
{
|
||||
$this->log(__FUNCTION__, $message, $context);
|
||||
}
|
||||
|
||||
/**
|
||||
* 记录警报信息
|
||||
* @access public
|
||||
* @param mixed $message 日志信息
|
||||
* @param array $context 替换内容
|
||||
* @return void
|
||||
*/
|
||||
public function alert($message, array $context = [])
|
||||
{
|
||||
$this->log(__FUNCTION__, $message, $context);
|
||||
}
|
||||
|
||||
/**
|
||||
* 记录紧急情况
|
||||
* @access public
|
||||
* @param mixed $message 日志信息
|
||||
* @param array $context 替换内容
|
||||
* @return void
|
||||
*/
|
||||
public function critical($message, array $context = [])
|
||||
{
|
||||
$this->log(__FUNCTION__, $message, $context);
|
||||
}
|
||||
|
||||
/**
|
||||
* 记录错误信息
|
||||
* @access public
|
||||
* @param mixed $message 日志信息
|
||||
* @param array $context 替换内容
|
||||
* @return void
|
||||
*/
|
||||
public function error($message, array $context = [])
|
||||
{
|
||||
$this->log(__FUNCTION__, $message, $context);
|
||||
}
|
||||
|
||||
/**
|
||||
* 记录warning信息
|
||||
* @access public
|
||||
* @param mixed $message 日志信息
|
||||
* @param array $context 替换内容
|
||||
* @return void
|
||||
*/
|
||||
public function warning($message, array $context = [])
|
||||
{
|
||||
$this->log(__FUNCTION__, $message, $context);
|
||||
}
|
||||
|
||||
/**
|
||||
* 记录notice信息
|
||||
* @access public
|
||||
* @param mixed $message 日志信息
|
||||
* @param array $context 替换内容
|
||||
* @return void
|
||||
*/
|
||||
public function notice($message, array $context = [])
|
||||
{
|
||||
$this->log(__FUNCTION__, $message, $context);
|
||||
}
|
||||
|
||||
/**
|
||||
* 记录一般信息
|
||||
* @access public
|
||||
* @param mixed $message 日志信息
|
||||
* @param array $context 替换内容
|
||||
* @return void
|
||||
*/
|
||||
public function info($message, array $context = [])
|
||||
{
|
||||
$this->log(__FUNCTION__, $message, $context);
|
||||
}
|
||||
|
||||
/**
|
||||
* 记录调试信息
|
||||
* @access public
|
||||
* @param mixed $message 日志信息
|
||||
* @param array $context 替换内容
|
||||
* @return void
|
||||
*/
|
||||
public function debug($message, array $context = [])
|
||||
{
|
||||
$this->log(__FUNCTION__, $message, $context);
|
||||
}
|
||||
|
||||
/**
|
||||
* 记录sql信息
|
||||
* @access public
|
||||
* @param mixed $message 日志信息
|
||||
* @param array $context 替换内容
|
||||
* @return void
|
||||
*/
|
||||
public function sql($message, array $context = [])
|
||||
{
|
||||
$this->log(__FUNCTION__, $message, $context);
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -2,30 +2,22 @@
|
|||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2019 http://thinkphp.cn All rights reserved.
|
||||
// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: zhangyajun <448901948@qq.com>
|
||||
// +----------------------------------------------------------------------
|
||||
declare (strict_types = 1);
|
||||
|
||||
namespace think;
|
||||
|
||||
use ArrayAccess;
|
||||
use ArrayIterator;
|
||||
use Closure;
|
||||
use Countable;
|
||||
use DomainException;
|
||||
use IteratorAggregate;
|
||||
use JsonSerializable;
|
||||
use think\paginator\driver\Bootstrap;
|
||||
use Traversable;
|
||||
|
||||
/**
|
||||
* 分页基础类
|
||||
* @method array all()
|
||||
*/
|
||||
abstract class Paginator implements ArrayAccess, Countable, IteratorAggregate, JsonSerializable
|
||||
{
|
||||
/**
|
||||
|
@ -81,24 +73,7 @@ abstract class Paginator implements ArrayAccess, Countable, IteratorAggregate, J
|
|||
'fragment' => '',
|
||||
];
|
||||
|
||||
/**
|
||||
* 获取当前页码
|
||||
* @var Closure
|
||||
*/
|
||||
protected static $currentPageResolver;
|
||||
|
||||
/**
|
||||
* 获取当前路径
|
||||
* @var Closure
|
||||
*/
|
||||
protected static $currentPathResolver;
|
||||
|
||||
/**
|
||||
* @var Closure
|
||||
*/
|
||||
protected static $maker;
|
||||
|
||||
public function __construct($items, int $listRows, int $currentPage = 1, int $total = null, bool $simple = false, array $options = [])
|
||||
public function __construct($items, $listRows, $currentPage = null, $total = null, $simple = false, $options = [])
|
||||
{
|
||||
$this->options = array_merge($this->options, $options);
|
||||
|
||||
|
@ -126,29 +101,20 @@ abstract class Paginator implements ArrayAccess, Countable, IteratorAggregate, J
|
|||
|
||||
/**
|
||||
* @access public
|
||||
* @param mixed $items
|
||||
* @param int $listRows
|
||||
* @param int $currentPage
|
||||
* @param int $total
|
||||
* @param $items
|
||||
* @param $listRows
|
||||
* @param null $currentPage
|
||||
* @param bool $simple
|
||||
* @param null $total
|
||||
* @param array $options
|
||||
* @return Paginator
|
||||
*/
|
||||
public static function make($items, int $listRows, int $currentPage = 1, int $total = null, bool $simple = false, array $options = [])
|
||||
public static function make($items, $listRows, $currentPage = null, $total = null, $simple = false, $options = [])
|
||||
{
|
||||
if (isset(static::$maker)) {
|
||||
return call_user_func(static::$maker, $items, $listRows, $currentPage, $total, $simple, $options);
|
||||
}
|
||||
|
||||
return new Bootstrap($items, $listRows, $currentPage, $total, $simple, $options);
|
||||
return new static($items, $listRows, $currentPage, $total, $simple, $options);
|
||||
}
|
||||
|
||||
public static function maker(Closure $resolver)
|
||||
{
|
||||
static::$maker = $resolver;
|
||||
}
|
||||
|
||||
protected function setCurrentPage(int $currentPage): int
|
||||
protected function setCurrentPage($currentPage)
|
||||
{
|
||||
if (!$this->simple && $currentPage > $this->lastPage) {
|
||||
return $this->lastPage > 0 ? $this->lastPage : 1;
|
||||
|
@ -161,10 +127,10 @@ abstract class Paginator implements ArrayAccess, Countable, IteratorAggregate, J
|
|||
* 获取页码对应的链接
|
||||
*
|
||||
* @access protected
|
||||
* @param int $page
|
||||
* @param $page
|
||||
* @return string
|
||||
*/
|
||||
protected function url(int $page): string
|
||||
protected function url($page)
|
||||
{
|
||||
if ($page <= 0) {
|
||||
$page = 1;
|
||||
|
@ -184,7 +150,7 @@ abstract class Paginator implements ArrayAccess, Countable, IteratorAggregate, J
|
|||
|
||||
$url = $path;
|
||||
if (!empty($parameters)) {
|
||||
$url .= '?' . http_build_query($parameters, '', '&');
|
||||
$url .= '?' . urldecode(http_build_query($parameters, null, '&'));
|
||||
}
|
||||
|
||||
return $url . $this->buildFragment();
|
||||
|
@ -193,75 +159,54 @@ abstract class Paginator implements ArrayAccess, Countable, IteratorAggregate, J
|
|||
/**
|
||||
* 自动获取当前页码
|
||||
* @access public
|
||||
* @param string $varPage
|
||||
* @param int $default
|
||||
* @param string $varPage
|
||||
* @param int $default
|
||||
* @return int
|
||||
*/
|
||||
public static function getCurrentPage(string $varPage = 'page', int $default = 1): int
|
||||
public static function getCurrentPage($varPage = 'page', $default = 1)
|
||||
{
|
||||
if (isset(static::$currentPageResolver)) {
|
||||
return call_user_func(static::$currentPageResolver, $varPage);
|
||||
$page = Container::get('request')->param($varPage);
|
||||
|
||||
if (filter_var($page, FILTER_VALIDATE_INT) !== false && (int) $page >= 1) {
|
||||
return $page;
|
||||
}
|
||||
|
||||
return $default;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置获取当前页码闭包
|
||||
* @param Closure $resolver
|
||||
*/
|
||||
public static function currentPageResolver(Closure $resolver)
|
||||
{
|
||||
static::$currentPageResolver = $resolver;
|
||||
}
|
||||
|
||||
/**
|
||||
* 自动获取当前的path
|
||||
* @access public
|
||||
* @param string $default
|
||||
* @return string
|
||||
*/
|
||||
public static function getCurrentPath($default = '/'): string
|
||||
public static function getCurrentPath()
|
||||
{
|
||||
if (isset(static::$currentPathResolver)) {
|
||||
return call_user_func(static::$currentPathResolver);
|
||||
}
|
||||
|
||||
return $default;
|
||||
return Container::get('request')->baseUrl();
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置获取当前路径闭包
|
||||
* @param Closure $resolver
|
||||
*/
|
||||
public static function currentPathResolver(Closure $resolver)
|
||||
{
|
||||
static::$currentPathResolver = $resolver;
|
||||
}
|
||||
|
||||
public function total(): int
|
||||
public function total()
|
||||
{
|
||||
if ($this->simple) {
|
||||
throw new DomainException('not support total');
|
||||
throw new \DomainException('not support total');
|
||||
}
|
||||
|
||||
return $this->total;
|
||||
}
|
||||
|
||||
public function listRows(): int
|
||||
public function listRows()
|
||||
{
|
||||
return $this->listRows;
|
||||
}
|
||||
|
||||
public function currentPage(): int
|
||||
public function currentPage()
|
||||
{
|
||||
return $this->currentPage;
|
||||
}
|
||||
|
||||
public function lastPage(): int
|
||||
public function lastPage()
|
||||
{
|
||||
if ($this->simple) {
|
||||
throw new DomainException('not support last');
|
||||
throw new \DomainException('not support last');
|
||||
}
|
||||
|
||||
return $this->lastPage;
|
||||
|
@ -270,9 +215,9 @@ abstract class Paginator implements ArrayAccess, Countable, IteratorAggregate, J
|
|||
/**
|
||||
* 数据是否足够分页
|
||||
* @access public
|
||||
* @return bool
|
||||
* @return boolean
|
||||
*/
|
||||
public function hasPages(): bool
|
||||
public function hasPages()
|
||||
{
|
||||
return !(1 == $this->currentPage && !$this->hasMore);
|
||||
}
|
||||
|
@ -281,11 +226,11 @@ abstract class Paginator implements ArrayAccess, Countable, IteratorAggregate, J
|
|||
* 创建一组分页链接
|
||||
*
|
||||
* @access public
|
||||
* @param int $start
|
||||
* @param int $end
|
||||
* @param int $start
|
||||
* @param int $end
|
||||
* @return array
|
||||
*/
|
||||
public function getUrlRange(int $start, int $end): array
|
||||
public function getUrlRange($start, $end)
|
||||
{
|
||||
$urls = [];
|
||||
|
||||
|
@ -300,10 +245,10 @@ abstract class Paginator implements ArrayAccess, Countable, IteratorAggregate, J
|
|||
* 设置URL锚点
|
||||
*
|
||||
* @access public
|
||||
* @param string|null $fragment
|
||||
* @param string|null $fragment
|
||||
* @return $this
|
||||
*/
|
||||
public function fragment(string $fragment = null)
|
||||
public function fragment($fragment)
|
||||
{
|
||||
$this->options['fragment'] = $fragment;
|
||||
|
||||
|
@ -314,12 +259,19 @@ abstract class Paginator implements ArrayAccess, Countable, IteratorAggregate, J
|
|||
* 添加URL参数
|
||||
*
|
||||
* @access public
|
||||
* @param array $append
|
||||
* @param array|string $key
|
||||
* @param string|null $value
|
||||
* @return $this
|
||||
*/
|
||||
public function appends(array $append)
|
||||
public function appends($key, $value = null)
|
||||
{
|
||||
foreach ($append as $k => $v) {
|
||||
if (!is_array($key)) {
|
||||
$queries = [$key => $value];
|
||||
} else {
|
||||
$queries = $key;
|
||||
}
|
||||
|
||||
foreach ($queries as $k => $v) {
|
||||
if ($k !== $this->options['var_page']) {
|
||||
$this->options['query'][$k] = $v;
|
||||
}
|
||||
|
@ -334,7 +286,7 @@ abstract class Paginator implements ArrayAccess, Countable, IteratorAggregate, J
|
|||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
protected function buildFragment(): string
|
||||
protected function buildFragment()
|
||||
{
|
||||
return $this->options['fragment'] ? '#' . $this->options['fragment'] : '';
|
||||
}
|
||||
|
@ -356,7 +308,7 @@ abstract class Paginator implements ArrayAccess, Countable, IteratorAggregate, J
|
|||
return $this->items;
|
||||
}
|
||||
|
||||
public function isEmpty(): bool
|
||||
public function isEmpty()
|
||||
{
|
||||
return $this->items->isEmpty();
|
||||
}
|
||||
|
@ -365,7 +317,7 @@ abstract class Paginator implements ArrayAccess, Countable, IteratorAggregate, J
|
|||
* 给每个元素执行个回调
|
||||
*
|
||||
* @access public
|
||||
* @param callable $callback
|
||||
* @param callable $callback
|
||||
* @return $this
|
||||
*/
|
||||
public function each(callable $callback)
|
||||
|
@ -397,7 +349,7 @@ abstract class Paginator implements ArrayAccess, Countable, IteratorAggregate, J
|
|||
/**
|
||||
* Whether a offset exists
|
||||
* @access public
|
||||
* @param mixed $offset
|
||||
* @param mixed $offset
|
||||
* @return bool
|
||||
*/
|
||||
public function offsetExists($offset)
|
||||
|
@ -408,7 +360,7 @@ abstract class Paginator implements ArrayAccess, Countable, IteratorAggregate, J
|
|||
/**
|
||||
* Offset to retrieve
|
||||
* @access public
|
||||
* @param mixed $offset
|
||||
* @param mixed $offset
|
||||
* @return mixed
|
||||
*/
|
||||
public function offsetGet($offset)
|
||||
|
@ -419,8 +371,8 @@ abstract class Paginator implements ArrayAccess, Countable, IteratorAggregate, J
|
|||
/**
|
||||
* Offset to set
|
||||
* @access public
|
||||
* @param mixed $offset
|
||||
* @param mixed $value
|
||||
* @param mixed $offset
|
||||
* @param mixed $value
|
||||
*/
|
||||
public function offsetSet($offset, $value)
|
||||
{
|
||||
|
@ -430,7 +382,7 @@ abstract class Paginator implements ArrayAccess, Countable, IteratorAggregate, J
|
|||
/**
|
||||
* Offset to unset
|
||||
* @access public
|
||||
* @param mixed $offset
|
||||
* @param mixed $offset
|
||||
* @return void
|
||||
* @since 5.0.0
|
||||
*/
|
||||
|
@ -442,7 +394,7 @@ abstract class Paginator implements ArrayAccess, Countable, IteratorAggregate, J
|
|||
/**
|
||||
* Count elements of an object
|
||||
*/
|
||||
public function count(): int
|
||||
public function count()
|
||||
{
|
||||
return $this->items->count();
|
||||
}
|
||||
|
@ -452,11 +404,11 @@ abstract class Paginator implements ArrayAccess, Countable, IteratorAggregate, J
|
|||
return (string) $this->render();
|
||||
}
|
||||
|
||||
public function toArray(): array
|
||||
public function toArray()
|
||||
{
|
||||
try {
|
||||
$total = $this->total();
|
||||
} catch (DomainException $e) {
|
||||
} catch (\DomainException $e) {
|
||||
$total = null;
|
||||
}
|
||||
|
||||
|
@ -479,15 +431,7 @@ abstract class Paginator implements ArrayAccess, Countable, IteratorAggregate, J
|
|||
|
||||
public function __call($name, $arguments)
|
||||
{
|
||||
$collection = $this->getCollection();
|
||||
|
||||
$result = call_user_func_array([$collection, $name], $arguments);
|
||||
|
||||
if ($result === $collection) {
|
||||
return $this;
|
||||
}
|
||||
|
||||
return $result;
|
||||
return call_user_func_array([$this->getCollection(), $name], $arguments);
|
||||
}
|
||||
|
||||
}
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -2,19 +2,17 @@
|
|||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2019 http://thinkphp.cn All rights reserved.
|
||||
// | Copyright (c) 2006~2018 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\response\Redirect as RedirectResponse;
|
||||
|
||||
class Response
|
||||
{
|
||||
/**
|
||||
|
@ -65,30 +63,26 @@ class Response
|
|||
*/
|
||||
protected $content = null;
|
||||
|
||||
/**
|
||||
* Cookie对象
|
||||
* @var Cookie
|
||||
*/
|
||||
protected $cookie;
|
||||
|
||||
/**
|
||||
* Session对象
|
||||
* @var Session
|
||||
*/
|
||||
protected $session;
|
||||
|
||||
/**
|
||||
* 架构函数
|
||||
* @access public
|
||||
* @param mixed $data 输出数据
|
||||
* @param int $code
|
||||
* @param array $header
|
||||
* @param array $options 输出参数
|
||||
*/
|
||||
public function __construct($data = '', int $code = 200)
|
||||
public function __construct($data = '', $code = 200, array $header = [], $options = [])
|
||||
{
|
||||
$this->data($data);
|
||||
$this->code = $code;
|
||||
|
||||
if (!empty($options)) {
|
||||
$this->options = array_merge($this->options, $options);
|
||||
}
|
||||
|
||||
$this->contentType($this->contentType, $this->charset);
|
||||
|
||||
$this->code = $code;
|
||||
$this->header = array_merge($this->header, $header);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -97,41 +91,21 @@ class Response
|
|||
* @param mixed $data 输出数据
|
||||
* @param string $type 输出类型
|
||||
* @param int $code
|
||||
* @param array $header
|
||||
* @param array $options 输出参数
|
||||
* @return Response
|
||||
*/
|
||||
public static function create($data = '', string $type = '', int $code = 200): Response
|
||||
public static function create($data = '', $type = '', $code = 200, array $header = [], $options = [])
|
||||
{
|
||||
$class = false !== strpos($type, '\\') ? $type : '\\think\\response\\' . ucfirst(strtolower($type));
|
||||
$type = empty($type) ? 'null' : strtolower($type);
|
||||
|
||||
$class = false !== strpos($type, '\\') ? $type : '\\think\\response\\' . ucfirst($type);
|
||||
|
||||
if (class_exists($class)) {
|
||||
return Container::getInstance()->invokeClass($class, [$data, $code]);
|
||||
return new $class($data, $code, $header, $options);
|
||||
} else {
|
||||
return new static($data, $code, $header, $options);
|
||||
}
|
||||
|
||||
return new static($data, $code);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置Cookie对象
|
||||
* @access public
|
||||
* @param Cookie $cookie Cookie对象
|
||||
* @return $this
|
||||
*/
|
||||
public function setCookie(Cookie $cookie)
|
||||
{
|
||||
$this->cookie = $cookie;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置Session对象
|
||||
* @access public
|
||||
* @param Session $session Session对象
|
||||
* @return $this
|
||||
*/
|
||||
public function setSession(Session $session)
|
||||
{
|
||||
$this->session = $session;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -140,11 +114,30 @@ class Response
|
|||
* @return void
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public function send(): void
|
||||
public function send()
|
||||
{
|
||||
// 监听response_send
|
||||
Container::get('hook')->listen('response_send', $this);
|
||||
|
||||
// 处理输出数据
|
||||
$data = $this->getContent();
|
||||
|
||||
// Trace调试注入
|
||||
if (Container::get('env')->get('app_trace', Container::get('app')->config('app.app_trace'))) {
|
||||
Container::get('debug')->inject($this, $data);
|
||||
}
|
||||
|
||||
if (200 == $this->code && $this->allowCache) {
|
||||
$cache = Container::get('request')->getCache();
|
||||
if ($cache) {
|
||||
$this->header['Cache-Control'] = 'max-age=' . $cache[1] . ',must-revalidate';
|
||||
$this->header['Last-Modified'] = gmdate('D, d M Y H:i:s') . ' GMT';
|
||||
$this->header['Expires'] = gmdate('D, d M Y H:i:s', $_SERVER['REQUEST_TIME'] + $cache[1]) . ' GMT';
|
||||
|
||||
Container::get('cache')->tag($cache[2])->set($cache[0], [$data, $this->header], $cache[1]);
|
||||
}
|
||||
}
|
||||
|
||||
if (!headers_sent() && !empty($this->header)) {
|
||||
// 发送状态码
|
||||
http_response_code($this->code);
|
||||
|
@ -154,14 +147,20 @@ class Response
|
|||
}
|
||||
}
|
||||
|
||||
$this->cookie->save();
|
||||
|
||||
$this->sendData($data);
|
||||
|
||||
if (function_exists('fastcgi_finish_request')) {
|
||||
// 提高页面响应
|
||||
fastcgi_finish_request();
|
||||
}
|
||||
|
||||
// 监听response_end
|
||||
Container::get('hook')->listen('response_end', $this);
|
||||
|
||||
// 清空当次请求有效的数据
|
||||
if (!($this instanceof RedirectResponse)) {
|
||||
Container::get('session')->flush();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -181,7 +180,7 @@ class Response
|
|||
* @param string $data 要处理的数据
|
||||
* @return void
|
||||
*/
|
||||
protected function sendData(string $data): void
|
||||
protected function sendData($data)
|
||||
{
|
||||
echo $data;
|
||||
}
|
||||
|
@ -192,7 +191,7 @@ class Response
|
|||
* @param mixed $options 输出参数
|
||||
* @return $this
|
||||
*/
|
||||
public function options(array $options = [])
|
||||
public function options($options = [])
|
||||
{
|
||||
$this->options = array_merge($this->options, $options);
|
||||
|
||||
|
@ -218,32 +217,27 @@ class Response
|
|||
* @param bool $cache 允许请求缓存
|
||||
* @return $this
|
||||
*/
|
||||
public function allowCache(bool $cache)
|
||||
public function allowCache($cache)
|
||||
{
|
||||
$this->allowCache = $cache;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否允许请求缓存
|
||||
* @access public
|
||||
* @return $this
|
||||
*/
|
||||
public function isAllowCache()
|
||||
{
|
||||
return $this->allowCache;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置响应头
|
||||
* @access public
|
||||
* @param array $header 参数
|
||||
* @param string|array $name 参数名
|
||||
* @param string $value 参数值
|
||||
* @return $this
|
||||
*/
|
||||
public function header(array $header = [])
|
||||
public function header($name, $value = null)
|
||||
{
|
||||
$this->header = array_merge($this->header, $header);
|
||||
if (is_array($name)) {
|
||||
$this->header = array_merge($this->header, $name);
|
||||
} else {
|
||||
$this->header[$name] = $value;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
@ -275,7 +269,7 @@ class Response
|
|||
* @param integer $code 状态码
|
||||
* @return $this
|
||||
*/
|
||||
public function code(int $code)
|
||||
public function code($code)
|
||||
{
|
||||
$this->code = $code;
|
||||
|
||||
|
@ -288,7 +282,7 @@ class Response
|
|||
* @param string $time
|
||||
* @return $this
|
||||
*/
|
||||
public function lastModified(string $time)
|
||||
public function lastModified($time)
|
||||
{
|
||||
$this->header['Last-Modified'] = $time;
|
||||
|
||||
|
@ -301,7 +295,7 @@ class Response
|
|||
* @param string $time
|
||||
* @return $this
|
||||
*/
|
||||
public function expires(string $time)
|
||||
public function expires($time)
|
||||
{
|
||||
$this->header['Expires'] = $time;
|
||||
|
||||
|
@ -314,7 +308,7 @@ class Response
|
|||
* @param string $eTag
|
||||
* @return $this
|
||||
*/
|
||||
public function eTag(string $eTag)
|
||||
public function eTag($eTag)
|
||||
{
|
||||
$this->header['ETag'] = $eTag;
|
||||
|
||||
|
@ -327,7 +321,7 @@ class Response
|
|||
* @param string $cache 状态码
|
||||
* @return $this
|
||||
*/
|
||||
public function cacheControl(string $cache)
|
||||
public function cacheControl($cache)
|
||||
{
|
||||
$this->header['Cache-control'] = $cache;
|
||||
|
||||
|
@ -341,7 +335,7 @@ class Response
|
|||
* @param string $charset 输出编码
|
||||
* @return $this
|
||||
*/
|
||||
public function contentType(string $contentType, string $charset = 'utf-8')
|
||||
public function contentType($contentType, $charset = 'utf-8')
|
||||
{
|
||||
$this->header['Content-Type'] = $contentType . '; charset=' . $charset;
|
||||
|
||||
|
@ -354,13 +348,13 @@ class Response
|
|||
* @param string $name 头部名称
|
||||
* @return mixed
|
||||
*/
|
||||
public function getHeader(string $name = '')
|
||||
public function getHeader($name = '')
|
||||
{
|
||||
if (!empty($name)) {
|
||||
return $this->header[$name] ?? null;
|
||||
return isset($this->header[$name]) ? $this->header[$name] : null;
|
||||
} else {
|
||||
return $this->header;
|
||||
}
|
||||
|
||||
return $this->header;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -376,9 +370,9 @@ class Response
|
|||
/**
|
||||
* 获取输出数据
|
||||
* @access public
|
||||
* @return string
|
||||
* @return mixed
|
||||
*/
|
||||
public function getContent(): string
|
||||
public function getContent()
|
||||
{
|
||||
if (null == $this->content) {
|
||||
$content = $this->output($this->data);
|
||||
|
@ -402,7 +396,7 @@ class Response
|
|||
* @access public
|
||||
* @return integer
|
||||
*/
|
||||
public function getCode(): int
|
||||
public function getCode()
|
||||
{
|
||||
return $this->code;
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,531 @@
|
|||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace think;
|
||||
|
||||
use think\exception\ClassNotFoundException;
|
||||
|
||||
class Session
|
||||
{
|
||||
/**
|
||||
* 前缀
|
||||
* @var string
|
||||
*/
|
||||
protected $prefix = '';
|
||||
|
||||
/**
|
||||
* 是否初始化
|
||||
* @var bool
|
||||
*/
|
||||
protected $init = null;
|
||||
|
||||
/**
|
||||
* 锁驱动
|
||||
* @var object
|
||||
*/
|
||||
protected $lockDriver = null;
|
||||
|
||||
/**
|
||||
* 锁key
|
||||
* @var string
|
||||
*/
|
||||
protected $sessKey = 'PHPSESSID';
|
||||
|
||||
/**
|
||||
* 锁超时时间
|
||||
* @var integer
|
||||
*/
|
||||
protected $lockTimeout = 3;
|
||||
|
||||
/**
|
||||
* 是否启用锁机制
|
||||
* @var bool
|
||||
*/
|
||||
protected $lock = false;
|
||||
|
||||
/**
|
||||
* 设置或者获取session作用域(前缀)
|
||||
* @access public
|
||||
* @param string $prefix
|
||||
* @return string|void
|
||||
*/
|
||||
public function prefix($prefix = '')
|
||||
{
|
||||
empty($this->init) && $this->boot();
|
||||
|
||||
if (empty($prefix) && null !== $prefix) {
|
||||
return $this->prefix;
|
||||
} else {
|
||||
$this->prefix = $prefix;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* session初始化
|
||||
* @access public
|
||||
* @param array $config
|
||||
* @return void
|
||||
* @throws \think\Exception
|
||||
*/
|
||||
public function init(array $config = [])
|
||||
{
|
||||
if (empty($config)) {
|
||||
$config = Container::get('config')->pull('session');
|
||||
}
|
||||
|
||||
// 记录初始化信息
|
||||
Container::get('app')->log('[ SESSION ] INIT ' . var_export($config, true));
|
||||
$isDoStart = false;
|
||||
if (isset($config['use_trans_sid'])) {
|
||||
ini_set('session.use_trans_sid', $config['use_trans_sid'] ? 1 : 0);
|
||||
}
|
||||
|
||||
// 启动session
|
||||
if (!empty($config['auto_start']) && PHP_SESSION_ACTIVE != session_status()) {
|
||||
ini_set('session.auto_start', 0);
|
||||
$isDoStart = true;
|
||||
}
|
||||
|
||||
if (isset($config['prefix'])) {
|
||||
$this->prefix = $config['prefix'];
|
||||
}
|
||||
|
||||
if (isset($config['use_lock'])) {
|
||||
$this->lock = $config['use_lock'];
|
||||
}
|
||||
|
||||
if (isset($config['var_session_id']) && isset($_REQUEST[$config['var_session_id']])) {
|
||||
session_id($_REQUEST[$config['var_session_id']]);
|
||||
} elseif (isset($config['id']) && !empty($config['id'])) {
|
||||
session_id($config['id']);
|
||||
}
|
||||
|
||||
if (isset($config['name'])) {
|
||||
session_name($config['name']);
|
||||
}
|
||||
|
||||
if (isset($config['path'])) {
|
||||
session_save_path($config['path']);
|
||||
}
|
||||
|
||||
if (isset($config['domain'])) {
|
||||
ini_set('session.cookie_domain', $config['domain']);
|
||||
}
|
||||
|
||||
if (isset($config['expire'])) {
|
||||
ini_set('session.gc_maxlifetime', $config['expire']);
|
||||
ini_set('session.cookie_lifetime', $config['expire']);
|
||||
}
|
||||
|
||||
if (isset($config['secure'])) {
|
||||
ini_set('session.cookie_secure', $config['secure']);
|
||||
}
|
||||
|
||||
if (isset($config['httponly'])) {
|
||||
ini_set('session.cookie_httponly', $config['httponly']);
|
||||
}
|
||||
|
||||
if (isset($config['use_cookies'])) {
|
||||
ini_set('session.use_cookies', $config['use_cookies'] ? 1 : 0);
|
||||
}
|
||||
|
||||
if (isset($config['cache_limiter'])) {
|
||||
session_cache_limiter($config['cache_limiter']);
|
||||
}
|
||||
|
||||
if (isset($config['cache_expire'])) {
|
||||
session_cache_expire($config['cache_expire']);
|
||||
}
|
||||
|
||||
if (!empty($config['type'])) {
|
||||
// 读取session驱动
|
||||
$class = false !== strpos($config['type'], '\\') ? $config['type'] : '\\think\\session\\driver\\' . ucwords($config['type']);
|
||||
|
||||
// 检查驱动类
|
||||
if (!class_exists($class) || !session_set_save_handler(new $class($config))) {
|
||||
throw new ClassNotFoundException('error session handler:' . $class, $class);
|
||||
}
|
||||
}
|
||||
|
||||
if ($isDoStart) {
|
||||
session_start();
|
||||
$this->init = true;
|
||||
} else {
|
||||
$this->init = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* session自动启动或者初始化
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function boot()
|
||||
{
|
||||
if (is_null($this->init)) {
|
||||
$this->init();
|
||||
} elseif (false === $this->init) {
|
||||
if (PHP_SESSION_ACTIVE != session_status()) {
|
||||
session_start();
|
||||
}
|
||||
$this->init = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* session设置
|
||||
* @access public
|
||||
* @param string $name session名称
|
||||
* @param mixed $value session值
|
||||
* @param string|null $prefix 作用域(前缀)
|
||||
* @return void
|
||||
*/
|
||||
public function set($name, $value, $prefix = null)
|
||||
{
|
||||
$this->lock();
|
||||
|
||||
empty($this->init) && $this->boot();
|
||||
|
||||
$prefix = !is_null($prefix) ? $prefix : $this->prefix;
|
||||
|
||||
if (strpos($name, '.')) {
|
||||
// 二维数组赋值
|
||||
list($name1, $name2) = explode('.', $name);
|
||||
if ($prefix) {
|
||||
$_SESSION[$prefix][$name1][$name2] = $value;
|
||||
} else {
|
||||
$_SESSION[$name1][$name2] = $value;
|
||||
}
|
||||
} elseif ($prefix) {
|
||||
$_SESSION[$prefix][$name] = $value;
|
||||
} else {
|
||||
$_SESSION[$name] = $value;
|
||||
}
|
||||
|
||||
$this->unlock();
|
||||
}
|
||||
|
||||
/**
|
||||
* session获取
|
||||
* @access public
|
||||
* @param string $name session名称
|
||||
* @param string|null $prefix 作用域(前缀)
|
||||
* @return mixed
|
||||
*/
|
||||
public function get($name = '', $prefix = null)
|
||||
{
|
||||
$this->lock();
|
||||
|
||||
empty($this->init) && $this->boot();
|
||||
|
||||
$prefix = !is_null($prefix) ? $prefix : $this->prefix;
|
||||
|
||||
$value = $prefix ? (!empty($_SESSION[$prefix]) ? $_SESSION[$prefix] : []) : $_SESSION;
|
||||
|
||||
if ('' != $name) {
|
||||
$name = explode('.', $name);
|
||||
|
||||
foreach ($name as $val) {
|
||||
if (isset($value[$val])) {
|
||||
$value = $value[$val];
|
||||
} else {
|
||||
$value = null;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->unlock();
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* session 读写锁驱动实例化
|
||||
*/
|
||||
protected function initDriver()
|
||||
{
|
||||
// 不在 init 方法中实例化lockDriver,是因为 init 方法不一定先于 set 或 get 方法调用
|
||||
$config = Container::get('config')->pull('session');
|
||||
|
||||
if (!empty($config['type']) && isset($config['use_lock']) && $config['use_lock']) {
|
||||
// 读取session驱动
|
||||
$class = false !== strpos($config['type'], '\\') ? $config['type'] : '\\think\\session\\driver\\' . ucwords($config['type']);
|
||||
|
||||
// 检查驱动类及类中是否存在 lock 和 unlock 函数
|
||||
if (class_exists($class) && method_exists($class, 'lock') && method_exists($class, 'unlock')) {
|
||||
$this->lockDriver = new $class($config);
|
||||
}
|
||||
}
|
||||
|
||||
// 通过cookie获得session_id
|
||||
if (isset($config['name']) && $config['name']) {
|
||||
$this->sessKey = $config['name'];
|
||||
}
|
||||
|
||||
if (isset($config['lock_timeout']) && $config['lock_timeout'] > 0) {
|
||||
$this->lockTimeout = $config['lock_timeout'];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* session 读写加锁
|
||||
* @access protected
|
||||
* @return void
|
||||
*/
|
||||
protected function lock()
|
||||
{
|
||||
if (empty($this->lock)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->initDriver();
|
||||
|
||||
if (null !== $this->lockDriver && method_exists($this->lockDriver, 'lock')) {
|
||||
$t = time();
|
||||
// 使用 session_id 作为互斥条件,即只对同一 session_id 的会话互斥。第一次请求没有 session_id
|
||||
$sessID = isset($_COOKIE[$this->sessKey]) ? $_COOKIE[$this->sessKey] : '';
|
||||
|
||||
do {
|
||||
if (time() - $t > $this->lockTimeout) {
|
||||
$this->unlock();
|
||||
}
|
||||
} while (!$this->lockDriver->lock($sessID, $this->lockTimeout));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* session 读写解锁
|
||||
* @access protected
|
||||
* @return void
|
||||
*/
|
||||
protected function unlock()
|
||||
{
|
||||
if (empty($this->lock)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->pause();
|
||||
|
||||
if ($this->lockDriver && method_exists($this->lockDriver, 'unlock')) {
|
||||
$sessID = isset($_COOKIE[$this->sessKey]) ? $_COOKIE[$this->sessKey] : '';
|
||||
$this->lockDriver->unlock($sessID);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* session获取并删除
|
||||
* @access public
|
||||
* @param string $name session名称
|
||||
* @param string|null $prefix 作用域(前缀)
|
||||
* @return mixed
|
||||
*/
|
||||
public function pull($name, $prefix = null)
|
||||
{
|
||||
$result = $this->get($name, $prefix);
|
||||
|
||||
if ($result) {
|
||||
$this->delete($name, $prefix);
|
||||
return $result;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* session设置 下一次请求有效
|
||||
* @access public
|
||||
* @param string $name session名称
|
||||
* @param mixed $value session值
|
||||
* @param string|null $prefix 作用域(前缀)
|
||||
* @return void
|
||||
*/
|
||||
public function flash($name, $value)
|
||||
{
|
||||
$this->set($name, $value);
|
||||
|
||||
if (!$this->has('__flash__.__time__')) {
|
||||
$this->set('__flash__.__time__', $_SERVER['REQUEST_TIME_FLOAT']);
|
||||
}
|
||||
|
||||
$this->push('__flash__', $name);
|
||||
}
|
||||
|
||||
/**
|
||||
* 清空当前请求的session数据
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function flush()
|
||||
{
|
||||
if (!$this->init) {
|
||||
return;
|
||||
}
|
||||
|
||||
$item = $this->get('__flash__');
|
||||
|
||||
if (!empty($item)) {
|
||||
$time = $item['__time__'];
|
||||
|
||||
if ($_SERVER['REQUEST_TIME_FLOAT'] > $time) {
|
||||
unset($item['__time__']);
|
||||
$this->delete($item);
|
||||
$this->set('__flash__', []);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除session数据
|
||||
* @access public
|
||||
* @param string|array $name session名称
|
||||
* @param string|null $prefix 作用域(前缀)
|
||||
* @return void
|
||||
*/
|
||||
public function delete($name, $prefix = null)
|
||||
{
|
||||
empty($this->init) && $this->boot();
|
||||
|
||||
$prefix = !is_null($prefix) ? $prefix : $this->prefix;
|
||||
|
||||
if (is_array($name)) {
|
||||
foreach ($name as $key) {
|
||||
$this->delete($key, $prefix);
|
||||
}
|
||||
} elseif (strpos($name, '.')) {
|
||||
list($name1, $name2) = explode('.', $name);
|
||||
if ($prefix) {
|
||||
unset($_SESSION[$prefix][$name1][$name2]);
|
||||
} else {
|
||||
unset($_SESSION[$name1][$name2]);
|
||||
}
|
||||
} else {
|
||||
if ($prefix) {
|
||||
unset($_SESSION[$prefix][$name]);
|
||||
} else {
|
||||
unset($_SESSION[$name]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 清空session数据
|
||||
* @access public
|
||||
* @param string|null $prefix 作用域(前缀)
|
||||
* @return void
|
||||
*/
|
||||
public function clear($prefix = null)
|
||||
{
|
||||
empty($this->init) && $this->boot();
|
||||
$prefix = !is_null($prefix) ? $prefix : $this->prefix;
|
||||
|
||||
if ($prefix) {
|
||||
unset($_SESSION[$prefix]);
|
||||
} else {
|
||||
$_SESSION = [];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断session数据
|
||||
* @access public
|
||||
* @param string $name session名称
|
||||
* @param string|null $prefix
|
||||
* @return bool
|
||||
*/
|
||||
public function has($name, $prefix = null)
|
||||
{
|
||||
empty($this->init) && $this->boot();
|
||||
$prefix = !is_null($prefix) ? $prefix : $this->prefix;
|
||||
|
||||
if (strpos($name, '.')) {
|
||||
// 支持数组
|
||||
list($name1, $name2) = explode('.', $name);
|
||||
|
||||
return $prefix ? isset($_SESSION[$prefix][$name1][$name2]) : isset($_SESSION[$name1][$name2]);
|
||||
} else {
|
||||
return $prefix ? isset($_SESSION[$prefix][$name]) : isset($_SESSION[$name]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加数据到一个session数组
|
||||
* @access public
|
||||
* @param string $key
|
||||
* @param mixed $value
|
||||
* @return void
|
||||
*/
|
||||
public function push($key, $value)
|
||||
{
|
||||
$array = $this->get($key);
|
||||
|
||||
if (is_null($array)) {
|
||||
$array = [];
|
||||
}
|
||||
|
||||
$array[] = $value;
|
||||
|
||||
$this->set($key, $array);
|
||||
}
|
||||
|
||||
/**
|
||||
* 启动session
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function start()
|
||||
{
|
||||
session_start();
|
||||
|
||||
$this->init = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 销毁session
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function destroy()
|
||||
{
|
||||
if (!empty($_SESSION)) {
|
||||
$_SESSION = [];
|
||||
}
|
||||
|
||||
session_unset();
|
||||
session_destroy();
|
||||
|
||||
$this->init = null;
|
||||
$this->lockDriver = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 重新生成session_id
|
||||
* @access public
|
||||
* @param bool $delete 是否删除关联会话文件
|
||||
* @return void
|
||||
*/
|
||||
public function regenerate($delete = false)
|
||||
{
|
||||
session_regenerate_id($delete);
|
||||
}
|
||||
|
||||
/**
|
||||
* 暂停session
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function pause()
|
||||
{
|
||||
// 暂停session
|
||||
session_write_close();
|
||||
$this->init = false;
|
||||
}
|
||||
}
|
|
@ -2,17 +2,16 @@
|
|||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2019 http://thinkphp.cn All rights reserved.
|
||||
// | Copyright (c) 2006~2018 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\template\exception\TemplateNotFoundException;
|
||||
use think\exception\TemplateNotFoundException;
|
||||
|
||||
/**
|
||||
* ThinkPHP分离出来的模板引擎
|
||||
|
@ -36,7 +35,6 @@ class Template
|
|||
'view_base' => '',
|
||||
'view_suffix' => 'html', // 默认模板文件后缀
|
||||
'view_depr' => DIRECTORY_SEPARATOR,
|
||||
'cache_path' => '',
|
||||
'cache_suffix' => 'php', // 默认模板缓存后缀
|
||||
'tpl_deny_func_list' => 'echo,exit', // 模板引擎禁用函数
|
||||
'tpl_deny_php' => false, // 默认模板引擎是否禁用PHP原生代码
|
||||
|
@ -87,34 +85,49 @@ class Template
|
|||
*/
|
||||
public function __construct(array $config = [])
|
||||
{
|
||||
$this->config = array_merge($this->config, $config);
|
||||
|
||||
$this->config['cache_path'] = Container::get('app')->getRuntimePath() . 'temp/';
|
||||
$this->config = array_merge($this->config, $config);
|
||||
$this->config['taglib_begin_origin'] = $this->config['taglib_begin'];
|
||||
$this->config['taglib_end_origin'] = $this->config['taglib_end'];
|
||||
|
||||
$this->config['taglib_begin'] = preg_quote($this->config['taglib_begin'], '/');
|
||||
$this->config['taglib_end'] = preg_quote($this->config['taglib_end'], '/');
|
||||
$this->config['tpl_begin'] = preg_quote($this->config['tpl_begin'], '/');
|
||||
$this->config['tpl_end'] = preg_quote($this->config['tpl_end'], '/');
|
||||
$this->config['taglib_begin'] = $this->stripPreg($this->config['taglib_begin']);
|
||||
$this->config['taglib_end'] = $this->stripPreg($this->config['taglib_end']);
|
||||
$this->config['tpl_begin'] = $this->stripPreg($this->config['tpl_begin']);
|
||||
$this->config['tpl_end'] = $this->stripPreg($this->config['tpl_end']);
|
||||
|
||||
// 初始化模板编译存储器
|
||||
$type = $this->config['compile_type'] ? $this->config['compile_type'] : 'File';
|
||||
$class = false !== strpos($type, '\\') ? $type : '\\think\\template\\driver\\' . ucwords($type);
|
||||
|
||||
$type = $this->config['compile_type'] ? $this->config['compile_type'] : 'File';
|
||||
$class = false !== strpos($type, '\\') ? $type : '\\think\\template\\driver\\' . ucwords($type);
|
||||
$this->storage = new $class();
|
||||
}
|
||||
|
||||
/**
|
||||
* 字符串替换 避免正则混淆
|
||||
* @access private
|
||||
* @param string $str
|
||||
* @return string
|
||||
*/
|
||||
private function stripPreg($str)
|
||||
{
|
||||
return str_replace(
|
||||
['{', '}', '(', ')', '|', '[', ']', '-', '+', '*', '.', '^', '?'],
|
||||
['\{', '\}', '\(', '\)', '\|', '\[', '\]', '\-', '\+', '\*', '\.', '\^', '\?'],
|
||||
$str);
|
||||
}
|
||||
|
||||
/**
|
||||
* 模板变量赋值
|
||||
* @access public
|
||||
* @param mixed $name
|
||||
* @param mixed $value
|
||||
* @return $this
|
||||
* @return void
|
||||
*/
|
||||
public function assign(array $vars = [])
|
||||
public function assign($name, $value = '')
|
||||
{
|
||||
$this->data = array_merge($this->data, $vars);
|
||||
return $this;
|
||||
if (is_array($name)) {
|
||||
$this->data = array_merge($this->data, $name);
|
||||
} else {
|
||||
$this->data[$name] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -129,26 +142,20 @@ class Template
|
|||
}
|
||||
|
||||
/**
|
||||
* 模板引擎配置
|
||||
* 模板引擎配置项
|
||||
* @access public
|
||||
* @param array $config
|
||||
* @return $this
|
||||
* @param array|string $config
|
||||
* @return void|array
|
||||
*/
|
||||
public function config(array $config)
|
||||
public function config($config)
|
||||
{
|
||||
$this->config = array_merge($this->config, $config);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取模板引擎配置项
|
||||
* @access public
|
||||
* @param string $name
|
||||
* @return mixed
|
||||
*/
|
||||
public function getConfig(string $name)
|
||||
{
|
||||
return $this->config[$name] ?? null;
|
||||
if (is_array($config)) {
|
||||
$this->config = array_merge($this->config, $config);
|
||||
} elseif (isset($this->config[$config])) {
|
||||
return $this->config[$config];
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -157,24 +164,24 @@ class Template
|
|||
* @param string $name 变量名
|
||||
* @return mixed
|
||||
*/
|
||||
public function get(string $name = '')
|
||||
public function get($name = '')
|
||||
{
|
||||
if ('' == $name) {
|
||||
return $this->data;
|
||||
}
|
||||
} else {
|
||||
$data = $this->data;
|
||||
|
||||
$data = $this->data;
|
||||
|
||||
foreach (explode('.', $name) as $key => $val) {
|
||||
if (isset($data[$val])) {
|
||||
$data = $data[$val];
|
||||
} else {
|
||||
$data = null;
|
||||
break;
|
||||
foreach (explode('.', $name) as $key => $val) {
|
||||
if (isset($data[$val])) {
|
||||
$data = $data[$val];
|
||||
} else {
|
||||
$data = null;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $data;
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -182,18 +189,35 @@ class Template
|
|||
* @access public
|
||||
* @param string $template 模板文件
|
||||
* @param array $vars 模板变量
|
||||
* @param array $config 模板参数
|
||||
* @return void
|
||||
*/
|
||||
public function fetch(string $template, array $vars = []): void
|
||||
public function fetch($template, $vars = [], $config = [])
|
||||
{
|
||||
if ($vars) {
|
||||
$this->data = array_merge($this->data, $vars);
|
||||
$this->data = $vars;
|
||||
}
|
||||
|
||||
if ($config) {
|
||||
$this->config($config);
|
||||
}
|
||||
|
||||
$cache = Container::get('cache');
|
||||
|
||||
if (!empty($this->config['cache_id']) && $this->config['display_cache']) {
|
||||
// 读取渲染缓存
|
||||
$cacheContent = $cache->get($this->config['cache_id']);
|
||||
|
||||
if (false !== $cacheContent) {
|
||||
echo $cacheContent;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
$template = $this->parseTemplateFile($template);
|
||||
|
||||
if ($template) {
|
||||
$cacheFile = $this->config['cache_path'] . $this->config['cache_prefix'] . md5($this->config['layout_on'] . $this->config['layout_name'] . $template) . '.' . ltrim($this->config['cache_suffix'], '.');
|
||||
$cacheFile = $this->config['cache_path'] . $this->config['cache_prefix'] . md5($this->config['layout_name'] . $template) . '.' . ltrim($this->config['cache_suffix'], '.');
|
||||
|
||||
if (!$this->checkCache($cacheFile)) {
|
||||
// 缓存无效 重新模板编译
|
||||
|
@ -211,6 +235,11 @@ class Template
|
|||
// 获取并清空缓存
|
||||
$content = ob_get_clean();
|
||||
|
||||
if (!empty($this->config['cache_id']) && $this->config['display_cache']) {
|
||||
// 缓存页面输出
|
||||
$cache->set($this->config['cache_id'], $content, $this->config['cache_time']);
|
||||
}
|
||||
|
||||
echo $content;
|
||||
}
|
||||
}
|
||||
|
@ -220,12 +249,17 @@ class Template
|
|||
* @access public
|
||||
* @param string $content 模板内容
|
||||
* @param array $vars 模板变量
|
||||
* @param array $config 模板参数
|
||||
* @return void
|
||||
*/
|
||||
public function display(string $content, array $vars = []): void
|
||||
public function display($content, $vars = [], $config = [])
|
||||
{
|
||||
if ($vars) {
|
||||
$this->data = array_merge($this->data, $vars);
|
||||
$this->data = $vars;
|
||||
}
|
||||
|
||||
if ($config) {
|
||||
$this->config($config);
|
||||
}
|
||||
|
||||
$cacheFile = $this->config['cache_path'] . $this->config['cache_prefix'] . md5($content) . '.' . ltrim($this->config['cache_suffix'], '.');
|
||||
|
@ -244,9 +278,9 @@ class Template
|
|||
* @access public
|
||||
* @param mixed $name 布局模板名称 false 则关闭布局
|
||||
* @param string $replace 布局模板内容替换标识
|
||||
* @return $this
|
||||
* @return object
|
||||
*/
|
||||
public function layout($name, string $replace = '')
|
||||
public function layout($name, $replace = '')
|
||||
{
|
||||
if (false === $name) {
|
||||
// 关闭布局
|
||||
|
@ -273,11 +307,22 @@ class Template
|
|||
* 如果无效则需要重新编译
|
||||
* @access private
|
||||
* @param string $cacheFile 缓存文件名
|
||||
* @return bool
|
||||
* @return boolean
|
||||
*/
|
||||
private function checkCache(string $cacheFile): bool
|
||||
private function checkCache($cacheFile)
|
||||
{
|
||||
if (!$this->config['tpl_cache'] || !is_file($cacheFile) || !$handle = @fopen($cacheFile, "r")) {
|
||||
// 未开启缓存功能
|
||||
if (!$this->config['tpl_cache']) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 缓存文件不存在
|
||||
if (!is_file($cacheFile)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 读取缓存文件失败
|
||||
if (!$handle = @fopen($cacheFile, "r")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -306,6 +351,22 @@ class Template
|
|||
return $this->storage->check($cacheFile, $this->config['cache_time']);
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查编译缓存是否存在
|
||||
* @access public
|
||||
* @param string $cacheId 缓存的id
|
||||
* @return boolean
|
||||
*/
|
||||
public function isCache($cacheId)
|
||||
{
|
||||
if ($cacheId && $this->config['display_cache']) {
|
||||
// 缓存页面输出
|
||||
return Container::get('cache')->has($cacheId);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 编译模板文件内容
|
||||
* @access private
|
||||
|
@ -313,7 +374,7 @@ class Template
|
|||
* @param string $cacheFile 缓存文件名
|
||||
* @return void
|
||||
*/
|
||||
private function compiler(string &$content, string $cacheFile): void
|
||||
private function compiler(&$content, $cacheFile)
|
||||
{
|
||||
// 判断是否启用布局
|
||||
if ($this->config['layout_on']) {
|
||||
|
@ -344,7 +405,7 @@ class Template
|
|||
}
|
||||
|
||||
// 优化生成的php代码
|
||||
$content = preg_replace('/\?>\s*<\?php\s(?!echo\b|\bend)/s', '', $content);
|
||||
$content = preg_replace('/\?>\s*<\?php\s(?!echo\b)/s', '', $content);
|
||||
|
||||
// 模板过滤输出
|
||||
$replace = $this->config['tpl_replace_string'];
|
||||
|
@ -356,6 +417,8 @@ class Template
|
|||
$this->storage->write($cacheFile, $content);
|
||||
|
||||
$this->includeFile = [];
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -365,7 +428,7 @@ class Template
|
|||
* @param string $content 要解析的模板内容
|
||||
* @return void
|
||||
*/
|
||||
public function parse(string &$content): void
|
||||
public function parse(&$content)
|
||||
{
|
||||
// 内容为空不解析
|
||||
if (empty($content)) {
|
||||
|
@ -427,6 +490,8 @@ class Template
|
|||
|
||||
// 还原被替换的Literal标签
|
||||
$this->parseLiteral($content, true);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -436,15 +501,17 @@ class Template
|
|||
* @return void
|
||||
* @throws \think\Exception
|
||||
*/
|
||||
private function parsePhp(string &$content): void
|
||||
private function parsePhp(&$content)
|
||||
{
|
||||
// 短标签的情况要将<?标签用echo方式输出 否则无法正常输出xml标识
|
||||
$content = preg_replace('/(<\?(?!php|=|$))/i', '<?php echo \'\\1\'; ?>' . "\n", $content);
|
||||
|
||||
// PHP语法检查
|
||||
if ($this->config['tpl_deny_php'] && false !== strpos($content, '<?php')) {
|
||||
throw new Exception('not allow php tag');
|
||||
throw new Exception('not allow php tag', 11600);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -453,7 +520,7 @@ class Template
|
|||
* @param string $content 要解析的模板内容
|
||||
* @return void
|
||||
*/
|
||||
private function parseLayout(string &$content): void
|
||||
private function parseLayout(&$content)
|
||||
{
|
||||
// 读取模板中的布局标签
|
||||
if (preg_match($this->getRegex('layout'), $content, $matches)) {
|
||||
|
@ -475,6 +542,8 @@ class Template
|
|||
} else {
|
||||
$content = str_replace('{__NOLAYOUT__}', '', $content);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -483,7 +552,7 @@ class Template
|
|||
* @param string $content 要解析的模板内容
|
||||
* @return void
|
||||
*/
|
||||
private function parseInclude(string &$content): void
|
||||
private function parseInclude(&$content)
|
||||
{
|
||||
$regex = $this->getRegex('include');
|
||||
$func = function ($template) use (&$func, &$regex, &$content) {
|
||||
|
@ -523,7 +592,7 @@ class Template
|
|||
* @param string $content 要解析的模板内容
|
||||
* @return void
|
||||
*/
|
||||
private function parseExtend(string &$content): void
|
||||
private function parseExtend(&$content)
|
||||
{
|
||||
$regex = $this->getRegex('extend');
|
||||
$array = $blocks = $baseBlocks = [];
|
||||
|
@ -612,7 +681,7 @@ class Template
|
|||
* @param boolean $restore 是否为还原
|
||||
* @return void
|
||||
*/
|
||||
private function parseLiteral(string &$content, bool $restore = false): void
|
||||
private function parseLiteral(&$content, $restore = false)
|
||||
{
|
||||
$regex = $this->getRegex($restore ? 'restoreliteral' : 'literal');
|
||||
|
||||
|
@ -647,7 +716,7 @@ class Template
|
|||
* @param boolean $sort 是否排序
|
||||
* @return array
|
||||
*/
|
||||
private function parseBlock(string &$content, bool $sort = false): array
|
||||
private function parseBlock(&$content, $sort = false)
|
||||
{
|
||||
$regex = $this->getRegex('block');
|
||||
$result = [];
|
||||
|
@ -699,7 +768,7 @@ class Template
|
|||
* @param string $content 模板内容
|
||||
* @return array|null
|
||||
*/
|
||||
private function getIncludeTagLib(string &$content)
|
||||
private function getIncludeTagLib(&$content)
|
||||
{
|
||||
// 搜索是否有TagLib标签
|
||||
if (preg_match($this->getRegex('taglib'), $content, $matches)) {
|
||||
|
@ -708,6 +777,8 @@ class Template
|
|||
|
||||
return explode(',', $matches['name']);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -718,7 +789,7 @@ class Template
|
|||
* @param boolean $hide 是否隐藏标签库前缀
|
||||
* @return void
|
||||
*/
|
||||
public function parseTagLib(string $tagLib, string &$content, bool $hide = false): void
|
||||
public function parseTagLib($tagLib, &$content, $hide = false)
|
||||
{
|
||||
if (false !== strpos($tagLib, '\\')) {
|
||||
// 支持指定标签库的命名空间
|
||||
|
@ -731,6 +802,8 @@ class Template
|
|||
$tLib = new $className($this);
|
||||
|
||||
$tLib->parseTag($content, $hide ? '' : $tagLib);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -740,7 +813,7 @@ class Template
|
|||
* @param string $name 不为空时返回指定的属性名
|
||||
* @return array
|
||||
*/
|
||||
public function parseAttr(string $str, string $name = null): array
|
||||
public function parseAttr($str, $name = null)
|
||||
{
|
||||
$regex = '/\s+(?>(?P<name>[\w-]+)\s*)=(?>\s*)([\"\'])(?P<value>(?:(?!\\2).)*)\\2/is';
|
||||
$array = [];
|
||||
|
@ -754,9 +827,9 @@ class Template
|
|||
|
||||
if (!empty($name) && isset($array[$name])) {
|
||||
return $array[$name];
|
||||
} else {
|
||||
return $array;
|
||||
}
|
||||
|
||||
return $array;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -766,7 +839,7 @@ class Template
|
|||
* @param string $content 要解析的模板内容
|
||||
* @return void
|
||||
*/
|
||||
private function parseTag(string &$content): void
|
||||
private function parseTag(&$content)
|
||||
{
|
||||
$regex = $this->getRegex('tag');
|
||||
|
||||
|
@ -902,7 +975,7 @@ class Template
|
|||
* @param string $varStr 变量数据
|
||||
* @return void
|
||||
*/
|
||||
public function parseVar(string &$varStr): void
|
||||
public function parseVar(&$varStr)
|
||||
{
|
||||
$varStr = trim($varStr);
|
||||
|
||||
|
@ -967,9 +1040,9 @@ class Template
|
|||
* @access public
|
||||
* @param string $varStr 变量字符串
|
||||
* @param bool $autoescape 自动转义
|
||||
* @return string
|
||||
* @return void
|
||||
*/
|
||||
public function parseVarFunction(string &$varStr, bool $autoescape = true): string
|
||||
public function parseVarFunction(&$varStr, $autoescape = true)
|
||||
{
|
||||
if (!$autoescape && false === strpos($varStr, '|')) {
|
||||
return $varStr;
|
||||
|
@ -1007,7 +1080,7 @@ class Template
|
|||
|
||||
switch (strtolower($fun)) {
|
||||
case 'raw':
|
||||
break;
|
||||
continue;
|
||||
case 'date':
|
||||
$name = 'date(' . $args[1] . ',!is_numeric(' . $name . ')? strtotime(' . $name . ') : ' . $name . ')';
|
||||
break;
|
||||
|
@ -1062,7 +1135,7 @@ class Template
|
|||
* @param array $vars 变量数组
|
||||
* @return string
|
||||
*/
|
||||
public function parseThinkVar(array $vars): string
|
||||
public function parseThinkVar($vars)
|
||||
{
|
||||
$type = strtoupper(trim(array_shift($vars)));
|
||||
$param = implode('.', $vars);
|
||||
|
@ -1070,29 +1143,35 @@ class Template
|
|||
if ($vars) {
|
||||
switch ($type) {
|
||||
case 'SERVER':
|
||||
$parseStr = '$_SERVER[\'' . $param . '\']';
|
||||
$parseStr = 'app(\'request\')->server(\'' . $param . '\')';
|
||||
break;
|
||||
case 'GET':
|
||||
$parseStr = '$_GET[\'' . $param . '\']';
|
||||
$parseStr = 'app(\'request\')->get(\'' . $param . '\')';
|
||||
break;
|
||||
case 'POST':
|
||||
$parseStr = '$_POST[\'' . $param . '\']';
|
||||
$parseStr = 'app(\'request\')->post(\'' . $param . '\')';
|
||||
break;
|
||||
case 'COOKIE':
|
||||
$parseStr = '$_COOKIE[\'' . $param . '\']';
|
||||
$parseStr = 'app(\'cookie\')->get(\'' . $param . '\')';
|
||||
break;
|
||||
case 'SESSION':
|
||||
$parseStr = '$_SESSION[\'' . $param . '\']';
|
||||
$parseStr = 'app(\'session\')->get(\'' . $param . '\')';
|
||||
break;
|
||||
case 'ENV':
|
||||
$parseStr = '$_ENV[\'' . $param . '\']';
|
||||
$parseStr = 'app(\'request\')->env(\'' . $param . '\')';
|
||||
break;
|
||||
case 'REQUEST':
|
||||
$parseStr = '$_REQUEST[\'' . $param . '\']';
|
||||
$parseStr = 'app(\'request\')->request(\'' . $param . '\')';
|
||||
break;
|
||||
case 'CONST':
|
||||
$parseStr = strtoupper($param);
|
||||
break;
|
||||
case 'LANG':
|
||||
$parseStr = 'app(\'lang\')->get(\'' . $param . '\')';
|
||||
break;
|
||||
case 'CONFIG':
|
||||
$parseStr = 'app(\'config\')->get(\'' . $param . '\')';
|
||||
break;
|
||||
default:
|
||||
$parseStr = '\'\'';
|
||||
break;
|
||||
|
@ -1102,6 +1181,9 @@ class Template
|
|||
case 'NOW':
|
||||
$parseStr = "date('Y-m-d g:i a',time())";
|
||||
break;
|
||||
case 'VERSION':
|
||||
$parseStr = 'app()->version()';
|
||||
break;
|
||||
case 'LDELIM':
|
||||
$parseStr = '\'' . ltrim($this->config['tpl_begin'], '\\') . '\'';
|
||||
break;
|
||||
|
@ -1126,7 +1208,7 @@ class Template
|
|||
* @param string $templateName 模板文件名
|
||||
* @return string
|
||||
*/
|
||||
private function parseTemplateName(string $templateName): string
|
||||
private function parseTemplateName($templateName)
|
||||
{
|
||||
$array = explode(',', $templateName);
|
||||
$parseStr = '';
|
||||
|
@ -1158,11 +1240,11 @@ class Template
|
|||
* @param string $template 文件名
|
||||
* @return string|false
|
||||
*/
|
||||
private function parseTemplateFile(string $template): string
|
||||
private function parseTemplateFile($template)
|
||||
{
|
||||
if ('' == pathinfo($template, PATHINFO_EXTENSION)) {
|
||||
if (strpos($template, '@')) {
|
||||
list($app, $template) = explode('@', $template);
|
||||
list($module, $template) = explode('@', $template);
|
||||
}
|
||||
|
||||
if (0 !== strpos($template, '/')) {
|
||||
|
@ -1172,10 +1254,10 @@ class Template
|
|||
}
|
||||
|
||||
if ($this->config['view_base']) {
|
||||
$app = isset($app) ? $app : '';
|
||||
$path = $this->config['view_base'] . ($app ? $app . DIRECTORY_SEPARATOR : '');
|
||||
$module = isset($module) ? $module : Container::get('request')->module();
|
||||
$path = $this->config['view_base'] . ($module ? $module . DIRECTORY_SEPARATOR : '');
|
||||
} else {
|
||||
$path = $this->config['view_path'];
|
||||
$path = isset($module) ? Container::get('app')->getAppPath() . $module . DIRECTORY_SEPARATOR . basename($this->config['view_path']) . DIRECTORY_SEPARATOR : $this->config['view_path'];
|
||||
}
|
||||
|
||||
$template = $path . $template . '.' . ltrim($this->config['view_suffix'], '.');
|
||||
|
@ -1186,9 +1268,9 @@ class Template
|
|||
$this->includeFile[$template] = filemtime($template);
|
||||
|
||||
return $template;
|
||||
} else {
|
||||
throw new TemplateNotFoundException('template not exists:' . $template, $template);
|
||||
}
|
||||
|
||||
throw new TemplateNotFoundException('template not exists:' . $template, $template);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1197,7 +1279,7 @@ class Template
|
|||
* @param string $tagName 标签名
|
||||
* @return string
|
||||
*/
|
||||
private function getRegex(string $tagName): string
|
||||
private function getRegex($tagName)
|
||||
{
|
||||
$regex = '';
|
||||
if ('tag' == $tagName) {
|
||||
|
@ -1217,9 +1299,9 @@ class Template
|
|||
switch ($tagName) {
|
||||
case 'block':
|
||||
if ($single) {
|
||||
$regex = $begin . '(?:' . $tagName . '\b\s+(?>(?:(?!name=).)*)\bname=([\'\"])(?P<name>[\$\w\-\/\.]+)\\1(?>[^' . $end . ']*)|\/' . $tagName . ')' . $end;
|
||||
$regex = $begin . '(?:' . $tagName . '\b(?>(?:(?!name=).)*)\bname=([\'\"])(?P<name>[\$\w\-\/\.]+)\\1(?>[^' . $end . ']*)|\/' . $tagName . ')' . $end;
|
||||
} else {
|
||||
$regex = $begin . '(?:' . $tagName . '\b\s+(?>(?:(?!name=).)*)\bname=([\'\"])(?P<name>[\$\w\-\/\.]+)\\1(?>(?:(?!' . $end . ').)*)|\/' . $tagName . ')' . $end;
|
||||
$regex = $begin . '(?:' . $tagName . '\b(?>(?:(?!name=).)*)\bname=([\'\"])(?P<name>[\$\w\-\/\.]+)\\1(?>(?:(?!' . $end . ').)*)|\/' . $tagName . ')' . $end;
|
||||
}
|
||||
break;
|
||||
case 'literal':
|
||||
|
@ -1245,9 +1327,9 @@ class Template
|
|||
$name = 'name';
|
||||
}
|
||||
if ($single) {
|
||||
$regex = $begin . $tagName . '\b\s+(?>(?:(?!' . $name . '=).)*)\b' . $name . '=([\'\"])(?P<name>[\$\w\-\/\.\:@,\\\\]+)\\1(?>[^' . $end . ']*)' . $end;
|
||||
$regex = $begin . $tagName . '\b(?>(?:(?!' . $name . '=).)*)\b' . $name . '=([\'\"])(?P<name>[\$\w\-\/\.\:@,\\\\]+)\\1(?>[^' . $end . ']*)' . $end;
|
||||
} else {
|
||||
$regex = $begin . $tagName . '\b\s+(?>(?:(?!' . $name . '=).)*)\b' . $name . '=([\'\"])(?P<name>[\$\w\-\/\.\:@,\\\\]+)\\1(?>(?:(?!' . $end . ').)*)' . $end;
|
||||
$regex = $begin . $tagName . '\b(?>(?:(?!' . $name . '=).)*)\b' . $name . '=([\'\"])(?P<name>[\$\w\-\/\.\:@,\\\\]+)\\1(?>(?:(?!' . $end . ').)*)' . $end;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -1255,12 +1337,4 @@ class Template
|
|||
|
||||
return '/' . $regex . '/is';
|
||||
}
|
||||
|
||||
public function __debugInfo()
|
||||
{
|
||||
$data = get_object_vars($this);
|
||||
unset($data['storage']);
|
||||
|
||||
return $data;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,356 @@
|
|||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace think;
|
||||
|
||||
class Url
|
||||
{
|
||||
/**
|
||||
* ROOT地址
|
||||
* @var string
|
||||
*/
|
||||
protected $root;
|
||||
|
||||
/**
|
||||
* 绑定检查
|
||||
* @var bool
|
||||
*/
|
||||
protected $bindCheck;
|
||||
|
||||
/**
|
||||
* 应用对象
|
||||
* @var App
|
||||
*/
|
||||
protected $app;
|
||||
|
||||
public function __construct(App $app)
|
||||
{
|
||||
$this->app = $app;
|
||||
|
||||
if (is_file($app->getRuntimePath() . 'route.php')) {
|
||||
// 读取路由映射文件
|
||||
$app['route']->setName(include $app->getRuntimePath() . 'route.php');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* URL生成 支持路由反射
|
||||
* @access public
|
||||
* @param string $url 路由地址
|
||||
* @param string|array $vars 参数(支持数组和字符串)a=val&b=val2... ['a'=>'val1', 'b'=>'val2']
|
||||
* @param string|bool $suffix 伪静态后缀,默认为true表示获取配置值
|
||||
* @param boolean|string $domain 是否显示域名 或者直接传入域名
|
||||
* @return string
|
||||
*/
|
||||
public function build($url = '', $vars = '', $suffix = true, $domain = false)
|
||||
{
|
||||
// 解析URL
|
||||
if (0 === strpos($url, '[') && $pos = strpos($url, ']')) {
|
||||
// [name] 表示使用路由命名标识生成URL
|
||||
$name = substr($url, 1, $pos - 1);
|
||||
$url = 'name' . substr($url, $pos + 1);
|
||||
}
|
||||
|
||||
if (false === strpos($url, '://') && 0 !== strpos($url, '/')) {
|
||||
$info = parse_url($url);
|
||||
$url = !empty($info['path']) ? $info['path'] : '';
|
||||
|
||||
if (isset($info['fragment'])) {
|
||||
// 解析锚点
|
||||
$anchor = $info['fragment'];
|
||||
|
||||
if (false !== strpos($anchor, '?')) {
|
||||
// 解析参数
|
||||
list($anchor, $info['query']) = explode('?', $anchor, 2);
|
||||
}
|
||||
|
||||
if (false !== strpos($anchor, '@')) {
|
||||
// 解析域名
|
||||
list($anchor, $domain) = explode('@', $anchor, 2);
|
||||
}
|
||||
} elseif (strpos($url, '@') && false === strpos($url, '\\')) {
|
||||
// 解析域名
|
||||
list($url, $domain) = explode('@', $url, 2);
|
||||
}
|
||||
}
|
||||
|
||||
// 解析参数
|
||||
if (is_string($vars)) {
|
||||
// aaa=1&bbb=2 转换成数组
|
||||
parse_str($vars, $vars);
|
||||
}
|
||||
|
||||
if ($url) {
|
||||
$rule = $this->app['route']->getName(isset($name) ? $name : $url . (isset($info['query']) ? '?' . $info['query'] : ''));
|
||||
|
||||
if (is_null($rule) && isset($info['query'])) {
|
||||
$rule = $this->app['route']->getName($url);
|
||||
// 解析地址里面参数 合并到vars
|
||||
parse_str($info['query'], $params);
|
||||
$vars = array_merge($params, $vars);
|
||||
unset($info['query']);
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($rule) && $match = $this->getRuleUrl($rule, $vars)) {
|
||||
// 匹配路由命名标识
|
||||
$url = $match[0];
|
||||
|
||||
if (!empty($match[1])) {
|
||||
$host = $this->app['config']->get('app_host') ?: $this->app['request']->host();
|
||||
if ($domain || $match[1] != $host) {
|
||||
$domain = $match[1];
|
||||
}
|
||||
}
|
||||
|
||||
if (!is_null($match[2])) {
|
||||
$suffix = $match[2];
|
||||
}
|
||||
} elseif (!empty($rule) && isset($name)) {
|
||||
throw new \InvalidArgumentException('route name not exists:' . $name);
|
||||
} else {
|
||||
// 检查别名路由
|
||||
$alias = $this->app['route']->getAlias();
|
||||
$matchAlias = false;
|
||||
|
||||
if ($alias) {
|
||||
// 别名路由解析
|
||||
foreach ($alias as $key => $val) {
|
||||
if (is_array($val)) {
|
||||
$val = $val[0];
|
||||
}
|
||||
|
||||
if (0 === strpos($url, $val)) {
|
||||
$url = $key . substr($url, strlen($val));
|
||||
$matchAlias = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!$matchAlias) {
|
||||
// 路由标识不存在 直接解析
|
||||
$url = $this->parseUrl($url);
|
||||
}
|
||||
|
||||
if (isset($info['query'])) {
|
||||
// 解析地址里面参数 合并到vars
|
||||
parse_str($info['query'], $params);
|
||||
$vars = array_merge($params, $vars);
|
||||
}
|
||||
}
|
||||
|
||||
// 检测URL绑定
|
||||
if (!$this->bindCheck) {
|
||||
$bind = $this->app['route']->getBind();
|
||||
|
||||
if ($bind && 0 === strpos($url, $bind)) {
|
||||
$url = substr($url, strlen($bind) + 1);
|
||||
}
|
||||
|
||||
}
|
||||
// 还原URL分隔符
|
||||
$depr = $this->app['config']->get('pathinfo_depr');
|
||||
$url = str_replace('/', $depr, $url);
|
||||
|
||||
// URL后缀
|
||||
if ('/' == substr($url, -1) || '' == $url) {
|
||||
$suffix = '';
|
||||
} else {
|
||||
$suffix = $this->parseSuffix($suffix);
|
||||
}
|
||||
|
||||
// 锚点
|
||||
$anchor = !empty($anchor) ? '#' . $anchor : '';
|
||||
|
||||
// 参数组装
|
||||
if (!empty($vars)) {
|
||||
// 添加参数
|
||||
if ($this->app['config']->get('url_common_param')) {
|
||||
$vars = http_build_query($vars);
|
||||
$url .= $suffix . '?' . $vars . $anchor;
|
||||
} else {
|
||||
$paramType = $this->app['config']->get('url_param_type');
|
||||
|
||||
foreach ($vars as $var => $val) {
|
||||
if ('' !== trim($val)) {
|
||||
if ($paramType) {
|
||||
$url .= $depr . urlencode($val);
|
||||
} else {
|
||||
$url .= $depr . $var . $depr . urlencode($val);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$url .= $suffix . $anchor;
|
||||
}
|
||||
} else {
|
||||
$url .= $suffix . $anchor;
|
||||
}
|
||||
|
||||
// 检测域名
|
||||
$domain = $this->parseDomain($url, $domain);
|
||||
|
||||
// URL组装
|
||||
$url = $domain . rtrim($this->root ?: $this->app['request']->root(), '/') . '/' . ltrim($url, '/');
|
||||
|
||||
$this->bindCheck = false;
|
||||
|
||||
return $url;
|
||||
}
|
||||
|
||||
// 直接解析URL地址
|
||||
protected function parseUrl($url)
|
||||
{
|
||||
$request = $this->app['request'];
|
||||
|
||||
if (0 === strpos($url, '/')) {
|
||||
// 直接作为路由地址解析
|
||||
$url = substr($url, 1);
|
||||
} elseif (false !== strpos($url, '\\')) {
|
||||
// 解析到类
|
||||
$url = ltrim(str_replace('\\', '/', $url), '/');
|
||||
} elseif (0 === strpos($url, '@')) {
|
||||
// 解析到控制器
|
||||
$url = substr($url, 1);
|
||||
} else {
|
||||
// 解析到 模块/控制器/操作
|
||||
$module = $request->module();
|
||||
$module = $module ? $module . '/' : '';
|
||||
$controller = $request->controller();
|
||||
|
||||
if ('' == $url) {
|
||||
$action = $request->action();
|
||||
} else {
|
||||
$path = explode('/', $url);
|
||||
$action = array_pop($path);
|
||||
$controller = empty($path) ? $controller : array_pop($path);
|
||||
$module = empty($path) ? $module : array_pop($path) . '/';
|
||||
}
|
||||
|
||||
if ($this->app['config']->get('url_convert')) {
|
||||
$action = strtolower($action);
|
||||
$controller = Loader::parseName($controller);
|
||||
}
|
||||
|
||||
$url = $module . $controller . '/' . $action;
|
||||
}
|
||||
|
||||
return $url;
|
||||
}
|
||||
|
||||
// 检测域名
|
||||
protected function parseDomain(&$url, $domain)
|
||||
{
|
||||
if (!$domain) {
|
||||
return '';
|
||||
}
|
||||
|
||||
if (true === $domain) {
|
||||
|
||||
// 自动判断域名
|
||||
$domain = $this->app['config']->get('app_host') ?: $this->app['request']->host();
|
||||
$rootDomain = $this->app['config']->get('url_domain_root');
|
||||
|
||||
$domains = $this->app['route']->getDomains();
|
||||
|
||||
if ($domains) {
|
||||
$route_domain = array_keys($domains);
|
||||
foreach ($route_domain as $domain_prefix) {
|
||||
if (0 === strpos($domain_prefix, '*.') && strpos($domain, ltrim($domain_prefix, '*.')) !== false) {
|
||||
foreach ($domains as $key => $rule) {
|
||||
$rule = is_array($rule) ? $rule[0] : $rule;
|
||||
if (is_string($rule) && false === strpos($key, '*') && 0 === strpos($url, $rule)) {
|
||||
$url = ltrim($url, $rule);
|
||||
$domain = $key;
|
||||
|
||||
// 生成对应子域名
|
||||
if (!empty($rootDomain)) {
|
||||
$domain .= $rootDomain;
|
||||
}
|
||||
break;
|
||||
} elseif (false !== strpos($key, '*')) {
|
||||
if (!empty($rootDomain)) {
|
||||
$domain .= $rootDomain;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (false !== strpos($domain, '://')) {
|
||||
$scheme = '';
|
||||
} else {
|
||||
$scheme = $this->app['request']->isSsl() || $this->app['config']->get('is_https') ? 'https://' : 'http://';
|
||||
|
||||
}
|
||||
|
||||
return $scheme . $domain;
|
||||
}
|
||||
|
||||
// 解析URL后缀
|
||||
protected function parseSuffix($suffix)
|
||||
{
|
||||
if ($suffix) {
|
||||
$suffix = true === $suffix ? $this->app['config']->get('url_html_suffix') : $suffix;
|
||||
|
||||
if ($pos = strpos($suffix, '|')) {
|
||||
$suffix = substr($suffix, 0, $pos);
|
||||
}
|
||||
}
|
||||
|
||||
return (empty($suffix) || 0 === strpos($suffix, '.')) ? $suffix : '.' . $suffix;
|
||||
}
|
||||
|
||||
// 匹配路由地址
|
||||
public function getRuleUrl($rule, &$vars = [])
|
||||
{
|
||||
foreach ($rule as $item) {
|
||||
list($url, $pattern, $domain, $suffix) = $item;
|
||||
if (empty($pattern)) {
|
||||
return [rtrim($url, '$'), $domain, $suffix];
|
||||
}
|
||||
|
||||
$type = $this->app['config']->get('url_common_param');
|
||||
|
||||
foreach ($pattern as $key => $val) {
|
||||
if (isset($vars[$key])) {
|
||||
$url = str_replace(['[:' . $key . ']', '[:' . $key . '$]', '<' . $key . '?>$', '<' . $key . '?>', ':' . $key . '$', ':' . $key . '', '<' . $key . '>$', '<' . $key . '>'], $type ? $vars[$key] : urlencode($vars[$key]), $url);
|
||||
unset($vars[$key]);
|
||||
|
||||
$result = [$url, $domain, $suffix];
|
||||
} elseif (2 == $val) {
|
||||
$url = str_replace(['/[:' . $key . ']', '/[:' . $key . '$]', '[:' . $key . ']', '[:' . $key . '$]', '<' . $key . '?>$', '<' . $key . '?>'], '', $url);
|
||||
$result = [$url, $domain, $suffix];
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($result)) {
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// 指定当前生成URL地址的root
|
||||
public function root($root)
|
||||
{
|
||||
$this->root = $root;
|
||||
$this->app['request']->root($root);
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -2,19 +2,15 @@
|
|||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2019 http://thinkphp.cn All rights reserved.
|
||||
// | Copyright (c) 2006~2018 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;
|
||||
|
||||
/**
|
||||
* 视图类
|
||||
*/
|
||||
class View
|
||||
{
|
||||
/**
|
||||
|
@ -35,35 +31,52 @@ class View
|
|||
*/
|
||||
protected $filter;
|
||||
|
||||
/**
|
||||
* 全局模板变量
|
||||
* @var array
|
||||
*/
|
||||
protected static $var = [];
|
||||
|
||||
/**
|
||||
* 初始化
|
||||
* @access public
|
||||
* @param array $options 模板引擎参数
|
||||
* @param mixed $engine 模板引擎参数
|
||||
* @return $this
|
||||
*/
|
||||
public function __construct(array $options = [])
|
||||
public function init($engine = [])
|
||||
{
|
||||
// 初始化模板引擎
|
||||
$type = $options['type'] ?? 'php';
|
||||
unset($options['type']);
|
||||
$this->engine($type, $options);
|
||||
$this->engine($engine);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public static function __make(Config $config)
|
||||
/**
|
||||
* 模板变量静态赋值
|
||||
* @access public
|
||||
* @param mixed $name 变量名
|
||||
* @param mixed $value 变量值
|
||||
* @return $this
|
||||
*/
|
||||
public function share($name, $value = '')
|
||||
{
|
||||
return new static($config->get('template'));
|
||||
if (is_array($name)) {
|
||||
self::$var = array_merge(self::$var, $name);
|
||||
} else {
|
||||
self::$var[$name] = $value;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 模板变量赋值
|
||||
* @access public
|
||||
* @param string|array $name 模板变量
|
||||
* @param mixed $value 变量值
|
||||
* @param mixed $name 变量名
|
||||
* @param mixed $value 变量值
|
||||
* @return $this
|
||||
*/
|
||||
public function assign($name, $value = null)
|
||||
public function assign($name, $value = '')
|
||||
{
|
||||
if (is_array($name)) {
|
||||
$this->data = array_merge($this->data, $name);
|
||||
|
@ -77,13 +90,25 @@ class View
|
|||
/**
|
||||
* 设置当前模板解析的引擎
|
||||
* @access public
|
||||
* @param string $type 模板引擎类型
|
||||
* @param array|string $options 模板引擎参数
|
||||
* @param array|string $options 引擎参数
|
||||
* @return $this
|
||||
*/
|
||||
public function engine(string $type, array $options = [])
|
||||
public function engine($options = [])
|
||||
{
|
||||
$this->engine = App::factory($type, '\\think\\view\\driver\\', $options);
|
||||
if (is_string($options)) {
|
||||
$type = $options;
|
||||
$options = [];
|
||||
} else {
|
||||
$type = !empty($options['type']) ? $options['type'] : 'Think';
|
||||
}
|
||||
|
||||
$class = false !== strpos($type, '\\') ? $type : '\\think\\view\\driver\\' . ucfirst($type);
|
||||
|
||||
if (isset($options['type'])) {
|
||||
unset($options['type']);
|
||||
}
|
||||
|
||||
$this->engine = new $class($options);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
@ -91,12 +116,13 @@ class View
|
|||
/**
|
||||
* 配置模板引擎
|
||||
* @access public
|
||||
* @param array $name 模板参数
|
||||
* @param string|array $name 参数名
|
||||
* @param mixed $value 参数值
|
||||
* @return $this
|
||||
*/
|
||||
public function config(array $config)
|
||||
public function config($name, $value = null)
|
||||
{
|
||||
$this->engine->config($config);
|
||||
$this->engine->config($name, $value);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
@ -104,10 +130,10 @@ class View
|
|||
/**
|
||||
* 检查模板是否存在
|
||||
* @access public
|
||||
* @param string $name 参数名
|
||||
* @param string|array $name 参数名
|
||||
* @return bool
|
||||
*/
|
||||
public function exists(string $name): bool
|
||||
public function exists($name)
|
||||
{
|
||||
return $this->engine->exists($name);
|
||||
}
|
||||
|
@ -118,7 +144,7 @@ class View
|
|||
* @param Callable $filter 过滤方法或闭包
|
||||
* @return $this
|
||||
*/
|
||||
public function filter(callable $filter = null)
|
||||
public function filter($filter)
|
||||
{
|
||||
$this->filter = $filter;
|
||||
return $this;
|
||||
|
@ -128,12 +154,17 @@ class View
|
|||
* 解析和获取模板内容 用于输出
|
||||
* @access public
|
||||
* @param string $template 模板文件名或者内容
|
||||
* @param array $vars 模板输出变量
|
||||
* @param array $config 模板参数
|
||||
* @param bool $renderContent 是否渲染内容
|
||||
* @return string
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function fetch(string $template = '', bool $renderContent = false): string
|
||||
public function fetch($template = '', $vars = [], $config = [], $renderContent = false)
|
||||
{
|
||||
// 模板变量
|
||||
$vars = array_merge(self::$var, $this->data, $vars);
|
||||
|
||||
// 页面缓存
|
||||
ob_start();
|
||||
ob_implicit_flush(0);
|
||||
|
@ -141,7 +172,7 @@ class View
|
|||
// 渲染输出
|
||||
try {
|
||||
$method = $renderContent ? 'display' : 'fetch';
|
||||
$this->engine->$method($template, $this->data);
|
||||
$this->engine->$method($template, $vars, $config);
|
||||
} catch (\Exception $e) {
|
||||
ob_end_clean();
|
||||
throw $e;
|
||||
|
@ -161,11 +192,13 @@ class View
|
|||
* 渲染内容输出
|
||||
* @access public
|
||||
* @param string $content 内容
|
||||
* @return string
|
||||
* @param array $vars 模板输出变量
|
||||
* @param array $config 模板参数
|
||||
* @return mixed
|
||||
*/
|
||||
public function display(string $content): string
|
||||
public function display($content, $vars = [], $config = [])
|
||||
{
|
||||
return $this->fetch($content, true);
|
||||
return $this->fetch($content, $vars, $config, true);
|
||||
}
|
||||
|
||||
/**
|
|
@ -0,0 +1,353 @@
|
|||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace think\cache;
|
||||
|
||||
use think\Container;
|
||||
|
||||
/**
|
||||
* 缓存基础类
|
||||
*/
|
||||
abstract class Driver
|
||||
{
|
||||
/**
|
||||
* 驱动句柄
|
||||
* @var object
|
||||
*/
|
||||
protected $handler = null;
|
||||
|
||||
/**
|
||||
* 缓存读取次数
|
||||
* @var integer
|
||||
*/
|
||||
protected $readTimes = 0;
|
||||
|
||||
/**
|
||||
* 缓存写入次数
|
||||
* @var integer
|
||||
*/
|
||||
protected $writeTimes = 0;
|
||||
|
||||
/**
|
||||
* 缓存参数
|
||||
* @var array
|
||||
*/
|
||||
protected $options = [];
|
||||
|
||||
/**
|
||||
* 缓存标签
|
||||
* @var string
|
||||
*/
|
||||
protected $tag;
|
||||
|
||||
/**
|
||||
* 序列化方法
|
||||
* @var array
|
||||
*/
|
||||
protected static $serialize = ['serialize', 'unserialize', 'think_serialize:', 16];
|
||||
|
||||
/**
|
||||
* 判断缓存是否存在
|
||||
* @access public
|
||||
* @param string $name 缓存变量名
|
||||
* @return bool
|
||||
*/
|
||||
abstract public function has($name);
|
||||
|
||||
/**
|
||||
* 读取缓存
|
||||
* @access public
|
||||
* @param string $name 缓存变量名
|
||||
* @param mixed $default 默认值
|
||||
* @return mixed
|
||||
*/
|
||||
abstract public function get($name, $default = false);
|
||||
|
||||
/**
|
||||
* 写入缓存
|
||||
* @access public
|
||||
* @param string $name 缓存变量名
|
||||
* @param mixed $value 存储数据
|
||||
* @param int $expire 有效时间 0为永久
|
||||
* @return boolean
|
||||
*/
|
||||
abstract public function set($name, $value, $expire = null);
|
||||
|
||||
/**
|
||||
* 自增缓存(针对数值缓存)
|
||||
* @access public
|
||||
* @param string $name 缓存变量名
|
||||
* @param int $step 步长
|
||||
* @return false|int
|
||||
*/
|
||||
abstract public function inc($name, $step = 1);
|
||||
|
||||
/**
|
||||
* 自减缓存(针对数值缓存)
|
||||
* @access public
|
||||
* @param string $name 缓存变量名
|
||||
* @param int $step 步长
|
||||
* @return false|int
|
||||
*/
|
||||
abstract public function dec($name, $step = 1);
|
||||
|
||||
/**
|
||||
* 删除缓存
|
||||
* @access public
|
||||
* @param string $name 缓存变量名
|
||||
* @return boolean
|
||||
*/
|
||||
abstract public function rm($name);
|
||||
|
||||
/**
|
||||
* 清除缓存
|
||||
* @access public
|
||||
* @param string $tag 标签名
|
||||
* @return boolean
|
||||
*/
|
||||
abstract public function clear($tag = null);
|
||||
|
||||
/**
|
||||
* 获取有效期
|
||||
* @access protected
|
||||
* @param integer|\DateTime $expire 有效期
|
||||
* @return integer
|
||||
*/
|
||||
protected function getExpireTime($expire)
|
||||
{
|
||||
if ($expire instanceof \DateTime) {
|
||||
$expire = $expire->getTimestamp() - time();
|
||||
}
|
||||
|
||||
return $expire;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取实际的缓存标识
|
||||
* @access protected
|
||||
* @param string $name 缓存名
|
||||
* @return string
|
||||
*/
|
||||
protected function getCacheKey($name)
|
||||
{
|
||||
return $this->options['prefix'] . $name;
|
||||
}
|
||||
|
||||
/**
|
||||
* 读取缓存并删除
|
||||
* @access public
|
||||
* @param string $name 缓存变量名
|
||||
* @return mixed
|
||||
*/
|
||||
public function pull($name)
|
||||
{
|
||||
$result = $this->get($name, false);
|
||||
|
||||
if ($result) {
|
||||
$this->rm($name);
|
||||
return $result;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 如果不存在则写入缓存
|
||||
* @access public
|
||||
* @param string $name 缓存变量名
|
||||
* @param mixed $value 存储数据
|
||||
* @param int $expire 有效时间 0为永久
|
||||
* @return mixed
|
||||
*/
|
||||
public function remember($name, $value, $expire = null)
|
||||
{
|
||||
if (!$this->has($name)) {
|
||||
$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->rm($name . '_lock');
|
||||
} catch (\Exception $e) {
|
||||
$this->rm($name . '_lock');
|
||||
throw $e;
|
||||
} catch (\throwable $e) {
|
||||
$this->rm($name . '_lock');
|
||||
throw $e;
|
||||
}
|
||||
} else {
|
||||
$value = $this->get($name);
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* 缓存标签
|
||||
* @access public
|
||||
* @param string $name 标签名
|
||||
* @param string|array $keys 缓存标识
|
||||
* @param bool $overlay 是否覆盖
|
||||
* @return $this
|
||||
*/
|
||||
public function tag($name, $keys = null, $overlay = false)
|
||||
{
|
||||
if (is_null($name)) {
|
||||
|
||||
} elseif (is_null($keys)) {
|
||||
$this->tag = $name;
|
||||
} else {
|
||||
$key = 'tag_' . md5($name);
|
||||
|
||||
if (is_string($keys)) {
|
||||
$keys = explode(',', $keys);
|
||||
}
|
||||
|
||||
$keys = array_map([$this, 'getCacheKey'], $keys);
|
||||
|
||||
if ($overlay) {
|
||||
$value = $keys;
|
||||
} else {
|
||||
$value = array_unique(array_merge($this->getTagItem($name), $keys));
|
||||
}
|
||||
|
||||
$this->set($key, implode(',', $value), 0);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新标签
|
||||
* @access protected
|
||||
* @param string $name 缓存标识
|
||||
* @return void
|
||||
*/
|
||||
protected function setTagItem($name)
|
||||
{
|
||||
if ($this->tag) {
|
||||
$key = 'tag_' . md5($this->tag);
|
||||
$prev = $this->tag;
|
||||
$this->tag = null;
|
||||
|
||||
if ($this->has($key)) {
|
||||
$value = explode(',', $this->get($key));
|
||||
$value[] = $name;
|
||||
$value = implode(',', array_unique($value));
|
||||
} else {
|
||||
$value = $name;
|
||||
}
|
||||
|
||||
$this->set($key, $value, 0);
|
||||
$this->tag = $prev;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取标签包含的缓存标识
|
||||
* @access protected
|
||||
* @param string $tag 缓存标签
|
||||
* @return array
|
||||
*/
|
||||
protected function getTagItem($tag)
|
||||
{
|
||||
$key = 'tag_' . md5($tag);
|
||||
$value = $this->get($key);
|
||||
|
||||
if ($value) {
|
||||
return array_filter(explode(',', $value));
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 序列化数据
|
||||
* @access protected
|
||||
* @param mixed $data
|
||||
* @return string
|
||||
*/
|
||||
protected function serialize($data)
|
||||
{
|
||||
if (is_scalar($data) || !$this->options['serialize']) {
|
||||
return $data;
|
||||
}
|
||||
|
||||
$serialize = self::$serialize[0];
|
||||
|
||||
return self::$serialize[2] . $serialize($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 反序列化数据
|
||||
* @access protected
|
||||
* @param string $data
|
||||
* @return mixed
|
||||
*/
|
||||
protected function unserialize($data)
|
||||
{
|
||||
if ($this->options['serialize'] && 0 === strpos($data, self::$serialize[2])) {
|
||||
$unserialize = self::$serialize[1];
|
||||
|
||||
return $unserialize(substr($data, self::$serialize[3]));
|
||||
} else {
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册序列化机制
|
||||
* @access public
|
||||
* @param callable $serialize 序列化方法
|
||||
* @param callable $unserialize 反序列化方法
|
||||
* @param string $prefix 序列化前缀标识
|
||||
* @return $this
|
||||
*/
|
||||
public static function registerSerialize($serialize, $unserialize, $prefix = 'think_serialize:')
|
||||
{
|
||||
self::$serialize = [$serialize, $unserialize, $prefix, strlen($prefix)];
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回句柄对象,可执行其它高级方法
|
||||
*
|
||||
* @access public
|
||||
* @return object
|
||||
*/
|
||||
public function handler()
|
||||
{
|
||||
return $this->handler;
|
||||
}
|
||||
|
||||
public function getReadTimes()
|
||||
{
|
||||
return $this->readTimes;
|
||||
}
|
||||
|
||||
public function getWriteTimes()
|
||||
{
|
||||
return $this->writeTimes;
|
||||
}
|
||||
}
|
|
@ -2,27 +2,24 @@
|
|||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2019 http://thinkphp.cn All rights reserved.
|
||||
// | Copyright (c) 2006~2018 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 think\cache\Driver;
|
||||
use think\Container;
|
||||
|
||||
/**
|
||||
* 文件缓存类
|
||||
* 文件类型缓存类
|
||||
* @author liu21st <liu21st@gmail.com>
|
||||
*/
|
||||
class File extends Driver
|
||||
{
|
||||
/**
|
||||
* 配置参数
|
||||
* @var array
|
||||
*/
|
||||
protected $options = [
|
||||
'expire' => 0,
|
||||
'cache_subdir' => true,
|
||||
|
@ -30,38 +27,55 @@ class File extends Driver
|
|||
'path' => '',
|
||||
'hash_type' => 'md5',
|
||||
'data_compress' => false,
|
||||
'tag_prefix' => 'tag:',
|
||||
'serialize' => [],
|
||||
'serialize' => true,
|
||||
];
|
||||
|
||||
/**
|
||||
* 有效期
|
||||
* @var int|\DateTime
|
||||
*/
|
||||
protected $expire;
|
||||
|
||||
/**
|
||||
* 架构函数
|
||||
* @param array $options 参数
|
||||
* @param array $options
|
||||
*/
|
||||
public function __construct(array $options = [])
|
||||
public function __construct($options = [])
|
||||
{
|
||||
if (!empty($options)) {
|
||||
$this->options = array_merge($this->options, $options);
|
||||
}
|
||||
|
||||
if (substr($this->options['path'], -1) != DIRECTORY_SEPARATOR) {
|
||||
if (empty($this->options['path'])) {
|
||||
$this->options['path'] = Container::get('app')->getRuntimePath() . 'cache/';
|
||||
} elseif (substr($this->options['path'], -1) != DIRECTORY_SEPARATOR) {
|
||||
$this->options['path'] .= DIRECTORY_SEPARATOR;
|
||||
}
|
||||
|
||||
$this->init();
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化检查
|
||||
* @access private
|
||||
* @return boolean
|
||||
*/
|
||||
private function init()
|
||||
{
|
||||
// 创建项目缓存目录
|
||||
if (!is_dir($this->options['path'])) {
|
||||
if (mkdir($this->options['path'], 0755, true)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 取得变量的存储文件名
|
||||
* @access public
|
||||
* @access protected
|
||||
* @param string $name 缓存变量名
|
||||
* @param bool $auto 是否自动创建目录
|
||||
* @return string
|
||||
*/
|
||||
public function getCacheKey(string $name): string
|
||||
protected function getCacheKey($name, $auto = false)
|
||||
{
|
||||
$name = hash($this->options['hash_type'], $name);
|
||||
|
||||
|
@ -74,7 +88,14 @@ class File extends Driver
|
|||
$name = $this->options['prefix'] . DIRECTORY_SEPARATOR . $name;
|
||||
}
|
||||
|
||||
return $this->options['path'] . $name . '.php';
|
||||
$filename = $this->options['path'] . $name . '.php';
|
||||
$dir = dirname($filename);
|
||||
|
||||
if ($auto && !is_dir($dir)) {
|
||||
mkdir($dir, 0755, true);
|
||||
}
|
||||
|
||||
return $filename;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -83,9 +104,9 @@ class File extends Driver
|
|||
* @param string $name 缓存变量名
|
||||
* @return bool
|
||||
*/
|
||||
public function has($name): bool
|
||||
public function has($name)
|
||||
{
|
||||
return false !== $this->get($name) ? true : false;
|
||||
return $this->get($name) ? true : false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -135,9 +156,9 @@ class File extends Driver
|
|||
* @param string $name 缓存变量名
|
||||
* @param mixed $value 存储数据
|
||||
* @param int|\DateTime $expire 有效时间 0为永久
|
||||
* @return bool
|
||||
* @return boolean
|
||||
*/
|
||||
public function set($name, $value, $expire = null): bool
|
||||
public function set($name, $value, $expire = null)
|
||||
{
|
||||
$this->writeTimes++;
|
||||
|
||||
|
@ -146,16 +167,10 @@ class File extends Driver
|
|||
}
|
||||
|
||||
$expire = $this->getExpireTime($expire);
|
||||
$filename = $this->getCacheKey($name);
|
||||
$filename = $this->getCacheKey($name, true);
|
||||
|
||||
$dir = dirname($filename);
|
||||
|
||||
if (!is_dir($dir)) {
|
||||
try {
|
||||
mkdir($dir, 0755, true);
|
||||
} catch (\Exception $e) {
|
||||
// 创建失败
|
||||
}
|
||||
if ($this->tag && !is_file($filename)) {
|
||||
$first = true;
|
||||
}
|
||||
|
||||
$data = $this->serialize($value);
|
||||
|
@ -169,21 +184,22 @@ class File extends Driver
|
|||
$result = file_put_contents($filename, $data);
|
||||
|
||||
if ($result) {
|
||||
isset($first) && $this->setTagItem($filename);
|
||||
clearstatcache();
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 自增缓存(针对数值缓存)
|
||||
* @access public
|
||||
* @param string $name 缓存变量名
|
||||
* @param int $step 步长
|
||||
* @param string $name 缓存变量名
|
||||
* @param int $step 步长
|
||||
* @return false|int
|
||||
*/
|
||||
public function inc(string $name, int $step = 1)
|
||||
public function inc($name, $step = 1)
|
||||
{
|
||||
if ($this->has($name)) {
|
||||
$value = $this->get($name) + $step;
|
||||
|
@ -199,11 +215,11 @@ class File extends Driver
|
|||
/**
|
||||
* 自减缓存(针对数值缓存)
|
||||
* @access public
|
||||
* @param string $name 缓存变量名
|
||||
* @param int $step 步长
|
||||
* @param string $name 缓存变量名
|
||||
* @param int $step 步长
|
||||
* @return false|int
|
||||
*/
|
||||
public function dec(string $name, int $step = 1)
|
||||
public function dec($name, $step = 1)
|
||||
{
|
||||
if ($this->has($name)) {
|
||||
$value = $this->get($name) - $step;
|
||||
|
@ -220,33 +236,40 @@ class File extends Driver
|
|||
* 删除缓存
|
||||
* @access public
|
||||
* @param string $name 缓存变量名
|
||||
* @return bool
|
||||
* @return boolean
|
||||
*/
|
||||
public function delete($name): bool
|
||||
public function rm($name)
|
||||
{
|
||||
$this->writeTimes++;
|
||||
|
||||
try {
|
||||
return $this->unlink($this->getCacheKey($name));
|
||||
} catch (\Exception $e) {
|
||||
return false;
|
||||
}
|
||||
return $this->unlink($this->getCacheKey($name));
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除缓存
|
||||
* @access public
|
||||
* @return bool
|
||||
* @param string $tag 标签名
|
||||
* @return boolean
|
||||
*/
|
||||
public function clear(): bool
|
||||
public function clear($tag = null)
|
||||
{
|
||||
if ($tag) {
|
||||
// 指定标签清除
|
||||
$keys = $this->getTagItem($tag);
|
||||
foreach ($keys as $key) {
|
||||
$this->unlink($key);
|
||||
}
|
||||
$this->rm('tag_' . md5($tag));
|
||||
return true;
|
||||
}
|
||||
|
||||
$this->writeTimes++;
|
||||
|
||||
$files = (array) glob($this->options['path'] . ($this->options['prefix'] ? $this->options['prefix'] . DIRECTORY_SEPARATOR : '') . '*');
|
||||
|
||||
foreach ($files as $path) {
|
||||
if (is_dir($path)) {
|
||||
$matches = glob($path . DIRECTORY_SEPARATOR . '*.php');
|
||||
$matches = glob($path . '/*.php');
|
||||
if (is_array($matches)) {
|
||||
array_map('unlink', $matches);
|
||||
}
|
||||
|
@ -259,26 +282,15 @@ class File extends Driver
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除缓存标签
|
||||
* @access public
|
||||
* @param array $keys 缓存标识列表
|
||||
* @return void
|
||||
*/
|
||||
public function clearTag(array $keys): void
|
||||
{
|
||||
foreach ($keys as $key) {
|
||||
$this->unlink($key);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断文件是否存在后,删除
|
||||
* @access private
|
||||
* @param string $path
|
||||
* @return bool
|
||||
* @author byron sampson <xiaobo.sun@qq.com>
|
||||
* @return boolean
|
||||
*/
|
||||
private function unlink(string $path): bool
|
||||
private function unlink($path)
|
||||
{
|
||||
return is_file($path) && unlink($path);
|
||||
}
|
|
@ -0,0 +1,209 @@
|
|||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace think\cache\driver;
|
||||
|
||||
use think\cache\Driver;
|
||||
|
||||
/**
|
||||
* 文件类型缓存类
|
||||
* @author liu21st <liu21st@gmail.com>
|
||||
*/
|
||||
class Lite extends Driver
|
||||
{
|
||||
protected $options = [
|
||||
'prefix' => '',
|
||||
'path' => '',
|
||||
'expire' => 0, // 等于 10*365*24*3600(10年)
|
||||
];
|
||||
|
||||
/**
|
||||
* 架构函数
|
||||
* @access public
|
||||
*
|
||||
* @param array $options
|
||||
*/
|
||||
public function __construct($options = [])
|
||||
{
|
||||
if (!empty($options)) {
|
||||
$this->options = array_merge($this->options, $options);
|
||||
}
|
||||
|
||||
if (substr($this->options['path'], -1) != DIRECTORY_SEPARATOR) {
|
||||
$this->options['path'] .= DIRECTORY_SEPARATOR;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 取得变量的存储文件名
|
||||
* @access protected
|
||||
* @param string $name 缓存变量名
|
||||
* @return string
|
||||
*/
|
||||
protected function getCacheKey($name)
|
||||
{
|
||||
return $this->options['path'] . $this->options['prefix'] . md5($name) . '.php';
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断缓存是否存在
|
||||
* @access public
|
||||
* @param string $name 缓存变量名
|
||||
* @return mixed
|
||||
*/
|
||||
public function has($name)
|
||||
{
|
||||
return $this->get($name) ? true : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 读取缓存
|
||||
* @access public
|
||||
* @param string $name 缓存变量名
|
||||
* @param mixed $default 默认值
|
||||
* @return mixed
|
||||
*/
|
||||
public function get($name, $default = false)
|
||||
{
|
||||
$this->readTimes++;
|
||||
|
||||
$filename = $this->getCacheKey($name);
|
||||
|
||||
if (is_file($filename)) {
|
||||
// 判断是否过期
|
||||
$mtime = filemtime($filename);
|
||||
|
||||
if ($mtime < time()) {
|
||||
// 清除已经过期的文件
|
||||
unlink($filename);
|
||||
return $default;
|
||||
}
|
||||
|
||||
return include $filename;
|
||||
} else {
|
||||
return $default;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 写入缓存
|
||||
* @access public
|
||||
* @param string $name 缓存变量名
|
||||
* @param mixed $value 存储数据
|
||||
* @param int|\DateTime $expire 有效时间 0为永久
|
||||
* @return bool
|
||||
*/
|
||||
public function set($name, $value, $expire = null)
|
||||
{
|
||||
$this->writeTimes++;
|
||||
|
||||
if (is_null($expire)) {
|
||||
$expire = $this->options['expire'];
|
||||
}
|
||||
|
||||
if ($expire instanceof \DateTime) {
|
||||
$expire = $expire->getTimestamp();
|
||||
} else {
|
||||
$expire = 0 === $expire ? 10 * 365 * 24 * 3600 : $expire;
|
||||
$expire = time() + $expire;
|
||||
}
|
||||
|
||||
$filename = $this->getCacheKey($name);
|
||||
|
||||
if ($this->tag && !is_file($filename)) {
|
||||
$first = true;
|
||||
}
|
||||
|
||||
$ret = file_put_contents($filename, ("<?php return " . var_export($value, true) . ";"));
|
||||
|
||||
// 通过设置修改时间实现有效期
|
||||
if ($ret) {
|
||||
isset($first) && $this->setTagItem($filename);
|
||||
touch($filename, $expire);
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* 自增缓存(针对数值缓存)
|
||||
* @access public
|
||||
* @param string $name 缓存变量名
|
||||
* @param int $step 步长
|
||||
* @return false|int
|
||||
*/
|
||||
public function inc($name, $step = 1)
|
||||
{
|
||||
if ($this->has($name)) {
|
||||
$value = $this->get($name) + $step;
|
||||
} else {
|
||||
$value = $step;
|
||||
}
|
||||
|
||||
return $this->set($name, $value, 0) ? $value : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 自减缓存(针对数值缓存)
|
||||
* @access public
|
||||
* @param string $name 缓存变量名
|
||||
* @param int $step 步长
|
||||
* @return false|int
|
||||
*/
|
||||
public function dec($name, $step = 1)
|
||||
{
|
||||
if ($this->has($name)) {
|
||||
$value = $this->get($name) - $step;
|
||||
} else {
|
||||
$value = -$step;
|
||||
}
|
||||
|
||||
return $this->set($name, $value, 0) ? $value : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除缓存
|
||||
* @access public
|
||||
* @param string $name 缓存变量名
|
||||
* @return boolean
|
||||
*/
|
||||
public function rm($name)
|
||||
{
|
||||
$this->writeTimes++;
|
||||
|
||||
return unlink($this->getCacheKey($name));
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除缓存
|
||||
* @access public
|
||||
* @param string $tag 标签名
|
||||
* @return bool
|
||||
*/
|
||||
public function clear($tag = null)
|
||||
{
|
||||
if ($tag) {
|
||||
// 指定标签清除
|
||||
$keys = $this->getTagItem($tag);
|
||||
foreach ($keys as $key) {
|
||||
unlink($key);
|
||||
}
|
||||
|
||||
$this->rm('tag_' . md5($tag));
|
||||
return true;
|
||||
}
|
||||
|
||||
$this->writeTimes++;
|
||||
|
||||
array_map("unlink", glob($this->options['path'] . ($this->options['prefix'] ? $this->options['prefix'] . DIRECTORY_SEPARATOR : '') . '*.php'));
|
||||
}
|
||||
}
|
|
@ -2,7 +2,7 @@
|
|||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2019 http://thinkphp.cn All rights reserved.
|
||||
// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
|
@ -13,15 +13,8 @@ namespace think\cache\driver;
|
|||
|
||||
use think\cache\Driver;
|
||||
|
||||
/**
|
||||
* Memcache缓存类
|
||||
*/
|
||||
class Memcache extends Driver
|
||||
{
|
||||
/**
|
||||
* 配置参数
|
||||
* @var array
|
||||
*/
|
||||
protected $options = [
|
||||
'host' => '127.0.0.1',
|
||||
'port' => 11211,
|
||||
|
@ -29,8 +22,7 @@ class Memcache extends Driver
|
|||
'timeout' => 0, // 超时时间(单位:毫秒)
|
||||
'persistent' => true,
|
||||
'prefix' => '',
|
||||
'tag_prefix' => 'tag:',
|
||||
'serialize' => [],
|
||||
'serialize' => true,
|
||||
];
|
||||
|
||||
/**
|
||||
|
@ -39,7 +31,7 @@ class Memcache extends Driver
|
|||
* @param array $options 缓存参数
|
||||
* @throws \BadFunctionCallException
|
||||
*/
|
||||
public function __construct(array $options = [])
|
||||
public function __construct($options = [])
|
||||
{
|
||||
if (!extension_loaded('memcache')) {
|
||||
throw new \BadFunctionCallException('not support: memcache');
|
||||
|
@ -52,19 +44,19 @@ class Memcache extends Driver
|
|||
$this->handler = new \Memcache;
|
||||
|
||||
// 支持集群
|
||||
$hosts = (array) $this->options['host'];
|
||||
$ports = (array) $this->options['port'];
|
||||
$hosts = explode(',', $this->options['host']);
|
||||
$ports = explode(',', $this->options['port']);
|
||||
|
||||
if (empty($ports[0])) {
|
||||
$ports[0] = 11211;
|
||||
}
|
||||
|
||||
// 建立连接
|
||||
foreach ($hosts as $i => $host) {
|
||||
$port = $ports[$i] ?? $ports[0];
|
||||
foreach ((array) $hosts as $i => $host) {
|
||||
$port = isset($ports[$i]) ? $ports[$i] : $ports[0];
|
||||
$this->options['timeout'] > 0 ?
|
||||
$this->handler->addServer($host, (int) $port, $this->options['persistent'], 1, $this->options['timeout']) :
|
||||
$this->handler->addServer($host, (int) $port, $this->options['persistent'], 1);
|
||||
$this->handler->addServer($host, $port, $this->options['persistent'], 1, $this->options['timeout']) :
|
||||
$this->handler->addServer($host, $port, $this->options['persistent'], 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -74,11 +66,11 @@ class Memcache extends Driver
|
|||
* @param string $name 缓存变量名
|
||||
* @return bool
|
||||
*/
|
||||
public function has($name): bool
|
||||
public function has($name)
|
||||
{
|
||||
$key = $this->getCacheKey($name);
|
||||
|
||||
return false !== $this->handler->get($key);
|
||||
return $this->handler->get($key) ? true : false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -102,10 +94,10 @@ class Memcache extends Driver
|
|||
* @access public
|
||||
* @param string $name 缓存变量名
|
||||
* @param mixed $value 存储数据
|
||||
* @param int|\DateTime $expire 有效时间(秒)
|
||||
* @param int|DateTime $expire 有效时间(秒)
|
||||
* @return bool
|
||||
*/
|
||||
public function set($name, $value, $expire = null): bool
|
||||
public function set($name, $value, $expire = null)
|
||||
{
|
||||
$this->writeTimes++;
|
||||
|
||||
|
@ -113,11 +105,16 @@ class Memcache extends Driver
|
|||
$expire = $this->options['expire'];
|
||||
}
|
||||
|
||||
if ($this->tag && !$this->has($name)) {
|
||||
$first = true;
|
||||
}
|
||||
|
||||
$key = $this->getCacheKey($name);
|
||||
$expire = $this->getExpireTime($expire);
|
||||
$value = $this->serialize($value);
|
||||
|
||||
if ($this->handler->set($key, $value, 0, $expire)) {
|
||||
isset($first) && $this->setTagItem($key);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -127,11 +124,11 @@ class Memcache extends Driver
|
|||
/**
|
||||
* 自增缓存(针对数值缓存)
|
||||
* @access public
|
||||
* @param string $name 缓存变量名
|
||||
* @param int $step 步长
|
||||
* @param string $name 缓存变量名
|
||||
* @param int $step 步长
|
||||
* @return false|int
|
||||
*/
|
||||
public function inc(string $name, int $step = 1)
|
||||
public function inc($name, $step = 1)
|
||||
{
|
||||
$this->writeTimes++;
|
||||
|
||||
|
@ -147,11 +144,11 @@ class Memcache extends Driver
|
|||
/**
|
||||
* 自减缓存(针对数值缓存)
|
||||
* @access public
|
||||
* @param string $name 缓存变量名
|
||||
* @param int $step 步长
|
||||
* @param string $name 缓存变量名
|
||||
* @param int $step 步长
|
||||
* @return false|int
|
||||
*/
|
||||
public function dec(string $name, int $step = 1)
|
||||
public function dec($name, $step = 1)
|
||||
{
|
||||
$this->writeTimes++;
|
||||
|
||||
|
@ -165,11 +162,11 @@ class Memcache extends Driver
|
|||
/**
|
||||
* 删除缓存
|
||||
* @access public
|
||||
* @param string $name 缓存变量名
|
||||
* @param bool|false $ttl
|
||||
* @param string $name 缓存变量名
|
||||
* @param bool|false $ttl
|
||||
* @return bool
|
||||
*/
|
||||
public function delete($name, $ttl = false): bool
|
||||
public function rm($name, $ttl = false)
|
||||
{
|
||||
$this->writeTimes++;
|
||||
|
||||
|
@ -183,26 +180,24 @@ class Memcache extends Driver
|
|||
/**
|
||||
* 清除缓存
|
||||
* @access public
|
||||
* @param string $tag 标签名
|
||||
* @return bool
|
||||
*/
|
||||
public function clear(): bool
|
||||
public function clear($tag = null)
|
||||
{
|
||||
if ($tag) {
|
||||
// 指定标签清除
|
||||
$keys = $this->getTagItem($tag);
|
||||
foreach ($keys as $key) {
|
||||
$this->handler->delete($key);
|
||||
}
|
||||
|
||||
$this->rm('tag_' . md5($tag));
|
||||
return true;
|
||||
}
|
||||
|
||||
$this->writeTimes++;
|
||||
|
||||
return $this->handler->flush();
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除缓存标签
|
||||
* @access public
|
||||
* @param array $keys 缓存标识列表
|
||||
* @return void
|
||||
*/
|
||||
public function clearTag(array $keys): void
|
||||
{
|
||||
foreach ($keys as $key) {
|
||||
$this->handler->delete($key);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -2,7 +2,7 @@
|
|||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2019 http://thinkphp.cn All rights reserved.
|
||||
// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
|
@ -13,26 +13,18 @@ namespace think\cache\driver;
|
|||
|
||||
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' => [],
|
||||
'host' => '127.0.0.1',
|
||||
'port' => 11211,
|
||||
'expire' => 0,
|
||||
'timeout' => 0, // 超时时间(单位:毫秒)
|
||||
'prefix' => '',
|
||||
'username' => '', //账号
|
||||
'password' => '', //密码
|
||||
'option' => [],
|
||||
'serialize' => true,
|
||||
];
|
||||
|
||||
/**
|
||||
|
@ -40,7 +32,7 @@ class Memcached extends Driver
|
|||
* @access public
|
||||
* @param array $options 缓存参数
|
||||
*/
|
||||
public function __construct(array $options = [])
|
||||
public function __construct($options = [])
|
||||
{
|
||||
if (!extension_loaded('memcached')) {
|
||||
throw new \BadFunctionCallException('not support: memcached');
|
||||
|
@ -62,16 +54,16 @@ class Memcached extends Driver
|
|||
}
|
||||
|
||||
// 支持集群
|
||||
$hosts = (array) $this->options['host'];
|
||||
$ports = (array) $this->options['port'];
|
||||
$hosts = explode(',', $this->options['host']);
|
||||
$ports = explode(',', $this->options['port']);
|
||||
if (empty($ports[0])) {
|
||||
$ports[0] = 11211;
|
||||
}
|
||||
|
||||
// 建立连接
|
||||
$servers = [];
|
||||
foreach ($hosts as $i => $host) {
|
||||
$servers[] = [$host, $ports[$i] ?? $ports[0], 1];
|
||||
foreach ((array) $hosts as $i => $host) {
|
||||
$servers[] = [$host, (isset($ports[$i]) ? $ports[$i] : $ports[0]), 1];
|
||||
}
|
||||
|
||||
$this->handler->addServers($servers);
|
||||
|
@ -88,7 +80,7 @@ class Memcached extends Driver
|
|||
* @param string $name 缓存变量名
|
||||
* @return bool
|
||||
*/
|
||||
public function has($name): bool
|
||||
public function has($name)
|
||||
{
|
||||
$key = $this->getCacheKey($name);
|
||||
|
||||
|
@ -119,7 +111,7 @@ class Memcached extends Driver
|
|||
* @param integer|\DateTime $expire 有效时间(秒)
|
||||
* @return bool
|
||||
*/
|
||||
public function set($name, $value, $expire = null): bool
|
||||
public function set($name, $value, $expire = null)
|
||||
{
|
||||
$this->writeTimes++;
|
||||
|
||||
|
@ -127,11 +119,16 @@ class Memcached extends Driver
|
|||
$expire = $this->options['expire'];
|
||||
}
|
||||
|
||||
if ($this->tag && !$this->has($name)) {
|
||||
$first = true;
|
||||
}
|
||||
|
||||
$key = $this->getCacheKey($name);
|
||||
$expire = $this->getExpireTime($expire);
|
||||
$value = $this->serialize($value);
|
||||
|
||||
if ($this->handler->set($key, $value, $expire)) {
|
||||
isset($first) && $this->setTagItem($key);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -141,11 +138,11 @@ class Memcached extends Driver
|
|||
/**
|
||||
* 自增缓存(针对数值缓存)
|
||||
* @access public
|
||||
* @param string $name 缓存变量名
|
||||
* @param int $step 步长
|
||||
* @param string $name 缓存变量名
|
||||
* @param int $step 步长
|
||||
* @return false|int
|
||||
*/
|
||||
public function inc(string $name, int $step = 1)
|
||||
public function inc($name, $step = 1)
|
||||
{
|
||||
$this->writeTimes++;
|
||||
|
||||
|
@ -161,11 +158,11 @@ class Memcached extends Driver
|
|||
/**
|
||||
* 自减缓存(针对数值缓存)
|
||||
* @access public
|
||||
* @param string $name 缓存变量名
|
||||
* @param int $step 步长
|
||||
* @param string $name 缓存变量名
|
||||
* @param int $step 步长
|
||||
* @return false|int
|
||||
*/
|
||||
public function dec(string $name, int $step = 1)
|
||||
public function dec($name, $step = 1)
|
||||
{
|
||||
$this->writeTimes++;
|
||||
|
||||
|
@ -183,7 +180,7 @@ class Memcached extends Driver
|
|||
* @param bool|false $ttl
|
||||
* @return bool
|
||||
*/
|
||||
public function delete($name, $ttl = false): bool
|
||||
public function rm($name, $ttl = false)
|
||||
{
|
||||
$this->writeTimes++;
|
||||
|
||||
|
@ -197,24 +194,23 @@ class Memcached extends Driver
|
|||
/**
|
||||
* 清除缓存
|
||||
* @access public
|
||||
* @param string $tag 标签名
|
||||
* @return bool
|
||||
*/
|
||||
public function clear(): bool
|
||||
public function clear($tag = null)
|
||||
{
|
||||
if ($tag) {
|
||||
// 指定标签清除
|
||||
$keys = $this->getTagItem($tag);
|
||||
|
||||
$this->handler->deleteMulti($keys);
|
||||
$this->rm('tag_' . md5($tag));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
$this->writeTimes++;
|
||||
|
||||
return $this->handler->flush();
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除缓存标签
|
||||
* @access public
|
||||
* @param array $keys 缓存标识列表
|
||||
* @return void
|
||||
*/
|
||||
public function clearTag(array $keys): void
|
||||
{
|
||||
$this->handler->deleteMulti($keys);
|
||||
}
|
||||
|
||||
}
|
|
@ -2,7 +2,7 @@
|
|||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2019 http://thinkphp.cn All rights reserved.
|
||||
// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
|
@ -22,10 +22,6 @@ use think\cache\Driver;
|
|||
*/
|
||||
class Redis extends Driver
|
||||
{
|
||||
/**
|
||||
* 配置参数
|
||||
* @var array
|
||||
*/
|
||||
protected $options = [
|
||||
'host' => '127.0.0.1',
|
||||
'port' => 6379,
|
||||
|
@ -35,8 +31,7 @@ class Redis extends Driver
|
|||
'expire' => 0,
|
||||
'persistent' => false,
|
||||
'prefix' => '',
|
||||
'tag_prefix' => 'tag:',
|
||||
'serialize' => [],
|
||||
'serialize' => true,
|
||||
];
|
||||
|
||||
/**
|
||||
|
@ -44,42 +39,26 @@ class Redis extends Driver
|
|||
* @access public
|
||||
* @param array $options 缓存参数
|
||||
*/
|
||||
public function __construct(array $options = [])
|
||||
public function __construct($options = [])
|
||||
{
|
||||
if (!extension_loaded('redis')) {
|
||||
throw new \BadFunctionCallException('not support: redis');
|
||||
}
|
||||
|
||||
if (!empty($options)) {
|
||||
$this->options = array_merge($this->options, $options);
|
||||
}
|
||||
|
||||
if (extension_loaded('redis')) {
|
||||
$this->handler = new \Redis;
|
||||
$this->handler = new \Redis;
|
||||
|
||||
if ($this->options['persistent']) {
|
||||
$this->handler->pconnect($this->options['host'], (int) $this->options['port'], $this->options['timeout'], 'persistent_id_' . $this->options['select']);
|
||||
} else {
|
||||
$this->handler->connect($this->options['host'], (int) $this->options['port'], $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'] = '';
|
||||
if ($this->options['persistent']) {
|
||||
$this->handler->pconnect($this->options['host'], $this->options['port'], $this->options['timeout'], 'persistent_id_' . $this->options['select']);
|
||||
} else {
|
||||
throw new \BadFunctionCallException('not support: redis');
|
||||
$this->handler->connect($this->options['host'], $this->options['port'], $this->options['timeout']);
|
||||
}
|
||||
|
||||
if ('' != $this->options['password']) {
|
||||
$this->handler->auth($this->options['password']);
|
||||
}
|
||||
|
||||
if (0 != $this->options['select']) {
|
||||
|
@ -93,9 +72,9 @@ class Redis extends Driver
|
|||
* @param string $name 缓存变量名
|
||||
* @return bool
|
||||
*/
|
||||
public function has($name): bool
|
||||
public function has($name)
|
||||
{
|
||||
return $this->handler->exists($this->getCacheKey($name));
|
||||
return $this->handler->get($this->getCacheKey($name)) ? true : false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -124,9 +103,9 @@ class Redis extends Driver
|
|||
* @param string $name 缓存变量名
|
||||
* @param mixed $value 存储数据
|
||||
* @param integer|\DateTime $expire 有效时间(秒)
|
||||
* @return bool
|
||||
* @return boolean
|
||||
*/
|
||||
public function set($name, $value, $expire = null): bool
|
||||
public function set($name, $value, $expire = null)
|
||||
{
|
||||
$this->writeTimes++;
|
||||
|
||||
|
@ -134,27 +113,34 @@ class Redis extends Driver
|
|||
$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);
|
||||
if ($this->tag && !$this->has($name)) {
|
||||
$first = true;
|
||||
}
|
||||
|
||||
return true;
|
||||
$key = $this->getCacheKey($name);
|
||||
$expire = $this->getExpireTime($expire);
|
||||
|
||||
$value = $this->serialize($value);
|
||||
|
||||
if ($expire) {
|
||||
$result = $this->handler->setex($key, $expire, $value);
|
||||
} else {
|
||||
$result = $this->handler->set($key, $value);
|
||||
}
|
||||
|
||||
isset($first) && $this->setTagItem($key);
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 自增缓存(针对数值缓存)
|
||||
* @access public
|
||||
* @param string $name 缓存变量名
|
||||
* @param int $step 步长
|
||||
* @param string $name 缓存变量名
|
||||
* @param int $step 步长
|
||||
* @return false|int
|
||||
*/
|
||||
public function inc(string $name, int $step = 1)
|
||||
public function inc($name, $step = 1)
|
||||
{
|
||||
$this->writeTimes++;
|
||||
|
||||
|
@ -166,11 +152,11 @@ class Redis extends Driver
|
|||
/**
|
||||
* 自减缓存(针对数值缓存)
|
||||
* @access public
|
||||
* @param string $name 缓存变量名
|
||||
* @param int $step 步长
|
||||
* @param string $name 缓存变量名
|
||||
* @param int $step 步长
|
||||
* @return false|int
|
||||
*/
|
||||
public function dec(string $name, int $step = 1)
|
||||
public function dec($name, $step = 1)
|
||||
{
|
||||
$this->writeTimes++;
|
||||
|
||||
|
@ -183,62 +169,38 @@ class Redis extends Driver
|
|||
* 删除缓存
|
||||
* @access public
|
||||
* @param string $name 缓存变量名
|
||||
* @return bool
|
||||
* @return boolean
|
||||
*/
|
||||
public function delete($name): bool
|
||||
public function rm($name)
|
||||
{
|
||||
$this->writeTimes++;
|
||||
|
||||
$this->handler->del($this->getCacheKey($name));
|
||||
return true;
|
||||
return $this->handler->delete($this->getCacheKey($name));
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除缓存
|
||||
* @access public
|
||||
* @return bool
|
||||
* @param string $tag 标签名
|
||||
* @return boolean
|
||||
*/
|
||||
public function clear(): bool
|
||||
public function clear($tag = null)
|
||||
{
|
||||
if ($tag) {
|
||||
// 指定标签清除
|
||||
$keys = $this->getTagItem($tag);
|
||||
|
||||
foreach ($keys as $key) {
|
||||
$this->handler->delete($key);
|
||||
}
|
||||
|
||||
$this->rm('tag_' . md5($tag));
|
||||
return true;
|
||||
}
|
||||
|
||||
$this->writeTimes++;
|
||||
|
||||
$this->handler->flushDB();
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除缓存标签
|
||||
* @access public
|
||||
* @param array $keys 缓存标识列表
|
||||
* @return void
|
||||
*/
|
||||
public function clearTag(array $keys): void
|
||||
{
|
||||
// 指定标签清除
|
||||
$this->handler->del($keys);
|
||||
}
|
||||
|
||||
/**
|
||||
* 追加(数组)缓存数据
|
||||
* @access public
|
||||
* @param string $name 缓存标识
|
||||
* @param mixed $value 数据
|
||||
* @return void
|
||||
*/
|
||||
public function push(string $name, $value): void
|
||||
{
|
||||
$this->handler->sAdd($name, $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取标签包含的缓存标识
|
||||
* @access public
|
||||
* @param string $tag 缓存标签
|
||||
* @return array
|
||||
*/
|
||||
public function getTagItems(string $tag): array
|
||||
{
|
||||
return $this->handler->sMembers($tag);
|
||||
return $this->handler->flushDB();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,233 @@
|
|||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace think\cache\driver;
|
||||
|
||||
use think\cache\Driver;
|
||||
|
||||
/**
|
||||
* Sqlite缓存驱动
|
||||
* @author liu21st <liu21st@gmail.com>
|
||||
*/
|
||||
class Sqlite extends Driver
|
||||
{
|
||||
protected $options = [
|
||||
'db' => ':memory:',
|
||||
'table' => 'sharedmemory',
|
||||
'prefix' => '',
|
||||
'expire' => 0,
|
||||
'persistent' => false,
|
||||
'serialize' => true,
|
||||
];
|
||||
|
||||
/**
|
||||
* 架构函数
|
||||
* @access public
|
||||
* @param array $options 缓存参数
|
||||
* @throws \BadFunctionCallException
|
||||
*/
|
||||
public function __construct($options = [])
|
||||
{
|
||||
if (!extension_loaded('sqlite')) {
|
||||
throw new \BadFunctionCallException('not support: sqlite');
|
||||
}
|
||||
|
||||
if (!empty($options)) {
|
||||
$this->options = array_merge($this->options, $options);
|
||||
}
|
||||
|
||||
$func = $this->options['persistent'] ? 'sqlite_popen' : 'sqlite_open';
|
||||
|
||||
$this->handler = $func($this->options['db']);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取实际的缓存标识
|
||||
* @access public
|
||||
* @param string $name 缓存名
|
||||
* @return string
|
||||
*/
|
||||
protected function getCacheKey($name)
|
||||
{
|
||||
return $this->options['prefix'] . sqlite_escape_string($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断缓存
|
||||
* @access public
|
||||
* @param string $name 缓存变量名
|
||||
* @return bool
|
||||
*/
|
||||
public function has($name)
|
||||
{
|
||||
$name = $this->getCacheKey($name);
|
||||
|
||||
$sql = 'SELECT value FROM ' . $this->options['table'] . ' WHERE var=\'' . $name . '\' AND (expire=0 OR expire >' . time() . ') LIMIT 1';
|
||||
$result = sqlite_query($this->handler, $sql);
|
||||
|
||||
return sqlite_num_rows($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 读取缓存
|
||||
* @access public
|
||||
* @param string $name 缓存变量名
|
||||
* @param mixed $default 默认值
|
||||
* @return mixed
|
||||
*/
|
||||
public function get($name, $default = false)
|
||||
{
|
||||
$this->readTimes++;
|
||||
|
||||
$name = $this->getCacheKey($name);
|
||||
|
||||
$sql = 'SELECT value FROM ' . $this->options['table'] . ' WHERE var=\'' . $name . '\' AND (expire=0 OR expire >' . time() . ') LIMIT 1';
|
||||
|
||||
$result = sqlite_query($this->handler, $sql);
|
||||
|
||||
if (sqlite_num_rows($result)) {
|
||||
$content = sqlite_fetch_single($result);
|
||||
if (function_exists('gzcompress')) {
|
||||
//启用数据压缩
|
||||
$content = gzuncompress($content);
|
||||
}
|
||||
|
||||
return $this->unserialize($content);
|
||||
}
|
||||
|
||||
return $default;
|
||||
}
|
||||
|
||||
/**
|
||||
* 写入缓存
|
||||
* @access public
|
||||
* @param string $name 缓存变量名
|
||||
* @param mixed $value 存储数据
|
||||
* @param integer|\DateTime $expire 有效时间(秒)
|
||||
* @return boolean
|
||||
*/
|
||||
public function set($name, $value, $expire = null)
|
||||
{
|
||||
$this->writeTimes++;
|
||||
|
||||
$name = $this->getCacheKey($name);
|
||||
|
||||
$value = sqlite_escape_string($this->serialize($value));
|
||||
|
||||
if (is_null($expire)) {
|
||||
$expire = $this->options['expire'];
|
||||
}
|
||||
|
||||
if ($expire instanceof \DateTime) {
|
||||
$expire = $expire->getTimestamp();
|
||||
} else {
|
||||
$expire = (0 == $expire) ? 0 : (time() + $expire); //缓存有效期为0表示永久缓存
|
||||
}
|
||||
|
||||
if (function_exists('gzcompress')) {
|
||||
//数据压缩
|
||||
$value = gzcompress($value, 3);
|
||||
}
|
||||
|
||||
if ($this->tag) {
|
||||
$tag = $this->tag;
|
||||
$this->tag = null;
|
||||
} else {
|
||||
$tag = '';
|
||||
}
|
||||
|
||||
$sql = 'REPLACE INTO ' . $this->options['table'] . ' (var, value, expire, tag) VALUES (\'' . $name . '\', \'' . $value . '\', \'' . $expire . '\', \'' . $tag . '\')';
|
||||
|
||||
if (sqlite_query($this->handler, $sql)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 自增缓存(针对数值缓存)
|
||||
* @access public
|
||||
* @param string $name 缓存变量名
|
||||
* @param int $step 步长
|
||||
* @return false|int
|
||||
*/
|
||||
public function inc($name, $step = 1)
|
||||
{
|
||||
if ($this->has($name)) {
|
||||
$value = $this->get($name) + $step;
|
||||
} else {
|
||||
$value = $step;
|
||||
}
|
||||
|
||||
return $this->set($name, $value, 0) ? $value : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 自减缓存(针对数值缓存)
|
||||
* @access public
|
||||
* @param string $name 缓存变量名
|
||||
* @param int $step 步长
|
||||
* @return false|int
|
||||
*/
|
||||
public function dec($name, $step = 1)
|
||||
{
|
||||
if ($this->has($name)) {
|
||||
$value = $this->get($name) - $step;
|
||||
} else {
|
||||
$value = -$step;
|
||||
}
|
||||
|
||||
return $this->set($name, $value, 0) ? $value : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除缓存
|
||||
* @access public
|
||||
* @param string $name 缓存变量名
|
||||
* @return boolean
|
||||
*/
|
||||
public function rm($name)
|
||||
{
|
||||
$this->writeTimes++;
|
||||
|
||||
$name = $this->getCacheKey($name);
|
||||
|
||||
$sql = 'DELETE FROM ' . $this->options['table'] . ' WHERE var=\'' . $name . '\'';
|
||||
sqlite_query($this->handler, $sql);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除缓存
|
||||
* @access public
|
||||
* @param string $tag 标签名
|
||||
* @return boolean
|
||||
*/
|
||||
public function clear($tag = null)
|
||||
{
|
||||
if ($tag) {
|
||||
$name = sqlite_escape_string($tag);
|
||||
$sql = 'DELETE FROM ' . $this->options['table'] . ' WHERE tag=\'' . $name . '\'';
|
||||
sqlite_query($this->handler, $sql);
|
||||
return true;
|
||||
}
|
||||
|
||||
$this->writeTimes++;
|
||||
|
||||
$sql = 'DELETE FROM ' . $this->options['table'];
|
||||
|
||||
sqlite_query($this->handler, $sql);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -2,7 +2,7 @@
|
|||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2019 http://thinkphp.cn All rights reserved.
|
||||
// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
|
@ -15,18 +15,14 @@ use think\cache\Driver;
|
|||
|
||||
/**
|
||||
* Wincache缓存驱动
|
||||
* @author liu21st <liu21st@gmail.com>
|
||||
*/
|
||||
class Wincache extends Driver
|
||||
{
|
||||
/**
|
||||
* 配置参数
|
||||
* @var array
|
||||
*/
|
||||
protected $options = [
|
||||
'prefix' => '',
|
||||
'expire' => 0,
|
||||
'tag_prefix' => 'tag:',
|
||||
'serialize' => [],
|
||||
'prefix' => '',
|
||||
'expire' => 0,
|
||||
'serialize' => true,
|
||||
];
|
||||
|
||||
/**
|
||||
|
@ -35,7 +31,7 @@ class Wincache extends Driver
|
|||
* @param array $options 缓存参数
|
||||
* @throws \BadFunctionCallException
|
||||
*/
|
||||
public function __construct(array $options = [])
|
||||
public function __construct($options = [])
|
||||
{
|
||||
if (!function_exists('wincache_ucache_info')) {
|
||||
throw new \BadFunctionCallException('not support: WinCache');
|
||||
|
@ -52,7 +48,7 @@ class Wincache extends Driver
|
|||
* @param string $name 缓存变量名
|
||||
* @return bool
|
||||
*/
|
||||
public function has($name): bool
|
||||
public function has($name)
|
||||
{
|
||||
$this->readTimes++;
|
||||
|
||||
|
@ -83,9 +79,9 @@ class Wincache extends Driver
|
|||
* @param string $name 缓存变量名
|
||||
* @param mixed $value 存储数据
|
||||
* @param integer|\DateTime $expire 有效时间(秒)
|
||||
* @return bool
|
||||
* @return boolean
|
||||
*/
|
||||
public function set($name, $value, $expire = null): bool
|
||||
public function set($name, $value, $expire = null)
|
||||
{
|
||||
$this->writeTimes++;
|
||||
|
||||
|
@ -97,7 +93,12 @@ class Wincache extends Driver
|
|||
$expire = $this->getExpireTime($expire);
|
||||
$value = $this->serialize($value);
|
||||
|
||||
if ($this->tag && !$this->has($name)) {
|
||||
$first = true;
|
||||
}
|
||||
|
||||
if (wincache_ucache_set($key, $value, $expire)) {
|
||||
isset($first) && $this->setTagItem($key);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -111,7 +112,7 @@ class Wincache extends Driver
|
|||
* @param int $step 步长
|
||||
* @return false|int
|
||||
*/
|
||||
public function inc(string $name, int $step = 1)
|
||||
public function inc($name, $step = 1)
|
||||
{
|
||||
$this->writeTimes++;
|
||||
|
||||
|
@ -127,7 +128,7 @@ class Wincache extends Driver
|
|||
* @param int $step 步长
|
||||
* @return false|int
|
||||
*/
|
||||
public function dec(string $name, int $step = 1)
|
||||
public function dec($name, $step = 1)
|
||||
{
|
||||
$this->writeTimes++;
|
||||
|
||||
|
@ -140,9 +141,9 @@ class Wincache extends Driver
|
|||
* 删除缓存
|
||||
* @access public
|
||||
* @param string $name 缓存变量名
|
||||
* @return bool
|
||||
* @return boolean
|
||||
*/
|
||||
public function delete($name): bool
|
||||
public function rm($name)
|
||||
{
|
||||
$this->writeTimes++;
|
||||
|
||||
|
@ -152,23 +153,22 @@ class Wincache extends Driver
|
|||
/**
|
||||
* 清除缓存
|
||||
* @access public
|
||||
* @return bool
|
||||
* @param string $tag 标签名
|
||||
* @return boolean
|
||||
*/
|
||||
public function clear(): bool
|
||||
public function clear($tag = null)
|
||||
{
|
||||
$this->writeTimes++;
|
||||
return wincache_ucache_clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除缓存标签
|
||||
* @access public
|
||||
* @param array $keys 缓存标识列表
|
||||
* @return void
|
||||
*/
|
||||
public function clearTag(array $keys): void
|
||||
{
|
||||
wincache_ucache_delete($keys);
|
||||
if ($tag) {
|
||||
$keys = $this->getTagItem($tag);
|
||||
foreach ($keys as $key) {
|
||||
wincache_ucache_delete($key);
|
||||
}
|
||||
$this->rm('tag_' . md5($tag));
|
||||
return true;
|
||||
} else {
|
||||
$this->writeTimes++;
|
||||
return wincache_ucache_clear();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,177 @@
|
|||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace think\cache\driver;
|
||||
|
||||
use think\cache\Driver;
|
||||
|
||||
/**
|
||||
* Xcache缓存驱动
|
||||
* @author liu21st <liu21st@gmail.com>
|
||||
*/
|
||||
class Xcache extends Driver
|
||||
{
|
||||
protected $options = [
|
||||
'prefix' => '',
|
||||
'expire' => 0,
|
||||
'serialize' => true,
|
||||
];
|
||||
|
||||
/**
|
||||
* 架构函数
|
||||
* @access public
|
||||
* @param array $options 缓存参数
|
||||
* @throws \BadFunctionCallException
|
||||
*/
|
||||
public function __construct($options = [])
|
||||
{
|
||||
if (!function_exists('xcache_info')) {
|
||||
throw new \BadFunctionCallException('not support: Xcache');
|
||||
}
|
||||
|
||||
if (!empty($options)) {
|
||||
$this->options = array_merge($this->options, $options);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断缓存
|
||||
* @access public
|
||||
* @param string $name 缓存变量名
|
||||
* @return bool
|
||||
*/
|
||||
public function has($name)
|
||||
{
|
||||
$key = $this->getCacheKey($name);
|
||||
|
||||
return xcache_isset($key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 读取缓存
|
||||
* @access public
|
||||
* @param string $name 缓存变量名
|
||||
* @param mixed $default 默认值
|
||||
* @return mixed
|
||||
*/
|
||||
public function get($name, $default = false)
|
||||
{
|
||||
$this->readTimes++;
|
||||
|
||||
$key = $this->getCacheKey($name);
|
||||
|
||||
return xcache_isset($key) ? $this->unserialize(xcache_get($key)) : $default;
|
||||
}
|
||||
|
||||
/**
|
||||
* 写入缓存
|
||||
* @access public
|
||||
* @param string $name 缓存变量名
|
||||
* @param mixed $value 存储数据
|
||||
* @param integer|\DateTime $expire 有效时间(秒)
|
||||
* @return boolean
|
||||
*/
|
||||
public function set($name, $value, $expire = null)
|
||||
{
|
||||
$this->writeTimes++;
|
||||
|
||||
if (is_null($expire)) {
|
||||
$expire = $this->options['expire'];
|
||||
}
|
||||
|
||||
if ($this->tag && !$this->has($name)) {
|
||||
$first = true;
|
||||
}
|
||||
|
||||
$key = $this->getCacheKey($name);
|
||||
$expire = $this->getExpireTime($expire);
|
||||
$value = $this->serialize($value);
|
||||
|
||||
if (xcache_set($key, $value, $expire)) {
|
||||
isset($first) && $this->setTagItem($key);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 自增缓存(针对数值缓存)
|
||||
* @access public
|
||||
* @param string $name 缓存变量名
|
||||
* @param int $step 步长
|
||||
* @return false|int
|
||||
*/
|
||||
public function inc($name, $step = 1)
|
||||
{
|
||||
$this->writeTimes++;
|
||||
|
||||
$key = $this->getCacheKey($name);
|
||||
|
||||
return xcache_inc($key, $step);
|
||||
}
|
||||
|
||||
/**
|
||||
* 自减缓存(针对数值缓存)
|
||||
* @access public
|
||||
* @param string $name 缓存变量名
|
||||
* @param int $step 步长
|
||||
* @return false|int
|
||||
*/
|
||||
public function dec($name, $step = 1)
|
||||
{
|
||||
$this->writeTimes++;
|
||||
|
||||
$key = $this->getCacheKey($name);
|
||||
|
||||
return xcache_dec($key, $step);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除缓存
|
||||
* @access public
|
||||
* @param string $name 缓存变量名
|
||||
* @return boolean
|
||||
*/
|
||||
public function rm($name)
|
||||
{
|
||||
$this->writeTimes++;
|
||||
|
||||
return xcache_unset($this->getCacheKey($name));
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除缓存
|
||||
* @access public
|
||||
* @param string $tag 标签名
|
||||
* @return boolean
|
||||
*/
|
||||
public function clear($tag = null)
|
||||
{
|
||||
if ($tag) {
|
||||
// 指定标签清除
|
||||
$keys = $this->getTagItem($tag);
|
||||
foreach ($keys as $key) {
|
||||
xcache_unset($key);
|
||||
}
|
||||
$this->rm('tag_' . md5($tag));
|
||||
return true;
|
||||
}
|
||||
|
||||
$this->writeTimes++;
|
||||
|
||||
if (function_exists('xcache_unset_by_prefix')) {
|
||||
return xcache_unset_by_prefix($this->options['prefix']);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -9,13 +9,16 @@
|
|||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
// +----------------------------------------------------------------------
|
||||
// | 控制台配置
|
||||
// +----------------------------------------------------------------------
|
||||
return [
|
||||
// 执行用户(Windows下无效)
|
||||
'user' => null,
|
||||
// 指令定义
|
||||
'commands' => [
|
||||
],
|
||||
];
|
||||
namespace think\config\driver;
|
||||
|
||||
class Ini
|
||||
{
|
||||
public function parse($config)
|
||||
{
|
||||
if (is_file($config)) {
|
||||
return parse_ini_file($config, true);
|
||||
} else {
|
||||
return parse_ini_string($config, true);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace think\config\driver;
|
||||
|
||||
class Json
|
||||
{
|
||||
public function parse($config)
|
||||
{
|
||||
if (is_file($config)) {
|
||||
$config = file_get_contents($config);
|
||||
}
|
||||
|
||||
$result = json_decode($config, true);
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace think\config\driver;
|
||||
|
||||
class Xml
|
||||
{
|
||||
public function parse($config)
|
||||
{
|
||||
if (is_file($config)) {
|
||||
$content = simplexml_load_file($config);
|
||||
} else {
|
||||
$content = simplexml_load_string($config);
|
||||
}
|
||||
|
||||
$result = (array) $content;
|
||||
foreach ($result as $key => $val) {
|
||||
if (is_object($val)) {
|
||||
$result[$key] = (array) $val;
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
|
@ -8,35 +8,30 @@
|
|||
// +----------------------------------------------------------------------
|
||||
// | 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
|
||||
class Command
|
||||
{
|
||||
|
||||
/** @var Console */
|
||||
private $console;
|
||||
private $name;
|
||||
private $processTitle;
|
||||
private $aliases = [];
|
||||
private $aliases = [];
|
||||
private $definition;
|
||||
private $help;
|
||||
private $description;
|
||||
private $ignoreValidationErrors = false;
|
||||
private $consoleDefinitionMerged = false;
|
||||
private $consoleDefinitionMergedWithArgs = false;
|
||||
private $synopsis = [];
|
||||
private $usages = [];
|
||||
private $code;
|
||||
private $synopsis = [];
|
||||
private $usages = [];
|
||||
|
||||
/** @var Input */
|
||||
protected $input;
|
||||
|
@ -44,29 +39,31 @@ abstract class Command
|
|||
/** @var Output */
|
||||
protected $output;
|
||||
|
||||
/** @var App */
|
||||
protected $app;
|
||||
|
||||
/**
|
||||
* 构造方法
|
||||
* @throws LogicException
|
||||
* @param string|null $name 命令名称,如果没有设置则比如在 configure() 里设置
|
||||
* @throws \LogicException
|
||||
* @api
|
||||
*/
|
||||
public function __construct()
|
||||
public function __construct($name = null)
|
||||
{
|
||||
$this->definition = new Definition();
|
||||
|
||||
if (null !== $name) {
|
||||
$this->setName($name);
|
||||
}
|
||||
|
||||
$this->configure();
|
||||
|
||||
if (!$this->name) {
|
||||
throw new LogicException(sprintf('The command defined in "%s" cannot have an empty name.', get_class($this)));
|
||||
throw new \LogicException(sprintf('The command defined in "%s" cannot have an empty name.', get_class($this)));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 忽略验证错误
|
||||
*/
|
||||
public function ignoreValidationErrors(): void
|
||||
public function ignoreValidationErrors()
|
||||
{
|
||||
$this->ignoreValidationErrors = true;
|
||||
}
|
||||
|
@ -75,7 +72,7 @@ abstract class Command
|
|||
* 设置控制台
|
||||
* @param Console $console
|
||||
*/
|
||||
public function setConsole(Console $console = null): void
|
||||
public function setConsole(Console $console = null)
|
||||
{
|
||||
$this->console = $console;
|
||||
}
|
||||
|
@ -85,34 +82,16 @@ abstract class Command
|
|||
* @return Console
|
||||
* @api
|
||||
*/
|
||||
public function getConsole(): Console
|
||||
public function getConsole()
|
||||
{
|
||||
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
|
||||
public function isEnabled()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
@ -129,12 +108,12 @@ abstract class Command
|
|||
* @param Input $input
|
||||
* @param Output $output
|
||||
* @return null|int
|
||||
* @throws LogicException
|
||||
* @throws \LogicException
|
||||
* @see setCode()
|
||||
*/
|
||||
protected function execute(Input $input, Output $output)
|
||||
{
|
||||
return $this->app->invoke([$this, 'handle']);
|
||||
throw new \LogicException('You must override the execute() method in the concrete command class.');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -160,11 +139,11 @@ abstract class Command
|
|||
* @param Input $input
|
||||
* @param Output $output
|
||||
* @return int
|
||||
* @throws Exception
|
||||
* @throws \Exception
|
||||
* @see setCode()
|
||||
* @see execute()
|
||||
*/
|
||||
public function run(Input $input, Output $output): int
|
||||
public function run(Input $input, Output $output)
|
||||
{
|
||||
$this->input = $input;
|
||||
$this->output = $output;
|
||||
|
@ -176,7 +155,7 @@ abstract class Command
|
|||
|
||||
try {
|
||||
$input->bind($this->definition);
|
||||
} catch (Exception $e) {
|
||||
} catch (\Exception $e) {
|
||||
if (!$this->ignoreValidationErrors) {
|
||||
throw $e;
|
||||
}
|
||||
|
@ -184,39 +163,51 @@ abstract class Command
|
|||
|
||||
$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);
|
||||
if ($this->code) {
|
||||
$statusCode = call_user_func($this->code, $input, $output);
|
||||
} else {
|
||||
$statusCode = $this->execute($input, $output);
|
||||
}
|
||||
|
||||
return is_numeric($statusCode) ? (int) $statusCode : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置执行代码
|
||||
* @param callable $code callable(InputInterface $input, OutputInterface $output)
|
||||
* @return Command
|
||||
* @throws \InvalidArgumentException
|
||||
* @see execute()
|
||||
*/
|
||||
public function setCode(callable $code)
|
||||
{
|
||||
if (!is_callable($code)) {
|
||||
throw new \InvalidArgumentException('Invalid callable provided to Command::setCode.');
|
||||
}
|
||||
|
||||
if (PHP_VERSION_ID >= 50400 && $code instanceof \Closure) {
|
||||
$r = new \ReflectionFunction($code);
|
||||
if (null === $r->getClosureThis()) {
|
||||
$code = \Closure::bind($code, $this);
|
||||
}
|
||||
}
|
||||
|
||||
$this->code = $code;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 合并参数定义
|
||||
* @param bool $mergeArgs
|
||||
*/
|
||||
public function mergeConsoleDefinition(bool $mergeArgs = true)
|
||||
public function mergeConsoleDefinition($mergeArgs = true)
|
||||
{
|
||||
if (null === $this->console
|
||||
|| (true === $this->consoleDefinitionMerged
|
||||
|
@ -263,7 +254,7 @@ abstract class Command
|
|||
* @return Definition
|
||||
* @api
|
||||
*/
|
||||
public function getDefinition(): Definition
|
||||
public function getDefinition()
|
||||
{
|
||||
return $this->definition;
|
||||
}
|
||||
|
@ -272,7 +263,7 @@ abstract class Command
|
|||
* 获取当前指令的参数定义
|
||||
* @return Definition
|
||||
*/
|
||||
public function getNativeDefinition(): Definition
|
||||
public function getNativeDefinition()
|
||||
{
|
||||
return $this->getDefinition();
|
||||
}
|
||||
|
@ -285,7 +276,7 @@ abstract class Command
|
|||
* @param mixed $default 默认值
|
||||
* @return Command
|
||||
*/
|
||||
public function addArgument(string $name, int $mode = null, string $description = '', $default = null)
|
||||
public function addArgument($name, $mode = null, $description = '', $default = null)
|
||||
{
|
||||
$this->definition->addArgument(new Argument($name, $mode, $description, $default));
|
||||
|
||||
|
@ -301,7 +292,7 @@ abstract class Command
|
|||
* @param mixed $default 默认值
|
||||
* @return Command
|
||||
*/
|
||||
public function addOption(string $name, string $shortcut = null, int $mode = null, string $description = '', $default = null)
|
||||
public function addOption($name, $shortcut = null, $mode = null, $description = '', $default = null)
|
||||
{
|
||||
$this->definition->addOption(new Option($name, $shortcut, $mode, $description, $default));
|
||||
|
||||
|
@ -312,9 +303,9 @@ abstract class Command
|
|||
* 设置指令名称
|
||||
* @param string $name
|
||||
* @return Command
|
||||
* @throws InvalidArgumentException
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public function setName(string $name)
|
||||
public function setName($name)
|
||||
{
|
||||
$this->validateName($name);
|
||||
|
||||
|
@ -323,29 +314,13 @@ abstract class Command
|
|||
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
|
||||
public function getName()
|
||||
{
|
||||
return $this->name ?: '';
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -353,7 +328,7 @@ abstract class Command
|
|||
* @param string $description
|
||||
* @return Command
|
||||
*/
|
||||
public function setDescription(string $description)
|
||||
public function setDescription($description)
|
||||
{
|
||||
$this->description = $description;
|
||||
|
||||
|
@ -364,9 +339,9 @@ abstract class Command
|
|||
* 获取描述
|
||||
* @return string
|
||||
*/
|
||||
public function getDescription(): string
|
||||
public function getDescription()
|
||||
{
|
||||
return $this->description ?: '';
|
||||
return $this->description;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -374,7 +349,7 @@ abstract class Command
|
|||
* @param string $help
|
||||
* @return Command
|
||||
*/
|
||||
public function setHelp(string $help)
|
||||
public function setHelp($help)
|
||||
{
|
||||
$this->help = $help;
|
||||
|
||||
|
@ -385,16 +360,16 @@ abstract class Command
|
|||
* 获取帮助信息
|
||||
* @return string
|
||||
*/
|
||||
public function getHelp(): string
|
||||
public function getHelp()
|
||||
{
|
||||
return $this->help ?: '';
|
||||
return $this->help;
|
||||
}
|
||||
|
||||
/**
|
||||
* 描述信息
|
||||
* @return string
|
||||
*/
|
||||
public function getProcessedHelp(): string
|
||||
public function getProcessedHelp()
|
||||
{
|
||||
$name = $this->name;
|
||||
|
||||
|
@ -414,10 +389,14 @@ abstract class Command
|
|||
* 设置别名
|
||||
* @param string[] $aliases
|
||||
* @return Command
|
||||
* @throws InvalidArgumentException
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public function setAliases(iterable $aliases)
|
||||
public function setAliases($aliases)
|
||||
{
|
||||
if (!is_array($aliases) && !$aliases instanceof \Traversable) {
|
||||
throw new \InvalidArgumentException('$aliases must be an array or an instance of \Traversable');
|
||||
}
|
||||
|
||||
foreach ($aliases as $alias) {
|
||||
$this->validateName($alias);
|
||||
}
|
||||
|
@ -431,7 +410,7 @@ abstract class Command
|
|||
* 获取别名
|
||||
* @return array
|
||||
*/
|
||||
public function getAliases(): array
|
||||
public function getAliases()
|
||||
{
|
||||
return $this->aliases;
|
||||
}
|
||||
|
@ -441,7 +420,7 @@ abstract class Command
|
|||
* @param bool $short 是否简单的
|
||||
* @return string
|
||||
*/
|
||||
public function getSynopsis(bool $short = false): string
|
||||
public function getSynopsis($short = false)
|
||||
{
|
||||
$key = $short ? 'short' : 'long';
|
||||
|
||||
|
@ -457,7 +436,7 @@ abstract class Command
|
|||
* @param string $usage
|
||||
* @return $this
|
||||
*/
|
||||
public function addUsage(string $usage)
|
||||
public function addUsage($usage)
|
||||
{
|
||||
if (0 !== strpos($usage, $this->name)) {
|
||||
$usage = sprintf('%s %s', $this->name, $usage);
|
||||
|
@ -472,7 +451,7 @@ abstract class Command
|
|||
* 获取用法介绍
|
||||
* @return array
|
||||
*/
|
||||
public function getUsages(): array
|
||||
public function getUsages()
|
||||
{
|
||||
return $this->usages;
|
||||
}
|
||||
|
@ -480,24 +459,12 @@ abstract class Command
|
|||
/**
|
||||
* 验证指令名称
|
||||
* @param string $name
|
||||
* @throws InvalidArgumentException
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
private function validateName(string $name)
|
||||
private function validateName($name)
|
||||
{
|
||||
if (!preg_match('/^[^\:]++(\:[^\:]++)*$/', $name)) {
|
||||
throw new InvalidArgumentException(sprintf('Command name "%s" is invalid.', $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;
|
||||
}
|
||||
}
|
|
@ -8,7 +8,6 @@
|
|||
// +----------------------------------------------------------------------
|
||||
// | Author: yunwuxin <448901948@qq.com>
|
||||
// +----------------------------------------------------------------------
|
||||
declare (strict_types = 1);
|
||||
|
||||
namespace think\console;
|
||||
|
||||
|
@ -61,7 +60,7 @@ class Input
|
|||
* 绑定实例
|
||||
* @param Definition $definition A InputDefinition instance
|
||||
*/
|
||||
public function bind(Definition $definition): void
|
||||
public function bind(Definition $definition)
|
||||
{
|
||||
$this->arguments = [];
|
||||
$this->options = [];
|
||||
|
@ -73,7 +72,7 @@ class Input
|
|||
/**
|
||||
* 解析参数
|
||||
*/
|
||||
protected function parse(): void
|
||||
protected function parse()
|
||||
{
|
||||
$parseOptions = true;
|
||||
$this->parsed = $this->tokens;
|
||||
|
@ -96,7 +95,7 @@ class Input
|
|||
* 解析短选项
|
||||
* @param string $token 当前的指令.
|
||||
*/
|
||||
private function parseShortOption(string $token): void
|
||||
private function parseShortOption($token)
|
||||
{
|
||||
$name = substr($token, 1);
|
||||
|
||||
|
@ -118,7 +117,7 @@ class Input
|
|||
* @param string $name 当前指令
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
private function parseShortOptionSet(string $name): void
|
||||
private function parseShortOptionSet($name)
|
||||
{
|
||||
$len = strlen($name);
|
||||
for ($i = 0; $i < $len; ++$i) {
|
||||
|
@ -141,7 +140,7 @@ class Input
|
|||
* 解析完整选项
|
||||
* @param string $token 当前指令
|
||||
*/
|
||||
private function parseLongOption(string $token): void
|
||||
private function parseLongOption($token)
|
||||
{
|
||||
$name = substr($token, 2);
|
||||
|
||||
|
@ -157,7 +156,7 @@ class Input
|
|||
* @param string $token 当前指令
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
private function parseArgument(string $token): void
|
||||
private function parseArgument($token)
|
||||
{
|
||||
$c = count($this->arguments);
|
||||
|
||||
|
@ -181,7 +180,7 @@ class Input
|
|||
* @param mixed $value 值
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
private function addShortOption(string $shortcut, $value): void
|
||||
private function addShortOption($shortcut, $value)
|
||||
{
|
||||
if (!$this->definition->hasShortcut($shortcut)) {
|
||||
throw new \RuntimeException(sprintf('The "-%s" option does not exist.', $shortcut));
|
||||
|
@ -196,7 +195,7 @@ class Input
|
|||
* @param mixed $value 值
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
private function addLongOption(string $name, $value): void
|
||||
private function addLongOption($name, $value)
|
||||
{
|
||||
if (!$this->definition->hasOption($name)) {
|
||||
throw new \RuntimeException(sprintf('The "--%s" option does not exist.', $name));
|
||||
|
@ -261,7 +260,7 @@ class Input
|
|||
* @param string|array $values 需要检查的值
|
||||
* @return bool
|
||||
*/
|
||||
public function hasParameterOption($values): bool
|
||||
public function hasParameterOption($values)
|
||||
{
|
||||
$values = (array) $values;
|
||||
|
||||
|
@ -319,7 +318,7 @@ class Input
|
|||
* 检查输入是否是交互的
|
||||
* @return bool
|
||||
*/
|
||||
public function isInteractive(): bool
|
||||
public function isInteractive()
|
||||
{
|
||||
return $this->interactive;
|
||||
}
|
||||
|
@ -328,16 +327,16 @@ class Input
|
|||
* 设置输入的交互
|
||||
* @param bool
|
||||
*/
|
||||
public function setInteractive(bool $interactive): void
|
||||
public function setInteractive($interactive)
|
||||
{
|
||||
$this->interactive = $interactive;
|
||||
$this->interactive = (bool) $interactive;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有的参数
|
||||
* @return Argument[]
|
||||
*/
|
||||
public function getArguments(): array
|
||||
public function getArguments()
|
||||
{
|
||||
return array_merge($this->definition->getArgumentDefaults(), $this->arguments);
|
||||
}
|
||||
|
@ -348,13 +347,13 @@ class Input
|
|||
* @return mixed
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public function getArgument(string $name)
|
||||
public function getArgument($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)
|
||||
return isset($this->arguments[$name]) ? $this->arguments[$name] : $this->definition->getArgument($name)
|
||||
->getDefault();
|
||||
}
|
||||
|
||||
|
@ -364,7 +363,7 @@ class Input
|
|||
* @param string $value 值
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public function setArgument(string $name, $value)
|
||||
public function setArgument($name, $value)
|
||||
{
|
||||
if (!$this->definition->hasArgument($name)) {
|
||||
throw new \InvalidArgumentException(sprintf('The "%s" argument does not exist.', $name));
|
||||
|
@ -378,7 +377,7 @@ class Input
|
|||
* @param string|int $name 参数名或位置
|
||||
* @return bool
|
||||
*/
|
||||
public function hasArgument($name): bool
|
||||
public function hasArgument($name)
|
||||
{
|
||||
return $this->definition->hasArgument($name);
|
||||
}
|
||||
|
@ -387,7 +386,7 @@ class Input
|
|||
* 获取所有的选项
|
||||
* @return Option[]
|
||||
*/
|
||||
public function getOptions(): array
|
||||
public function getOptions()
|
||||
{
|
||||
return array_merge($this->definition->getOptionDefaults(), $this->options);
|
||||
}
|
||||
|
@ -398,13 +397,13 @@ class Input
|
|||
* @return mixed
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public function getOption(string $name)
|
||||
public function getOption($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();
|
||||
return isset($this->options[$name]) ? $this->options[$name] : $this->definition->getOption($name)->getDefault();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -413,7 +412,7 @@ class Input
|
|||
* @param string|bool $value 值
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public function setOption(string $name, $value): void
|
||||
public function setOption($name, $value)
|
||||
{
|
||||
if (!$this->definition->hasOption($name)) {
|
||||
throw new \InvalidArgumentException(sprintf('The "%s" option does not exist.', $name));
|
||||
|
@ -427,7 +426,7 @@ class Input
|
|||
* @param string $name 选项名
|
||||
* @return bool
|
||||
*/
|
||||
public function hasOption(string $name): bool
|
||||
public function hasOption($name)
|
||||
{
|
||||
return $this->definition->hasOption($name) && isset($this->options[$name]);
|
||||
}
|
||||
|
@ -437,7 +436,7 @@ class Input
|
|||
* @param string $token
|
||||
* @return string
|
||||
*/
|
||||
public function escapeToken(string $token): string
|
||||
public function escapeToken($token)
|
||||
{
|
||||
return preg_match('{^[\w-]+$}', $token) ? $token : escapeshellarg($token);
|
||||
}
|
|
@ -8,7 +8,6 @@
|
|||
// +----------------------------------------------------------------------
|
||||
// | Author: yunwuxin <448901948@qq.com>
|
||||
// +----------------------------------------------------------------------
|
||||
declare (strict_types = 1);
|
||||
|
||||
namespace think\console;
|
||||
|
||||
|
@ -21,7 +20,6 @@ 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
|
||||
|
@ -63,7 +61,7 @@ class Output
|
|||
'comment',
|
||||
'question',
|
||||
'highlight',
|
||||
'warning',
|
||||
'warning'
|
||||
];
|
||||
|
||||
public function __construct($driver = 'console')
|
||||
|
@ -121,7 +119,7 @@ class Output
|
|||
return $answer;
|
||||
}
|
||||
|
||||
protected function block(string $style, string $message): void
|
||||
protected function block($style, $message)
|
||||
{
|
||||
$this->writeln("<{$style}>{$message}</$style>");
|
||||
}
|
||||
|
@ -130,7 +128,7 @@ class Output
|
|||
* 输出空行
|
||||
* @param int $count
|
||||
*/
|
||||
public function newLine(int $count = 1): void
|
||||
public function newLine($count = 1)
|
||||
{
|
||||
$this->write(str_repeat(PHP_EOL, $count));
|
||||
}
|
||||
|
@ -140,7 +138,7 @@ class Output
|
|||
* @param string $messages
|
||||
* @param int $type
|
||||
*/
|
||||
public function writeln(string $messages, int $type = 0): void
|
||||
public function writeln($messages, $type = self::OUTPUT_NORMAL)
|
||||
{
|
||||
$this->write($messages, true, $type);
|
||||
}
|
||||
|
@ -151,12 +149,12 @@ class Output
|
|||
* @param bool $newline
|
||||
* @param int $type
|
||||
*/
|
||||
public function write(string $messages, bool $newline = false, int $type = 0): void
|
||||
public function write($messages, $newline = false, $type = self::OUTPUT_NORMAL)
|
||||
{
|
||||
$this->handle->write($messages, $newline, $type);
|
||||
}
|
||||
|
||||
public function renderException(Throwable $e): void
|
||||
public function renderException(\Exception $e)
|
||||
{
|
||||
$this->handle->renderException($e);
|
||||
}
|
||||
|
@ -164,40 +162,40 @@ class Output
|
|||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setVerbosity(int $level)
|
||||
public function setVerbosity($level)
|
||||
{
|
||||
$this->verbosity = $level;
|
||||
$this->verbosity = (int) $level;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getVerbosity(): int
|
||||
public function getVerbosity()
|
||||
{
|
||||
return $this->verbosity;
|
||||
}
|
||||
|
||||
public function isQuiet(): bool
|
||||
public function isQuiet()
|
||||
{
|
||||
return self::VERBOSITY_QUIET === $this->verbosity;
|
||||
}
|
||||
|
||||
public function isVerbose(): bool
|
||||
public function isVerbose()
|
||||
{
|
||||
return self::VERBOSITY_VERBOSE <= $this->verbosity;
|
||||
}
|
||||
|
||||
public function isVeryVerbose(): bool
|
||||
public function isVeryVerbose()
|
||||
{
|
||||
return self::VERBOSITY_VERY_VERBOSE <= $this->verbosity;
|
||||
}
|
||||
|
||||
public function isDebug(): bool
|
||||
public function isDebug()
|
||||
{
|
||||
return self::VERBOSITY_DEBUG <= $this->verbosity;
|
||||
}
|
||||
|
||||
public function describe($object, array $options = []): void
|
||||
public function describe($object, array $options = [])
|
||||
{
|
||||
$descriptor = new Descriptor();
|
||||
$options = array_merge([
|
|
@ -0,0 +1,60 @@
|
|||
<?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\Option;
|
||||
use think\console\Output;
|
||||
use think\facade\App;
|
||||
use think\facade\Build as AppBuild;
|
||||
|
||||
class Build extends Command
|
||||
{
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function configure()
|
||||
{
|
||||
$this->setName('build')
|
||||
->setDefinition([
|
||||
new Option('config', null, Option::VALUE_OPTIONAL, "build.php path"),
|
||||
new Option('module', null, Option::VALUE_OPTIONAL, "module name"),
|
||||
])
|
||||
->setDescription('Build Application Dirs');
|
||||
}
|
||||
|
||||
protected function execute(Input $input, Output $output)
|
||||
{
|
||||
if ($input->hasOption('module')) {
|
||||
AppBuild::module($input->getOption('module'));
|
||||
$output->writeln("Successed");
|
||||
return;
|
||||
}
|
||||
|
||||
if ($input->hasOption('config')) {
|
||||
$build = include $input->getOption('config');
|
||||
} else {
|
||||
$build = include App::getAppPath() . 'build.php';
|
||||
}
|
||||
|
||||
if (empty($build)) {
|
||||
$output->writeln("Build Config Is Empty");
|
||||
return;
|
||||
}
|
||||
|
||||
AppBuild::run($build);
|
||||
$output->writeln("Successed");
|
||||
|
||||
}
|
||||
}
|
|
@ -8,26 +8,38 @@
|
|||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
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;
|
||||
use think\facade\App;
|
||||
|
||||
class Version extends Command
|
||||
class Clear extends Command
|
||||
{
|
||||
protected function configure()
|
||||
{
|
||||
// 指令配置
|
||||
$this->setName('version')
|
||||
->setDescription('show thinkphp framework version');
|
||||
$this
|
||||
->setName('clear')
|
||||
->addOption('path', 'd', Option::VALUE_OPTIONAL, 'path to clear', null)
|
||||
->setDescription('Clear runtime file');
|
||||
}
|
||||
|
||||
protected function execute(Input $input, Output $output)
|
||||
{
|
||||
$output->writeln('v' . $this->app->version());
|
||||
$path = $input->getOption('path') ?: App::getRuntimePath();
|
||||
$files = scandir($path);
|
||||
if ($files) {
|
||||
foreach ($files as $file) {
|
||||
if ('.' != $file && '..' != $file && is_dir($path . $file)) {
|
||||
array_map('unlink', glob($path . $file . '/*.*'));
|
||||
} elseif ('.gitignore' != $file && is_file($path . $file)) {
|
||||
unlink($path . $file);
|
||||
}
|
||||
}
|
||||
}
|
||||
$output->writeln("<info>Clear Successed</info>");
|
||||
}
|
||||
|
||||
}
|
|
@ -46,7 +46,7 @@ EOF
|
|||
* Sets the command.
|
||||
* @param Command $command The command to set
|
||||
*/
|
||||
public function setCommand(Command $command): void
|
||||
public function setCommand(Command $command)
|
||||
{
|
||||
$this->command = $command;
|
||||
}
|
|
@ -13,13 +13,14 @@ 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;
|
||||
use think\console\input\Argument as InputArgument;
|
||||
use think\console\input\Option as InputOption;
|
||||
use think\console\input\Definition as InputDefinition;
|
||||
|
||||
class Lists extends Command
|
||||
{
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
@ -44,7 +45,7 @@ EOF
|
|||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getNativeDefinition(): InputDefinition
|
||||
public function getNativeDefinition()
|
||||
{
|
||||
return $this->createDefinition();
|
||||
}
|
||||
|
@ -63,11 +64,11 @@ EOF
|
|||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
private function createDefinition(): InputDefinition
|
||||
private function createDefinition()
|
||||
{
|
||||
return new InputDefinition([
|
||||
new InputArgument('namespace', InputArgument::OPTIONAL, 'The namespace name'),
|
||||
new InputOption('raw', null, InputOption::VALUE_NONE, 'To output raw command list'),
|
||||
new InputOption('raw', null, InputOption::VALUE_NONE, 'To output raw command list')
|
||||
]);
|
||||
}
|
||||
}
|
|
@ -15,9 +15,13 @@ use think\console\Command;
|
|||
use think\console\Input;
|
||||
use think\console\input\Argument;
|
||||
use think\console\Output;
|
||||
use think\facade\App;
|
||||
use think\facade\Config;
|
||||
use think\facade\Env;
|
||||
|
||||
abstract class Make extends Command
|
||||
{
|
||||
|
||||
protected $type;
|
||||
|
||||
abstract protected function getStub();
|
||||
|
@ -29,6 +33,7 @@ abstract class Make extends Command
|
|||
|
||||
protected function execute(Input $input, Output $output)
|
||||
{
|
||||
|
||||
$name = trim($input->getArgument('name'));
|
||||
|
||||
$classname = $this->getClassName($name);
|
||||
|
@ -36,20 +41,21 @@ abstract class Make extends Command
|
|||
$pathname = $this->getPathName($classname);
|
||||
|
||||
if (is_file($pathname)) {
|
||||
$output->writeln('<error>' . $this->type . ':' . $classname . ' already exists!</error>');
|
||||
$output->writeln('<error>' . $this->type . ' already exists!</error>');
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!is_dir(dirname($pathname))) {
|
||||
mkdir(dirname($pathname), 0755, true);
|
||||
mkdir(strtolower(dirname($pathname)), 0755, true);
|
||||
}
|
||||
|
||||
file_put_contents($pathname, $this->buildClass($classname));
|
||||
|
||||
$output->writeln('<info>' . $this->type . ':' . $classname . ' created successfully.</info>');
|
||||
$output->writeln('<info>' . $this->type . ' created successfully.</info>');
|
||||
|
||||
}
|
||||
|
||||
protected function buildClass(string $name)
|
||||
protected function buildClass($name)
|
||||
{
|
||||
$stub = file_get_contents($this->getStub());
|
||||
|
||||
|
@ -57,43 +63,49 @@ abstract class Make extends Command
|
|||
|
||||
$class = str_replace($namespace . '\\', '', $name);
|
||||
|
||||
return str_replace(['{%className%}', '{%actionSuffix%}', '{%namespace%}', '{%app_namespace%}'], [
|
||||
return str_replace(['{%className%}', '{%namespace%}', '{%app_namespace%}'], [
|
||||
$class,
|
||||
$this->app->config->get('route.action_suffix'),
|
||||
$namespace,
|
||||
$this->app->getNamespace(),
|
||||
App::getNamespace(),
|
||||
], $stub);
|
||||
|
||||
}
|
||||
|
||||
protected function getPathName(string $name): string
|
||||
protected function getPathName($name)
|
||||
{
|
||||
$name = str_replace('app\\', '', $name);
|
||||
$name = str_replace(App::getNamespace() . '\\', '', $name);
|
||||
|
||||
return $this->app->getBasePath() . ltrim(str_replace('\\', '/', $name), '/') . '.php';
|
||||
return Env::get('app_path') . ltrim(str_replace('\\', '/', $name), '/') . '.php';
|
||||
}
|
||||
|
||||
protected function getClassName(string $name): string
|
||||
protected function getClassName($name)
|
||||
{
|
||||
if (strpos($name, '\\') !== false) {
|
||||
$appNamespace = App::getNamespace();
|
||||
|
||||
if (strpos($name, $appNamespace . '\\') !== false) {
|
||||
return $name;
|
||||
}
|
||||
|
||||
if (strpos($name, '@')) {
|
||||
list($app, $name) = explode('@', $name);
|
||||
if (Config::get('app_multi_module')) {
|
||||
if (strpos($name, '/')) {
|
||||
list($module, $name) = explode('/', $name, 2);
|
||||
} else {
|
||||
$module = 'common';
|
||||
}
|
||||
} else {
|
||||
$app = '';
|
||||
$module = null;
|
||||
}
|
||||
|
||||
if (strpos($name, '/') !== false) {
|
||||
$name = str_replace('/', '\\', $name);
|
||||
}
|
||||
|
||||
return $this->getNamespace($app) . '\\' . $name;
|
||||
return $this->getNamespace($appNamespace, $module) . '\\' . $name;
|
||||
}
|
||||
|
||||
protected function getNamespace(string $app): string
|
||||
protected function getNamespace($appNamespace, $module)
|
||||
{
|
||||
return 'app' . ($app ? '\\' . $app : '');
|
||||
return $module ? ($appNamespace . '\\' . $module) : $appNamespace;
|
||||
}
|
||||
|
||||
}
|
|
@ -8,26 +8,26 @@
|
|||
// +----------------------------------------------------------------------
|
||||
// | 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;
|
||||
use think\facade\App;
|
||||
|
||||
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')
|
||||
'The host to server the application on', '127.0.0.1')
|
||||
->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', '')
|
||||
'The document root of the application', App::getRootPath() . 'public')
|
||||
->setDescription('PHP Built-in Server for ThinkPHP');
|
||||
}
|
||||
|
||||
|
@ -36,19 +36,16 @@ class RunServer extends Command
|
|||
$host = $input->getOption('host');
|
||||
$port = $input->getOption('port');
|
||||
$root = $input->getOption('root');
|
||||
if (empty($root)) {
|
||||
$root = $this->app->getRootPath() . 'public';
|
||||
}
|
||||
|
||||
$command = sprintf(
|
||||
'php -S %s:%d -t %s %s',
|
||||
$host,
|
||||
$port,
|
||||
escapeshellarg($root),
|
||||
escapeshellarg($root . DIRECTORY_SEPARATOR . 'router.php')
|
||||
escapeshellarg($root . '/router.php')
|
||||
);
|
||||
|
||||
$output->writeln(sprintf('ThinkPHP Development server is started On <http://%s:%s/>', '0.0.0.0' == $host ? '127.0.0.1' : $host, $port));
|
||||
$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);
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue