Compare commits
No commits in common. "master" and "coding-pages" have entirely different histories.
master
...
coding-pag
60
.gitignore
vendored
60
.gitignore
vendored
@ -1,58 +1,4 @@
|
||||
# Eclipse stuff
|
||||
/.settings
|
||||
|
||||
# netbeans
|
||||
/nbproject
|
||||
|
||||
# we use maven!
|
||||
/build.xml
|
||||
|
||||
# maven
|
||||
/target
|
||||
/repo
|
||||
|
||||
# vim
|
||||
.*.sw[a-p]
|
||||
|
||||
# various other potential build files
|
||||
/build
|
||||
/bin
|
||||
/dist
|
||||
/manifest.mf
|
||||
|
||||
# Mac filesystem dust
|
||||
*.DS_Store
|
||||
|
||||
# intellij
|
||||
.idea
|
||||
composer.lock
|
||||
*.log
|
||||
*.iml
|
||||
*.ipr
|
||||
*.iws
|
||||
.idea/
|
||||
|
||||
# Project Stuff
|
||||
/src/main/resources/Soulbound
|
||||
|
||||
# Atlassian Stuff
|
||||
/atlassian-ide-plugin.xml
|
||||
|
||||
# Eclipse
|
||||
.project
|
||||
.classpath
|
||||
.factorypath
|
||||
.settings
|
||||
|
||||
# Visual Studio Code
|
||||
.vscode
|
||||
|
||||
# NodeJs PHP LOCK File
|
||||
*.lock
|
||||
|
||||
# PHP Vendor
|
||||
vendor/
|
||||
|
||||
# Minecraft Data
|
||||
/world
|
||||
**/node_modules/
|
||||
|
||||
# Gradle
|
||||
.gradle
|
||||
|
42
.travis.yml
Normal file
42
.travis.yml
Normal file
@ -0,0 +1,42 @@
|
||||
sudo: false
|
||||
|
||||
language: php
|
||||
|
||||
branches:
|
||||
only:
|
||||
- stable
|
||||
|
||||
cache:
|
||||
directories:
|
||||
- $HOME/.composer/cache
|
||||
|
||||
before_install:
|
||||
- composer self-update
|
||||
|
||||
install:
|
||||
- composer install --no-dev --no-interaction --ignore-platform-reqs
|
||||
- zip -r --exclude='*.git*' --exclude='*.zip' --exclude='*.travis.yml' ThinkPHP_Core.zip .
|
||||
- composer require --update-no-dev --no-interaction "topthink/think-image:^1.0"
|
||||
- composer require --update-no-dev --no-interaction "topthink/think-migration:^1.0"
|
||||
- composer require --update-no-dev --no-interaction "topthink/think-captcha:^1.0"
|
||||
- composer require --update-no-dev --no-interaction "topthink/think-mongo:^1.0"
|
||||
- composer require --update-no-dev --no-interaction "topthink/think-worker:^1.0"
|
||||
- composer require --update-no-dev --no-interaction "topthink/think-helper:^1.0"
|
||||
- composer require --update-no-dev --no-interaction "topthink/think-queue:^1.0"
|
||||
- composer require --update-no-dev --no-interaction "topthink/think-angular:^1.0"
|
||||
- composer require --dev --update-no-dev --no-interaction "topthink/think-testing:^1.0"
|
||||
- zip -r --exclude='*.git*' --exclude='*.zip' --exclude='*.travis.yml' ThinkPHP_Full.zip .
|
||||
|
||||
script:
|
||||
- php think unit
|
||||
|
||||
deploy:
|
||||
provider: releases
|
||||
api_key:
|
||||
secure: TSF6bnl2JYN72UQOORAJYL+CqIryP2gHVKt6grfveQ7d9rleAEoxlq6PWxbvTI4jZ5nrPpUcBUpWIJHNgVcs+bzLFtyh5THaLqm39uCgBbrW7M8rI26L8sBh/6nsdtGgdeQrO/cLu31QoTzbwuz1WfAVoCdCkOSZeXyT/CclH99qV6RYyQYqaD2wpRjrhA5O4fSsEkiPVuk0GaOogFlrQHx+C+lHnf6pa1KxEoN1A0UxxVfGX6K4y5g4WQDO5zT4bLeubkWOXK0G51XSvACDOZVIyLdjApaOFTwamPcD3S1tfvuxRWWvsCD5ljFvb2kSmx5BIBNwN80MzuBmrGIC27XLGOxyMerwKxB6DskNUO9PflKHDPI61DRq0FTy1fv70SFMSiAtUv9aJRT41NQh9iJJ0vC8dl+xcxrWIjU1GG6+l/ZcRqVx9V1VuGQsLKndGhja7SQ+X1slHl76fRq223sMOql7MFCd0vvvxVQ2V39CcFKao/LB1aPH3VhODDEyxwx6aXoTznvC/QPepgWsHOWQzKj9ftsgDbsNiyFlXL4cu8DWUty6rQy8zT2b4O8b1xjcwSUCsy+auEjBamzQkMJFNlZAIUrukL/NbUhQU37TAbwsFyz7X0E/u/VMle/nBCNAzgkMwAUjiHM6FqrKKBRWFbPrSIixjfjkCnrMEPw=
|
||||
file:
|
||||
- ThinkPHP_Core.zip
|
||||
- ThinkPHP_Full.zip
|
||||
skip_cleanup: true
|
||||
on:
|
||||
tags: true
|
32
LICENSE.txt
Normal file
32
LICENSE.txt
Normal file
@ -0,0 +1,32 @@
|
||||
|
||||
ThinkPHP遵循Apache2开源协议发布,并提供免费使用。
|
||||
版权所有Copyright © 2006-2016 by ThinkPHP (http://thinkphp.cn)
|
||||
All rights reserved。
|
||||
ThinkPHP® 商标和著作权所有者为上海顶想信息科技有限公司。
|
||||
|
||||
Apache Licence是著名的非盈利开源组织Apache采用的协议。
|
||||
该协议和BSD类似,鼓励代码共享和尊重原作者的著作权,
|
||||
允许代码修改,再作为开源或商业软件发布。需要满足
|
||||
的条件:
|
||||
1. 需要给代码的用户一份Apache Licence ;
|
||||
2. 如果你修改了代码,需要在被修改的文件中说明;
|
||||
3. 在延伸的代码中(修改和有源代码衍生的代码中)需要
|
||||
带有原来代码中的协议,商标,专利声明和其他原来作者规
|
||||
定需要包含的说明;
|
||||
4. 如果再发布的产品中包含一个Notice文件,则在Notice文
|
||||
件中需要带有本协议内容。你可以在Notice中增加自己的
|
||||
许可,但不可以表现为对Apache Licence构成更改。
|
||||
具体的协议参考:http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
132
README.md
132
README.md
@ -1,11 +1,129 @@
|
||||
# MiaoScript
|
||||
ThinkPHP 5.0
|
||||
===============
|
||||
|
||||
> 一个兼容 Spigot Sponge Nukkit BungeeCord 的 脚本插件运行时
|
||||
[![Total Downloads](https://poser.pugx.org/topthink/think/downloads)](https://packagist.org/packages/topthink/think)
|
||||
[![Latest Stable Version](https://poser.pugx.org/topthink/think/v/stable)](https://packagist.org/packages/topthink/think)
|
||||
[![Latest Unstable Version](https://poser.pugx.org/topthink/think/v/unstable)](https://packagist.org/packages/topthink/think)
|
||||
[![License](https://poser.pugx.org/topthink/think/license)](https://packagist.org/packages/topthink/think)
|
||||
|
||||
## 简介
|
||||
ThinkPHP5在保持快速开发和大道至简的核心理念不变的同时,PHP版本要求提升到5.4,对已有的CBD模式做了更深的强化,优化核心,减少依赖,基于全新的架构思想和命名空间实现,是ThinkPHP突破原有框架思路的颠覆之作,其主要特性包括:
|
||||
|
||||
## 安装
|
||||
+ 基于命名空间和众多PHP新特性
|
||||
+ 核心功能组件化
|
||||
+ 强化路由功能
|
||||
+ 更灵活的控制器
|
||||
+ 重构的模型和数据库类
|
||||
+ 配置文件可分离
|
||||
+ 重写的自动验证和完成
|
||||
+ 简化扩展机制
|
||||
+ API支持完善
|
||||
+ 改进的Log类
|
||||
+ 命令行访问支持
|
||||
+ REST支持
|
||||
+ 引导文件支持
|
||||
+ 方便的自动生成定义
|
||||
+ 真正惰性加载
|
||||
+ 分布式环境支持
|
||||
+ 更多的社交类库
|
||||
|
||||
- 下载后放入对应服务器目录
|
||||
- Bukkit Nukkit BungeeCord 以及其分支 => `plugins`
|
||||
- Sponge => `mods`
|
||||
> ThinkPHP5的运行环境要求PHP5.4以上。
|
||||
|
||||
详细开发文档参考 [ThinkPHP5完全开发手册](http://www.kancloud.cn/manual/thinkphp5)
|
||||
|
||||
## 目录结构
|
||||
|
||||
初始的目录结构如下:
|
||||
|
||||
~~~
|
||||
www WEB部署目录(或者子目录)
|
||||
├─application 应用目录
|
||||
│ ├─common 公共模块目录(可以更改)
|
||||
│ ├─module_name 模块目录
|
||||
│ │ ├─config.php 模块配置文件
|
||||
│ │ ├─common.php 模块函数文件
|
||||
│ │ ├─controller 控制器目录
|
||||
│ │ ├─model 模型目录
|
||||
│ │ ├─view 视图目录
|
||||
│ │ └─ ... 更多类库目录
|
||||
│ │
|
||||
│ ├─command.php 命令行工具配置文件
|
||||
│ ├─common.php 公共函数文件
|
||||
│ ├─config.php 公共配置文件
|
||||
│ ├─route.php 路由配置文件
|
||||
│ ├─tags.php 应用行为扩展定义文件
|
||||
│ └─database.php 数据库配置文件
|
||||
│
|
||||
├─public WEB目录(对外访问目录)
|
||||
│ ├─index.php 入口文件
|
||||
│ ├─router.php 快速测试文件
|
||||
│ └─.htaccess 用于apache的重写
|
||||
│
|
||||
├─thinkphp 框架系统目录
|
||||
│ ├─lang 语言文件目录
|
||||
│ ├─library 框架类库目录
|
||||
│ │ ├─think Think类库包目录
|
||||
│ │ └─traits 系统Trait目录
|
||||
│ │
|
||||
│ ├─tpl 系统模板目录
|
||||
│ ├─base.php 基础定义文件
|
||||
│ ├─console.php 控制台入口文件
|
||||
│ ├─convention.php 框架惯例配置文件
|
||||
│ ├─helper.php 助手函数文件
|
||||
│ ├─phpunit.xml phpunit配置文件
|
||||
│ └─start.php 框架入口文件
|
||||
│
|
||||
├─extend 扩展类库目录
|
||||
├─runtime 应用的运行时目录(可写,可定制)
|
||||
├─vendor 第三方类库目录(Composer依赖库)
|
||||
├─build.php 自动生成定义文件(参考)
|
||||
├─composer.json composer 定义文件
|
||||
├─LICENSE.txt 授权说明文件
|
||||
├─README.md README 文件
|
||||
├─think 命令行入口文件
|
||||
~~~
|
||||
|
||||
> router.php用于php自带webserver支持,可用于快速测试
|
||||
> 切换到public目录后,启动命令:php -S localhost:8888 router.php
|
||||
> 上面的目录结构和名称是可以改变的,这取决于你的入口文件和配置参数。
|
||||
|
||||
## 命名规范
|
||||
|
||||
`ThinkPHP5`遵循PSR-2命名规范和PSR-4自动加载规范,并且注意如下规范:
|
||||
|
||||
### 目录和文件
|
||||
|
||||
* 目录不强制规范,驼峰和小写+下划线模式均支持;
|
||||
* 类库、函数文件统一以`.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`字段,不建议使用驼峰和中文作为数据表字段命名。
|
||||
|
||||
## 参与开发
|
||||
请参阅 [ThinkPHP5 核心框架包](https://github.com/top-think/framework)。
|
||||
|
||||
## 版权信息
|
||||
|
||||
ThinkPHP遵循Apache2开源协议发布,并提供免费使用。
|
||||
|
||||
本项目包含的第三方源码和二进制文件之版权信息另行标注。
|
||||
|
||||
版权所有Copyright © 2006-2017 by ThinkPHP (http://thinkphp.cn)
|
||||
|
||||
All rights reserved。
|
||||
|
||||
ThinkPHP® 商标和著作权所有者为上海顶想信息科技有限公司。
|
||||
|
||||
更多细节参阅 [LICENSE.txt](LICENSE.txt)
|
||||
|
1
application/.htaccess
Normal file
1
application/.htaccess
Normal file
@ -0,0 +1 @@
|
||||
deny from all
|
12
application/command.php
Normal file
12
application/command.php
Normal file
@ -0,0 +1,12 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006-2016 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: yunwuxin <448901948@qq.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
return [];
|
12
application/common.php
Normal file
12
application/common.php
Normal file
@ -0,0 +1,12 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006-2016 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: 流年 <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
// 应用公共文件
|
241
application/config.php
Normal file
241
application/config.php
Normal file
@ -0,0 +1,241 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2016 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
return [
|
||||
// +----------------------------------------------------------------------
|
||||
// | 应用设置
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
// 应用命名空间
|
||||
'app_namespace' => 'app',
|
||||
// 应用调试模式
|
||||
'app_debug' => false,
|
||||
// 应用Trace
|
||||
'app_trace' => false,
|
||||
// 应用模式状态
|
||||
'app_status' => '',
|
||||
// 是否支持多模块
|
||||
'app_multi_module' => true,
|
||||
// 入口自动绑定模块
|
||||
'auto_bind_module' => false,
|
||||
// 注册的根命名空间
|
||||
'root_namespace' => [],
|
||||
// 扩展函数文件
|
||||
'extra_file_list' => [THINK_PATH . 'helper' . EXT],
|
||||
// 默认输出类型
|
||||
'default_return_type' => 'html',
|
||||
// 默认AJAX 数据返回格式,可选json xml ...
|
||||
'default_ajax_return' => 'json',
|
||||
// 默认JSONP格式返回的处理方法
|
||||
'default_jsonp_handler' => 'jsonpReturn',
|
||||
// 默认JSONP处理方法
|
||||
'var_jsonp_handler' => 'callback',
|
||||
// 默认时区
|
||||
'default_timezone' => 'PRC',
|
||||
// 是否开启多语言
|
||||
'lang_switch_on' => false,
|
||||
// 默认全局过滤方法 用逗号分隔多个
|
||||
'default_filter' => '',
|
||||
// 默认语言
|
||||
'default_lang' => 'zh-cn',
|
||||
// 应用类库后缀
|
||||
'class_suffix' => false,
|
||||
// 控制器类后缀
|
||||
'controller_suffix' => false,
|
||||
|
||||
// +----------------------------------------------------------------------
|
||||
// | 模块设置
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
// 默认模块名
|
||||
'default_module' => 'index',
|
||||
// 禁止访问模块
|
||||
'deny_module_list' => ['common'],
|
||||
// 默认控制器名
|
||||
'default_controller' => 'Index',
|
||||
// 默认操作名
|
||||
'default_action' => 'index',
|
||||
// 默认验证器
|
||||
'default_validate' => '',
|
||||
// 默认的空控制器名
|
||||
'empty_controller' => 'Error',
|
||||
// 操作方法后缀
|
||||
'action_suffix' => '',
|
||||
// 自动搜索控制器
|
||||
'controller_auto_search' => false,
|
||||
|
||||
// +----------------------------------------------------------------------
|
||||
// | URL设置
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
// PATHINFO变量名 用于兼容模式
|
||||
'var_pathinfo' => 's',
|
||||
// 兼容PATH_INFO获取
|
||||
'pathinfo_fetch' => ['ORIG_PATH_INFO', 'REDIRECT_PATH_INFO', 'REDIRECT_URL'],
|
||||
// pathinfo分隔符
|
||||
'pathinfo_depr' => '/',
|
||||
// URL伪静态后缀
|
||||
'url_html_suffix' => 'html',
|
||||
// URL普通方式参数 用于自动生成
|
||||
'url_common_param' => false,
|
||||
// URL参数方式 0 按名称成对解析 1 按顺序解析
|
||||
'url_param_type' => 0,
|
||||
// 是否开启路由
|
||||
'url_route_on' => true,
|
||||
// 路由使用完整匹配
|
||||
'route_complete_match' => false,
|
||||
// 路由配置文件(支持配置多个)
|
||||
'route_config_file' => ['route'],
|
||||
// 是否强制使用路由
|
||||
'url_route_must' => false,
|
||||
// 域名部署
|
||||
'url_domain_deploy' => false,
|
||||
// 域名根,如thinkphp.cn
|
||||
'url_domain_root' => '',
|
||||
// 是否自动转换URL中的控制器和操作名
|
||||
'url_convert' => true,
|
||||
// 默认的访问控制器层
|
||||
'url_controller_layer' => 'controller',
|
||||
// 表单请求类型伪装变量
|
||||
'var_method' => '_method',
|
||||
// 表单ajax伪装变量
|
||||
'var_ajax' => '_ajax',
|
||||
// 表单pjax伪装变量
|
||||
'var_pjax' => '_pjax',
|
||||
// 是否开启请求缓存 true自动缓存 支持设置请求缓存规则
|
||||
'request_cache' => false,
|
||||
// 请求缓存有效期
|
||||
'request_cache_expire' => null,
|
||||
// 全局请求缓存排除规则
|
||||
'request_cache_except' => [],
|
||||
|
||||
// +----------------------------------------------------------------------
|
||||
// | 模板设置
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
'template' => [
|
||||
// 模板引擎类型 支持 php think 支持扩展
|
||||
'type' => 'Think',
|
||||
// 模板路径
|
||||
'view_path' => '',
|
||||
// 模板后缀
|
||||
'view_suffix' => 'html',
|
||||
// 模板文件名分隔符
|
||||
'view_depr' => DS,
|
||||
// 模板引擎普通标签开始标记
|
||||
'tpl_begin' => '{',
|
||||
// 模板引擎普通标签结束标记
|
||||
'tpl_end' => '}',
|
||||
// 标签库标签开始标记
|
||||
'taglib_begin' => '{',
|
||||
// 标签库标签结束标记
|
||||
'taglib_end' => '}',
|
||||
],
|
||||
|
||||
// 视图输出字符串内容替换
|
||||
'view_replace_str' => [],
|
||||
// 默认跳转页面对应的模板文件
|
||||
'dispatch_success_tmpl' => THINK_PATH . 'tpl' . DS . 'dispatch_jump.tpl',
|
||||
'dispatch_error_tmpl' => THINK_PATH . 'tpl' . DS . 'dispatch_jump.tpl',
|
||||
|
||||
// +----------------------------------------------------------------------
|
||||
// | 异常及错误设置
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
// 异常页面的模板文件
|
||||
'exception_tmpl' => THINK_PATH . 'tpl' . DS . 'think_exception.tpl',
|
||||
|
||||
// 错误显示信息,非调试模式有效
|
||||
'error_message' => '页面错误!请稍后再试~',
|
||||
// 显示错误信息
|
||||
'show_error_msg' => false,
|
||||
// 异常处理handle类 留空使用 \think\exception\Handle
|
||||
'exception_handle' => '',
|
||||
|
||||
// +----------------------------------------------------------------------
|
||||
// | 日志设置
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
'log' => [
|
||||
// 日志记录方式,内置 file socket 支持扩展
|
||||
'type' => 'File',
|
||||
// 日志保存目录
|
||||
'path' => LOG_PATH,
|
||||
// 日志记录级别
|
||||
'level' => [],
|
||||
],
|
||||
|
||||
// +----------------------------------------------------------------------
|
||||
// | Trace设置 开启 app_trace 后 有效
|
||||
// +----------------------------------------------------------------------
|
||||
'trace' => [
|
||||
// 内置Html Console 支持扩展
|
||||
'type' => 'Html',
|
||||
],
|
||||
|
||||
// +----------------------------------------------------------------------
|
||||
// | 缓存设置
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
'cache' => [
|
||||
// 驱动方式
|
||||
'type' => 'File',
|
||||
// 缓存保存目录
|
||||
'path' => CACHE_PATH,
|
||||
// 缓存前缀
|
||||
'prefix' => '',
|
||||
// 缓存有效期 0表示永久缓存
|
||||
'expire' => 0,
|
||||
],
|
||||
|
||||
// +----------------------------------------------------------------------
|
||||
// | 会话设置
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
'session' => [
|
||||
'id' => '',
|
||||
// SESSION_ID的提交变量,解决flash上传跨域
|
||||
'var_session_id' => '',
|
||||
// SESSION 前缀
|
||||
'prefix' => 'think',
|
||||
// 驱动方式 支持redis memcache memcached
|
||||
'type' => '',
|
||||
// 是否自动开启 SESSION
|
||||
'auto_start' => true,
|
||||
],
|
||||
|
||||
// +----------------------------------------------------------------------
|
||||
// | Cookie设置
|
||||
// +----------------------------------------------------------------------
|
||||
'cookie' => [
|
||||
// cookie 名称前缀
|
||||
'prefix' => '',
|
||||
// cookie 保存时间
|
||||
'expire' => 0,
|
||||
// cookie 保存路径
|
||||
'path' => '/',
|
||||
// cookie 有效域名
|
||||
'domain' => '',
|
||||
// cookie 启用安全传输
|
||||
'secure' => false,
|
||||
// httponly设置
|
||||
'httponly' => '',
|
||||
// 是否使用 setcookie
|
||||
'setcookie' => true,
|
||||
],
|
||||
|
||||
//分页配置
|
||||
'paginate' => [
|
||||
'type' => 'bootstrap',
|
||||
'var_page' => 'page',
|
||||
'list_rows' => 15,
|
||||
],
|
||||
];
|
53
application/database.php
Normal file
53
application/database.php
Normal file
@ -0,0 +1,53 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2016 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
return [
|
||||
// 数据库类型
|
||||
'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',
|
||||
// 自动写入时间戳字段
|
||||
'auto_timestamp' => false,
|
||||
// 时间字段取出后的默认时间格式
|
||||
'datetime_format' => 'Y-m-d H:i:s',
|
||||
// 是否需要进行SQL性能分析
|
||||
'sql_explain' => false,
|
||||
];
|
10
application/index/controller/Index.php
Normal file
10
application/index/controller/Index.php
Normal file
@ -0,0 +1,10 @@
|
||||
<?php
|
||||
namespace app\index\controller;
|
||||
|
||||
class Index
|
||||
{
|
||||
public function index()
|
||||
{
|
||||
return view();
|
||||
}
|
||||
}
|
62
application/index/view/index/index.html
Normal file
62
application/index/view/index/index.html
Normal file
@ -0,0 +1,62 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
|
||||
<!-- UC应用模式 -->
|
||||
<meta name="browsermode" content="application">
|
||||
<!-- QQ应用模式 -->
|
||||
<meta name="x5-page-mode" content="app">
|
||||
<title>MiaoScript 在线编辑器</title>
|
||||
<script src="//cdn.bootcss.com/jquery/3.1.1/jquery.min.js"></script>
|
||||
<script src="//cdn.bootcss.com/pagedown/1.0/Markdown.Converter.min.js"></script>
|
||||
<link href="//cdn.bootcss.com/github-markdown-css/2.4.1/github-markdown.min.css" rel="stylesheet">
|
||||
<script src="//cdn.bootcss.com/avalon.js/2.2.4/avalon.min.js"></script>
|
||||
<script src="//cdn.bootcss.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
|
||||
<link href="//cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
|
||||
<script src="//cdn.bootcss.com/js-yaml/3.8.1/js-yaml.min.js"></script>
|
||||
|
||||
<link href="//cdn.bootcss.com/messenger/1.5.0/css/messenger.min.css" rel="stylesheet">
|
||||
<link href="//cdn.bootcss.com/messenger/1.5.0/css/messenger-theme-future.min.css" rel="stylesheet">
|
||||
<script src="//cdn.bootcss.com/messenger/1.5.0/js/messenger.min.js"></script>
|
||||
<script src="//cdn.bootcss.com/messenger/1.5.0/js/messenger-theme-future.min.js"></script>
|
||||
|
||||
<link href="//cdn.bootcss.com/codemirror/5.30.0/codemirror.css" rel="stylesheet">
|
||||
<script src="//cdn.bootcss.com/codemirror/5.30.0/codemirror.js"></script>
|
||||
|
||||
<script src="//cdn.bootcss.com/codemirror/5.30.0/mode/javascript/javascript.js"></script>
|
||||
<script src="//cdn.bootcss.com/codemirror/5.30.0/addon/lint/javascript-lint.js"></script>
|
||||
<script src="//cdn.bootcss.com/codemirror/5.30.0/addon/hint/javascript-hint.js"></script>
|
||||
|
||||
<script src="//cdn.bootcss.com/codemirror/5.30.0/addon/fold/foldcode.js"></script>
|
||||
<link href="//cdn.bootcss.com/codemirror/5.30.0/addon/fold/foldgutter.css" rel="stylesheet">
|
||||
<script src="//cdn.bootcss.com/codemirror/5.30.0/addon/fold/foldgutter.js"></script>
|
||||
|
||||
<script src="//cdn.bootcss.com/codemirror/5.30.0/addon/lint/yaml-lint.js"></script>
|
||||
</head>
|
||||
<script>
|
||||
window.onload = function () {
|
||||
code = document.getElementById("code");
|
||||
window.editor = CodeMirror.fromTextArea(code, {
|
||||
mode: "javascript",
|
||||
lineNumbers: true,
|
||||
lineWrapping: true,
|
||||
extraKeys: {
|
||||
"Ctrl-Q": function (cm) {
|
||||
cm.foldCode(cm.getCursor());
|
||||
},
|
||||
"Ctrl-s": function (cm) {
|
||||
console.log('执行保存!');
|
||||
}
|
||||
},
|
||||
foldGutter: true,
|
||||
gutters: ["CodeMirror-linenumbers", "CodeMirror-foldgutter"]
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<body>
|
||||
<textarea id="code" style="height: 100%"></textarea>
|
||||
</body>
|
21
application/route.php
Normal file
21
application/route.php
Normal file
@ -0,0 +1,21 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2016 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
return [
|
||||
'__pattern__' => [
|
||||
'name' => '\w+',
|
||||
],
|
||||
'[hello]' => [
|
||||
':id' => ['index/hello', ['method' => 'get'], ['id' => '\d+']],
|
||||
':name' => ['index/hello', ['method' => 'post']],
|
||||
],
|
||||
|
||||
];
|
28
application/tags.php
Normal file
28
application/tags.php
Normal file
@ -0,0 +1,28 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2016 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
// 应用行为扩展定义文件
|
||||
return [
|
||||
// 应用初始化
|
||||
'app_init' => [],
|
||||
// 应用开始
|
||||
'app_begin' => [],
|
||||
// 模块初始化
|
||||
'module_init' => [],
|
||||
// 操作开始执行
|
||||
'action_begin' => [],
|
||||
// 视图内容过滤
|
||||
'view_filter' => [],
|
||||
// 日志写入
|
||||
'log_write' => [],
|
||||
// 应用结束
|
||||
'app_end' => [],
|
||||
];
|
25
build.php
Normal file
25
build.php
Normal file
@ -0,0 +1,25 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2016 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
return [
|
||||
// 生成应用公共文件
|
||||
'__file__' => ['common.php', 'config.php', 'database.php'],
|
||||
|
||||
// 定义demo模块的自动生成 (按照实际定义的文件名生成)
|
||||
'demo' => [
|
||||
'__file__' => ['common.php'],
|
||||
'__dir__' => ['behavior', 'controller', 'model', 'view'],
|
||||
'controller' => ['Index', 'Test', 'UserType'],
|
||||
'model' => ['User', 'UserType'],
|
||||
'view' => ['index/index'],
|
||||
],
|
||||
// 其他更多的模块定义
|
||||
];
|
28
composer.json
Normal file
28
composer.json
Normal file
@ -0,0 +1,28 @@
|
||||
{
|
||||
"name": "topthink/think",
|
||||
"description": "the new thinkphp framework",
|
||||
"type": "project",
|
||||
"keywords": [
|
||||
"framework",
|
||||
"thinkphp",
|
||||
"ORM"
|
||||
],
|
||||
"homepage": "http://thinkphp.cn/",
|
||||
"license": "Apache-2.0",
|
||||
"authors": [
|
||||
{
|
||||
"name": "liu21st",
|
||||
"email": "liu21st@gmail.com"
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": ">=5.4.0",
|
||||
"topthink/framework": "~5.0.0"
|
||||
},
|
||||
"extra": {
|
||||
"think-path": "thinkphp"
|
||||
},
|
||||
"config": {
|
||||
"preferred-install": "dist"
|
||||
}
|
||||
}
|
2
extend/.gitignore
vendored
Normal file
2
extend/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
*
|
||||
!.gitignore
|
17
index.php
Normal file
17
index.php
Normal file
@ -0,0 +1,17 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006-2016 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
// [ 应用入口文件 ]
|
||||
|
||||
// 定义应用目录
|
||||
define('APP_PATH', __DIR__ . '/application/');
|
||||
// 加载框架引导文件
|
||||
require __DIR__ . '/thinkphp/start.php';
|
215
pom.xml
215
pom.xml
@ -1,215 +0,0 @@
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>pw.yumc</groupId>
|
||||
<artifactId>MiaoScript</artifactId>
|
||||
<version>0.28.0</version>
|
||||
<developers>
|
||||
<developer>
|
||||
<id>502647092</id>
|
||||
<name>MiaoWoo</name>
|
||||
<email>admin@yumc.pw</email>
|
||||
<url>https://www.yumc.pw</url>
|
||||
</developer>
|
||||
</developers>
|
||||
<build>
|
||||
<finalName>${project.artifactId}</finalName>
|
||||
<resources>
|
||||
<resource>
|
||||
<directory>src/main/resources</directory>
|
||||
<filtering>true</filtering>
|
||||
</resource>
|
||||
</resources>
|
||||
</build>
|
||||
<ciManagement>
|
||||
<system>Jenkins</system>
|
||||
<url>https://ci.yumc.pw/job/Minecraft/job/${project.artifactId}/</url>
|
||||
</ciManagement>
|
||||
<properties>
|
||||
<env.GIT_COMMIT>DEV</env.GIT_COMMIT>
|
||||
<update.changes>
|
||||
§623-10-25 §afeat: 升级 asm 版本;
|
||||
§623-07-30 §afeat: 优化 require 性能;
|
||||
§cfix: 修复 require 加载特殊文件异常;
|
||||
§623-07-22 §afeat: 网络加载 jtar 优化包大小;
|
||||
§aremove: 移除 Spring 相关支持;
|
||||
§adeps: 更新 Nashorn 和 GraalvmJS 引擎版本
|
||||
</update.changes>
|
||||
<update.changelog>
|
||||
§622-11-22 §afeat: 兼容 1.7.10-1.19.2 版本;
|
||||
§afeat: 新增 MiaoScriptAPI 相关方法;
|
||||
§622-06-21 §afeat: 兼容 1.7.10-1.19 版本;
|
||||
§afeat: 兼容 JDK17 BungeeCord;
|
||||
§622-05-25 §afeat: 兼容 1.7.10-1.18.2 版本;
|
||||
§622-05-21 §afeat: 优化 框架加载逻辑;
|
||||
§622-05-20 §afeat: 调整 require 主包逻辑;
|
||||
§622-04-09 §afeat: 优化 引擎初始化逻辑;
|
||||
§afeat: 优化 require 网络加载;
|
||||
§afeat: 新增 JS 类型定义文件;
|
||||
§afeat: 新增 自定义类型加载逻辑;
|
||||
§622-02-16 §afeat: 新增 MiaoScriptAPI;
|
||||
§afeat: 新增 ScriptEvent;
|
||||
§afeat: 新增 .mjs .json 类型加载;
|
||||
§622-02-16 §afeat: 优化 初始化逻辑 加快引擎加载速度;
|
||||
§afeat: 新增 root 目录变更检测 变更后重新生成缓存;
|
||||
§afeat: 添加常用库的软依赖;
|
||||
§622-01-01 §afeat: 兼容JDK17 更新Nashorn;
|
||||
§621-11-04 §afeat: 优化系统模块升级逻辑;
|
||||
§621-07-10 §afeat: 优化网络相关功能;
|
||||
§621-06-25 §afeat: 调整启动逻辑 兼容 Arclight;
|
||||
§621-06-22 §afeat: 新增本地版本锁定功能;
|
||||
§621-06-19 §afeat: 兼容JDK16 反射异常;
|
||||
§621-05-15 §afeat: 兼容JDK15+ 自动下载Nashorn类库;
|
||||
§621-03-25 §afeat: 异步加载 polyfill 并且同步加载 @ccms/core;
|
||||
§621-03-25 §cfix: 修改 ployfill 为 polyfill;
|
||||
§620-12-22 §cfix: 增加 require 效验;
|
||||
§620-12-17 §afeat: JavaScriptTask 新增任务ID 并通过 ID 比较优先级;
|
||||
§620-12-16 §afeat: 新增 require 缓存 优化路径寻找速度;
|
||||
§620-12-15 §cfix: 修复 非主线程重载时发生的异常;
|
||||
§620-12-07 §cfix: 修复 Windows 环境 重载异常;
|
||||
§620-11-19 §afeat: 新增 JavaScriptTask 类;
|
||||
§620-11-11 §afeat: 新增 package 版本锁定逻辑;
|
||||
§620-09-21 §afeat: 完善 upgrade 逻辑;
|
||||
§620-08-27 §afeat: 新增 ProtocolLib 依赖;
|
||||
§620-07-28 §afeat: 新增框架升级功能;
|
||||
§620-06-23 §afeat: 支持自定义参数;
|
||||
§620-06-22 §afeat: 优化 require 加载逻辑;
|
||||
§620-05-28 §afeat: 新增 Spring 的支持;
|
||||
§620-05-02 §afeat: 调整 scope 为 @ccms;
|
||||
§620-04-10 §afeat: 默认从 classpath 加载内建的 js 模块;
|
||||
§620-04-07 §afeat: 默认初始化 内建 nodejs 模块;
|
||||
§620-04-03 §afeat: 优化 框架卸载逻辑;
|
||||
§620-03-31 §afeat: require 新增 内建 nodejs 模块;
|
||||
§620-03-03 §afeat: require 新增 淘宝镜像源拉取;
|
||||
§620-02-27 §afeat: 异步加载脚本引擎;
|
||||
§620-02-25 §afeat: 新增 Nukkit 的支持;
|
||||
§620-02-16 §afeat: 新增 Source Map 支持;
|
||||
§620-02-02 §afeat: 迁移 ployfill 到 @ms/ployfill;
|
||||
§620-01-14 §afeat: 新增 Bungee 支持;
|
||||
§afeat: 新增 instance 实例获取;
|
||||
§619-09-24 §cremove: 移除 okhttp3 类库;
|
||||
§afeat: 新增require自动下载模块功能;
|
||||
§619-09-21 §afeat: 新增 okhttp3 类库;
|
||||
§619-08-31 §afeat: 新增 tar 类库 支持 tar.gz 解压;
|
||||
§619-08-29 §erefactor: 移动插件文件 默认自带MSPM插件 优化bios;
|
||||
§618-5-20 §afeat: 新增MiaoBoard插件;
|
||||
§618-5-20 §afeat: 新增MiaoAuth插件;
|
||||
§618-5-20 §afeat: 修改初始化函数名称;
|
||||
§618-5-20 §cfix: file.js修复一个语法错误;
|
||||
§618-5-20 §afeat: 新增config默认值绑定 匿名函数添加名称;
|
||||
§618-5-20 §afeat: PAPI支持直接替换数组;
|
||||
§618-5-20 §afeat: 调整Task任务模块;
|
||||
§618-5-20 §afeat: 新增模板预编译插件功能;
|
||||
§618-5-18 §afeat: 清除不必要的代码;
|
||||
§618-5-17 §afeat: 新增MiaoChat插件描述;
|
||||
§618-5-17 §afeat: MiaoScriptPackageManager 新增restart和run方法;
|
||||
§618-5-17 §cfix: 修复Sponge命令参数存在空字符串的问题;
|
||||
§618-5-17 §cfix: 修复混淆导致的重载方法丢失;
|
||||
§618-5-17 §afeat: 新增引擎Shutdown方法 关闭资源;
|
||||
§618-5-17 §afeat: 格式化代码 添加d.ts文件 去除引擎无关代码 清理单元测试;
|
||||
§618-5-17 §cfix: 修复TellRaw类库错误;
|
||||
§618-5-17 §cfix: 修复pkg不存在的问题;
|
||||
§618-5-17 §cfix: 修复下载错误的问题;
|
||||
§618-5-17 §afeat: 更新版本号;
|
||||
§618-05-17 §afeat: 新增Hook提示;
|
||||
§618-05-17 §afeat: 调整列表载入顺序;
|
||||
§618-05-17 §afeat: 完善MiaoChat的PAPI的替换;
|
||||
§618-05-17 §afeat: 完善服务获取类;
|
||||
§618-05-17 §afeat: 新增PAPI代理类;
|
||||
§618-05-17 §afeat: 去除调试代码;
|
||||
§618-05-17 §afeat: 迁移配置 完善reload命令;
|
||||
§618-05-15 §afeat: 分离TellRaw类库;
|
||||
§618-05-15 §afeat: 完善MiaoChat的Bukkit版本;
|
||||
§618-05-15 §afeat: 补全内部引入方法的参数;
|
||||
§618-05-15 §afeat: 调整Event载入提示 完善Bukkit的聊天发送;
|
||||
§618-05-15 §afeat: 调整API引入结构;
|
||||
§618-05-15 §afeat: 新增MiaoChat插件;
|
||||
§618-05-14 §afeat: 更新API相关类;
|
||||
§618-05-14 §afeat: 调整相关API名称;
|
||||
§618-05-14 §afeat: 新增Object.values垫片;
|
||||
§618-05-14 §afeat: 新增工具类;
|
||||
§618-05-14 §afeat: 更新MiaoScriptPackageManager;
|
||||
§618-05-14 §cfix: 修复命令执行相关BUG;
|
||||
§618-05-14 §afeat: 新增聊天相关API;
|
||||
§618-05-14 §afeat: 优化方法调用;
|
||||
§618-03-18 §afeat: 调整get方法 data 参数自动转query;
|
||||
§618-03-18 §afeat: 优化插件代码结构;
|
||||
§618-03-18 §cfix: 修复玩家人数获取错误 更新插件;
|
||||
§618-01-11 §afeat: 更新http类库 server通过orElse返回undefined;
|
||||
§618-01-11 §afeat: 更新基础类库;
|
||||
§618-01-11 §afeat: 新增插件管理模块;
|
||||
§618-01-10 §cfix: 修复主线程加载的BUG;
|
||||
§618-01-10 §afeat: 修复fs相关BUG 优化插件加载 优化命令补全;
|
||||
§618-01-10 §afeat: 更新.gitignore文件;
|
||||
§618-01-10 §afeat: 新增案例插件 更新插件版本;
|
||||
§618-01-09 §afeat: 优化API 修复http模块错误;
|
||||
§618-01-09 §afeat: 更新 fs 类库 优化 require;
|
||||
§618-01-09 §afeat: 安全起见暂时屏蔽load方法和disable方法;
|
||||
§618-01-09 §cfix: 修复调试信息错误;
|
||||
§618-01-08 §afeat: require新增基础目录api;
|
||||
§618-01-08 §3doc: 新增README;
|
||||
§618-01-08 §cfix: 修复重载命令无效的BUG;
|
||||
§618-01-09 §afeat: 优化加载流程 完善事件注册;
|
||||
§618-01-02 §afeat: 新增http网络访问模块;
|
||||
§617-12-28 §afeat: 完善Sponge事件注册 新增player封装类;
|
||||
§617-11-30 §afeat: 新增Sponge的兼容;
|
||||
§617-11-03 §afeat: 新增抽奖插件;
|
||||
§617-10-16 §cfix: 修复关闭MiaoScript时task异常;
|
||||
§617-10-15 §6alpha: 第一个版本发布;
|
||||
</update.changelog>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<maven.compiler.source>1.8</maven.compiler.source>
|
||||
<maven.compiler.target>1.8</maven.compiler.target>
|
||||
<repo.url>https://repo.yumc.pw</repo.url>
|
||||
</properties>
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>yumc-repo</id>
|
||||
<url>${repo.url}/repository/maven-public/</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
<pluginRepositories>
|
||||
<pluginRepository>
|
||||
<id>yumc-repo</id>
|
||||
<url>${repo.url}/repository/maven-public/</url>
|
||||
</pluginRepository>
|
||||
</pluginRepositories>
|
||||
<distributionManagement>
|
||||
<repository>
|
||||
<id>jtb</id>
|
||||
<name>YUMC</name>
|
||||
<url>${repo.url}/repository/yumcenter/</url>
|
||||
</repository>
|
||||
</distributionManagement>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<version>1.18.24</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.spigotmc</groupId>
|
||||
<artifactId>spigot-api</artifactId>
|
||||
<version>1.18.2-R0.1-SNAPSHOT</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.spongepowered</groupId>
|
||||
<artifactId>spongeapi</artifactId>
|
||||
<version>7.3.0</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.md-5</groupId>
|
||||
<artifactId>bungeecord-api</artifactId>
|
||||
<version>1.16-R0.4</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.nukkit</groupId>
|
||||
<artifactId>nukkit</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
8
public/.htaccess
Normal file
8
public/.htaccess
Normal file
@ -0,0 +1,8 @@
|
||||
<IfModule mod_rewrite.c>
|
||||
Options +FollowSymlinks -Multiviews
|
||||
RewriteEngine On
|
||||
|
||||
RewriteCond %{REQUEST_FILENAME} !-d
|
||||
RewriteCond %{REQUEST_FILENAME} !-f
|
||||
RewriteRule ^(.*)$ index.php/$1 [QSA,PT,L]
|
||||
</IfModule>
|
BIN
public/favicon.ico
Normal file
BIN
public/favicon.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.1 KiB |
2
public/robots.txt
Normal file
2
public/robots.txt
Normal file
@ -0,0 +1,2 @@
|
||||
User-agent: *
|
||||
Disallow:
|
20
public/router.php
Normal file
20
public/router.php
Normal file
@ -0,0 +1,20 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2016 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
// $Id$
|
||||
|
||||
if (is_file($_SERVER["DOCUMENT_ROOT"] . $_SERVER["REQUEST_URI"])) {
|
||||
return false;
|
||||
} else {
|
||||
if (!isset($_SERVER['PATH_INFO'])) {
|
||||
$_SERVER['PATH_INFO'] = $_SERVER['REQUEST_URI'];
|
||||
}
|
||||
require __DIR__ . "/index.php";
|
||||
}
|
2
public/static/.gitignore
vendored
Normal file
2
public/static/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
*
|
||||
!.gitignore
|
2
runtime/.gitignore
vendored
Normal file
2
runtime/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
*
|
||||
!.gitignore
|
@ -1,40 +0,0 @@
|
||||
package pw.yumc.MiaoScript;
|
||||
|
||||
import lombok.SneakyThrows;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
import pw.yumc.MiaoScript.api.MiaoScriptAPI;
|
||||
import pw.yumc.MiaoScript.api.ScriptEngine;
|
||||
|
||||
/**
|
||||
* 喵式脚本
|
||||
*
|
||||
* @author 喵♂呜
|
||||
* @since 2016年8月29日 上午7:50:39
|
||||
*/
|
||||
public class MiaoScriptBukkit extends JavaPlugin {
|
||||
private ScriptEngine engine;
|
||||
|
||||
@SneakyThrows
|
||||
public MiaoScriptBukkit() {
|
||||
ClassLoader origin = Thread.currentThread().getContextClassLoader();
|
||||
Thread.currentThread().setContextClassLoader(getClassLoader());
|
||||
engine = MiaoScriptAPI.createEngine(getDataFolder().getCanonicalPath(), getLogger(), this);
|
||||
Thread.currentThread().setContextClassLoader(origin);
|
||||
engine.loadEngine();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoad() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
engine.enableEngine();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisable() {
|
||||
engine.disableEngine();
|
||||
engine = null;
|
||||
}
|
||||
}
|
@ -1,38 +0,0 @@
|
||||
package pw.yumc.MiaoScript;
|
||||
|
||||
import lombok.SneakyThrows;
|
||||
import net.md_5.bungee.api.plugin.Plugin;
|
||||
import pw.yumc.MiaoScript.api.MiaoScriptAPI;
|
||||
import pw.yumc.MiaoScript.api.ScriptEngine;
|
||||
|
||||
/**
|
||||
* Created with IntelliJ IDEA
|
||||
*
|
||||
* @author MiaoWoo
|
||||
* Created on 2020/1/14 16:02.
|
||||
*/
|
||||
public class MiaoScriptBungee extends Plugin {
|
||||
private ScriptEngine engine;
|
||||
|
||||
@SneakyThrows
|
||||
public MiaoScriptBungee() {
|
||||
Thread.currentThread().setContextClassLoader(this.getClass().getClassLoader());
|
||||
engine = MiaoScriptAPI.createEngine(getDataFolder().getCanonicalPath(), getLogger(), this);
|
||||
engine.loadEngine();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoad() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
engine.enableEngine();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisable() {
|
||||
engine.disableEngine();
|
||||
engine = null;
|
||||
}
|
||||
}
|
@ -1,35 +0,0 @@
|
||||
package pw.yumc.MiaoScript;
|
||||
|
||||
import cn.nukkit.plugin.PluginBase;
|
||||
import lombok.SneakyThrows;
|
||||
import pw.yumc.MiaoScript.api.MiaoScriptAPI;
|
||||
import pw.yumc.MiaoScript.api.ScriptEngine;
|
||||
|
||||
/**
|
||||
* @author MiaoWoo
|
||||
*/
|
||||
public class MiaoScriptNukkit extends PluginBase {
|
||||
private ScriptEngine engine;
|
||||
|
||||
@SneakyThrows
|
||||
public MiaoScriptNukkit() {
|
||||
Thread.currentThread().setContextClassLoader(this.getClass().getClassLoader());
|
||||
engine = MiaoScriptAPI.createEngine(getDataFolder().getCanonicalPath(), super.getLogger(), this);
|
||||
engine.loadEngine();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoad() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
engine.enableEngine();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisable() {
|
||||
engine.disableEngine();
|
||||
engine = null;
|
||||
}
|
||||
}
|
@ -1,62 +0,0 @@
|
||||
package pw.yumc.MiaoScript;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import lombok.SneakyThrows;
|
||||
import org.slf4j.Logger;
|
||||
import org.spongepowered.api.config.ConfigDir;
|
||||
import org.spongepowered.api.event.Listener;
|
||||
import org.spongepowered.api.event.game.GameReloadEvent;
|
||||
import org.spongepowered.api.event.game.state.GamePreInitializationEvent;
|
||||
import org.spongepowered.api.event.game.state.GameStartedServerEvent;
|
||||
import org.spongepowered.api.event.game.state.GameStoppingServerEvent;
|
||||
import org.spongepowered.api.plugin.Plugin;
|
||||
import pw.yumc.MiaoScript.api.MiaoScriptAPI;
|
||||
import pw.yumc.MiaoScript.api.ScriptEngine;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* Created with IntelliJ IDEA
|
||||
*
|
||||
* @author 喵♂呜
|
||||
* Created on 2017/10/25 20:35.
|
||||
*/
|
||||
@Plugin(id = "miaoscript", name = "MiaoScript", description = "MiaoScript runtime in Sponge", version = MiaoScriptAPI.VERSION, authors = "MiaoWoo")
|
||||
public class MiaoScriptSponge {
|
||||
private ScriptEngine engine;
|
||||
@Inject
|
||||
private Logger logger;
|
||||
|
||||
@Inject
|
||||
@ConfigDir(sharedRoot = false)
|
||||
private File pluginConfigDir;
|
||||
|
||||
@Listener
|
||||
@SneakyThrows
|
||||
public void onPreInitialization(GamePreInitializationEvent event) {
|
||||
engine = MiaoScriptAPI.createEngine(pluginConfigDir.getCanonicalPath(), logger, this);
|
||||
engine.loadEngine();
|
||||
}
|
||||
|
||||
@Listener
|
||||
@SneakyThrows
|
||||
public void onStarted(GameStartedServerEvent event) {
|
||||
engine.enableEngine();
|
||||
}
|
||||
|
||||
@Listener
|
||||
@SneakyThrows
|
||||
public void onStop(GameStoppingServerEvent event) {
|
||||
engine.disableEngine();
|
||||
engine = null;
|
||||
}
|
||||
|
||||
@Listener
|
||||
@SneakyThrows
|
||||
public void reload(GameReloadEvent event) {
|
||||
engine.disableEngine();
|
||||
System.gc();
|
||||
engine.loadEngine();
|
||||
engine.enableEngine();
|
||||
}
|
||||
}
|
@ -1,128 +0,0 @@
|
||||
package pw.yumc.MiaoScript.api;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
|
||||
/**
|
||||
* Created with IntelliJ IDEA
|
||||
*
|
||||
* @author 喵♂呜
|
||||
* Created on 2017/10/9 12:40.
|
||||
*/
|
||||
@Getter
|
||||
public class Base {
|
||||
private final Object instance;
|
||||
|
||||
Base(Object instance) {
|
||||
this.instance = instance;
|
||||
}
|
||||
|
||||
public String getVersion() {
|
||||
return MiaoScriptAPI.VERSION;
|
||||
}
|
||||
|
||||
public Class<?> getClass(String name) throws ClassNotFoundException {
|
||||
try {
|
||||
return Class.forName(name);
|
||||
} catch (Throwable ignored) {
|
||||
}
|
||||
try {
|
||||
return Class.forName(name, true, instance.getClass().getClassLoader());
|
||||
} catch (Throwable ex) {
|
||||
return Class.forName(name, true, instance.getClass().getClassLoader().getParent());
|
||||
}
|
||||
}
|
||||
|
||||
public Class<?> getProxyClass() {
|
||||
return ProxyClass.class;
|
||||
}
|
||||
|
||||
public Class<?> getJavaScriptTaskClass() {
|
||||
return JavaScriptTask.class;
|
||||
}
|
||||
|
||||
public File[] loadMavenDepend(String groupId, String artifactId, String version) {
|
||||
return MiaoScriptAPI.loadMavenDepend(groupId, artifactId, version);
|
||||
}
|
||||
|
||||
public File[] loadMavenDepend(String groupId, String artifactId, String version, ClassLoader classLoader) {
|
||||
return MiaoScriptAPI.loadMavenDepend(groupId, artifactId, version, classLoader);
|
||||
}
|
||||
|
||||
public File[] parentLoadMavenDepend(String groupId, String artifactId, String version) {
|
||||
return MiaoScriptAPI.parentLoadMavenDepend(groupId, artifactId, version);
|
||||
}
|
||||
|
||||
public String read(String path) throws IOException {
|
||||
return read(Paths.get(path));
|
||||
}
|
||||
|
||||
public String read(File file) throws IOException {
|
||||
return read(file.toPath());
|
||||
}
|
||||
|
||||
public String read(Path path) throws IOException {
|
||||
return new String(Files.readAllBytes(path), StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
public Path save(String path, String content) throws IOException {
|
||||
return save(Paths.get(path), content);
|
||||
}
|
||||
|
||||
public Path save(File file, String content) throws IOException {
|
||||
return save(file.toPath(), content);
|
||||
}
|
||||
|
||||
public Path save(Path path, String content) throws IOException {
|
||||
path.getParent().toFile().mkdirs();
|
||||
return Files.write(path, content.getBytes(StandardCharsets.UTF_8));
|
||||
}
|
||||
|
||||
public boolean move(String source, String target) {
|
||||
return move(new File(source), new File(target));
|
||||
}
|
||||
|
||||
public boolean move(File source, File target) {
|
||||
return source.renameTo(target);
|
||||
}
|
||||
|
||||
public boolean delete(String path) throws IOException {
|
||||
return delete(new File(path));
|
||||
}
|
||||
|
||||
public boolean delete(Path path) throws IOException {
|
||||
return delete(path.toFile());
|
||||
}
|
||||
|
||||
public boolean delete(File file) throws IOException {
|
||||
if (!file.exists()) {
|
||||
return false;
|
||||
}
|
||||
if (file.isFile()) {
|
||||
return file.delete();
|
||||
}
|
||||
File[] files = file.listFiles();
|
||||
if (files != null) {
|
||||
for (File f : files) {
|
||||
if (f.isFile()) {
|
||||
if (!f.delete()) {
|
||||
f.deleteOnExit();
|
||||
}
|
||||
} else {
|
||||
this.delete(f);
|
||||
}
|
||||
}
|
||||
}
|
||||
boolean result = file.delete();
|
||||
if (!result) {
|
||||
file.deleteOnExit();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
@ -1,41 +0,0 @@
|
||||
package pw.yumc.MiaoScript.api;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
import java.util.concurrent.Delayed;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@Getter
|
||||
public class JavaScriptTask implements Delayed {
|
||||
private final long id;
|
||||
private final Object task;
|
||||
private final long startTime;
|
||||
private final long executeTime;
|
||||
|
||||
public JavaScriptTask(Object task, long ms) {
|
||||
this(0, task, ms);
|
||||
}
|
||||
|
||||
public JavaScriptTask(long id, Object task, long ms) {
|
||||
this.id = id;
|
||||
this.task = task;
|
||||
this.startTime = System.currentTimeMillis();
|
||||
this.executeTime = ms;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getDelay(TimeUnit unit) {
|
||||
return unit.convert((this.startTime + this.executeTime) - System.currentTimeMillis(), TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(Delayed delayed) {
|
||||
JavaScriptTask task = (JavaScriptTask) delayed;
|
||||
int delay = (int) ((this.startTime + this.executeTime) - (task.getStartTime() + task.getExecuteTime()));
|
||||
if (delay != 0) {
|
||||
return delay;
|
||||
} else {
|
||||
return (int) (this.id - task.getId());
|
||||
}
|
||||
}
|
||||
}
|
@ -1,62 +0,0 @@
|
||||
package pw.yumc.MiaoScript.api;
|
||||
|
||||
import lombok.Getter;
|
||||
import pw.yumc.MiaoScript.api.loader.MavenDependLoader;
|
||||
import pw.yumc.MiaoScript.api.plugin.PluginManager;
|
||||
import pw.yumc.MiaoScript.engine.MiaoScriptEngine;
|
||||
|
||||
import java.io.File;
|
||||
import java.nio.file.Paths;
|
||||
|
||||
public class MiaoScriptAPI {
|
||||
public static final String VERSION = "0.28.0";
|
||||
@Getter
|
||||
private static String root;
|
||||
private static String libPath;
|
||||
private static ScriptEngine scriptEngine;
|
||||
@Getter
|
||||
private static PluginManager pluginManager;
|
||||
|
||||
public static ScriptEngine createEngine(String root, Object logger, Object instance) {
|
||||
MiaoScriptAPI.scriptEngine = new ScriptEngine(root, logger, instance);
|
||||
return MiaoScriptAPI.scriptEngine;
|
||||
}
|
||||
|
||||
static void setRoot(String root) {
|
||||
MiaoScriptAPI.root = root;
|
||||
MiaoScriptAPI.libPath = Paths.get(root, "libs").toString();
|
||||
}
|
||||
|
||||
public static MiaoScriptEngine getEngine() {
|
||||
return MiaoScriptAPI.scriptEngine.getEngine();
|
||||
}
|
||||
|
||||
static void setEngine(ScriptEngine scriptEngine) {
|
||||
MiaoScriptAPI.scriptEngine = scriptEngine;
|
||||
}
|
||||
|
||||
public static void setPluginManager(Object pluginManager) {
|
||||
MiaoScriptAPI.pluginManager = getEngine().getInterface(pluginManager, PluginManager.class);
|
||||
}
|
||||
|
||||
public static File[] loadMavenDepend(String groupId, String artifactId, String version) {
|
||||
if (root == null || scriptEngine == null) {
|
||||
throw new IllegalStateException("root can't be null before loadMavenDepend.");
|
||||
}
|
||||
return MavenDependLoader.load(MiaoScriptAPI.libPath, groupId, artifactId, version);
|
||||
}
|
||||
|
||||
public static File[] loadMavenDepend(String groupId, String artifactId, String version, ClassLoader classLoader) {
|
||||
if (root == null || scriptEngine == null) {
|
||||
throw new IllegalStateException("root can't be null before loadMavenDepend.");
|
||||
}
|
||||
return MavenDependLoader.load(MiaoScriptAPI.libPath, groupId, artifactId, version, classLoader);
|
||||
}
|
||||
|
||||
public static File[] parentLoadMavenDepend(String groupId, String artifactId, String version) {
|
||||
if (root == null || scriptEngine == null) {
|
||||
throw new IllegalStateException("root can't be null before loadMavenDepend.");
|
||||
}
|
||||
return MavenDependLoader.parentLoad(MiaoScriptAPI.libPath, groupId, artifactId, version);
|
||||
}
|
||||
}
|
@ -1,51 +0,0 @@
|
||||
package pw.yumc.MiaoScript.api;
|
||||
|
||||
import javax.script.Bindings;
|
||||
import javax.script.ScriptEngine;
|
||||
import javax.script.ScriptException;
|
||||
|
||||
/**
|
||||
* Created with IntelliJ IDEA
|
||||
*
|
||||
* @author MiaoWoo
|
||||
* Created on 2020/1/16 9:04.
|
||||
*/
|
||||
public class ProxyClass {
|
||||
private ScriptEngine engine;
|
||||
private String script;
|
||||
private Bindings bindings;
|
||||
|
||||
public ProxyClass(ScriptEngine engine, String script, Bindings bindings) {
|
||||
this.engine = engine;
|
||||
this.script = script;
|
||||
this.bindings = bindings;
|
||||
}
|
||||
|
||||
public Object method(Object args) throws ScriptException {
|
||||
bindings.put("args", args);
|
||||
return engine.eval(script, bindings);
|
||||
}
|
||||
|
||||
public Object one(Object arg1) throws ScriptException {
|
||||
bindings.put("arg1", arg1);
|
||||
return engine.eval(script, bindings);
|
||||
}
|
||||
|
||||
public Object two(Object arg1, Object arg2) throws ScriptException {
|
||||
bindings.put("arg1", arg1);
|
||||
bindings.put("arg2", arg2);
|
||||
return engine.eval(script, bindings);
|
||||
}
|
||||
|
||||
public Object three(Object arg1, Object arg2, Object arg3) throws ScriptException {
|
||||
bindings.put("arg1", arg1);
|
||||
bindings.put("arg2", arg2);
|
||||
bindings.put("arg3", arg3);
|
||||
return engine.eval(script, bindings);
|
||||
}
|
||||
|
||||
public Object args(Object... args) throws ScriptException {
|
||||
bindings.put("args", args);
|
||||
return engine.eval(script, bindings);
|
||||
}
|
||||
}
|
@ -1,76 +0,0 @@
|
||||
package pw.yumc.MiaoScript.api;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.SneakyThrows;
|
||||
import pw.yumc.MiaoScript.engine.MiaoScriptEngine;
|
||||
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
|
||||
/**
|
||||
* Created with IntelliJ IDEA
|
||||
*
|
||||
* @author 喵♂呜 Created on 2017/10/25 21:01.
|
||||
*/
|
||||
public class ScriptEngine {
|
||||
private final ClassLoader loader;
|
||||
private final Object logger;
|
||||
private final String root;
|
||||
private final Base base;
|
||||
@Getter
|
||||
private MiaoScriptEngine engine;
|
||||
private Object future;
|
||||
|
||||
ScriptEngine(String root, Object logger, Object instance) {
|
||||
this.loader = Thread.currentThread().getContextClassLoader();
|
||||
this.root = root;
|
||||
this.logger = logger;
|
||||
this.base = new Base(instance);
|
||||
MiaoScriptAPI.setRoot(root);
|
||||
MiaoScriptAPI.setEngine(this);
|
||||
}
|
||||
|
||||
public void createEngine() {
|
||||
synchronized (logger) {
|
||||
if (this.engine == null) {
|
||||
this.engine = new MiaoScriptEngine(root);
|
||||
this.engine.put("base", this.base);
|
||||
this.engine.put("ScriptEngineContextHolder", this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
public void loadEngine() {
|
||||
ClassLoader originLoader = Thread.currentThread().getContextClassLoader();
|
||||
Thread.currentThread().setContextClassLoader(this.loader);
|
||||
createEngine();
|
||||
Path bios = Paths.get(root, "bios.js");
|
||||
// 如果存在自定义bios就加载自定义的
|
||||
if (Files.exists(bios)) {
|
||||
this.engine.eval("load('" + bios.toFile().getCanonicalPath() + "')");
|
||||
} else {
|
||||
this.engine.eval("load('classpath:bios.js')");
|
||||
}
|
||||
future = engine.invokeFunction("boot", root, logger);
|
||||
Thread.currentThread().setContextClassLoader(originLoader);
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
public void enableEngine() {
|
||||
if (this.engine != null) {
|
||||
engine.invokeFunction("enable", future);
|
||||
}
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
public void disableEngine() {
|
||||
synchronized (logger) {
|
||||
if (this.engine != null) {
|
||||
this.engine.invokeFunction("disable");
|
||||
this.engine = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,39 +0,0 @@
|
||||
package pw.yumc.MiaoScript.api.bukkit;
|
||||
|
||||
import lombok.Getter;
|
||||
import org.bukkit.event.Cancellable;
|
||||
import org.bukkit.event.Event;
|
||||
import org.bukkit.event.HandlerList;
|
||||
|
||||
import javax.script.Bindings;
|
||||
|
||||
@Getter
|
||||
public class EngineEvent extends Event implements Cancellable {
|
||||
private final String event;
|
||||
private final Bindings data;
|
||||
|
||||
private boolean cancelled = false;
|
||||
|
||||
public EngineEvent(String event, Bindings data) {
|
||||
this.event = event;
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCancelled() {
|
||||
return this.cancelled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCancelled(boolean b) {
|
||||
this.cancelled = b;
|
||||
}
|
||||
|
||||
@Getter
|
||||
private static final HandlerList handlerList = new HandlerList();
|
||||
|
||||
@Override
|
||||
public HandlerList getHandlers() {
|
||||
return handlerList;
|
||||
}
|
||||
}
|
@ -1,41 +0,0 @@
|
||||
package pw.yumc.MiaoScript.api.bukkit;
|
||||
|
||||
import lombok.Getter;
|
||||
import org.bukkit.event.Cancellable;
|
||||
import org.bukkit.event.Event;
|
||||
import org.bukkit.event.HandlerList;
|
||||
|
||||
import javax.script.Bindings;
|
||||
|
||||
@Getter
|
||||
public class ScriptEvent extends Event implements Cancellable {
|
||||
private final Bindings plugin;
|
||||
private final String event;
|
||||
private final Bindings data;
|
||||
|
||||
private boolean cancelled = false;
|
||||
|
||||
public ScriptEvent(Bindings plugin, String event, Bindings data) {
|
||||
this.plugin = plugin;
|
||||
this.event = event;
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCancelled() {
|
||||
return this.cancelled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCancelled(boolean b) {
|
||||
this.cancelled = b;
|
||||
}
|
||||
|
||||
@Getter
|
||||
private static final HandlerList handlerList = new HandlerList();
|
||||
|
||||
@Override
|
||||
public HandlerList getHandlers() {
|
||||
return handlerList;
|
||||
}
|
||||
}
|
@ -1,67 +0,0 @@
|
||||
package pw.yumc.MiaoScript.api.loader;
|
||||
|
||||
import lombok.SneakyThrows;
|
||||
|
||||
import java.io.File;
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.URL;
|
||||
|
||||
public class JarLoader {
|
||||
private static sun.misc.Unsafe unsafe;
|
||||
private static long offset;
|
||||
private static Object parentUcp;
|
||||
private static Object ucp;
|
||||
private static MethodHandle addURLMethodHandle;
|
||||
|
||||
static {
|
||||
initReflect();
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
public static File load(File file) {
|
||||
addURLMethodHandle.invoke(ucp, file.toURI().toURL());
|
||||
return file;
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
public static File parentLoad(File file) {
|
||||
if (parentUcp == null)
|
||||
throw new IllegalStateException("parentUcp is null.");
|
||||
addURLMethodHandle.invoke(parentUcp, file.toURI().toURL());
|
||||
return file;
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
public static File load(File file, ClassLoader loader) {
|
||||
addURLMethodHandle.invoke(unsafe.getObject(loader, offset), file.toURI().toURL());
|
||||
return file;
|
||||
}
|
||||
|
||||
private static void initReflect() {
|
||||
try {
|
||||
ClassLoader loader = JarLoader.class.getClassLoader();
|
||||
Field theUnsafe = sun.misc.Unsafe.class.getDeclaredField("theUnsafe");
|
||||
theUnsafe.setAccessible(true);
|
||||
unsafe = (sun.misc.Unsafe) theUnsafe.get(null);
|
||||
Field field = MethodHandles.Lookup.class.getDeclaredField("IMPL_LOOKUP");
|
||||
MethodHandles.Lookup lookup = (MethodHandles.Lookup) unsafe.getObject(unsafe.staticFieldBase(field), unsafe.staticFieldOffset(field));
|
||||
Field ucpField;
|
||||
try {
|
||||
ucpField = loader.getClass().getDeclaredField("ucp");
|
||||
} catch (NoSuchFieldException e) {
|
||||
ucpField = loader.getClass().getSuperclass().getDeclaredField("ucp");
|
||||
}
|
||||
offset = unsafe.objectFieldOffset(ucpField);
|
||||
ucp = unsafe.getObject(loader, offset);
|
||||
Method method = ucp.getClass().getDeclaredMethod("addURL", URL.class);
|
||||
addURLMethodHandle = lookup.unreflect(method);
|
||||
if (loader.getParent() != null)
|
||||
parentUcp = unsafe.getObject(loader.getParent(), offset);
|
||||
} catch (Throwable e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,98 +0,0 @@
|
||||
package pw.yumc.MiaoScript.api.loader;
|
||||
|
||||
import lombok.SneakyThrows;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.nio.MappedByteBuffer;
|
||||
import java.nio.channels.FileChannel;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
import java.security.MessageDigest;
|
||||
|
||||
public class MavenDependLoader {
|
||||
public static final String MavenRepo = "https://maven.aliyun.com/repository/public";
|
||||
|
||||
public static File[] load(String libPath, String groupId, String artifactId, String version) {
|
||||
return new File[]{
|
||||
downloadAndCheckSha1(libPath, groupId, artifactId, version, "pom"),
|
||||
JarLoader.load(downloadAndCheckSha1(libPath, groupId, artifactId, version, "jar"))
|
||||
};
|
||||
}
|
||||
|
||||
public static File[] parentLoad(String libPath, String groupId, String artifactId, String version) {
|
||||
return new File[]{
|
||||
downloadAndCheckSha1(libPath, groupId, artifactId, version, "pom"),
|
||||
JarLoader.parentLoad(downloadAndCheckSha1(libPath, groupId, artifactId, version, "jar"))
|
||||
};
|
||||
}
|
||||
|
||||
public static File[] load(String libPath, String groupId, String artifactId, String version, ClassLoader loader) {
|
||||
return new File[]{
|
||||
downloadAndCheckSha1(libPath, groupId, artifactId, version, "pom"),
|
||||
JarLoader.load(downloadAndCheckSha1(libPath, groupId, artifactId, version, "jar"), loader)
|
||||
};
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
public static File downloadAndCheckSha1(String libPath, String groupId, String artifactId, String version, String ext) {
|
||||
File sha1 = getMavenFile(libPath, groupId, artifactId, version, ext + ".sha1");
|
||||
if (!sha1.exists()) {
|
||||
downloadFile(sha1, groupId, artifactId, version, ext + ".sha1");
|
||||
}
|
||||
File file = getMavenFile(libPath, groupId, artifactId, version, ext);
|
||||
if (!file.exists()) {
|
||||
downloadFile(file, groupId, artifactId, version, ext);
|
||||
}
|
||||
if (!new String(Files.readAllBytes(sha1.toPath())).equals(getSha1(file))) {
|
||||
sha1.delete();
|
||||
file.delete();
|
||||
throw new IllegalStateException("file " + file.getName() + " sha1 not match.");
|
||||
}
|
||||
return file;
|
||||
}
|
||||
|
||||
public static File getMavenFile(String libPath, String groupId, String artifactId, String version, String ext) {
|
||||
return Paths.get(libPath, groupId.replace(".", File.separator), artifactId, version, String.format("%s-%s.%s", artifactId, version, ext)).toFile();
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
public static void downloadFile(File target, String groupId, String artifactId, String version, String ext) {
|
||||
target.getParentFile().mkdirs();
|
||||
URLConnection connection = new URL(MavenRepo +
|
||||
String.format("/%1$s/%2$s/%3$s/%2$s-%3$s.%4$s",
|
||||
groupId.replace(".", "/"),
|
||||
artifactId,
|
||||
version,
|
||||
ext)
|
||||
).openConnection();
|
||||
connection.setConnectTimeout(5000);
|
||||
connection.setReadTimeout(120000);
|
||||
connection.setUseCaches(true);
|
||||
try (InputStream inputStream = connection.getInputStream()) {
|
||||
Files.copy(inputStream, target.toPath(), StandardCopyOption.REPLACE_EXISTING);
|
||||
}
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
private static String getSha1(File file) {
|
||||
MessageDigest digest = MessageDigest.getInstance("SHA-1");
|
||||
try (FileInputStream in = new FileInputStream(file)) {
|
||||
MappedByteBuffer byteBuffer = in.getChannel().map(FileChannel.MapMode.READ_ONLY, 0, file.length());
|
||||
digest.update(byteBuffer);
|
||||
return getHash(digest.digest());
|
||||
}
|
||||
}
|
||||
|
||||
private static String getHash(byte[] bytes) {
|
||||
StringBuilder result = new StringBuilder();
|
||||
for (byte b : bytes) {
|
||||
result.append(String.format("%02x", b));
|
||||
}
|
||||
return result.toString();
|
||||
}
|
||||
}
|
@ -1,22 +0,0 @@
|
||||
package pw.yumc.MiaoScript.api.plugin;
|
||||
|
||||
import javax.script.Bindings;
|
||||
import java.util.Map;
|
||||
|
||||
public interface PluginManager {
|
||||
Map<String, Bindings> getPlugins();
|
||||
|
||||
Bindings getPlugin(String name);
|
||||
|
||||
boolean has(String name);
|
||||
|
||||
Bindings get(String name);
|
||||
|
||||
boolean enable(String name);
|
||||
|
||||
boolean disable(String name);
|
||||
|
||||
boolean install(String name);
|
||||
|
||||
boolean uninstall(String name);
|
||||
}
|
@ -1,268 +0,0 @@
|
||||
package pw.yumc.MiaoScript.engine;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.SneakyThrows;
|
||||
import pw.yumc.MiaoScript.api.loader.JarLoader;
|
||||
import pw.yumc.MiaoScript.api.loader.MavenDependLoader;
|
||||
|
||||
import javax.script.*;
|
||||
import java.io.File;
|
||||
import java.io.Reader;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 喵式脚本引擎
|
||||
*
|
||||
* @author 喵♂呜
|
||||
* @since 2016年8月29日 上午7:51:43
|
||||
*/
|
||||
public class MiaoScriptEngine implements ScriptEngine, Invocable {
|
||||
private final String libsRoot;
|
||||
|
||||
@Getter
|
||||
private ScriptEngine engine;
|
||||
|
||||
@SneakyThrows
|
||||
public MiaoScriptEngine(String engineRoot) {
|
||||
File libRootFile = new File(engineRoot, "libs");
|
||||
libRootFile.mkdirs();
|
||||
this.libsRoot = libRootFile.getCanonicalPath();
|
||||
if (new File(engineRoot, "debug").exists()) {
|
||||
System.setProperty("nashorn.debug", "true");
|
||||
}
|
||||
MavenDependLoader.load(this.libsRoot, "org.kamranzafar", "jtar", "2.3");
|
||||
this.loadScriptEngine(engineRoot);
|
||||
if (this.engine == null)
|
||||
throw new UnsupportedOperationException("当前环境不支持 Nashorn 或 GraalJS 脚本引擎.");
|
||||
}
|
||||
|
||||
private void loadScriptEngine(String engineRoot) {
|
||||
if (new File(engineRoot, "graal").exists()) {
|
||||
this.engine = this.loadNetworkGraalJS();
|
||||
return;
|
||||
}
|
||||
if (getJavaVersion() > 15) {
|
||||
this.loadGraalJS();
|
||||
} else {
|
||||
this.loadNashorn();
|
||||
}
|
||||
}
|
||||
|
||||
private void loadGraalJS() {
|
||||
try {
|
||||
this.engine = this.parentLoadNetworkNashorn();
|
||||
} catch (Throwable ex) {
|
||||
this.engine = this.loadNetworkNashorn();
|
||||
}
|
||||
if (this.engine == null) {
|
||||
this.engine = this.loadNetworkGraalJS();
|
||||
}
|
||||
}
|
||||
|
||||
private void loadNashorn() {
|
||||
try {
|
||||
this.createEngineByName();
|
||||
} catch (final Throwable ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
try {
|
||||
String extDirs = System.getProperty("java.ext.dirs");
|
||||
if (this.engine == null && extDirs != null) {
|
||||
this.engine = this.loadLocalNashorn(extDirs);
|
||||
}
|
||||
} catch (final Throwable ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
try {
|
||||
if (this.engine == null) {
|
||||
this.engine = this.loadNetworkNashorn();
|
||||
}
|
||||
} catch (final Throwable ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
if (this.engine == null)
|
||||
throw new UnsupportedOperationException("当前环境不支持 Nashorn 脚本引擎.");
|
||||
}
|
||||
|
||||
private int getJavaVersion() {
|
||||
String version = System.getProperty("java.version");
|
||||
if (version.startsWith("1.")) {
|
||||
version = version.substring(2, 3);
|
||||
} else {
|
||||
int dot = version.indexOf(".");
|
||||
if (dot != -1) {
|
||||
version = version.substring(0, dot);
|
||||
}
|
||||
}
|
||||
return Integer.parseInt(version);
|
||||
}
|
||||
|
||||
private ScriptEngine loadLocalNashorn(String extDirs) {
|
||||
String[] dirs = extDirs.split(File.pathSeparator);
|
||||
for (String dir : dirs) {
|
||||
File nashorn = new File(dir, "nashorn.jar");
|
||||
if (nashorn.exists()) {
|
||||
JarLoader.load(nashorn);
|
||||
return this.createEngineByName();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private String nashornVersion = "15.4";
|
||||
private String asmVersion = "9.6";
|
||||
|
||||
private ScriptEngine loadNetworkNashorn() {
|
||||
MavenDependLoader.load(this.libsRoot, "org.openjdk.nashorn", "nashorn-core", this.nashornVersion);
|
||||
MavenDependLoader.load(this.libsRoot, "org.ow2.asm", "asm", this.asmVersion);
|
||||
MavenDependLoader.load(this.libsRoot, "org.ow2.asm", "asm-commons", this.asmVersion);
|
||||
MavenDependLoader.load(this.libsRoot, "org.ow2.asm", "asm-tree", this.asmVersion);
|
||||
MavenDependLoader.load(this.libsRoot, "org.ow2.asm", "asm-util", this.asmVersion);
|
||||
return createEngineByFactoryClassName("org.openjdk.nashorn.api.scripting.NashornScriptEngineFactory", false);
|
||||
}
|
||||
|
||||
private ScriptEngine parentLoadNetworkNashorn() {
|
||||
MavenDependLoader.parentLoad(this.libsRoot, "org.openjdk.nashorn", "nashorn-core", this.nashornVersion);
|
||||
MavenDependLoader.parentLoad(this.libsRoot, "org.ow2.asm", "asm", this.asmVersion);
|
||||
MavenDependLoader.parentLoad(this.libsRoot, "org.ow2.asm", "asm-commons", this.asmVersion);
|
||||
MavenDependLoader.parentLoad(this.libsRoot, "org.ow2.asm", "asm-tree", this.asmVersion);
|
||||
MavenDependLoader.parentLoad(this.libsRoot, "org.ow2.asm", "asm-util", this.asmVersion);
|
||||
return createEngineByFactoryClassName("org.openjdk.nashorn.api.scripting.NashornScriptEngineFactory", false);
|
||||
}
|
||||
|
||||
private String graalVersion = "23.0.2";
|
||||
private String icu4jVersion = "72.1";
|
||||
|
||||
@SneakyThrows
|
||||
private ScriptEngine loadNetworkGraalJS() {
|
||||
MavenDependLoader.load(this.libsRoot, "org.graalvm.js", "js", this.graalVersion);
|
||||
MavenDependLoader.load(this.libsRoot, "com.ibm.icu", "icu4j", this.icu4jVersion);
|
||||
MavenDependLoader.load(this.libsRoot, "org.graalvm.js", "js-scriptengine", this.graalVersion);
|
||||
MavenDependLoader.load(this.libsRoot, "org.graalvm.regex", "regex", this.graalVersion);
|
||||
MavenDependLoader.load(this.libsRoot, "org.graalvm.sdk", "graal-sdk", this.graalVersion);
|
||||
MavenDependLoader.load(this.libsRoot, "org.graalvm.truffle", "truffle-api", this.graalVersion);
|
||||
System.setProperty("polyglot.engine.AllowExperimentalOptions", "true");
|
||||
System.setProperty("polyglot.engine.WarnInterpreterOnly", "false");
|
||||
System.setProperty("polyglot.js.nashorn-compat", "true");
|
||||
System.setProperty("polyglot.js.scripting", "true");
|
||||
System.setProperty("polyglot.js.ecmascript-version", "5");
|
||||
Class<?> NashornScriptEngineFactory = Class.forName("com.oracle.truffle.js.scriptengine.GraalJSEngineFactory");
|
||||
Method getScriptEngine = NashornScriptEngineFactory.getMethod("getScriptEngine");
|
||||
Object factory = NashornScriptEngineFactory.newInstance();
|
||||
ScriptEngine engine = (ScriptEngine) getScriptEngine.invoke(factory);
|
||||
Bindings bind = engine.getBindings(ScriptContext.ENGINE_SCOPE);
|
||||
bind.put("polyglot.js.allowAllAccess", true);
|
||||
return engine;
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
private ScriptEngine createEngineByName() {
|
||||
return createEngineByFactoryClassName("jdk.nashorn.api.scripting.NashornScriptEngineFactory", true);
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
private ScriptEngine createEngineByFactoryClassName(String factoryClassName, boolean jdk) {
|
||||
Class<?> NashornScriptEngineFactory = Class.forName(factoryClassName);
|
||||
Method getScriptEngine = NashornScriptEngineFactory.getMethod("getScriptEngine", String[].class);
|
||||
Object factory = NashornScriptEngineFactory.newInstance();
|
||||
List<String> engineArgs = new ArrayList<>();
|
||||
engineArgs.add("--language=es5");
|
||||
engineArgs.add("--optimistic-types=false");
|
||||
if (getJavaVersion() >= 11 && jdk) {
|
||||
engineArgs.add("--no-deprecation-warning");
|
||||
}
|
||||
return (ScriptEngine) getScriptEngine.invoke(factory, (Object) engineArgs.toArray(new String[] {}));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Bindings createBindings() {
|
||||
return engine.createBindings();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object eval(final Reader reader) throws ScriptException {
|
||||
return engine.eval(reader);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object eval(final Reader reader, final Bindings n) throws ScriptException {
|
||||
return engine.eval(reader, n);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object eval(final Reader reader, final ScriptContext context) throws ScriptException {
|
||||
return engine.eval(reader, context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object eval(final String script) throws ScriptException {
|
||||
return engine.eval(script);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object eval(final String script, final Bindings n) throws ScriptException {
|
||||
return engine.eval(script, n);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object eval(final String script, final ScriptContext context) throws ScriptException {
|
||||
return engine.eval(script, context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object get(final String key) {
|
||||
return engine.get(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Bindings getBindings(final int scope) {
|
||||
return engine.getBindings(scope);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScriptContext getContext() {
|
||||
return engine.getContext();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScriptEngineFactory getFactory() {
|
||||
return engine.getFactory();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T getInterface(final Class<T> cls) {
|
||||
return ((Invocable) engine).getInterface(cls);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T getInterface(final Object thiz, final Class<T> cls) {
|
||||
return ((Invocable) engine).getInterface(thiz, cls);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object invokeFunction(final String name, final Object... args) throws ScriptException, NoSuchMethodException {
|
||||
return ((Invocable) engine).invokeFunction(name, args);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object invokeMethod(final Object thiz, final String name, final Object... args) throws ScriptException, NoSuchMethodException {
|
||||
return ((Invocable) engine).invokeMethod(thiz, name, args);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void put(final String key, final Object value) {
|
||||
engine.put(key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBindings(final Bindings bindings, final int scope) {
|
||||
engine.setBindings(bindings, scope);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setContext(final ScriptContext context) {
|
||||
engine.setContext(context);
|
||||
}
|
||||
}
|
@ -1,97 +0,0 @@
|
||||
'use strict'
|
||||
var global = this;
|
||||
/**
|
||||
* Init MiaoScriptEngine Runtime
|
||||
*/
|
||||
/*global base ScriptEngineContextHolder*/
|
||||
(function () {
|
||||
var Files = Java.type('java.nio.file.Files')
|
||||
var Paths = Java.type('java.nio.file.Paths')
|
||||
var System = Java.type('java.lang.System')
|
||||
var Thread = Java.type('java.lang.Thread')
|
||||
var FutureTask = Java.type('java.util.concurrent.FutureTask')
|
||||
|
||||
global.boot = function (root, logger) {
|
||||
global.scope = System.getenv("MS_NODE_CORE_SCOPE") || "@ccms"
|
||||
global.logger = logger
|
||||
// Development Env Detect
|
||||
global.root = root || "src/main/resources"
|
||||
readEnvironment()
|
||||
if (!global.debug) { checkUpgrade() }
|
||||
return bootEngineThread(checkClassLoader())
|
||||
}
|
||||
|
||||
function bootEngineThread(loader) {
|
||||
logger.info("ScriptEngine: " + ScriptEngineContextHolder.getEngine().getEngine().class.name)
|
||||
var future = new FutureTask(function () {
|
||||
Thread.currentThread().contextClassLoader = loader
|
||||
load(System.getenv("MS_NODE_CORE_POLYFILL") || 'classpath:core/polyfill.js')(root, logger)
|
||||
var core = require(System.getenv("MS_NODE_CORE_MODULE") || (global.scope + '/core'))
|
||||
return core.default || core
|
||||
})
|
||||
// Async Loading MiaoScript Engine
|
||||
new Thread(future, "MiaoScript thread").start()
|
||||
return future
|
||||
}
|
||||
|
||||
global.enable = function (future) {
|
||||
// await polyfill loading
|
||||
if (!future.isDone()) { logger.info("MiaoScript booting...") }
|
||||
// faster load core
|
||||
var core = future.get()
|
||||
logger.info("MiaoScript starting...")
|
||||
global.engineDisableImpl = core.enable()
|
||||
}
|
||||
|
||||
global.disable = function () {
|
||||
(global.engineDisableImpl || function () {
|
||||
logger.info('Error: abnormal Initialization MiaoScript Engine. Skip disable step...')
|
||||
})()
|
||||
}
|
||||
|
||||
function readEnvironment() {
|
||||
if (__FILE__.indexOf('!') === -1) {
|
||||
logger.info('loading custom BIOS file ' + __FILE__)
|
||||
global.debug = true
|
||||
}
|
||||
if (Files.exists(Paths.get(root, "debug"))) {
|
||||
logger.info('running in debug mode...')
|
||||
global.debug = true
|
||||
}
|
||||
if (Files.exists(Paths.get(root, "level"))) {
|
||||
global.ScriptEngineLoggerLevel = base.read(Paths.get(root, "level"))
|
||||
logger.info('found level set ScriptEngineLoggerLevel to ' + global.ScriptEngineLoggerLevel + '.')
|
||||
}
|
||||
if (Files.exists(Paths.get(root, "channel"))) {
|
||||
global.ScriptEngineChannel = base.read(Paths.get(root, "channel"))
|
||||
logger.info('found channel set ScriptEngineChannel to ' + global.ScriptEngineChannel + '.')
|
||||
}
|
||||
}
|
||||
|
||||
function checkUpgrade() {
|
||||
if (Files.exists(Paths.get(root, "upgrade"))) {
|
||||
logger.info('found upgrade file starting upgrade...')
|
||||
base.move(Paths.get(root, "node_modules"), Paths.get(root, "old_node_modules"))
|
||||
base.delete(Paths.get(root, "upgrade"))
|
||||
}
|
||||
new Thread(function () {
|
||||
try {
|
||||
base.delete(Paths.get(root, "old_node_modules"))
|
||||
} catch (ex) {
|
||||
}
|
||||
}, "MiaoScript node_modules clean thread").start()
|
||||
}
|
||||
|
||||
function checkClassLoader() {
|
||||
// Check Class Loader, Sometimes Server will can't found plugin.yml file
|
||||
var classLoader = Thread.currentThread().contextClassLoader
|
||||
if (classLoader.getResource("bios.js") === null) {
|
||||
throw Error("Error class loader: " + classLoader.class.name + " Please contact the author MiaoWoo!")
|
||||
}
|
||||
logger.info("Class loader compatible: " + classLoader.class.name)
|
||||
if (classLoader.parent) {
|
||||
logger.info("Parent class loader: " + classLoader.parent.class.name)
|
||||
}
|
||||
return classLoader
|
||||
}
|
||||
})()
|
@ -1,5 +0,0 @@
|
||||
name: ${project.artifactId}
|
||||
description: ${project.description}
|
||||
main: ${project.groupId}.${project.artifactId}.${project.artifactId}Bungee
|
||||
version: ${project.version}
|
||||
author: MiaoWoo
|
@ -1,56 +0,0 @@
|
||||
/// <reference path="./index.d.ts" />
|
||||
// @ts-check
|
||||
(
|
||||
/**
|
||||
* @param {{
|
||||
* info: (arg0: string) => void;
|
||||
* warn: (arg0: string) => void;
|
||||
* debug: (arg0: string) => void;
|
||||
* error: (arg0: string) => void;
|
||||
* warning: (arg0: string) => void;
|
||||
* }} logger
|
||||
*/
|
||||
function (logger) {
|
||||
function log() {
|
||||
logger.info(Array.prototype.join.call(arguments, ' '))
|
||||
}
|
||||
function warn() {
|
||||
logger.warn(Array.prototype.join.call(arguments, ' '))
|
||||
}
|
||||
function debug() {
|
||||
logger.debug(Array.prototype.join.call(arguments, ' '))
|
||||
}
|
||||
function error() {
|
||||
logger.error(Array.prototype.join.call(arguments, ' '))
|
||||
}
|
||||
function warning() {
|
||||
logger.warning(Array.prototype.join.call(arguments, ' '))
|
||||
}
|
||||
/**
|
||||
* @param {string} prefix
|
||||
*/
|
||||
function _proxy(prefix) {
|
||||
return function () {
|
||||
log('[' + prefix + ']', Array.prototype.join.call(arguments, ' '))
|
||||
}
|
||||
}
|
||||
var logProxy = {
|
||||
log: log,
|
||||
info: log,
|
||||
ex: log,
|
||||
trace: global.ScriptEngineLoggerLevel === "trace" ? _proxy('TRACE') : global.noop,
|
||||
debug: global.debug ? logger.debug ? debug : _proxy('DEBUG') : global.noop,
|
||||
warn: _proxy('WARN'),
|
||||
error: _proxy('ERROR')
|
||||
}
|
||||
if (logger.warn) {
|
||||
logProxy.warn = warn
|
||||
}
|
||||
if (logger.warning) {
|
||||
logProxy.warn = warning
|
||||
}
|
||||
if (logger.error) {
|
||||
logProxy.error = error
|
||||
}
|
||||
return logProxy
|
||||
})
|
25
src/main/resources/core/index.d.ts
vendored
25
src/main/resources/core/index.d.ts
vendored
@ -1,25 +0,0 @@
|
||||
declare const global: any
|
||||
declare const root: string
|
||||
declare const base: Core
|
||||
declare function engineLoad(str: string | { script: string, name: string }): any
|
||||
interface Core {
|
||||
version: string
|
||||
getClass(name: String): any
|
||||
getProxyClass(): any
|
||||
getJavaScriptTaskClass(): any
|
||||
getInstance(): any
|
||||
read(path: string): string
|
||||
save(path: string, content: string): void
|
||||
delete(path: string): void
|
||||
}
|
||||
namespace Java {
|
||||
function type<T = any>(clazz: string): T
|
||||
function from<T = any>(javaObj: T[]): T[]
|
||||
function to<T = any>(array: T[], type?: T): T[]
|
||||
function extend(...parentTypes: any[]): any
|
||||
function synchronized(func: () => void, lock: any): Function
|
||||
function isJavaObject(obj: any): boolean
|
||||
function asJSONCompatible<T = any>(obj: T): T
|
||||
//@ts-ignore
|
||||
// function super(type: any);
|
||||
}
|
@ -1,32 +0,0 @@
|
||||
/// <reference path="./index.d.ts" />
|
||||
(
|
||||
/**
|
||||
* @param {string} root
|
||||
* @param {any} logger
|
||||
*/
|
||||
function (root, logger) {
|
||||
var System = Java.type('java.lang.System')
|
||||
var Thread = Java.type('java.lang.Thread')
|
||||
|
||||
// Init Global Value
|
||||
global.root = root
|
||||
global.logger = logger
|
||||
global.ScriptEngineStartTime = new Date().getTime()
|
||||
global.engineLoad = load
|
||||
global.noop = function () { }
|
||||
global.load = load = function __PreventGlobalLoadFunction__() { throw new Error('Internal engine system not allow use `load` function!') }
|
||||
global.setGlobal = function (key, value, config) {
|
||||
if (config) {
|
||||
config.value = value
|
||||
Object.defineProperty(global, key, config)
|
||||
} else {
|
||||
global[key] = value
|
||||
}
|
||||
}
|
||||
// Init console and require
|
||||
global.console = engineLoad(System.getenv("MS_NODE_CORE_CONSOLE") || 'classpath:core/console.js')(logger)
|
||||
console.log("Loading Engine at Thread", Thread.currentThread().name)
|
||||
global.require = engineLoad(System.getenv("MS_NODE_CORE_REQUIRE") || 'classpath:core/require.js')(root)
|
||||
return require(global.scope + '/polyfill')
|
||||
}
|
||||
)
|
@ -1,771 +0,0 @@
|
||||
/**
|
||||
* 符合 CommonJS 规范的 类似 Node 的模块化加载
|
||||
* 一. 注: MiaoScript 中 require.main 不存在
|
||||
* 二. 加载 require 流程 例如 在 dir 目录下 调用 require('xx');
|
||||
* a) 加载流程
|
||||
* 1. 如果xx模块是一个內建模块
|
||||
* a. 编译并返回该模块
|
||||
* b. 停止执行
|
||||
* 2. 如果模块以 `./` `../` 开头
|
||||
* a. 尝试使用 resolveAsFile(dir/xx) 加载文件
|
||||
* b. 尝试使用 resolveAsDirectory(dir/xx) 加载目录
|
||||
* 3. 尝试去 root root/node_modules => xx 加载模块
|
||||
* a. 尝试使用 resolveAsFile(xx/xx) 加载文件
|
||||
* b. 尝试使用 resolveAsDirectory(xx/xx) 加载目录
|
||||
* 4. 抛出 not found 异常
|
||||
* b) resolveAsFile 解析流程
|
||||
* 1. 如果 xx 是一个文件 则作为 `javascript` 文本加载 并停止执行
|
||||
* 2. 如果 xx.js 是一个文件 则作为 `javascript` 文本加载 并停止执行
|
||||
* 3. 如果 xx.json 是一个文件 则使用 `JSON.parse(xx.json)` 解析为对象加载 并停止执行
|
||||
* 暂不支持 4. 如果 xx.msm 是一个文件 则使用MScript解析器解析 并停止执行
|
||||
* c) resolveAsDirectory 解析流程
|
||||
* 1. 如果 xx/package.json 存在 则使用 `JSON.parse(xx/package.json)` 解析并取得 main 字段使用 resolveAsFile(main) 加载
|
||||
* 2. 如果 xx/index.js 存在 则使用 resolveAsFile(xx/index.js) 加载
|
||||
* 3. 如果 xx/index.json 存在 则使用 `xx/index.json` 解析为对象加载 并停止执行
|
||||
* 暂不支持 4. 如果 xx/index.msm 是一个文件 则使用MScript解析器解析 并停止执行
|
||||
*/
|
||||
/// <reference path="./index.d.ts" />
|
||||
// @ts-check
|
||||
(
|
||||
/**
|
||||
* @param {string} root
|
||||
*/
|
||||
function (root) {
|
||||
'use strict'
|
||||
var System = Java.type('java.lang.System')
|
||||
|
||||
var File = Java.type('java.io.File')
|
||||
var Paths = Java.type('java.nio.file.Paths')
|
||||
var Files = Java.type('java.nio.file.Files')
|
||||
var StandardCopyOption = Java.type('java.nio.file.StandardCopyOption')
|
||||
|
||||
var TarInputStream = Java.type('org.kamranzafar.jtar.TarInputStream')
|
||||
var GZIPInputStream = Java.type('java.util.zip.GZIPInputStream')
|
||||
var BufferedInputStream = Java.type('java.io.BufferedInputStream')
|
||||
|
||||
var URL = Java.type('java.net.URL')
|
||||
var ByteArrayOutputStream = Java.type("java.io.ByteArrayOutputStream")
|
||||
var ByteArray = Java.type("byte[]")
|
||||
var Thread = Java.type('java.lang.Thread')
|
||||
var Callable = Java.type('java.util.concurrent.Callable')
|
||||
var Executors = Java.type('java.util.concurrent.Executors')
|
||||
var TimeUnit = Java.type('java.util.concurrent.TimeUnit')
|
||||
var separatorChar = File.separatorChar
|
||||
|
||||
var MS_NODE_PATH = System.getenv("MS_NODE_PATH") || root + separatorChar + 'node_modules'
|
||||
var MS_NODE_REGISTRY = System.getenv("MS_NODE_REGISTRY") || 'https://registry.npmmirror.com'
|
||||
var MS_FALLBACK_NODE_REGISTRY = System.getenv("MS_FALLBACK_NODE_REGISTRY") || 'https://repo.yumc.pw/repository/npm'
|
||||
var MS_SCRIPT_PACKAGE_CENTER = System.getenv("MS_SCRIPT_PACKAGE_CENTER") || 'https://mscript.yumc.pw/api/plugin/download'
|
||||
var MS_NETWORK_CONNECT_TIMEOUT = System.getenv("MS_NETWORK_CONNECT_TIMEOUT") || 5000
|
||||
var MS_NETWORK_READ_TIMEOUT = System.getenv("MS_NETWORK_TIMEOUT") || 45000
|
||||
var MS_NETWORK_DOWNLOAD_TIMEOUT = System.getenv("MS_NETWORK_DOWNLOAD_TIMEOUT") || 60000
|
||||
var MS_NETWORK_USE_CACHES = System.getenv("MS_NETWORK_USE_CACHES") || true
|
||||
|
||||
var CoreModules = [
|
||||
"assert", "async_hooks", "Buffer", "child_process", "cluster", "crypto",
|
||||
"dgram", "dns", "domain", "events", "fs", "http", "http2", "https",
|
||||
"inspector", "net", "os", "path", "perf_hooks", "process", "punycode",
|
||||
"querystring", "readline", "repl", "stream", "string_decoder",
|
||||
"timer", "tls", "trace_events", "tty", "url", "util",
|
||||
"v8", "vm", "wasi", "worker_threads", "zlib"
|
||||
]
|
||||
|
||||
var VersionLockModules = {}
|
||||
|
||||
/**
|
||||
* @param {...object} t
|
||||
*/
|
||||
function __assign(t) {
|
||||
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
||||
s = arguments[i]
|
||||
if (s === undefined) {
|
||||
continue
|
||||
}
|
||||
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
|
||||
t[p] = s[p]
|
||||
}
|
||||
return t
|
||||
}
|
||||
|
||||
// noinspection JSValidateJSDoc
|
||||
/**
|
||||
* 判断是否为一个文件
|
||||
* @param {any} file
|
||||
* @returns {*}
|
||||
*/
|
||||
function _isFile(file) {
|
||||
return file && file.isFile && file.isFile()
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得文件规范路径
|
||||
* @param {any} file
|
||||
* @returns {*}
|
||||
*/
|
||||
function _canonical(file) {
|
||||
return file.canonicalPath
|
||||
}
|
||||
|
||||
function __error(message, name) {
|
||||
var error = new Error(message)
|
||||
if (name) { error.name = name }
|
||||
console.error(message)
|
||||
return error
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析模块名称为文件
|
||||
* 按照下列顺序查找
|
||||
* 当前目录 ./
|
||||
* 父目录 ../
|
||||
* 递归模块目录 ../node_modules 到root
|
||||
* 寻找 ${NODE_PATH}
|
||||
* @param {string} name 模块名称
|
||||
* @param {string} parent 父目录
|
||||
* @param {any} optional 附加参数
|
||||
*/
|
||||
function resolve(name, parent, optional) {
|
||||
name = _canonical(name) || name
|
||||
// 解析本地目录
|
||||
if (optional.local) {
|
||||
return resolveAsFile(name, parent) || resolveAsDirectory(name, parent) || undefined
|
||||
} else {
|
||||
// 解析 root 模块目录
|
||||
var rootModule = resolveAsFile(name, MS_NODE_PATH) || resolveAsDirectory(name, MS_NODE_PATH)
|
||||
if (rootModule) { return rootModule }
|
||||
// 解析Node目录
|
||||
var dir = [parent, 'node_modules'].join(separatorChar)
|
||||
return resolveAsFile(name, dir) || resolveAsDirectory(name, dir) ||
|
||||
(parent && parent.toString().startsWith(root) ?
|
||||
resolve(name, new File(parent).getParent(), optional) : undefined)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析文件
|
||||
* @param {any} file 文件
|
||||
* @param {string | undefined} dir 目录
|
||||
* @returns {*}
|
||||
*/
|
||||
function resolveAsFile(file, dir) {
|
||||
file = dir !== undefined ? new File(dir, file) : new File(file)
|
||||
// 直接文件
|
||||
// 只解析带后缀的文件 其他文件视为非法文件
|
||||
if (file.isFile() && file.name.lastIndexOf('.') != -1) {
|
||||
return file
|
||||
}
|
||||
// JS文件
|
||||
var js = new File(normalizeName(_canonical(file), '.js'))
|
||||
if (js.isFile()) {
|
||||
return js
|
||||
}
|
||||
// JSON文件
|
||||
var json = new File(normalizeName(_canonical(file), '.json'))
|
||||
if (json.isFile()) {
|
||||
return json
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析目录
|
||||
* @param {string} file 文件
|
||||
* @param {string | undefined} dir 目录
|
||||
* @returns {*}
|
||||
*/
|
||||
function resolveAsDirectory(file, dir) {
|
||||
dir = dir !== undefined ? new File(dir, file) : new File(file)
|
||||
var _package = new File(dir, 'package.json')
|
||||
if (_package.exists()) {
|
||||
try {
|
||||
var json = JSON.parse(base.read(_package))
|
||||
if (json.main) {
|
||||
return resolveAsFile(json.main, dir) || resolveAsFile('index.js', new File(dir, json.main))
|
||||
}
|
||||
} catch (error) {
|
||||
throw __error('resolveAsDirectory ' + dir + ' package.json error ' + error)
|
||||
}
|
||||
}
|
||||
// if no package or package.main exists, look for index.js
|
||||
return resolveAsFile('index.js', dir)
|
||||
}
|
||||
|
||||
/**
|
||||
* 后缀检测和添加
|
||||
* @param {string} fileName 文件名称
|
||||
* @param {string} ext 后缀
|
||||
* @returns {*}
|
||||
*/
|
||||
function normalizeName(fileName, ext) {
|
||||
var extension = ext || '.js'
|
||||
if (fileName.endsWith(extension)) {
|
||||
return fileName
|
||||
}
|
||||
return fileName + extension
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查模块缓存
|
||||
* @param {string} id 模块ID
|
||||
* @param {any} file 模块文件
|
||||
* @param {any} optional 附加选项
|
||||
* @returns {Object}
|
||||
*/
|
||||
function getCacheModule(id, file, optional) {
|
||||
var module = cacheModules[id]
|
||||
if (optional.cache && module) {
|
||||
return module
|
||||
}
|
||||
return createModule(id, file, optional)
|
||||
}
|
||||
|
||||
/**
|
||||
* 编译模块
|
||||
* @param {string} id 模块ID
|
||||
* @param {any} file 模块文件
|
||||
* @param {any} optional 附加选项
|
||||
* @returns {Object}
|
||||
*/
|
||||
function createModule(id, file, optional) {
|
||||
var filename = file.name
|
||||
var lastDotIndexOf = filename.lastIndexOf('.')
|
||||
if (lastDotIndexOf == -1) {
|
||||
throw __error("can't require file " + file + '. error: module must include file ext.')
|
||||
}
|
||||
var name = filename.substring(0, lastDotIndexOf)
|
||||
var ext = filename.substring(lastDotIndexOf + 1)
|
||||
var loader = requireLoaders[ext]
|
||||
if (!loader) {
|
||||
throw __error('Unsupported module ' + filename + '. require loader not found.')
|
||||
}
|
||||
/**
|
||||
* @type any
|
||||
*/
|
||||
var module = {
|
||||
id: id,
|
||||
name: name,
|
||||
ext: ext,
|
||||
parent: optional.parent,
|
||||
exports: {},
|
||||
loaded: false,
|
||||
loader: loader,
|
||||
path: _canonical(file.parentFile),
|
||||
filename: _canonical(file),
|
||||
children: []
|
||||
}
|
||||
module.require = getRequire(module)
|
||||
if (module.parent && module.parent.children && module.parent.children.indexOf(module) == -1) {
|
||||
module.parent.children.push(module)
|
||||
}
|
||||
console.trace('Loading module', name + '(' + id + ')', 'Optional', JSON.stringify(__assign(optional, { parent: undefined })))
|
||||
cacheModules[id] = module
|
||||
return loader(module, file, __assign(optional, { id: id }))
|
||||
}
|
||||
|
||||
/**
|
||||
* 预编译JS
|
||||
* @param {any} module JS模块
|
||||
* @param {any} file JS文件
|
||||
* @param {any} optional 附加选项
|
||||
* @returns {any}
|
||||
*/
|
||||
function compileJsFile(module, file, optional) {
|
||||
return compileJs(module, base.read(file), optional)
|
||||
}
|
||||
|
||||
/**
|
||||
* 预编译JS
|
||||
* @param {any} module JS模块
|
||||
* @param {any} script JS脚本
|
||||
* @param {any} optional 附加选项
|
||||
* @returns {any}
|
||||
*/
|
||||
function compileJs(module, script, optional) {
|
||||
if (optional.beforeCompile) {
|
||||
script = optional.beforeCompile(script)
|
||||
}
|
||||
// 2019-09-19 使用 扩展函数直接 load 无需保存/删除文件
|
||||
// 2020-02-16 结尾新增换行 防止有注释导致加载失败
|
||||
var wrapperScript = '(function (module, exports, require, __dirname, __filename) {' + script + '\n});'
|
||||
var compiledWrapper = engineLoad({
|
||||
script: wrapperScript,
|
||||
name: optional.id
|
||||
})
|
||||
compiledWrapper.apply(module.exports, [
|
||||
module, module.exports, module.require, module.path, module.filename
|
||||
])
|
||||
module.loaded = true
|
||||
if (optional.afterCompile) {
|
||||
module = optional.afterCompile(module) || module
|
||||
}
|
||||
return module
|
||||
}
|
||||
|
||||
/**
|
||||
* 预编译Json
|
||||
* @param {{ id?: string | null; exports?: {}; loaded: any; require?: any; }} module Json模块
|
||||
* @param {any} file Json 文件
|
||||
* @returns {any}
|
||||
*/
|
||||
function compileJson(module, file) {
|
||||
module.exports = JSON.parse(base.read(file))
|
||||
module.loaded = true
|
||||
return module
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得网络链接
|
||||
* @param {string} url 网址
|
||||
*/
|
||||
function getConnection(url) {
|
||||
var connection = new URL(url).openConnection()
|
||||
connection.setConnectTimeout(MS_NETWORK_CONNECT_TIMEOUT)
|
||||
connection.setReadTimeout(MS_NETWORK_READ_TIMEOUT)
|
||||
connection.setUseCaches(MS_NETWORK_USE_CACHES)
|
||||
return connection
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得网络流
|
||||
* @param {string} url 网址
|
||||
*/
|
||||
function getConnectionStream(url) {
|
||||
var connection = getConnection(url)
|
||||
return connection.getInputStream()
|
||||
}
|
||||
|
||||
function splitVersionFromName(name) {
|
||||
// process package name
|
||||
// es6-map/implement => [es6-map/implement, undefined]
|
||||
// @ccms/common/dist/reflect => [@ccms/common, undefined]
|
||||
var name_arr = name.split('/')
|
||||
var module_name = ''
|
||||
var module_version = ''
|
||||
if (name.startsWith('@')) {
|
||||
var module_version_arr = name_arr[1].split('@')
|
||||
module_name = name_arr[0] + '/' + module_version_arr[0]
|
||||
} else {
|
||||
var module_version_arr = name_arr[0].split('@')
|
||||
module_name = module_version_arr[0]
|
||||
}
|
||||
// handle internal package version
|
||||
if (name.startsWith(global.scope) && global.ScriptEngineChannel) {
|
||||
module_version = global.ScriptEngineChannel
|
||||
} else {
|
||||
module_version = module_version_arr[1]
|
||||
}
|
||||
return [module_name, module_version]
|
||||
}
|
||||
|
||||
/**
|
||||
* 尝试从网络下载依赖包
|
||||
* @param {string} name 包名称
|
||||
* @param {string} optional 附加选项
|
||||
* @param {number} retry 重试次数
|
||||
*/
|
||||
function download(name, optional, retry) {
|
||||
var name_arr = splitVersionFromName(name)
|
||||
var module_name = name_arr[0]
|
||||
var module_version = name_arr[1]
|
||||
try {
|
||||
var target = MS_NODE_PATH + separatorChar + module_name
|
||||
if (new File(target, 'package.json').exists()) { return name }
|
||||
var info = fetchPackageInfo(module_name)
|
||||
if (!module_version) {
|
||||
// if not special version get from lock or tag
|
||||
module_version = VersionLockModules[module_name]
|
||||
} else if (!/\d+\.\d+\.\w+/.test(module_version)) {
|
||||
// maybe module_version = latest if special version not exist then fallback latest
|
||||
console.log('try get node_module ' + module_name + ' version from ' + module_version + ' tag waiting...')
|
||||
module_version = info['dist-tags'][module_version]
|
||||
}
|
||||
if (!module_version) {
|
||||
console.log('try get node_module ' + module_name + ' version from latest tag waiting...')
|
||||
module_version = info['dist-tags']['latest']
|
||||
}
|
||||
if (!module_version) { throw __error('fetch node_module ' + module_name + " failed. can't found version from " + name + ".", 'ModuleNotFoundError') }
|
||||
var _version = info.versions[module_version]
|
||||
if (!_version) { throw __error('fetch node_module ' + module_name + ' version ' + module_version + " failed. can't found tarball from versions.", 'ModuleNotFoundError') }
|
||||
var url = _version.dist.tarball
|
||||
console.log('fetch node_module ' + module_name + ' version ' + module_version + ' waiting...')
|
||||
return executor.submit(new Callable(function () {
|
||||
var tis = new TarInputStream(new BufferedInputStream(new GZIPInputStream(getConnectionStream(url))))
|
||||
var entry
|
||||
while ((entry = tis.getNextEntry()) != null) {
|
||||
var targetPath = Paths.get(target + separatorChar + entry.getName().substring(8))
|
||||
var parentFile = targetPath.toFile().getParentFile()
|
||||
if (!parentFile.isDirectory()) {
|
||||
parentFile.delete()
|
||||
parentFile.mkdirs()
|
||||
}
|
||||
Files.copy(tis, targetPath, StandardCopyOption.REPLACE_EXISTING)
|
||||
}
|
||||
return name
|
||||
})).get(MS_NETWORK_DOWNLOAD_TIMEOUT, TimeUnit.MILLISECONDS)
|
||||
} catch (error) {
|
||||
if (error.name == 'ModuleNotFoundError') { throw error }
|
||||
if (retry > 3) { throw __error('fetch node_module ' + module_name + ' version ' + module_version + ' failed. greater than 3 times stop retry.') }
|
||||
console.log('fetch node_module ' + module_name + ' version ' + module_version + ' failed retrying...')
|
||||
return download(name, optional, ++retry)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取包信息
|
||||
* @param {string} module_name
|
||||
*/
|
||||
function fetchPackageInfo(module_name) {
|
||||
var content = ''
|
||||
try {
|
||||
content = fetchContent(MS_NODE_REGISTRY + '/' + module_name)
|
||||
} catch (ex) {
|
||||
console.warn("can't fetch package " + module_name + ' from ' + MS_NODE_REGISTRY + ' registry. try fetch from ' + MS_FALLBACK_NODE_REGISTRY + ' registry...')
|
||||
content = fetchContent(MS_FALLBACK_NODE_REGISTRY + '/' + module_name)
|
||||
}
|
||||
return JSON.parse(content)
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取网络内容
|
||||
* @param {string} url 网址
|
||||
* @param {number} [timeout] 超时时间
|
||||
*/
|
||||
function fetchContent(url, timeout) {
|
||||
return executor.submit(new Callable(function fetchContent() {
|
||||
var input = getConnectionStream(url)
|
||||
var output = new ByteArrayOutputStream()
|
||||
var buffer = new ByteArray(1024)
|
||||
try {
|
||||
var n
|
||||
while ((n = input.read(buffer)) !== -1) {
|
||||
output.write(buffer, 0, n)
|
||||
}
|
||||
return output.toString("UTF-8")
|
||||
} finally {
|
||||
input.close()
|
||||
output.close()
|
||||
}
|
||||
})).get(timeout || MS_NETWORK_READ_TIMEOUT, TimeUnit.MILLISECONDS)
|
||||
}
|
||||
|
||||
var lastModule = ''
|
||||
|
||||
/**
|
||||
* 检查核心模块
|
||||
* @param {string} name
|
||||
* @param {string} path
|
||||
*/
|
||||
function checkCoreModule(name, path, optional) {
|
||||
if (name.startsWith('@ms') && lastModule.endsWith('.js')) {
|
||||
console.warn(lastModule + ' load deprecated module ' + name + ' auto replace to ' + (name = name.replace('@ms', global.scope)) + '...')
|
||||
return name
|
||||
} else {
|
||||
lastModule = name
|
||||
}
|
||||
if (CoreModules.indexOf(name) !== -1) {
|
||||
var newName = global.scope + '/nodejs/dist/' + name
|
||||
if (resolve(newName, path, optional) !== undefined) {
|
||||
return newName
|
||||
}
|
||||
throw __error("can't load nodejs core module " + name + " . maybe later will auto replace to " + global.scope + "/nodejs/" + name + ' to compatible...')
|
||||
}
|
||||
return name
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查缓存模块
|
||||
*/
|
||||
function checkCacheModule(optional) {
|
||||
return optional.local ? cacheModuleIds[optional.parent.id] && cacheModuleIds[optional.parent.id][optional.path] : cacheModuleIds[optional.path]
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载模块
|
||||
* @param {string} name 模块名称
|
||||
* @param {string} path 路径
|
||||
* @param {any} optional 附加选项
|
||||
* @returns {*}
|
||||
*/
|
||||
function _require(name, path, optional) {
|
||||
// require direct file
|
||||
var file = _isFile(name) ? name : new File(name)
|
||||
if (_isFile(file) && file.name.lastIndexOf('.') != -1) {
|
||||
return _requireFile(file, optional)
|
||||
}
|
||||
// require cache module
|
||||
var cachePath = checkCacheModule(optional)
|
||||
var cacheFile = new File(cachePath)
|
||||
if (cachePath && cacheFile.exists()) {
|
||||
return _requireFile(cacheFile, optional)
|
||||
}
|
||||
// check core module
|
||||
name = checkCoreModule(name, path, optional)
|
||||
var file = resolve(name, path, optional)
|
||||
// search module
|
||||
if (file === undefined) {
|
||||
// excloud local dir, prevent too many recursive call and cache not found module
|
||||
if (optional.local || optional.recursive || notFoundModules[name]) {
|
||||
delete optional.parent
|
||||
throw __error("can't found module " + name + '(' + JSON.stringify(optional) + ') at local ' + path + ' or network!')
|
||||
}
|
||||
optional.recursive = true
|
||||
return _require(download(name, optional, 1), path, optional)
|
||||
}
|
||||
setCacheModule(file, optional)
|
||||
return _requireFile(file, optional)
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置模块缓存
|
||||
* @param {any} file
|
||||
* @param {any} optional
|
||||
*/
|
||||
function setCacheModule(file, optional) {
|
||||
if (optional.local) {
|
||||
var parent = cacheModuleIds[optional.parent.id]
|
||||
if (!parent) {
|
||||
cacheModuleIds[optional.parent.id] = {}
|
||||
}
|
||||
return cacheModuleIds[optional.parent.id][optional.path] = _canonical(file)
|
||||
}
|
||||
return cacheModuleIds[optional.path] = _canonical(file)
|
||||
}
|
||||
|
||||
function _requireFile(file, optional) {
|
||||
// 重定向文件名称和类型
|
||||
return getCacheModule(_canonical(file), file, optional)
|
||||
}
|
||||
|
||||
/**
|
||||
* 闭包方法
|
||||
* @param {any} parent 父模块
|
||||
* @returns {Function}
|
||||
*/
|
||||
function exports(parent) {
|
||||
/**
|
||||
* @param {string} path
|
||||
* @param {any} optional
|
||||
*/
|
||||
var require = function __DynamicRequire__(path, optional) {
|
||||
if (!path) {
|
||||
throw __error("require path can't be undefined or empty!")
|
||||
}
|
||||
var optional = __assign({
|
||||
cache: true,
|
||||
parent: parent,
|
||||
path: path,
|
||||
local: path.startsWith('.') || path.startsWith('/')
|
||||
}, optional)
|
||||
return _require(path, parent.path, optional).exports
|
||||
}
|
||||
require.resolve = function __DynamicResolve__(path, optional) {
|
||||
return _canonical(new File(resolve(path, root, __assign({
|
||||
parent: parent,
|
||||
cache: true,
|
||||
local: path.startsWith('.') || path.startsWith('/')
|
||||
}, optional))))
|
||||
}
|
||||
return require
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} name
|
||||
*/
|
||||
function __DynamicClear__(name) {
|
||||
for (var cacheModule in cacheModules) {
|
||||
if (cacheModule.indexOf(name) !== -1) {
|
||||
console.trace('clear module ' + cacheModule + ' ...')
|
||||
delete cacheModules[cacheModule]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function __DynamicDisable__() {
|
||||
base.save(cacheModuleIdsFile, JSON.stringify(upgradeMode ? {} : cacheModuleIds))
|
||||
for (var cacheModule in cacheModules) {
|
||||
delete cacheModules[cacheModule]
|
||||
}
|
||||
cacheModules = {}
|
||||
for (var cacheModuleId in cacheModuleIds) {
|
||||
delete cacheModuleIds[cacheModuleId]
|
||||
}
|
||||
cacheModuleIds = {}
|
||||
notFoundModules = {}
|
||||
}
|
||||
|
||||
function __setUpgradeMode__(status) {
|
||||
upgradeMode = status
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {any} parent
|
||||
*/
|
||||
function getRequire(parent) {
|
||||
/**
|
||||
* @type {any} require
|
||||
*/
|
||||
var require = exports(parent)
|
||||
require.main = mainRequire
|
||||
require.cache = cacheModules
|
||||
require.clear = __DynamicClear__
|
||||
require.disable = __DynamicDisable__
|
||||
require.setUpgradeMode = __setUpgradeMode__
|
||||
require.loader = {
|
||||
register: registerLoader,
|
||||
get: getLoader,
|
||||
unregister: unregisterLoader,
|
||||
}
|
||||
require.loaders = requireLoaders
|
||||
require.internal = {
|
||||
coreModules: CoreModules,
|
||||
cacheModules: cacheModules,
|
||||
cacheModuleIds: cacheModuleIds,
|
||||
notFoundModules: notFoundModules,
|
||||
versionLockModules: VersionLockModules
|
||||
}
|
||||
require.loadCoreScript = loadCoreScript
|
||||
return require
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} ext
|
||||
* @param {any} loader
|
||||
*/
|
||||
function registerLoader(ext, loader) {
|
||||
if (requireLoaders[ext]) {
|
||||
return console.error('require loader ' + ext + ' already register ignore. if you want override loader please unregister before register.')
|
||||
}
|
||||
requireExts.push(ext)
|
||||
requireLoaders[ext] = loader
|
||||
console.info('register require loader ' + ext + ' => ' + (loader.name || '<anonymous>') + '.')
|
||||
}
|
||||
/**
|
||||
* @param {*} ext
|
||||
*/
|
||||
function getLoader(ext) {
|
||||
return requireLoaders[ext]
|
||||
}
|
||||
/**
|
||||
* @param {*} ext
|
||||
*/
|
||||
function unregisterLoader(ext) {
|
||||
requireExts.splice(requireExts.indexOf(ext), 1);
|
||||
delete requireLoaders[ext]
|
||||
console.info('unregister require loader ' + ext + '.')
|
||||
}
|
||||
|
||||
function printRequireInfo() {
|
||||
console.info('Initialization require module.')
|
||||
console.info('ParentDir:', root)
|
||||
console.info('Require module env list:')
|
||||
console.info('- JAVA_VERSION:', System.getProperty("java.version"))
|
||||
console.info('- PLUGIN_VERSION:', base.version)
|
||||
console.info('- MS_NODE_PATH:', MS_NODE_PATH.startsWith(root) ? MS_NODE_PATH.split(root)[1] : MS_NODE_PATH)
|
||||
console.info('- MS_NODE_REGISTRY:', MS_NODE_REGISTRY)
|
||||
console.info('- MS_FALLBACK_NODE_REGISTRY:', MS_FALLBACK_NODE_REGISTRY)
|
||||
}
|
||||
|
||||
function initCacheModuleIds() {
|
||||
try {
|
||||
cacheModuleIds = JSON.parse(base.read(cacheModuleIdsFile))
|
||||
if (cacheModuleIds['@ccms-cache-module-root'] != MS_NODE_PATH) {
|
||||
throw __error('canonicalRoot Change ' + cacheModuleIds['@ccms-cache-module-root'] + ' to ' + MS_NODE_PATH + ' Clear Cache!')
|
||||
}
|
||||
console.log('Read cacheModuleIds from file', cacheModuleIdsFile.startsWith(root) ? cacheModuleIdsFile.split(root)[1] : cacheModuleIdsFile)
|
||||
} catch (error) {
|
||||
cacheModuleIds = {}
|
||||
cacheModuleIds['@ccms-cache-module-root'] = MS_NODE_PATH
|
||||
console.log('Initialization new cacheModuleIds: ' + error)
|
||||
}
|
||||
}
|
||||
|
||||
function initVersionLock() {
|
||||
try {
|
||||
var version_lock_url = MS_SCRIPT_PACKAGE_CENTER + '?name=version_lock' + (global.debug ? '-debug' : '')
|
||||
VersionLockModules = JSON.parse(fetchContent(version_lock_url, 5000))
|
||||
try {
|
||||
VersionLockModules = __assign(VersionLockModules, JSON.parse(base.read(localVersionLockFile)))
|
||||
} catch (e) {
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn("无法获取到最新的版本锁定信息 使用默认配置.")
|
||||
console.warn("InitVersionLock Error:", error)
|
||||
console.debug(error)
|
||||
VersionLockModules = {
|
||||
"@babel/standalone": "7.12.18",
|
||||
"crypto-js": "3.3.0",
|
||||
"core-js": "3.33.1"
|
||||
}
|
||||
}
|
||||
console.info('Lock module version List:')
|
||||
for (var key in VersionLockModules) {
|
||||
console.info('- ' + key + ': ' + VersionLockModules[key])
|
||||
}
|
||||
}
|
||||
|
||||
function initRequireLoader(require) {
|
||||
registerLoader('js', compileJsFile)
|
||||
registerLoader('json', compileJson)
|
||||
try {
|
||||
loadCoreScript('require_loader')(require)
|
||||
} catch (error) {
|
||||
console.warn("无法获取到最新的加载器信息 使用默认配置.")
|
||||
console.warn("InitRequireLoader Error:", error)
|
||||
console.debug(error)
|
||||
registerLoader('ms', compileJsFile)
|
||||
}
|
||||
require.main = mainRequire = require
|
||||
return require
|
||||
}
|
||||
|
||||
function loadCoreScript(name) {
|
||||
return engineLoad({
|
||||
script: fetchContent(MS_SCRIPT_PACKAGE_CENTER + '?name=' + name, 5000),
|
||||
name: 'core/' + name + '.js'
|
||||
})
|
||||
}
|
||||
|
||||
if (typeof parent === 'string') {
|
||||
parent = new File(parent)
|
||||
}
|
||||
var mainRequire = undefined
|
||||
/**
|
||||
* require 支持的后缀
|
||||
* @type {string[]} requireExts
|
||||
*/
|
||||
var requireExts = []
|
||||
/**
|
||||
* require加载器
|
||||
* @type {{[key:string]:(module:any, file:string, optional?:any)=>any}} requireLoader
|
||||
*/
|
||||
var requireLoaders = {}
|
||||
/**
|
||||
* 已缓存的模块
|
||||
* @type {{[key:string]:any}} [cacheModules]
|
||||
*/
|
||||
var cacheModules = {}
|
||||
var cacheModuleIdsFile = _canonical(new File(MS_NODE_PATH, 'cacheModuleIds.json'))
|
||||
var localVersionLockFile = _canonical(new File(MS_NODE_PATH, 'moduleVersionLock.json'))
|
||||
/**
|
||||
* 已缓存的模块ID
|
||||
* @type {{[key:string]:{[key:string]:string}|string}} [cacheModuleIds]
|
||||
*/
|
||||
var cacheModuleIds = {}
|
||||
/**
|
||||
* 未找到的模块
|
||||
* @type {{[key:string]:boolean}}
|
||||
*/
|
||||
var notFoundModules = {}
|
||||
var upgradeMode = false
|
||||
var executor = Executors.newSingleThreadExecutor(function (r) {
|
||||
return new Thread(r, "MiaoScript require thread")
|
||||
})
|
||||
|
||||
printRequireInfo()
|
||||
initCacheModuleIds()
|
||||
initVersionLock()
|
||||
|
||||
return initRequireLoader(getRequire({
|
||||
id: 'main',
|
||||
path: root
|
||||
}))
|
||||
})
|
@ -1,6 +0,0 @@
|
||||
name: ${project.artifactId}
|
||||
description: ${project.description}
|
||||
main: ${project.groupId}.${project.artifactId}.${project.artifactId}Nukkit
|
||||
version: ${project.version}
|
||||
api: "1.0.0"
|
||||
author: MiaoWoo
|
@ -1,26 +0,0 @@
|
||||
name: ${project.artifactId}
|
||||
description: ${project.description}
|
||||
main: ${project.groupId}.${project.artifactId}.${project.artifactId}Bukkit
|
||||
version: ${project.version}
|
||||
api-version: 1.13
|
||||
author: MiaoWoo
|
||||
website: ${ciManagement.url}
|
||||
softdepend:
|
||||
- OriginAttribute
|
||||
- AttributeSystem
|
||||
- ItemLoreOrigin
|
||||
- PlaceholderAPI
|
||||
- AttributePlus
|
||||
- PlayerPoints
|
||||
- SX-Attribute
|
||||
- CrazyCrates
|
||||
- ProtocolLib
|
||||
- DragonCore
|
||||
- MythicMobs
|
||||
- WorldGuard
|
||||
- Adyeshach
|
||||
- WorldEdit
|
||||
- SkillAPI
|
||||
- TradeMe
|
||||
- Chemdah
|
||||
- Vault
|
@ -1,12 +0,0 @@
|
||||
package pw.yumc.MiaoScript;
|
||||
|
||||
/**
|
||||
* Created with IntelliJ IDEA
|
||||
*
|
||||
* @author 喵♂呜
|
||||
* Created on 2017/9/14 10:08.
|
||||
*/
|
||||
public class MiaoScriptTest {
|
||||
public void testBoot() {
|
||||
}
|
||||
}
|
17
think
Normal file
17
think
Normal file
@ -0,0 +1,17 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006-2016 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: yunwuxin <448901948@qq.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
// 定义项目路径
|
||||
define('APP_PATH', __DIR__ . '/application/');
|
||||
|
||||
// 加载框架引导文件
|
||||
require __DIR__.'/thinkphp/console.php';
|
4
thinkphp/.gitignore
vendored
Normal file
4
thinkphp/.gitignore
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
/composer.lock
|
||||
/vendor
|
||||
.idea
|
||||
.DS_Store
|
1
thinkphp/.htaccess
Normal file
1
thinkphp/.htaccess
Normal file
@ -0,0 +1 @@
|
||||
deny from all
|
47
thinkphp/.travis.yml
Normal file
47
thinkphp/.travis.yml
Normal file
@ -0,0 +1,47 @@
|
||||
sudo: false
|
||||
|
||||
language: php
|
||||
|
||||
services:
|
||||
- memcached
|
||||
- mongodb
|
||||
- mysql
|
||||
- postgresql
|
||||
- redis-server
|
||||
|
||||
matrix:
|
||||
fast_finish: true
|
||||
include:
|
||||
- php: 5.4
|
||||
- php: 5.5
|
||||
- php: 5.6
|
||||
- php: 7.0
|
||||
- php: hhvm
|
||||
allow_failures:
|
||||
- php: hhvm
|
||||
|
||||
cache:
|
||||
directories:
|
||||
- $HOME/.composer/cache
|
||||
|
||||
before_install:
|
||||
- composer self-update
|
||||
- mysql -e "create database IF NOT EXISTS test;" -uroot
|
||||
- psql -c 'DROP DATABASE IF EXISTS test;' -U postgres
|
||||
- psql -c 'create database test;' -U postgres
|
||||
|
||||
install:
|
||||
- ./tests/script/install.sh
|
||||
|
||||
script:
|
||||
## LINT
|
||||
- find . -path ./vendor -prune -o -type f -name \*.php -exec php -l {} \;
|
||||
## PHP Copy/Paste Detector
|
||||
- vendor/bin/phpcpd --verbose --exclude vendor ./ || true
|
||||
## PHPLOC
|
||||
- vendor/bin/phploc --exclude vendor ./
|
||||
## PHPUNIT
|
||||
- vendor/bin/phpunit --coverage-clover=coverage.xml --configuration=phpunit.xml
|
||||
|
||||
after_success:
|
||||
- bash <(curl -s https://codecov.io/bash)
|
119
thinkphp/CONTRIBUTING.md
Normal file
119
thinkphp/CONTRIBUTING.md
Normal file
@ -0,0 +1,119 @@
|
||||
如何贡献我的源代码
|
||||
===
|
||||
|
||||
此文档介绍了 ThinkPHP 团队的组成以及运转机制,您提交的代码将给 ThinkPHP 项目带来什么好处,以及如何才能加入我们的行列。
|
||||
|
||||
## 通过 Github 贡献代码
|
||||
|
||||
ThinkPHP 目前使用 Git 来控制程序版本,如果你想为 ThinkPHP 贡献源代码,请先大致了解 Git 的使用方法。我们目前把项目托管在 GitHub 上,任何 GitHub 用户都可以向我们贡献代码。
|
||||
|
||||
参与的方式很简单,`fork`一份 ThinkPHP 的代码到你的仓库中,修改后提交,并向我们发起`pull request`申请,我们会及时对代码进行审查并处理你的申请并。审查通过后,你的代码将被`merge`进我们的仓库中,这样你就会自动出现在贡献者名单里了,非常方便。
|
||||
|
||||
我们希望你贡献的代码符合:
|
||||
|
||||
* ThinkPHP 的编码规范
|
||||
* 适当的注释,能让其他人读懂
|
||||
* 遵循 Apache2 开源协议
|
||||
|
||||
**如果想要了解更多细节或有任何疑问,请继续阅读下面的内容**
|
||||
|
||||
### 注意事项
|
||||
|
||||
* 本项目代码格式化标准选用 [**PSR-2**](http://www.kancloud.cn/thinkphp/php-fig-psr/3141);
|
||||
* 类名和类文件名遵循 [**PSR-4**](http://www.kancloud.cn/thinkphp/php-fig-psr/3144);
|
||||
* 对于 Issues 的处理,请使用诸如 `fix #xxx(Issue ID)` 的 commit title 直接关闭 issue。
|
||||
* 系统会自动在 PHP 5.4 5.5 5.6 7.0 和 HHVM 上测试修改,其中 HHVM 下的测试容许报错,请确保你的修改符合 PHP 5.4 ~ 5.6 和 PHP 7.0 的语法规范;
|
||||
* 管理员不会合并造成 CI faild 的修改,若出现 CI faild 请检查自己的源代码或修改相应的[单元测试文件](tests);
|
||||
|
||||
## GitHub Issue
|
||||
|
||||
GitHub 提供了 Issue 功能,该功能可以用于:
|
||||
|
||||
* 提出 bug
|
||||
* 提出功能改进
|
||||
* 反馈使用体验
|
||||
|
||||
该功能不应该用于:
|
||||
|
||||
* 提出修改意见(涉及代码署名和修订追溯问题)
|
||||
* 不友善的言论
|
||||
|
||||
## 快速修改
|
||||
|
||||
**GitHub 提供了快速编辑文件的功能**
|
||||
|
||||
1. 登录 GitHub 帐号;
|
||||
2. 浏览项目文件,找到要进行修改的文件;
|
||||
3. 点击右上角铅笔图标进行修改;
|
||||
4. 填写 `Commit changes` 相关内容(Title 必填);
|
||||
5. 提交修改,等待 CI 验证和管理员合并。
|
||||
|
||||
**若您需要一次提交大量修改,请继续阅读下面的内容**
|
||||
|
||||
## 完整流程
|
||||
|
||||
1. `fork`本项目;
|
||||
2. 克隆(`clone`)你 `fork` 的项目到本地;
|
||||
3. 新建分支(`branch`)并检出(`checkout`)新分支;
|
||||
4. 添加本项目到你的本地 git 仓库作为上游(`upstream`);
|
||||
5. 进行修改,若你的修改包含方法或函数的增减,请记得修改[单元测试文件](tests);
|
||||
6. 变基(衍合 `rebase`)你的分支到上游 master 分支;
|
||||
7. `push` 你的本地仓库到 GitHub;
|
||||
8. 提交 `pull request`;
|
||||
9. 等待 CI 验证(若不通过则重复 5~7,GitHub 会自动更新你的 `pull request`);
|
||||
10. 等待管理员处理,并及时 `rebase` 你的分支到上游 master 分支(若上游 master 分支有修改)。
|
||||
|
||||
*若有必要,可以 `git push -f` 强行推送 rebase 后的分支到自己的 `fork`*
|
||||
|
||||
*绝对不可以使用 `git push -f` 强行推送修改到上游*
|
||||
|
||||
### 注意事项
|
||||
|
||||
* 若对上述流程有任何不清楚的地方,请查阅 GIT 教程,如 [这个](http://backlogtool.com/git-guide/cn/);
|
||||
* 对于代码**不同方面**的修改,请在自己 `fork` 的项目中**创建不同的分支**(原因参见`完整流程`第9条备注部分);
|
||||
* 变基及交互式变基操作参见 [Git 交互式变基](http://pakchoi.me/2015/03/17/git-interactive-rebase/)
|
||||
|
||||
## 推荐资源
|
||||
|
||||
### 开发环境
|
||||
|
||||
* XAMPP for Windows 5.5.x
|
||||
* WampServer (for Windows)
|
||||
* upupw Apache PHP5.4 ( for Windows)
|
||||
|
||||
或自行安装
|
||||
|
||||
- Apache / Nginx
|
||||
- PHP 5.4 ~ 5.6
|
||||
- MySQL / MariaDB
|
||||
|
||||
*Windows 用户推荐添加 PHP bin 目录到 PATH,方便使用 composer*
|
||||
|
||||
*Linux 用户自行配置环境, Mac 用户推荐使用内置 Apache 配合 Homebrew 安装 PHP 和 MariaDB*
|
||||
|
||||
### 编辑器
|
||||
|
||||
Sublime Text 3 + phpfmt 插件
|
||||
|
||||
phpfmt 插件参数
|
||||
|
||||
```json
|
||||
{
|
||||
"autocomplete": true,
|
||||
"enable_auto_align": true,
|
||||
"format_on_save": true,
|
||||
"indent_with_space": true,
|
||||
"psr1_naming": false,
|
||||
"psr2": true,
|
||||
"version": 4
|
||||
}
|
||||
```
|
||||
|
||||
或其他 编辑器 / IDE 配合 PSR2 自动格式化工具
|
||||
|
||||
### Git GUI
|
||||
|
||||
* SourceTree
|
||||
* GitHub Desktop
|
||||
|
||||
或其他 Git 图形界面客户端
|
32
thinkphp/LICENSE.txt
Normal file
32
thinkphp/LICENSE.txt
Normal file
@ -0,0 +1,32 @@
|
||||
|
||||
ThinkPHP遵循Apache2开源协议发布,并提供免费使用。
|
||||
版权所有Copyright © 2006-2016 by ThinkPHP (http://thinkphp.cn)
|
||||
All rights reserved。
|
||||
ThinkPHP® 商标和著作权所有者为上海顶想信息科技有限公司。
|
||||
|
||||
Apache Licence是著名的非盈利开源组织Apache采用的协议。
|
||||
该协议和BSD类似,鼓励代码共享和尊重原作者的著作权,
|
||||
允许代码修改,再作为开源或商业软件发布。需要满足
|
||||
的条件:
|
||||
1. 需要给代码的用户一份Apache Licence ;
|
||||
2. 如果你修改了代码,需要在被修改的文件中说明;
|
||||
3. 在延伸的代码中(修改和有源代码衍生的代码中)需要
|
||||
带有原来代码中的协议,商标,专利声明和其他原来作者规
|
||||
定需要包含的说明;
|
||||
4. 如果再发布的产品中包含一个Notice文件,则在Notice文
|
||||
件中需要带有本协议内容。你可以在Notice中增加自己的
|
||||
许可,但不可以表现为对Apache Licence构成更改。
|
||||
具体的协议参考:http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
114
thinkphp/README.md
Normal file
114
thinkphp/README.md
Normal file
@ -0,0 +1,114 @@
|
||||
ThinkPHP 5.0
|
||||
===============
|
||||
|
||||
[![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在保持快速开发和大道至简的核心理念不变的同时,PHP版本要求提升到5.4,优化核心,减少依赖,基于全新的架构思想和命名空间实现,是ThinkPHP突破原有框架思路的颠覆之作,其主要特性包括:
|
||||
|
||||
+ 基于命名空间和众多PHP新特性
|
||||
+ 核心功能组件化
|
||||
+ 强化路由功能
|
||||
+ 更灵活的控制器
|
||||
+ 重构的模型和数据库类
|
||||
+ 配置文件可分离
|
||||
+ 重写的自动验证和完成
|
||||
+ 简化扩展机制
|
||||
+ API支持完善
|
||||
+ 改进的Log类
|
||||
+ 命令行访问支持
|
||||
+ REST支持
|
||||
+ 引导文件支持
|
||||
+ 方便的自动生成定义
|
||||
+ 真正惰性加载
|
||||
+ 分布式环境支持
|
||||
+ 支持Composer
|
||||
+ 支持MongoDb
|
||||
|
||||
> ThinkPHP5的运行环境要求PHP5.4以上。
|
||||
|
||||
详细开发文档参考 [ThinkPHP5完全开发手册](http://www.kancloud.cn/manual/thinkphp5) 以及[ThinkPHP5入门系列教程](http://www.kancloud.cn/special/thinkphp5_quickstart)
|
||||
|
||||
## 目录结构
|
||||
|
||||
初始的目录结构如下:
|
||||
|
||||
~~~
|
||||
www WEB部署目录(或者子目录)
|
||||
├─application 应用目录
|
||||
│ ├─common 公共模块目录(可以更改)
|
||||
│ ├─module_name 模块目录
|
||||
│ │ ├─config.php 模块配置文件
|
||||
│ │ ├─common.php 模块函数文件
|
||||
│ │ ├─controller 控制器目录
|
||||
│ │ ├─model 模型目录
|
||||
│ │ ├─view 视图目录
|
||||
│ │ └─ ... 更多类库目录
|
||||
│ │
|
||||
│ ├─command.php 命令行工具配置文件
|
||||
│ ├─common.php 公共函数文件
|
||||
│ ├─config.php 公共配置文件
|
||||
│ ├─route.php 路由配置文件
|
||||
│ ├─tags.php 应用行为扩展定义文件
|
||||
│ └─database.php 数据库配置文件
|
||||
│
|
||||
├─public WEB目录(对外访问目录)
|
||||
│ ├─index.php 入口文件
|
||||
│ ├─router.php 快速测试文件
|
||||
│ └─.htaccess 用于apache的重写
|
||||
│
|
||||
├─thinkphp 框架系统目录
|
||||
│ ├─lang 语言文件目录
|
||||
│ ├─library 框架类库目录
|
||||
│ │ ├─think Think类库包目录
|
||||
│ │ └─traits 系统Trait目录
|
||||
│ │
|
||||
│ ├─tpl 系统模板目录
|
||||
│ ├─base.php 基础定义文件
|
||||
│ ├─console.php 控制台入口文件
|
||||
│ ├─convention.php 框架惯例配置文件
|
||||
│ ├─helper.php 助手函数文件
|
||||
│ ├─phpunit.xml phpunit配置文件
|
||||
│ └─start.php 框架入口文件
|
||||
│
|
||||
├─extend 扩展类库目录
|
||||
├─runtime 应用的运行时目录(可写,可定制)
|
||||
├─vendor 第三方类库目录(Composer依赖库)
|
||||
├─build.php 自动生成定义文件(参考)
|
||||
├─composer.json composer 定义文件
|
||||
├─LICENSE.txt 授权说明文件
|
||||
├─README.md README 文件
|
||||
├─think 命令行入口文件
|
||||
~~~
|
||||
|
||||
> router.php用于php自带webserver支持,可用于快速测试
|
||||
> 切换到public目录后,启动命令:php -S localhost:8888 router.php
|
||||
> 上面的目录结构和名称是可以改变的,这取决于你的入口文件和配置参数。
|
||||
|
||||
## 命名规范
|
||||
|
||||
ThinkPHP5的命名规范遵循PSR-2规范以及PSR-4自动加载规范。
|
||||
|
||||
## 参与开发
|
||||
注册并登录 Github 帐号, fork 本项目并进行改动。
|
||||
|
||||
更多细节参阅 [CONTRIBUTING.md](CONTRIBUTING.md)
|
||||
|
||||
## 版权信息
|
||||
|
||||
ThinkPHP遵循Apache2开源协议发布,并提供免费使用。
|
||||
|
||||
本项目包含的第三方源码和二进制文件之版权信息另行标注。
|
||||
|
||||
版权所有Copyright © 2006-2016 by ThinkPHP (http://thinkphp.cn)
|
||||
|
||||
All rights reserved。
|
||||
|
||||
ThinkPHP® 商标和著作权所有者为上海顶想信息科技有限公司。
|
||||
|
||||
更多细节参阅 [LICENSE.txt](LICENSE.txt)
|
63
thinkphp/base.php
Normal file
63
thinkphp/base.php
Normal file
@ -0,0 +1,63 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
define('THINK_VERSION', '5.0.11');
|
||||
define('THINK_START_TIME', microtime(true));
|
||||
define('THINK_START_MEM', memory_get_usage());
|
||||
define('EXT', '.php');
|
||||
define('DS', DIRECTORY_SEPARATOR);
|
||||
defined('THINK_PATH') or define('THINK_PATH', __DIR__ . DS);
|
||||
define('LIB_PATH', THINK_PATH . 'library' . DS);
|
||||
define('CORE_PATH', LIB_PATH . 'think' . DS);
|
||||
define('TRAIT_PATH', LIB_PATH . 'traits' . DS);
|
||||
defined('APP_PATH') or define('APP_PATH', dirname($_SERVER['SCRIPT_FILENAME']) . DS);
|
||||
defined('ROOT_PATH') or define('ROOT_PATH', dirname(realpath(APP_PATH)) . DS);
|
||||
defined('EXTEND_PATH') or define('EXTEND_PATH', ROOT_PATH . 'extend' . DS);
|
||||
defined('VENDOR_PATH') or define('VENDOR_PATH', ROOT_PATH . 'vendor' . DS);
|
||||
defined('RUNTIME_PATH') or define('RUNTIME_PATH', ROOT_PATH . 'runtime' . DS);
|
||||
defined('LOG_PATH') or define('LOG_PATH', RUNTIME_PATH . 'log' . DS);
|
||||
defined('CACHE_PATH') or define('CACHE_PATH', RUNTIME_PATH . 'cache' . DS);
|
||||
defined('TEMP_PATH') or define('TEMP_PATH', RUNTIME_PATH . 'temp' . DS);
|
||||
defined('CONF_PATH') or define('CONF_PATH', APP_PATH); // 配置文件目录
|
||||
defined('CONF_EXT') or define('CONF_EXT', EXT); // 配置文件后缀
|
||||
defined('ENV_PREFIX') or define('ENV_PREFIX', 'PHP_'); // 环境变量的配置前缀
|
||||
|
||||
// 环境常量
|
||||
define('IS_CLI', PHP_SAPI == 'cli' ? true : false);
|
||||
define('IS_WIN', strpos(PHP_OS, 'WIN') !== false);
|
||||
|
||||
// 载入Loader类
|
||||
require CORE_PATH . 'Loader.php';
|
||||
|
||||
// 加载环境变量配置文件
|
||||
if (is_file(ROOT_PATH . '.env')) {
|
||||
$env = parse_ini_file(ROOT_PATH . '.env', true);
|
||||
foreach ($env as $key => $val) {
|
||||
$name = ENV_PREFIX . strtoupper($key);
|
||||
if (is_array($val)) {
|
||||
foreach ($val as $k => $v) {
|
||||
$item = $name . '_' . strtoupper($k);
|
||||
putenv("$item=$v");
|
||||
}
|
||||
} else {
|
||||
putenv("$name=$val");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 注册自动加载
|
||||
\think\Loader::register();
|
||||
|
||||
// 注册错误和异常处理机制
|
||||
\think\Error::register();
|
||||
|
||||
// 加载惯例配置文件
|
||||
\think\Config::set(include THINK_PATH . 'convention' . EXT);
|
12
thinkphp/codecov.yml
Normal file
12
thinkphp/codecov.yml
Normal file
@ -0,0 +1,12 @@
|
||||
comment:
|
||||
layout: header, changes, diff
|
||||
coverage:
|
||||
ignore:
|
||||
- base.php
|
||||
- helper.php
|
||||
- convention.php
|
||||
- lang/zh-cn.php
|
||||
- start.php
|
||||
- console.php
|
||||
status:
|
||||
patch: false
|
35
thinkphp/composer.json
Normal file
35
thinkphp/composer.json
Normal file
@ -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"
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": ">=5.4.0",
|
||||
"topthink/think-installer": "~1.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "4.8.*",
|
||||
"johnkary/phpunit-speedtrap": "^1.0",
|
||||
"mikey179/vfsStream": "~1.6",
|
||||
"phploc/phploc": "2.*",
|
||||
"sebastian/phpcpd": "2.*",
|
||||
"phpdocumentor/reflection-docblock": "^2.0"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"think\\": "library/think"
|
||||
}
|
||||
}
|
||||
}
|
20
thinkphp/console.php
Normal file
20
thinkphp/console.php
Normal file
@ -0,0 +1,20 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006-2017 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: yunwuxin <448901948@qq.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace think;
|
||||
|
||||
// ThinkPHP 引导文件
|
||||
// 加载基础文件
|
||||
require __DIR__ . '/base.php';
|
||||
|
||||
// 执行应用
|
||||
App::initCommon();
|
||||
Console::init();
|
289
thinkphp/convention.php
Normal file
289
thinkphp/convention.php
Normal file
@ -0,0 +1,289 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
// +----------------------------------------------------------------------
|
||||
// | 应用设置
|
||||
// +----------------------------------------------------------------------
|
||||
// 默认Host地址
|
||||
'app_host' => '',
|
||||
// 应用调试模式
|
||||
'app_debug' => false,
|
||||
// 应用Trace
|
||||
'app_trace' => false,
|
||||
// 应用模式状态
|
||||
'app_status' => '',
|
||||
// 是否支持多模块
|
||||
'app_multi_module' => true,
|
||||
// 入口自动绑定模块
|
||||
'auto_bind_module' => false,
|
||||
// 注册的根命名空间
|
||||
'root_namespace' => [],
|
||||
// 扩展函数文件
|
||||
'extra_file_list' => [THINK_PATH . 'helper' . EXT],
|
||||
// 默认输出类型
|
||||
'default_return_type' => 'html',
|
||||
// 默认AJAX 数据返回格式,可选json xml ...
|
||||
'default_ajax_return' => 'json',
|
||||
// 默认JSONP格式返回的处理方法
|
||||
'default_jsonp_handler' => 'jsonpReturn',
|
||||
// 默认JSONP处理方法
|
||||
'var_jsonp_handler' => 'callback',
|
||||
// 默认时区
|
||||
'default_timezone' => 'PRC',
|
||||
// 是否开启多语言
|
||||
'lang_switch_on' => false,
|
||||
// 默认全局过滤方法 用逗号分隔多个
|
||||
'default_filter' => '',
|
||||
// 默认语言
|
||||
'default_lang' => 'zh-cn',
|
||||
// 应用类库后缀
|
||||
'class_suffix' => false,
|
||||
// 控制器类后缀
|
||||
'controller_suffix' => false,
|
||||
|
||||
// +----------------------------------------------------------------------
|
||||
// | 模块设置
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
// 默认模块名
|
||||
'default_module' => 'index',
|
||||
// 禁止访问模块
|
||||
'deny_module_list' => ['common'],
|
||||
// 默认控制器名
|
||||
'default_controller' => 'Index',
|
||||
// 默认操作名
|
||||
'default_action' => 'index',
|
||||
// 默认验证器
|
||||
'default_validate' => '',
|
||||
// 默认的空控制器名
|
||||
'empty_controller' => 'Error',
|
||||
// 操作方法前缀
|
||||
'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_route_on' => true,
|
||||
// 路由配置文件(支持配置多个)
|
||||
'route_config_file' => ['route'],
|
||||
// 路由使用完整匹配
|
||||
'route_complete_match' => false,
|
||||
// 是否强制使用路由
|
||||
'url_route_must' => false,
|
||||
// 域名部署
|
||||
'url_domain_deploy' => 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' => [],
|
||||
|
||||
// +----------------------------------------------------------------------
|
||||
// | 模板设置
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
'template' => [
|
||||
// 模板引擎类型 支持 php think 支持扩展
|
||||
'type' => 'Think',
|
||||
// 视图基础目录,配置目录为所有模块的视图起始目录
|
||||
'view_base' => '',
|
||||
// 当前模板的视图目录 留空为自动获取
|
||||
'view_path' => '',
|
||||
// 模板后缀
|
||||
'view_suffix' => 'html',
|
||||
// 模板文件名分隔符
|
||||
'view_depr' => DS,
|
||||
// 模板引擎普通标签开始标记
|
||||
'tpl_begin' => '{',
|
||||
// 模板引擎普通标签结束标记
|
||||
'tpl_end' => '}',
|
||||
// 标签库标签开始标记
|
||||
'taglib_begin' => '{',
|
||||
// 标签库标签结束标记
|
||||
'taglib_end' => '}',
|
||||
],
|
||||
|
||||
// 视图输出字符串内容替换
|
||||
'view_replace_str' => [],
|
||||
// 默认跳转页面对应的模板文件
|
||||
'dispatch_success_tmpl' => THINK_PATH . 'tpl' . DS . 'dispatch_jump.tpl',
|
||||
'dispatch_error_tmpl' => THINK_PATH . 'tpl' . DS . 'dispatch_jump.tpl',
|
||||
|
||||
// +----------------------------------------------------------------------
|
||||
// | 异常及错误设置
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
// 异常页面的模板文件
|
||||
'exception_tmpl' => THINK_PATH . 'tpl' . DS . 'think_exception.tpl',
|
||||
|
||||
// 错误显示信息,非调试模式有效
|
||||
'error_message' => '页面错误!请稍后再试~',
|
||||
// 显示错误信息
|
||||
'show_error_msg' => false,
|
||||
// 异常处理handle类 留空使用 \think\exception\Handle
|
||||
'exception_handle' => '',
|
||||
// 是否记录trace信息到日志
|
||||
'record_trace' => false,
|
||||
|
||||
// +----------------------------------------------------------------------
|
||||
// | 日志设置
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
'log' => [
|
||||
// 日志记录方式,内置 file socket 支持扩展
|
||||
'type' => 'File',
|
||||
// 日志保存目录
|
||||
'path' => LOG_PATH,
|
||||
// 日志记录级别
|
||||
'level' => [],
|
||||
],
|
||||
|
||||
// +----------------------------------------------------------------------
|
||||
// | Trace设置 开启 app_trace 后 有效
|
||||
// +----------------------------------------------------------------------
|
||||
'trace' => [
|
||||
// 内置Html Console 支持扩展
|
||||
'type' => 'Html',
|
||||
],
|
||||
|
||||
// +----------------------------------------------------------------------
|
||||
// | 缓存设置
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
'cache' => [
|
||||
// 驱动方式
|
||||
'type' => 'File',
|
||||
// 缓存保存目录
|
||||
'path' => CACHE_PATH,
|
||||
// 缓存前缀
|
||||
'prefix' => '',
|
||||
// 缓存有效期 0表示永久缓存
|
||||
'expire' => 0,
|
||||
],
|
||||
|
||||
// +----------------------------------------------------------------------
|
||||
// | 会话设置
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
'session' => [
|
||||
'id' => '',
|
||||
// SESSION_ID的提交变量,解决flash上传跨域
|
||||
'var_session_id' => '',
|
||||
// SESSION 前缀
|
||||
'prefix' => 'think',
|
||||
// 驱动方式 支持redis memcache memcached
|
||||
'type' => '',
|
||||
// 是否自动开启 SESSION
|
||||
'auto_start' => true,
|
||||
'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,
|
||||
],
|
||||
|
||||
//分页配置
|
||||
'paginate' => [
|
||||
'type' => 'bootstrap',
|
||||
'var_page' => 'page',
|
||||
'list_rows' => 15,
|
||||
],
|
||||
|
||||
];
|
589
thinkphp/helper.php
Normal file
589
thinkphp/helper.php
Normal file
@ -0,0 +1,589 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
//------------------------
|
||||
// ThinkPHP 助手函数
|
||||
//-------------------------
|
||||
|
||||
use think\Cache;
|
||||
use think\Config;
|
||||
use think\Cookie;
|
||||
use think\Db;
|
||||
use think\Debug;
|
||||
use think\exception\HttpException;
|
||||
use think\exception\HttpResponseException;
|
||||
use think\Lang;
|
||||
use think\Loader;
|
||||
use think\Log;
|
||||
use think\Model;
|
||||
use think\Request;
|
||||
use think\Response;
|
||||
use think\Session;
|
||||
use think\Url;
|
||||
use think\View;
|
||||
|
||||
if (!function_exists('load_trait')) {
|
||||
/**
|
||||
* 快速导入Traits PHP5.5以上无需调用
|
||||
* @param string $class trait库
|
||||
* @param string $ext 类库后缀
|
||||
* @return boolean
|
||||
*/
|
||||
function load_trait($class, $ext = EXT)
|
||||
{
|
||||
return Loader::import($class, TRAIT_PATH, $ext);
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('exception')) {
|
||||
/**
|
||||
* 抛出异常处理
|
||||
*
|
||||
* @param string $msg 异常消息
|
||||
* @param integer $code 异常代码 默认为0
|
||||
* @param string $exception 异常类
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
function exception($msg, $code = 0, $exception = '')
|
||||
{
|
||||
$e = $exception ?: '\think\Exception';
|
||||
throw new $e($msg, $code);
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('debug')) {
|
||||
/**
|
||||
* 记录时间(微秒)和内存使用情况
|
||||
* @param string $start 开始标签
|
||||
* @param string $end 结束标签
|
||||
* @param integer|string $dec 小数位 如果是m 表示统计内存占用
|
||||
* @return mixed
|
||||
*/
|
||||
function debug($start, $end = '', $dec = 6)
|
||||
{
|
||||
if ('' == $end) {
|
||||
Debug::remark($start);
|
||||
} else {
|
||||
return 'm' == $dec ? Debug::getRangeMem($start, $end) : Debug::getRangeTime($start, $end, $dec);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('lang')) {
|
||||
/**
|
||||
* 获取语言变量值
|
||||
* @param string $name 语言变量名
|
||||
* @param array $vars 动态变量值
|
||||
* @param string $lang 语言
|
||||
* @return mixed
|
||||
*/
|
||||
function lang($name, $vars = [], $lang = '')
|
||||
{
|
||||
return Lang::get($name, $vars, $lang);
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('config')) {
|
||||
/**
|
||||
* 获取和设置配置参数
|
||||
* @param string|array $name 参数名
|
||||
* @param mixed $value 参数值
|
||||
* @param string $range 作用域
|
||||
* @return mixed
|
||||
*/
|
||||
function config($name = '', $value = null, $range = '')
|
||||
{
|
||||
if (is_null($value) && is_string($name)) {
|
||||
return 0 === strpos($name, '?') ? Config::has(substr($name, 1), $range) : Config::get($name, $range);
|
||||
} else {
|
||||
return Config::set($name, $value, $range);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('input')) {
|
||||
/**
|
||||
* 获取输入数据 支持默认值和过滤
|
||||
* @param string $key 获取的变量名
|
||||
* @param mixed $default 默认值
|
||||
* @param string $filter 过滤方法
|
||||
* @return mixed
|
||||
*/
|
||||
function input($key = '', $default = null, $filter = '')
|
||||
{
|
||||
if (0 === strpos($key, '?')) {
|
||||
$key = substr($key, 1);
|
||||
$has = true;
|
||||
}
|
||||
if ($pos = strpos($key, '.')) {
|
||||
// 指定参数来源
|
||||
list($method, $key) = explode('.', $key, 2);
|
||||
if (!in_array($method, ['get', 'post', 'put', 'patch', 'delete', 'route', 'param', 'request', 'session', 'cookie', 'server', 'env', 'path', 'file'])) {
|
||||
$key = $method . '.' . $key;
|
||||
$method = 'param';
|
||||
}
|
||||
} else {
|
||||
// 默认为自动判断
|
||||
$method = 'param';
|
||||
}
|
||||
if (isset($has)) {
|
||||
return request()->has($key, $method, $default);
|
||||
} else {
|
||||
return request()->$method($key, $default, $filter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('widget')) {
|
||||
/**
|
||||
* 渲染输出Widget
|
||||
* @param string $name Widget名称
|
||||
* @param array $data 传入的参数
|
||||
* @return mixed
|
||||
*/
|
||||
function widget($name, $data = [])
|
||||
{
|
||||
return Loader::action($name, $data, 'widget');
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('model')) {
|
||||
/**
|
||||
* 实例化Model
|
||||
* @param string $name Model名称
|
||||
* @param string $layer 业务层名称
|
||||
* @param bool $appendSuffix 是否添加类名后缀
|
||||
* @return \think\Model
|
||||
*/
|
||||
function model($name = '', $layer = 'model', $appendSuffix = false)
|
||||
{
|
||||
return Loader::model($name, $layer, $appendSuffix);
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('validate')) {
|
||||
/**
|
||||
* 实例化验证器
|
||||
* @param string $name 验证器名称
|
||||
* @param string $layer 业务层名称
|
||||
* @param bool $appendSuffix 是否添加类名后缀
|
||||
* @return \think\Validate
|
||||
*/
|
||||
function validate($name = '', $layer = 'validate', $appendSuffix = false)
|
||||
{
|
||||
return Loader::validate($name, $layer, $appendSuffix);
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('db')) {
|
||||
/**
|
||||
* 实例化数据库类
|
||||
* @param string $name 操作的数据表名称(不含前缀)
|
||||
* @param array|string $config 数据库配置参数
|
||||
* @param bool $force 是否强制重新连接
|
||||
* @return \think\db\Query
|
||||
*/
|
||||
function db($name = '', $config = [], $force = false)
|
||||
{
|
||||
return Db::connect($config, $force)->name($name);
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('controller')) {
|
||||
/**
|
||||
* 实例化控制器 格式:[模块/]控制器
|
||||
* @param string $name 资源地址
|
||||
* @param string $layer 控制层名称
|
||||
* @param bool $appendSuffix 是否添加类名后缀
|
||||
* @return \think\Controller
|
||||
*/
|
||||
function controller($name, $layer = 'controller', $appendSuffix = false)
|
||||
{
|
||||
return Loader::controller($name, $layer, $appendSuffix);
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('action')) {
|
||||
/**
|
||||
* 调用模块的操作方法 参数格式 [模块/控制器/]操作
|
||||
* @param string $url 调用地址
|
||||
* @param string|array $vars 调用参数 支持字符串和数组
|
||||
* @param string $layer 要调用的控制层名称
|
||||
* @param bool $appendSuffix 是否添加类名后缀
|
||||
* @return mixed
|
||||
*/
|
||||
function action($url, $vars = [], $layer = 'controller', $appendSuffix = false)
|
||||
{
|
||||
return Loader::action($url, $vars, $layer, $appendSuffix);
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('import')) {
|
||||
/**
|
||||
* 导入所需的类库 同java的Import 本函数有缓存功能
|
||||
* @param string $class 类库命名空间字符串
|
||||
* @param string $baseUrl 起始路径
|
||||
* @param string $ext 导入的文件扩展名
|
||||
* @return boolean
|
||||
*/
|
||||
function import($class, $baseUrl = '', $ext = EXT)
|
||||
{
|
||||
return Loader::import($class, $baseUrl, $ext);
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('vendor')) {
|
||||
/**
|
||||
* 快速导入第三方框架类库 所有第三方框架的类库文件统一放到 系统的Vendor目录下面
|
||||
* @param string $class 类库
|
||||
* @param string $ext 类库后缀
|
||||
* @return boolean
|
||||
*/
|
||||
function vendor($class, $ext = EXT)
|
||||
{
|
||||
return Loader::import($class, VENDOR_PATH, $ext);
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('dump')) {
|
||||
/**
|
||||
* 浏览器友好的变量输出
|
||||
* @param mixed $var 变量
|
||||
* @param boolean $echo 是否输出 默认为true 如果为false 则返回输出字符串
|
||||
* @param string $label 标签 默认为空
|
||||
* @return void|string
|
||||
*/
|
||||
function dump($var, $echo = true, $label = null)
|
||||
{
|
||||
return Debug::dump($var, $echo, $label);
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('url')) {
|
||||
/**
|
||||
* Url生成
|
||||
* @param string $url 路由地址
|
||||
* @param string|array $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('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 ? null : $value);
|
||||
} elseif ('' === $value) {
|
||||
// 判断或获取
|
||||
return 0 === strpos($name, '?') ? Session::has(substr($name, 1), $prefix) : Session::get($name, $prefix);
|
||||
} elseif (is_null($value)) {
|
||||
// 删除
|
||||
return Session::delete($name, $prefix);
|
||||
} else {
|
||||
// 设置
|
||||
return Session::set($name, $value, $prefix);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('cookie')) {
|
||||
/**
|
||||
* Cookie管理
|
||||
* @param string|array $name cookie名称,如果为数组表示进行cookie设置
|
||||
* @param mixed $value cookie值
|
||||
* @param mixed $option 参数
|
||||
* @return mixed
|
||||
*/
|
||||
function cookie($name, $value = '', $option = null)
|
||||
{
|
||||
if (is_array($name)) {
|
||||
// 初始化
|
||||
Cookie::init($name);
|
||||
} elseif (is_null($name)) {
|
||||
// 清除
|
||||
Cookie::clear($value);
|
||||
} elseif ('' === $value) {
|
||||
// 获取
|
||||
return 0 === strpos($name, '?') ? Cookie::has(substr($name, 1), $option) : Cookie::get($name, $option);
|
||||
} elseif (is_null($value)) {
|
||||
// 删除
|
||||
return Cookie::delete($name);
|
||||
} else {
|
||||
// 设置
|
||||
return Cookie::set($name, $value, $option);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('cache')) {
|
||||
/**
|
||||
* 缓存管理
|
||||
* @param mixed $name 缓存名称,如果为数组表示进行缓存设置
|
||||
* @param mixed $value 缓存值
|
||||
* @param mixed $options 缓存参数
|
||||
* @param string $tag 缓存标签
|
||||
* @return mixed
|
||||
*/
|
||||
function cache($name, $value = '', $options = null, $tag = null)
|
||||
{
|
||||
if (is_array($options)) {
|
||||
// 缓存操作的同时初始化
|
||||
$cache = Cache::connect($options);
|
||||
} elseif (is_array($name)) {
|
||||
// 缓存初始化
|
||||
return Cache::connect($name);
|
||||
} else {
|
||||
$cache = Cache::init();
|
||||
}
|
||||
|
||||
if (is_null($name)) {
|
||||
return $cache->clear($value);
|
||||
} elseif ('' === $value) {
|
||||
// 获取缓存
|
||||
return 0 === strpos($name, '?') ? $cache->has(substr($name, 1)) : $cache->get($name);
|
||||
} elseif (is_null($value)) {
|
||||
// 删除缓存
|
||||
return $cache->rm($name);
|
||||
} elseif (0 === strpos($name, '?') && '' !== $value) {
|
||||
$expire = is_numeric($options) ? $options : null;
|
||||
return $cache->remember(substr($name, 1), $value, $expire);
|
||||
} 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('trace')) {
|
||||
/**
|
||||
* 记录日志信息
|
||||
* @param mixed $log log信息 支持字符串和数组
|
||||
* @param string $level 日志级别
|
||||
* @return void|array
|
||||
*/
|
||||
function trace($log = '[think]', $level = 'log')
|
||||
{
|
||||
if ('[think]' === $log) {
|
||||
return Log::getLog();
|
||||
} else {
|
||||
Log::record($log, $level);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('request')) {
|
||||
/**
|
||||
* 获取当前Request对象实例
|
||||
* @return Request
|
||||
*/
|
||||
function request()
|
||||
{
|
||||
return Request::instance();
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('response')) {
|
||||
/**
|
||||
* 创建普通 Response 对象实例
|
||||
* @param mixed $data 输出数据
|
||||
* @param int|string $code 状态码
|
||||
* @param array $header 头信息
|
||||
* @param string $type
|
||||
* @return Response
|
||||
*/
|
||||
function response($data = [], $code = 200, $header = [], $type = 'html')
|
||||
{
|
||||
return Response::create($data, $type, $code, $header);
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('view')) {
|
||||
/**
|
||||
* 渲染模板输出
|
||||
* @param string $template 模板文件
|
||||
* @param array $vars 模板变量
|
||||
* @param array $replace 模板替换
|
||||
* @param integer $code 状态码
|
||||
* @return \think\response\View
|
||||
*/
|
||||
function view($template = '', $vars = [], $replace = [], $code = 200)
|
||||
{
|
||||
return Response::create($template, 'view', $code)->replace($replace)->assign($vars);
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('json')) {
|
||||
/**
|
||||
* 获取\think\response\Json对象实例
|
||||
* @param mixed $data 返回的数据
|
||||
* @param integer $code 状态码
|
||||
* @param array $header 头部
|
||||
* @param array $options 参数
|
||||
* @return \think\response\Json
|
||||
*/
|
||||
function json($data = [], $code = 200, $header = [], $options = [])
|
||||
{
|
||||
return Response::create($data, 'json', $code, $header, $options);
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('jsonp')) {
|
||||
/**
|
||||
* 获取\think\response\Jsonp对象实例
|
||||
* @param mixed $data 返回的数据
|
||||
* @param integer $code 状态码
|
||||
* @param array $header 头部
|
||||
* @param array $options 参数
|
||||
* @return \think\response\Jsonp
|
||||
*/
|
||||
function jsonp($data = [], $code = 200, $header = [], $options = [])
|
||||
{
|
||||
return Response::create($data, 'jsonp', $code, $header, $options);
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('xml')) {
|
||||
/**
|
||||
* 获取\think\response\Xml对象实例
|
||||
* @param mixed $data 返回的数据
|
||||
* @param integer $code 状态码
|
||||
* @param array $header 头部
|
||||
* @param array $options 参数
|
||||
* @return \think\response\Xml
|
||||
*/
|
||||
function xml($data = [], $code = 200, $header = [], $options = [])
|
||||
{
|
||||
return Response::create($data, 'xml', $code, $header, $options);
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('redirect')) {
|
||||
/**
|
||||
* 获取\think\response\Redirect对象实例
|
||||
* @param mixed $url 重定向地址 支持Url::build方法的地址
|
||||
* @param array|integer $params 额外参数
|
||||
* @param integer $code 状态码
|
||||
* @param array $with 隐式传参
|
||||
* @return \think\response\Redirect
|
||||
*/
|
||||
function redirect($url = [], $params = [], $code = 302, $with = [])
|
||||
{
|
||||
if (is_integer($params)) {
|
||||
$code = $params;
|
||||
$params = [];
|
||||
}
|
||||
return Response::create($url, 'redirect', $code)->params($params)->with($with);
|
||||
}
|
||||
}
|
||||
|
||||
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('halt')) {
|
||||
/**
|
||||
* 调试变量并且中断输出
|
||||
* @param mixed $var 调试变量或者信息
|
||||
*/
|
||||
function halt($var)
|
||||
{
|
||||
dump($var);
|
||||
throw new HttpResponseException(new Response);
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('token')) {
|
||||
/**
|
||||
* 生成表单令牌
|
||||
* @param string $name 令牌名称
|
||||
* @param mixed $type 令牌生成方法
|
||||
* @return string
|
||||
*/
|
||||
function token($name = '__token__', $type = 'md5')
|
||||
{
|
||||
$token = Request::instance()->token($name, $type);
|
||||
return '<input type="hidden" name="' . $name . '" value="' . $token . '" />';
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('load_relation')) {
|
||||
/**
|
||||
* 延迟预载入关联查询
|
||||
* @param mixed $resultSet 数据集
|
||||
* @param mixed $relation 关联
|
||||
* @return array
|
||||
*/
|
||||
function load_relation($resultSet, $relation)
|
||||
{
|
||||
$item = current($resultSet);
|
||||
if ($item instanceof Model) {
|
||||
$item->eagerlyResultSet($resultSet, $relation);
|
||||
}
|
||||
return $resultSet;
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('collection')) {
|
||||
/**
|
||||
* 数组转换为数据集对象
|
||||
* @param array $resultSet 数据集数组
|
||||
* @return \think\model\Collection|\think\Collection
|
||||
*/
|
||||
function collection($resultSet)
|
||||
{
|
||||
$item = current($resultSet);
|
||||
if ($item instanceof Model) {
|
||||
return \think\model\Collection::make($resultSet);
|
||||
} else {
|
||||
return \think\Collection::make($resultSet);
|
||||
}
|
||||
}
|
||||
}
|
69
thinkphp/lang/zh-cn.php
Normal file
69
thinkphp/lang/zh-cn.php
Normal file
@ -0,0 +1,69 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
// 核心中文语言包
|
||||
return [
|
||||
// 系统错误提示
|
||||
'Undefined variable' => '未定义变量',
|
||||
'Undefined index' => '未定义数组索引',
|
||||
'Undefined offset' => '未定义数组下标',
|
||||
'Parse error' => '语法解析错误',
|
||||
'Type error' => '类型错误',
|
||||
'Fatal error' => '致命错误',
|
||||
'syntax error' => '语法错误',
|
||||
|
||||
// 框架核心错误提示
|
||||
'dispatch type not support' => '不支持的调度类型',
|
||||
'method param miss' => '方法参数错误',
|
||||
'method not exists' => '方法不存在',
|
||||
'module not exists' => '模块不存在',
|
||||
'controller not exists' => '控制器不存在',
|
||||
'class not exists' => '类不存在',
|
||||
'property not exists' => '类的属性不存在',
|
||||
'template not exists' => '模板文件不存在',
|
||||
'illegal controller name' => '非法的控制器名称',
|
||||
'illegal action name' => '非法的操作名称',
|
||||
'url suffix deny' => '禁止的URL后缀访问',
|
||||
'Route Not Found' => '当前访问路由未定义',
|
||||
'Undefined db type' => '未定义数据库类型',
|
||||
'variable type error' => '变量类型错误',
|
||||
'PSR-4 error' => 'PSR-4 规范错误',
|
||||
'not support total' => '简洁模式下不能获取数据总数',
|
||||
'not support last' => '简洁模式下不能获取最后一页',
|
||||
'error session handler' => '错误的SESSION处理器类',
|
||||
'not allow php tag' => '模板不允许使用PHP语法',
|
||||
'not support' => '不支持',
|
||||
'redisd master' => 'Redisd 主服务器错误',
|
||||
'redisd slave' => 'Redisd 从服务器错误',
|
||||
'must run at sae' => '必须在SAE运行',
|
||||
'memcache init error' => '未开通Memcache服务,请在SAE管理平台初始化Memcache服务',
|
||||
'KVDB init error' => '没有初始化KVDB,请在SAE管理平台初始化KVDB服务',
|
||||
'fields not exists' => '数据表字段不存在',
|
||||
'where express error' => '查询表达式错误',
|
||||
'no data to update' => '没有任何数据需要更新',
|
||||
'miss data to insert' => '缺少需要写入的数据',
|
||||
'miss complex primary data' => '缺少复合主键数据',
|
||||
'miss update condition' => '缺少更新条件',
|
||||
'model data Not Found' => '模型数据不存在',
|
||||
'table data not Found' => '表数据不存在',
|
||||
'delete without condition' => '没有条件不会执行删除操作',
|
||||
'miss relation data' => '缺少关联表数据',
|
||||
'tag attr must' => '模板标签属性必须',
|
||||
'tag error' => '模板标签错误',
|
||||
'cache write error' => '缓存写入失败',
|
||||
'sae mc write error' => 'SAE mc 写入错误',
|
||||
'route name not exists' => '路由标识不存在(或参数不够)',
|
||||
'invalid request' => '非法请求',
|
||||
'bind attr has exists' => '模型的属性已经存在',
|
||||
'relation data not exists' => '关联数据不存在',
|
||||
'relation not support' => '关联不支持',
|
||||
'chunk not support order' => 'Chunk不支持调用order方法',
|
||||
];
|
591
thinkphp/library/think/App.php
Normal file
591
thinkphp/library/think/App.php
Normal file
@ -0,0 +1,591 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2017 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\HttpException;
|
||||
use think\exception\HttpResponseException;
|
||||
use think\exception\RouteNotFoundException;
|
||||
|
||||
/**
|
||||
* App 应用管理
|
||||
* @author liu21st <liu21st@gmail.com>
|
||||
*/
|
||||
class App
|
||||
{
|
||||
/**
|
||||
* @var bool 是否初始化过
|
||||
*/
|
||||
protected static $init = false;
|
||||
|
||||
/**
|
||||
* @var string 当前模块路径
|
||||
*/
|
||||
public static $modulePath;
|
||||
|
||||
/**
|
||||
* @var bool 应用调试模式
|
||||
*/
|
||||
public static $debug = true;
|
||||
|
||||
/**
|
||||
* @var string 应用类库命名空间
|
||||
*/
|
||||
public static $namespace = 'app';
|
||||
|
||||
/**
|
||||
* @var bool 应用类库后缀
|
||||
*/
|
||||
public static $suffix = false;
|
||||
|
||||
/**
|
||||
* @var bool 应用路由检测
|
||||
*/
|
||||
protected static $routeCheck;
|
||||
|
||||
/**
|
||||
* @var bool 严格路由检测
|
||||
*/
|
||||
protected static $routeMust;
|
||||
|
||||
protected static $dispatch;
|
||||
protected static $file = [];
|
||||
|
||||
/**
|
||||
* 执行应用程序
|
||||
* @access public
|
||||
* @param Request $request Request对象
|
||||
* @return Response
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function run(Request $request = null)
|
||||
{
|
||||
is_null($request) && $request = Request::instance();
|
||||
|
||||
try {
|
||||
$config = self::initCommon();
|
||||
if (defined('BIND_MODULE')) {
|
||||
// 模块/控制器绑定
|
||||
BIND_MODULE && Route::bind(BIND_MODULE);
|
||||
} elseif ($config['auto_bind_module']) {
|
||||
// 入口自动绑定
|
||||
$name = pathinfo($request->baseFile(), PATHINFO_FILENAME);
|
||||
if ($name && 'index' != $name && is_dir(APP_PATH . $name)) {
|
||||
Route::bind($name);
|
||||
}
|
||||
}
|
||||
|
||||
$request->filter($config['default_filter']);
|
||||
|
||||
// 默认语言
|
||||
Lang::range($config['default_lang']);
|
||||
if ($config['lang_switch_on']) {
|
||||
// 开启多语言机制 检测当前语言
|
||||
Lang::detect();
|
||||
}
|
||||
$request->langset(Lang::range());
|
||||
|
||||
// 加载系统语言包
|
||||
Lang::load([
|
||||
THINK_PATH . 'lang' . DS . $request->langset() . EXT,
|
||||
APP_PATH . 'lang' . DS . $request->langset() . EXT,
|
||||
]);
|
||||
|
||||
// 获取应用调度信息
|
||||
$dispatch = self::$dispatch;
|
||||
if (empty($dispatch)) {
|
||||
// 进行URL路由检测
|
||||
$dispatch = self::routeCheck($request, $config);
|
||||
}
|
||||
// 记录当前调度信息
|
||||
$request->dispatch($dispatch);
|
||||
|
||||
// 记录路由和请求信息
|
||||
if (self::$debug) {
|
||||
Log::record('[ ROUTE ] ' . var_export($dispatch, true), 'info');
|
||||
Log::record('[ HEADER ] ' . var_export($request->header(), true), 'info');
|
||||
Log::record('[ PARAM ] ' . var_export($request->param(), true), 'info');
|
||||
}
|
||||
|
||||
// 监听app_begin
|
||||
Hook::listen('app_begin', $dispatch);
|
||||
// 请求缓存检查
|
||||
$request->cache($config['request_cache'], $config['request_cache_expire'], $config['request_cache_except']);
|
||||
|
||||
$data = self::exec($dispatch, $config);
|
||||
} catch (HttpResponseException $exception) {
|
||||
$data = $exception->getResponse();
|
||||
}
|
||||
|
||||
// 清空类的实例化
|
||||
Loader::clearInstance();
|
||||
|
||||
// 输出数据到客户端
|
||||
if ($data instanceof Response) {
|
||||
$response = $data;
|
||||
} elseif (!is_null($data)) {
|
||||
// 默认自动识别响应输出类型
|
||||
$isAjax = $request->isAjax();
|
||||
$type = $isAjax ? Config::get('default_ajax_return') : Config::get('default_return_type');
|
||||
$response = Response::create($data, $type);
|
||||
} else {
|
||||
$response = Response::create();
|
||||
}
|
||||
|
||||
// 监听app_end
|
||||
Hook::listen('app_end', $response);
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置当前请求的调度信息
|
||||
* @access public
|
||||
* @param array|string $dispatch 调度信息
|
||||
* @param string $type 调度类型
|
||||
* @return void
|
||||
*/
|
||||
public static function dispatch($dispatch, $type = 'module')
|
||||
{
|
||||
self::$dispatch = ['type' => $type, $type => $dispatch];
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行函数或者闭包方法 支持参数调用
|
||||
* @access public
|
||||
* @param string|array|\Closure $function 函数或者闭包
|
||||
* @param array $vars 变量
|
||||
* @return mixed
|
||||
*/
|
||||
public static function invokeFunction($function, $vars = [])
|
||||
{
|
||||
$reflect = new \ReflectionFunction($function);
|
||||
$args = self::bindParams($reflect, $vars);
|
||||
// 记录执行信息
|
||||
self::$debug && Log::record('[ RUN ] ' . $reflect->__toString(), 'info');
|
||||
return $reflect->invokeArgs($args);
|
||||
}
|
||||
|
||||
/**
|
||||
* 调用反射执行类的方法 支持参数绑定
|
||||
* @access public
|
||||
* @param string|array $method 方法
|
||||
* @param array $vars 变量
|
||||
* @return mixed
|
||||
*/
|
||||
public static function invokeMethod($method, $vars = [])
|
||||
{
|
||||
if (is_array($method)) {
|
||||
$class = is_object($method[0]) ? $method[0] : self::invokeClass($method[0]);
|
||||
$reflect = new \ReflectionMethod($class, $method[1]);
|
||||
} else {
|
||||
// 静态方法
|
||||
$reflect = new \ReflectionMethod($method);
|
||||
}
|
||||
$args = self::bindParams($reflect, $vars);
|
||||
|
||||
self::$debug && Log::record('[ RUN ] ' . $reflect->class . '->' . $reflect->name . '[ ' . $reflect->getFileName() . ' ]', 'info');
|
||||
return $reflect->invokeArgs(isset($class) ? $class : null, $args);
|
||||
}
|
||||
|
||||
/**
|
||||
* 调用反射执行类的实例化 支持依赖注入
|
||||
* @access public
|
||||
* @param string $class 类名
|
||||
* @param array $vars 变量
|
||||
* @return mixed
|
||||
*/
|
||||
public static function invokeClass($class, $vars = [])
|
||||
{
|
||||
$reflect = new \ReflectionClass($class);
|
||||
$constructor = $reflect->getConstructor();
|
||||
if ($constructor) {
|
||||
$args = self::bindParams($constructor, $vars);
|
||||
} else {
|
||||
$args = [];
|
||||
}
|
||||
return $reflect->newInstanceArgs($args);
|
||||
}
|
||||
|
||||
/**
|
||||
* 绑定参数
|
||||
* @access private
|
||||
* @param \ReflectionMethod|\ReflectionFunction $reflect 反射类
|
||||
* @param array $vars 变量
|
||||
* @return array
|
||||
*/
|
||||
private static function bindParams($reflect, $vars = [])
|
||||
{
|
||||
if (empty($vars)) {
|
||||
// 自动获取请求变量
|
||||
if (Config::get('url_param_type')) {
|
||||
$vars = Request::instance()->route();
|
||||
} else {
|
||||
$vars = Request::instance()->param();
|
||||
}
|
||||
}
|
||||
$args = [];
|
||||
if ($reflect->getNumberOfParameters() > 0) {
|
||||
// 判断数组类型 数字数组时按顺序绑定参数
|
||||
reset($vars);
|
||||
$type = key($vars) === 0 ? 1 : 0;
|
||||
$params = $reflect->getParameters();
|
||||
foreach ($params as $param) {
|
||||
$args[] = self::getParamValue($param, $vars, $type);
|
||||
}
|
||||
}
|
||||
return $args;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取参数值
|
||||
* @access private
|
||||
* @param \ReflectionParameter $param
|
||||
* @param array $vars 变量
|
||||
* @param string $type
|
||||
* @return array
|
||||
*/
|
||||
private static function getParamValue($param, &$vars, $type)
|
||||
{
|
||||
$name = $param->getName();
|
||||
$class = $param->getClass();
|
||||
if ($class) {
|
||||
$className = $class->getName();
|
||||
$bind = Request::instance()->$name;
|
||||
if ($bind instanceof $className) {
|
||||
$result = $bind;
|
||||
} else {
|
||||
if (method_exists($className, 'invoke')) {
|
||||
$method = new \ReflectionMethod($className, 'invoke');
|
||||
if ($method->isPublic() && $method->isStatic()) {
|
||||
return $className::invoke(Request::instance());
|
||||
}
|
||||
}
|
||||
$result = method_exists($className, 'instance') ? $className::instance() : new $className;
|
||||
}
|
||||
} elseif (1 == $type && !empty($vars)) {
|
||||
$result = array_shift($vars);
|
||||
} elseif (0 == $type && isset($vars[$name])) {
|
||||
$result = $vars[$name];
|
||||
} elseif ($param->isDefaultValueAvailable()) {
|
||||
$result = $param->getDefaultValue();
|
||||
} else {
|
||||
throw new \InvalidArgumentException('method param miss:' . $name);
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
protected static function exec($dispatch, $config)
|
||||
{
|
||||
switch ($dispatch['type']) {
|
||||
case 'redirect':
|
||||
// 执行重定向跳转
|
||||
$data = Response::create($dispatch['url'], 'redirect')->code($dispatch['status']);
|
||||
break;
|
||||
case 'module':
|
||||
// 模块/控制器/操作
|
||||
$data = self::module($dispatch['module'], $config, isset($dispatch['convert']) ? $dispatch['convert'] : null);
|
||||
break;
|
||||
case 'controller':
|
||||
// 执行控制器操作
|
||||
$vars = array_merge(Request::instance()->param(), $dispatch['var']);
|
||||
$data = Loader::action($dispatch['controller'], $vars, $config['url_controller_layer'], $config['controller_suffix']);
|
||||
break;
|
||||
case 'method':
|
||||
// 执行回调方法
|
||||
$vars = array_merge(Request::instance()->param(), $dispatch['var']);
|
||||
$data = self::invokeMethod($dispatch['method'], $vars);
|
||||
break;
|
||||
case 'function':
|
||||
// 执行闭包
|
||||
$data = self::invokeFunction($dispatch['function']);
|
||||
break;
|
||||
case 'response':
|
||||
$data = $dispatch['response'];
|
||||
break;
|
||||
default:
|
||||
throw new \InvalidArgumentException('dispatch type not support');
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行模块
|
||||
* @access public
|
||||
* @param array $result 模块/控制器/操作
|
||||
* @param array $config 配置参数
|
||||
* @param bool $convert 是否自动转换控制器和操作名
|
||||
* @return mixed
|
||||
*/
|
||||
public static function module($result, $config, $convert = null)
|
||||
{
|
||||
if (is_string($result)) {
|
||||
$result = explode('/', $result);
|
||||
}
|
||||
$request = Request::instance();
|
||||
if ($config['app_multi_module']) {
|
||||
// 多模块部署
|
||||
$module = strip_tags(strtolower($result[0] ?: $config['default_module']));
|
||||
$bind = Route::getBind('module');
|
||||
$available = false;
|
||||
if ($bind) {
|
||||
// 绑定模块
|
||||
list($bindModule) = explode('/', $bind);
|
||||
if (empty($result[0])) {
|
||||
$module = $bindModule;
|
||||
$available = true;
|
||||
} elseif ($module == $bindModule) {
|
||||
$available = true;
|
||||
}
|
||||
} elseif (!in_array($module, $config['deny_module_list']) && is_dir(APP_PATH . $module)) {
|
||||
$available = true;
|
||||
}
|
||||
|
||||
// 模块初始化
|
||||
if ($module && $available) {
|
||||
// 初始化模块
|
||||
$request->module($module);
|
||||
$config = self::init($module);
|
||||
// 模块请求缓存检查
|
||||
$request->cache($config['request_cache'], $config['request_cache_expire'], $config['request_cache_except']);
|
||||
} else {
|
||||
throw new HttpException(404, 'module not exists:' . $module);
|
||||
}
|
||||
} else {
|
||||
// 单一模块部署
|
||||
$module = '';
|
||||
$request->module($module);
|
||||
}
|
||||
// 当前模块路径
|
||||
App::$modulePath = APP_PATH . ($module ? $module . DS : '');
|
||||
|
||||
// 是否自动转换控制器和操作名
|
||||
$convert = is_bool($convert) ? $convert : $config['url_convert'];
|
||||
// 获取控制器名
|
||||
$controller = strip_tags($result[1] ?: $config['default_controller']);
|
||||
$controller = $convert ? strtolower($controller) : $controller;
|
||||
|
||||
// 获取操作名
|
||||
$actionName = strip_tags($result[2] ?: $config['default_action']);
|
||||
$actionName = $convert ? strtolower($actionName) : $actionName;
|
||||
|
||||
// 设置当前请求的控制器、操作
|
||||
$request->controller(Loader::parseName($controller, 1))->action($actionName);
|
||||
|
||||
// 监听module_init
|
||||
Hook::listen('module_init', $request);
|
||||
|
||||
try {
|
||||
$instance = Loader::controller($controller, $config['url_controller_layer'], $config['controller_suffix'], $config['empty_controller']);
|
||||
} catch (ClassNotFoundException $e) {
|
||||
throw new HttpException(404, 'controller not exists:' . $e->getClass());
|
||||
}
|
||||
|
||||
// 获取当前操作名
|
||||
$action = $actionName . $config['action_suffix'];
|
||||
|
||||
$vars = [];
|
||||
if (is_callable([$instance, $action])) {
|
||||
// 执行操作方法
|
||||
$call = [$instance, $action];
|
||||
} elseif (is_callable([$instance, '_empty'])) {
|
||||
// 空操作
|
||||
$call = [$instance, '_empty'];
|
||||
$vars = [$actionName];
|
||||
} else {
|
||||
// 操作不存在
|
||||
throw new HttpException(404, 'method not exists:' . get_class($instance) . '->' . $action . '()');
|
||||
}
|
||||
|
||||
Hook::listen('action_begin', $call);
|
||||
|
||||
return self::invokeMethod($call, $vars);
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化应用
|
||||
*/
|
||||
public static function initCommon()
|
||||
{
|
||||
if (empty(self::$init)) {
|
||||
if (defined('APP_NAMESPACE')) {
|
||||
self::$namespace = APP_NAMESPACE;
|
||||
}
|
||||
Loader::addNamespace(self::$namespace, APP_PATH);
|
||||
|
||||
// 初始化应用
|
||||
$config = self::init();
|
||||
self::$suffix = $config['class_suffix'];
|
||||
|
||||
// 应用调试模式
|
||||
self::$debug = Env::get('app_debug', Config::get('app_debug'));
|
||||
if (!self::$debug) {
|
||||
ini_set('display_errors', 'Off');
|
||||
} elseif (!IS_CLI) {
|
||||
//重新申请一块比较大的buffer
|
||||
if (ob_get_level() > 0) {
|
||||
$output = ob_get_clean();
|
||||
}
|
||||
ob_start();
|
||||
if (!empty($output)) {
|
||||
echo $output;
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($config['root_namespace'])) {
|
||||
Loader::addNamespace($config['root_namespace']);
|
||||
}
|
||||
|
||||
// 加载额外文件
|
||||
if (!empty($config['extra_file_list'])) {
|
||||
foreach ($config['extra_file_list'] as $file) {
|
||||
$file = strpos($file, '.') ? $file : APP_PATH . $file . EXT;
|
||||
if (is_file($file) && !isset(self::$file[$file])) {
|
||||
include $file;
|
||||
self::$file[$file] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 设置系统时区
|
||||
date_default_timezone_set($config['default_timezone']);
|
||||
|
||||
// 监听app_init
|
||||
Hook::listen('app_init');
|
||||
|
||||
self::$init = true;
|
||||
}
|
||||
return Config::get();
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化应用或模块
|
||||
* @access public
|
||||
* @param string $module 模块名
|
||||
* @return array
|
||||
*/
|
||||
private static function init($module = '')
|
||||
{
|
||||
// 定位模块目录
|
||||
$module = $module ? $module . DS : '';
|
||||
|
||||
// 加载初始化文件
|
||||
if (is_file(APP_PATH . $module . 'init' . EXT)) {
|
||||
include APP_PATH . $module . 'init' . EXT;
|
||||
} elseif (is_file(RUNTIME_PATH . $module . 'init' . EXT)) {
|
||||
include RUNTIME_PATH . $module . 'init' . EXT;
|
||||
} else {
|
||||
$path = APP_PATH . $module;
|
||||
// 加载模块配置
|
||||
$config = Config::load(CONF_PATH . $module . 'config' . CONF_EXT);
|
||||
// 读取数据库配置文件
|
||||
$filename = CONF_PATH . $module . 'database' . CONF_EXT;
|
||||
Config::load($filename, 'database');
|
||||
// 读取扩展配置文件
|
||||
if (is_dir(CONF_PATH . $module . 'extra')) {
|
||||
$dir = CONF_PATH . $module . 'extra';
|
||||
$files = scandir($dir);
|
||||
foreach ($files as $file) {
|
||||
if ('.' . pathinfo($file, PATHINFO_EXTENSION) === CONF_EXT) {
|
||||
$filename = $dir . DS . $file;
|
||||
Config::load($filename, pathinfo($file, PATHINFO_FILENAME));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 加载应用状态配置
|
||||
if ($config['app_status']) {
|
||||
$config = Config::load(CONF_PATH . $module . $config['app_status'] . CONF_EXT);
|
||||
}
|
||||
|
||||
// 加载行为扩展文件
|
||||
if (is_file(CONF_PATH . $module . 'tags' . EXT)) {
|
||||
Hook::import(include CONF_PATH . $module . 'tags' . EXT);
|
||||
}
|
||||
|
||||
// 加载公共文件
|
||||
if (is_file($path . 'common' . EXT)) {
|
||||
include $path . 'common' . EXT;
|
||||
}
|
||||
|
||||
// 加载当前模块语言包
|
||||
if ($module) {
|
||||
Lang::load($path . 'lang' . DS . Request::instance()->langset() . EXT);
|
||||
}
|
||||
}
|
||||
return Config::get();
|
||||
}
|
||||
|
||||
/**
|
||||
* URL路由检测(根据PATH_INFO)
|
||||
* @access public
|
||||
* @param \think\Request $request
|
||||
* @param array $config
|
||||
* @return array
|
||||
* @throws \think\Exception
|
||||
*/
|
||||
public static function routeCheck($request, array $config)
|
||||
{
|
||||
$path = $request->path();
|
||||
$depr = $config['pathinfo_depr'];
|
||||
$result = false;
|
||||
// 路由检测
|
||||
$check = !is_null(self::$routeCheck) ? self::$routeCheck : $config['url_route_on'];
|
||||
if ($check) {
|
||||
// 开启路由
|
||||
if (is_file(RUNTIME_PATH . 'route.php')) {
|
||||
// 读取路由缓存
|
||||
$rules = include RUNTIME_PATH . 'route.php';
|
||||
if (is_array($rules)) {
|
||||
Route::rules($rules);
|
||||
}
|
||||
} else {
|
||||
$files = $config['route_config_file'];
|
||||
foreach ($files as $file) {
|
||||
if (is_file(CONF_PATH . $file . CONF_EXT)) {
|
||||
// 导入路由配置
|
||||
$rules = include CONF_PATH . $file . CONF_EXT;
|
||||
if (is_array($rules)) {
|
||||
Route::import($rules);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 路由检测(根据路由定义返回不同的URL调度)
|
||||
$result = Route::check($request, $path, $depr, $config['url_domain_deploy']);
|
||||
$must = !is_null(self::$routeMust) ? self::$routeMust : $config['url_route_must'];
|
||||
if ($must && false === $result) {
|
||||
// 路由无效
|
||||
throw new RouteNotFoundException();
|
||||
}
|
||||
}
|
||||
if (false === $result) {
|
||||
// 路由无效 解析模块/控制器/操作/参数... 支持控制器自动搜索
|
||||
$result = Route::parseUrl($path, $depr, $config['controller_auto_search']);
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置应用的路由检测机制
|
||||
* @access public
|
||||
* @param bool $route 是否需要检测路由
|
||||
* @param bool $must 是否强制检测路由
|
||||
* @return void
|
||||
*/
|
||||
public static function route($route, $must = false)
|
||||
{
|
||||
self::$routeCheck = $route;
|
||||
self::$routeMust = $must;
|
||||
}
|
||||
}
|
205
thinkphp/library/think/Build.php
Normal file
205
thinkphp/library/think/Build.php
Normal file
@ -0,0 +1,205 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace think;
|
||||
|
||||
class Build
|
||||
{
|
||||
/**
|
||||
* 根据传入的build资料创建目录和文件
|
||||
* @access protected
|
||||
* @param array $build build列表
|
||||
* @param string $namespace 应用类库命名空间
|
||||
* @param bool $suffix 类库后缀
|
||||
* @return void
|
||||
*/
|
||||
public static function run(array $build = [], $namespace = 'app', $suffix = false)
|
||||
{
|
||||
// 锁定
|
||||
$lockfile = APP_PATH . 'build.lock';
|
||||
if (is_writable($lockfile)) {
|
||||
return;
|
||||
} elseif (!touch($lockfile)) {
|
||||
throw new Exception('应用目录[' . APP_PATH . ']不可写,目录无法自动生成!<BR>请手动生成项目目录~', 10006);
|
||||
}
|
||||
foreach ($build as $module => $list) {
|
||||
if ('__dir__' == $module) {
|
||||
// 创建目录列表
|
||||
self::buildDir($list);
|
||||
} elseif ('__file__' == $module) {
|
||||
// 创建文件列表
|
||||
self::buildFile($list);
|
||||
} else {
|
||||
// 创建模块
|
||||
self::module($module, $list, $namespace, $suffix);
|
||||
}
|
||||
}
|
||||
// 解除锁定
|
||||
unlink($lockfile);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建目录
|
||||
* @access protected
|
||||
* @param array $list 目录列表
|
||||
* @return void
|
||||
*/
|
||||
protected static function buildDir($list)
|
||||
{
|
||||
foreach ($list as $dir) {
|
||||
if (!is_dir(APP_PATH . $dir)) {
|
||||
// 创建目录
|
||||
mkdir(APP_PATH . $dir, 0755, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建文件
|
||||
* @access protected
|
||||
* @param array $list 文件列表
|
||||
* @return void
|
||||
*/
|
||||
protected static function buildFile($list)
|
||||
{
|
||||
foreach ($list as $file) {
|
||||
if (!is_dir(APP_PATH . dirname($file))) {
|
||||
// 创建目录
|
||||
mkdir(APP_PATH . dirname($file), 0755, true);
|
||||
}
|
||||
if (!is_file(APP_PATH . $file)) {
|
||||
file_put_contents(APP_PATH . $file, 'php' == pathinfo($file, PATHINFO_EXTENSION) ? "<?php\n" : '');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建模块
|
||||
* @access public
|
||||
* @param string $module 模块名
|
||||
* @param array $list build列表
|
||||
* @param string $namespace 应用类库命名空间
|
||||
* @param bool $suffix 类库后缀
|
||||
* @return void
|
||||
*/
|
||||
public static function module($module = '', $list = [], $namespace = 'app', $suffix = false)
|
||||
{
|
||||
$module = $module ? $module : '';
|
||||
if (!is_dir(APP_PATH . $module)) {
|
||||
// 创建模块目录
|
||||
mkdir(APP_PATH . $module);
|
||||
}
|
||||
if (basename(RUNTIME_PATH) != $module) {
|
||||
// 创建配置文件和公共文件
|
||||
self::buildCommon($module);
|
||||
// 创建模块的默认页面
|
||||
self::buildHello($module, $namespace, $suffix);
|
||||
}
|
||||
if (empty($list)) {
|
||||
// 创建默认的模块目录和文件
|
||||
$list = [
|
||||
'__file__' => ['config.php', 'common.php'],
|
||||
'__dir__' => ['controller', 'model', 'view'],
|
||||
];
|
||||
}
|
||||
// 创建子目录和文件
|
||||
foreach ($list as $path => $file) {
|
||||
$modulePath = APP_PATH . $module . DS;
|
||||
if ('__dir__' == $path) {
|
||||
// 生成子目录
|
||||
foreach ($file as $dir) {
|
||||
self::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 . DS . $val . ($suffix ? ucfirst($path) : '') . EXT;
|
||||
$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 . DS . $val . '.html';
|
||||
self::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 string $module 模块名
|
||||
* @param string $namespace 应用类库命名空间
|
||||
* @param bool $suffix 类库后缀
|
||||
* @return void
|
||||
*/
|
||||
protected static function buildHello($module, $namespace, $suffix = false)
|
||||
{
|
||||
$filename = APP_PATH . ($module ? $module . DS : '') . 'controller' . DS . 'Index' . ($suffix ? 'Controller' : '') . EXT;
|
||||
if (!is_file($filename)) {
|
||||
$content = file_get_contents(THINK_PATH . 'tpl' . DS . 'default_index.tpl');
|
||||
$content = str_replace(['{$app}', '{$module}', '{layer}', '{$suffix}'], [$namespace, $module ? $module . '\\' : '', 'controller', $suffix ? 'Controller' : ''], $content);
|
||||
self::checkDirBuild(dirname($filename));
|
||||
file_put_contents($filename, $content);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建模块的公共文件
|
||||
* @access public
|
||||
* @param string $module 模块名
|
||||
* @return void
|
||||
*/
|
||||
protected static function buildCommon($module)
|
||||
{
|
||||
$filename = CONF_PATH . ($module ? $module . DS : '') . 'config.php';
|
||||
|
||||
self::checkDirBuild(dirname($filename));
|
||||
if (!is_file($filename)) {
|
||||
file_put_contents($filename, "<?php\n//配置文件\nreturn [\n\n];");
|
||||
}
|
||||
$filename = APP_PATH . ($module ? $module . DS : '') . 'common.php';
|
||||
if (!is_file($filename)) {
|
||||
file_put_contents($filename, "<?php\n");
|
||||
}
|
||||
}
|
||||
|
||||
protected static function checkDirBuild($dirname)
|
||||
{
|
||||
if (!is_dir($dirname)) {
|
||||
mkdir($dirname, 0755, true);
|
||||
}
|
||||
}
|
||||
}
|
222
thinkphp/library/think/Cache.php
Normal file
222
thinkphp/library/think/Cache.php
Normal file
@ -0,0 +1,222 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2017 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
|
||||
{
|
||||
protected static $instance = [];
|
||||
public static $readTimes = 0;
|
||||
public static $writeTimes = 0;
|
||||
|
||||
/**
|
||||
* 操作句柄
|
||||
* @var object
|
||||
* @access protected
|
||||
*/
|
||||
protected static $handler;
|
||||
|
||||
/**
|
||||
* 连接缓存
|
||||
* @access public
|
||||
* @param array $options 配置数组
|
||||
* @param bool|string $name 缓存连接标识 true 强制重新连接
|
||||
* @return Driver
|
||||
*/
|
||||
public static function connect(array $options = [], $name = false)
|
||||
{
|
||||
$type = !empty($options['type']) ? $options['type'] : 'File';
|
||||
if (false === $name) {
|
||||
$name = md5(serialize($options));
|
||||
}
|
||||
|
||||
if (true === $name || !isset(self::$instance[$name])) {
|
||||
$class = false !== strpos($type, '\\') ? $type : '\\think\\cache\\driver\\' . ucwords($type);
|
||||
|
||||
// 记录初始化信息
|
||||
App::$debug && Log::record('[ CACHE ] INIT ' . $type, 'info');
|
||||
if (true === $name) {
|
||||
return new $class($options);
|
||||
} else {
|
||||
self::$instance[$name] = new $class($options);
|
||||
}
|
||||
}
|
||||
return self::$instance[$name];
|
||||
}
|
||||
|
||||
/**
|
||||
* 自动初始化缓存
|
||||
* @access public
|
||||
* @param array $options 配置数组
|
||||
* @return Driver
|
||||
*/
|
||||
public static function init(array $options = [])
|
||||
{
|
||||
if (is_null(self::$handler)) {
|
||||
// 自动初始化缓存
|
||||
if (!empty($options)) {
|
||||
$connect = self::connect($options);
|
||||
} elseif ('complex' == Config::get('cache.type')) {
|
||||
$connect = self::connect(Config::get('cache.default'));
|
||||
} else {
|
||||
$connect = self::connect(Config::get('cache'));
|
||||
}
|
||||
self::$handler = $connect;
|
||||
}
|
||||
return self::$handler;
|
||||
}
|
||||
|
||||
/**
|
||||
* 切换缓存类型 需要配置 cache.type 为 complex
|
||||
* @access public
|
||||
* @param string $name 缓存标识
|
||||
* @return Driver
|
||||
*/
|
||||
public static function store($name = '')
|
||||
{
|
||||
if ('' !== $name && 'complex' == Config::get('cache.type')) {
|
||||
return self::connect(Config::get('cache.' . $name), strtolower($name));
|
||||
}
|
||||
return self::init();
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断缓存是否存在
|
||||
* @access public
|
||||
* @param string $name 缓存变量名
|
||||
* @return bool
|
||||
*/
|
||||
public static function has($name)
|
||||
{
|
||||
self::$readTimes++;
|
||||
return self::init()->has($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* 读取缓存
|
||||
* @access public
|
||||
* @param string $name 缓存标识
|
||||
* @param mixed $default 默认值
|
||||
* @return mixed
|
||||
*/
|
||||
public static function get($name, $default = false)
|
||||
{
|
||||
self::$readTimes++;
|
||||
return self::init()->get($name, $default);
|
||||
}
|
||||
|
||||
/**
|
||||
* 写入缓存
|
||||
* @access public
|
||||
* @param string $name 缓存标识
|
||||
* @param mixed $value 存储数据
|
||||
* @param int|null $expire 有效时间 0为永久
|
||||
* @return boolean
|
||||
*/
|
||||
public static function set($name, $value, $expire = null)
|
||||
{
|
||||
self::$writeTimes++;
|
||||
return self::init()->set($name, $value, $expire);
|
||||
}
|
||||
|
||||
/**
|
||||
* 自增缓存(针对数值缓存)
|
||||
* @access public
|
||||
* @param string $name 缓存变量名
|
||||
* @param int $step 步长
|
||||
* @return false|int
|
||||
*/
|
||||
public static function inc($name, $step = 1)
|
||||
{
|
||||
self::$writeTimes++;
|
||||
return self::init()->inc($name, $step);
|
||||
}
|
||||
|
||||
/**
|
||||
* 自减缓存(针对数值缓存)
|
||||
* @access public
|
||||
* @param string $name 缓存变量名
|
||||
* @param int $step 步长
|
||||
* @return false|int
|
||||
*/
|
||||
public static function dec($name, $step = 1)
|
||||
{
|
||||
self::$writeTimes++;
|
||||
return self::init()->dec($name, $step);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除缓存
|
||||
* @access public
|
||||
* @param string $name 缓存标识
|
||||
* @return boolean
|
||||
*/
|
||||
public static function rm($name)
|
||||
{
|
||||
self::$writeTimes++;
|
||||
return self::init()->rm($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除缓存
|
||||
* @access public
|
||||
* @param string $tag 标签名
|
||||
* @return boolean
|
||||
*/
|
||||
public static function clear($tag = null)
|
||||
{
|
||||
self::$writeTimes++;
|
||||
return self::init()->clear($tag);
|
||||
}
|
||||
|
||||
/**
|
||||
* 读取缓存并删除
|
||||
* @access public
|
||||
* @param string $name 缓存变量名
|
||||
* @return mixed
|
||||
*/
|
||||
public static function pull($name)
|
||||
{
|
||||
self::$readTimes++;
|
||||
self::$writeTimes++;
|
||||
return self::init()->pull($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* 如果不存在则写入缓存
|
||||
* @access public
|
||||
* @param string $name 缓存变量名
|
||||
* @param mixed $value 存储数据
|
||||
* @param int $expire 有效时间 0为永久
|
||||
* @return mixed
|
||||
*/
|
||||
public static function remember($name, $value, $expire = null)
|
||||
{
|
||||
self::$readTimes++;
|
||||
return self::init()->remember($name, $value, $expire);
|
||||
}
|
||||
|
||||
/**
|
||||
* 缓存标签
|
||||
* @access public
|
||||
* @param string $name 标签名
|
||||
* @param string|array $keys 缓存标识
|
||||
* @param bool $overlay 是否覆盖
|
||||
* @return Driver
|
||||
*/
|
||||
public static function tag($name, $keys = null, $overlay = false)
|
||||
{
|
||||
return self::init()->tag($name, $keys, $overlay);
|
||||
}
|
||||
|
||||
}
|
376
thinkphp/library/think/Collection.php
Normal file
376
thinkphp/library/think/Collection.php
Normal file
@ -0,0 +1,376 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2017 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
|
||||
{
|
||||
protected $items = [];
|
||||
|
||||
public function __construct($items = [])
|
||||
{
|
||||
$this->items = $this->convertToArray($items);
|
||||
}
|
||||
|
||||
public static function make($items = [])
|
||||
{
|
||||
return new static($items);
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否为空
|
||||
* @return bool
|
||||
*/
|
||||
public function isEmpty()
|
||||
{
|
||||
return empty($this->items);
|
||||
}
|
||||
|
||||
public function toArray()
|
||||
{
|
||||
return array_map(function ($value) {
|
||||
return ($value instanceof Model || $value instanceof self) ? $value->toArray() : $value;
|
||||
}, $this->items);
|
||||
}
|
||||
|
||||
public function all()
|
||||
{
|
||||
return $this->items;
|
||||
}
|
||||
|
||||
/**
|
||||
* 合并数组
|
||||
*
|
||||
* @param mixed $items
|
||||
* @return static
|
||||
*/
|
||||
public function merge($items)
|
||||
{
|
||||
return new static(array_merge($this->items, $this->convertToArray($items)));
|
||||
}
|
||||
|
||||
/**
|
||||
* 比较数组,返回差集
|
||||
*
|
||||
* @param mixed $items
|
||||
* @return static
|
||||
*/
|
||||
public function diff($items)
|
||||
{
|
||||
return new static(array_diff($this->items, $this->convertToArray($items)));
|
||||
}
|
||||
|
||||
/**
|
||||
* 交换数组中的键和值
|
||||
*
|
||||
* @return static
|
||||
*/
|
||||
public function flip()
|
||||
{
|
||||
return new static(array_flip($this->items));
|
||||
}
|
||||
|
||||
/**
|
||||
* 比较数组,返回交集
|
||||
*
|
||||
* @param mixed $items
|
||||
* @return static
|
||||
*/
|
||||
public function intersect($items)
|
||||
{
|
||||
return new static(array_intersect($this->items, $this->convertToArray($items)));
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回数组中所有的键名
|
||||
*
|
||||
* @return static
|
||||
*/
|
||||
public function keys()
|
||||
{
|
||||
return new static(array_keys($this->items));
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除数组的最后一个元素(出栈)
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function pop()
|
||||
{
|
||||
return array_pop($this->items);
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过使用用户自定义函数,以字符串返回数组
|
||||
*
|
||||
* @param callable $callback
|
||||
* @param mixed $initial
|
||||
* @return mixed
|
||||
*/
|
||||
public function reduce(callable $callback, $initial = null)
|
||||
{
|
||||
return array_reduce($this->items, $callback, $initial);
|
||||
}
|
||||
|
||||
/**
|
||||
* 以相反的顺序返回数组。
|
||||
*
|
||||
* @return static
|
||||
*/
|
||||
public function reverse()
|
||||
{
|
||||
return new static(array_reverse($this->items));
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除数组中首个元素,并返回被删除元素的值
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function shift()
|
||||
{
|
||||
return array_shift($this->items);
|
||||
}
|
||||
|
||||
/**
|
||||
* 把一个数组分割为新的数组块.
|
||||
*
|
||||
* @param int $size
|
||||
* @param bool $preserveKeys
|
||||
* @return static
|
||||
*/
|
||||
public function chunk($size, $preserveKeys = false)
|
||||
{
|
||||
$chunks = [];
|
||||
|
||||
foreach (array_chunk($this->items, $size, $preserveKeys) as $chunk) {
|
||||
$chunks[] = new static($chunk);
|
||||
}
|
||||
|
||||
return new static($chunks);
|
||||
}
|
||||
|
||||
/**
|
||||
* 在数组开头插入一个元素
|
||||
* @param mixed $value
|
||||
* @param null $key
|
||||
* @return int
|
||||
*/
|
||||
public function unshift($value, $key = null)
|
||||
{
|
||||
if (is_null($key)) {
|
||||
array_unshift($this->items, $value);
|
||||
} else {
|
||||
$this->items = [$key => $value] + $this->items;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 给每个元素执行个回调
|
||||
*
|
||||
* @param callable $callback
|
||||
* @return $this
|
||||
*/
|
||||
public function each(callable $callback)
|
||||
{
|
||||
foreach ($this->items as $key => $item) {
|
||||
$result = $callback($item, $key);
|
||||
if (false === $result) {
|
||||
break;
|
||||
} elseif (!is_object($item)) {
|
||||
$this->items[$key] = $result;
|
||||
}
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 用回调函数过滤数组中的元素
|
||||
* @param callable|null $callback
|
||||
* @return static
|
||||
*/
|
||||
public function filter(callable $callback = null)
|
||||
{
|
||||
if ($callback) {
|
||||
return new static(array_filter($this->items, $callback));
|
||||
}
|
||||
|
||||
return new static(array_filter($this->items));
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回数组中指定的一列
|
||||
* @param $column_key
|
||||
* @param null $index_key
|
||||
* @return array
|
||||
*/
|
||||
public function column($column_key, $index_key = null)
|
||||
{
|
||||
if (function_exists('array_column')) {
|
||||
return array_column($this->items, $column_key, $index_key);
|
||||
}
|
||||
|
||||
$result = [];
|
||||
foreach ($this->items as $row) {
|
||||
$key = $value = null;
|
||||
$keySet = $valueSet = false;
|
||||
if (null !== $index_key && array_key_exists($index_key, $row)) {
|
||||
$keySet = true;
|
||||
$key = (string) $row[$index_key];
|
||||
}
|
||||
if (null === $column_key) {
|
||||
$valueSet = true;
|
||||
$value = $row;
|
||||
} elseif (is_array($row) && array_key_exists($column_key, $row)) {
|
||||
$valueSet = true;
|
||||
$value = $row[$column_key];
|
||||
}
|
||||
if ($valueSet) {
|
||||
if ($keySet) {
|
||||
$result[$key] = $value;
|
||||
} else {
|
||||
$result[] = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 对数组排序
|
||||
*
|
||||
* @param callable|null $callback
|
||||
* @return static
|
||||
*/
|
||||
public function sort(callable $callback = null)
|
||||
{
|
||||
$items = $this->items;
|
||||
|
||||
$callback ? uasort($items, $callback) : uasort($items, function ($a, $b) {
|
||||
|
||||
if ($a == $b) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return ($a < $b) ? -1 : 1;
|
||||
});
|
||||
|
||||
return new static($items);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将数组打乱
|
||||
*
|
||||
* @return static
|
||||
*/
|
||||
public function shuffle()
|
||||
{
|
||||
$items = $this->items;
|
||||
|
||||
shuffle($items);
|
||||
|
||||
return new static($items);
|
||||
}
|
||||
|
||||
/**
|
||||
* 截取数组
|
||||
*
|
||||
* @param int $offset
|
||||
* @param int $length
|
||||
* @param bool $preserveKeys
|
||||
* @return static
|
||||
*/
|
||||
public function slice($offset, $length = null, $preserveKeys = false)
|
||||
{
|
||||
return new static(array_slice($this->items, $offset, $length, $preserveKeys));
|
||||
}
|
||||
|
||||
// ArrayAccess
|
||||
public function offsetExists($offset)
|
||||
{
|
||||
return array_key_exists($offset, $this->items);
|
||||
}
|
||||
|
||||
public function offsetGet($offset)
|
||||
{
|
||||
return $this->items[$offset];
|
||||
}
|
||||
|
||||
public function offsetSet($offset, $value)
|
||||
{
|
||||
if (is_null($offset)) {
|
||||
$this->items[] = $value;
|
||||
} else {
|
||||
$this->items[$offset] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
public function offsetUnset($offset)
|
||||
{
|
||||
unset($this->items[$offset]);
|
||||
}
|
||||
|
||||
//Countable
|
||||
public function count()
|
||||
{
|
||||
return count($this->items);
|
||||
}
|
||||
|
||||
//IteratorAggregate
|
||||
public function getIterator()
|
||||
{
|
||||
return new ArrayIterator($this->items);
|
||||
}
|
||||
|
||||
//JsonSerializable
|
||||
public function jsonSerialize()
|
||||
{
|
||||
return $this->toArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换当前数据集为JSON字符串
|
||||
* @access public
|
||||
* @param integer $options json参数
|
||||
* @return string
|
||||
*/
|
||||
public function toJson($options = JSON_UNESCAPED_UNICODE)
|
||||
{
|
||||
return json_encode($this->toArray(), $options);
|
||||
}
|
||||
|
||||
public function __toString()
|
||||
{
|
||||
return $this->toJson();
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换成数组
|
||||
*
|
||||
* @param mixed $items
|
||||
* @return array
|
||||
*/
|
||||
protected function convertToArray($items)
|
||||
{
|
||||
if ($items instanceof self) {
|
||||
return $items->all();
|
||||
}
|
||||
return (array) $items;
|
||||
}
|
||||
}
|
178
thinkphp/library/think/Config.php
Normal file
178
thinkphp/library/think/Config.php
Normal file
@ -0,0 +1,178 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace think;
|
||||
|
||||
class Config
|
||||
{
|
||||
// 配置参数
|
||||
private static $config = [];
|
||||
// 参数作用域
|
||||
private static $range = '_sys_';
|
||||
|
||||
// 设定配置参数的作用域
|
||||
public static function range($range)
|
||||
{
|
||||
self::$range = $range;
|
||||
if (!isset(self::$config[$range])) {
|
||||
self::$config[$range] = [];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析配置文件或内容
|
||||
* @param string $config 配置文件路径或内容
|
||||
* @param string $type 配置解析类型
|
||||
* @param string $name 配置名(如设置即表示二级配置)
|
||||
* @param string $range 作用域
|
||||
* @return mixed
|
||||
*/
|
||||
public static function parse($config, $type = '', $name = '', $range = '')
|
||||
{
|
||||
$range = $range ?: self::$range;
|
||||
if (empty($type)) {
|
||||
$type = pathinfo($config, PATHINFO_EXTENSION);
|
||||
}
|
||||
$class = false !== strpos($type, '\\') ? $type : '\\think\\config\\driver\\' . ucwords($type);
|
||||
return self::set((new $class())->parse($config), $name, $range);
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载配置文件(PHP格式)
|
||||
* @param string $file 配置文件名
|
||||
* @param string $name 配置名(如设置即表示二级配置)
|
||||
* @param string $range 作用域
|
||||
* @return mixed
|
||||
*/
|
||||
public static function load($file, $name = '', $range = '')
|
||||
{
|
||||
$range = $range ?: self::$range;
|
||||
if (!isset(self::$config[$range])) {
|
||||
self::$config[$range] = [];
|
||||
}
|
||||
if (is_file($file)) {
|
||||
$name = strtolower($name);
|
||||
$type = pathinfo($file, PATHINFO_EXTENSION);
|
||||
if ('php' == $type) {
|
||||
return self::set(include $file, $name, $range);
|
||||
} elseif ('yaml' == $type && function_exists('yaml_parse_file')) {
|
||||
return self::set(yaml_parse_file($file), $name, $range);
|
||||
} else {
|
||||
return self::parse($file, $type, $name, $range);
|
||||
}
|
||||
} else {
|
||||
return self::$config[$range];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检测配置是否存在
|
||||
* @param string $name 配置参数名(支持二级配置 .号分割)
|
||||
* @param string $range 作用域
|
||||
* @return bool
|
||||
*/
|
||||
public static function has($name, $range = '')
|
||||
{
|
||||
$range = $range ?: self::$range;
|
||||
|
||||
if (!strpos($name, '.')) {
|
||||
return isset(self::$config[$range][strtolower($name)]);
|
||||
} else {
|
||||
// 二维数组设置和获取支持
|
||||
$name = explode('.', $name, 2);
|
||||
return isset(self::$config[$range][strtolower($name[0])][$name[1]]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取配置参数 为空则获取所有配置
|
||||
* @param string $name 配置参数名(支持二级配置 .号分割)
|
||||
* @param string $range 作用域
|
||||
* @return mixed
|
||||
*/
|
||||
public static function get($name = null, $range = '')
|
||||
{
|
||||
$range = $range ?: self::$range;
|
||||
// 无参数时获取所有
|
||||
if (empty($name) && isset(self::$config[$range])) {
|
||||
return self::$config[$range];
|
||||
}
|
||||
|
||||
if (!strpos($name, '.')) {
|
||||
$name = strtolower($name);
|
||||
return isset(self::$config[$range][$name]) ? self::$config[$range][$name] : null;
|
||||
} else {
|
||||
// 二维数组设置和获取支持
|
||||
$name = explode('.', $name, 2);
|
||||
$name[0] = strtolower($name[0]);
|
||||
|
||||
if (!isset(self::$config[$range][$name[0]])) {
|
||||
// 动态载入额外配置
|
||||
$module = Request::instance()->module();
|
||||
$file = CONF_PATH . ($module ? $module . DS : '') . 'extra' . DS . $name[0] . CONF_EXT;
|
||||
|
||||
is_file($file) && self::load($file, $name[0]);
|
||||
}
|
||||
|
||||
return isset(self::$config[$range][$name[0]][$name[1]]) ? self::$config[$range][$name[0]][$name[1]] : null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置配置参数 name为数组则为批量设置
|
||||
* @param string|array $name 配置参数名(支持二级配置 .号分割)
|
||||
* @param mixed $value 配置值
|
||||
* @param string $range 作用域
|
||||
* @return mixed
|
||||
*/
|
||||
public static function set($name, $value = null, $range = '')
|
||||
{
|
||||
$range = $range ?: self::$range;
|
||||
if (!isset(self::$config[$range])) {
|
||||
self::$config[$range] = [];
|
||||
}
|
||||
if (is_string($name)) {
|
||||
if (!strpos($name, '.')) {
|
||||
self::$config[$range][strtolower($name)] = $value;
|
||||
} else {
|
||||
// 二维数组设置和获取支持
|
||||
$name = explode('.', $name, 2);
|
||||
self::$config[$range][strtolower($name[0])][$name[1]] = $value;
|
||||
}
|
||||
return;
|
||||
} elseif (is_array($name)) {
|
||||
// 批量设置
|
||||
if (!empty($value)) {
|
||||
self::$config[$range][$value] = isset(self::$config[$range][$value]) ?
|
||||
array_merge(self::$config[$range][$value], $name) : $name;
|
||||
return self::$config[$range][$value];
|
||||
} else {
|
||||
return self::$config[$range] = array_merge(self::$config[$range], array_change_key_case($name));
|
||||
}
|
||||
} else {
|
||||
// 为空直接返回 已有配置
|
||||
return self::$config[$range];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 重置配置参数
|
||||
*/
|
||||
public static function reset($range = '')
|
||||
{
|
||||
$range = $range ?: self::$range;
|
||||
if (true === $range) {
|
||||
self::$config = [];
|
||||
} else {
|
||||
self::$config[$range] = [];
|
||||
}
|
||||
}
|
||||
}
|
719
thinkphp/library/think/Console.php
Normal file
719
thinkphp/library/think/Console.php
Normal file
@ -0,0 +1,719 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | TopThink [ WE CAN DO IT JUST THINK IT ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2015 http://www.topthink.com All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: zhangyajun <448901948@qq.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace think;
|
||||
|
||||
use think\console\Command;
|
||||
use think\console\command\Help as HelpCommand;
|
||||
use think\console\Input;
|
||||
use think\console\input\Argument as InputArgument;
|
||||
use think\console\input\Definition as InputDefinition;
|
||||
use think\console\input\Option as InputOption;
|
||||
use think\console\Output;
|
||||
use think\console\output\driver\Buffer;
|
||||
|
||||
class Console
|
||||
{
|
||||
|
||||
private $name;
|
||||
private $version;
|
||||
|
||||
/** @var Command[] */
|
||||
private $commands = [];
|
||||
|
||||
private $wantHelps = false;
|
||||
|
||||
private $catchExceptions = true;
|
||||
private $autoExit = true;
|
||||
private $definition;
|
||||
private $defaultCommand;
|
||||
|
||||
private static $defaultCommands = [
|
||||
"think\\console\\command\\Help",
|
||||
"think\\console\\command\\Lists",
|
||||
"think\\console\\command\\Build",
|
||||
"think\\console\\command\\Clear",
|
||||
"think\\console\\command\\make\\Controller",
|
||||
"think\\console\\command\\make\\Model",
|
||||
"think\\console\\command\\optimize\\Autoload",
|
||||
"think\\console\\command\\optimize\\Config",
|
||||
"think\\console\\command\\optimize\\Route",
|
||||
"think\\console\\command\\optimize\\Schema",
|
||||
];
|
||||
|
||||
public function __construct($name = 'UNKNOWN', $version = 'UNKNOWN')
|
||||
{
|
||||
$this->name = $name;
|
||||
$this->version = $version;
|
||||
|
||||
$this->defaultCommand = 'list';
|
||||
$this->definition = $this->getDefaultInputDefinition();
|
||||
|
||||
foreach ($this->getDefaultCommands() as $command) {
|
||||
$this->add($command);
|
||||
}
|
||||
}
|
||||
|
||||
public static function init($run = true)
|
||||
{
|
||||
static $console;
|
||||
if (!$console) {
|
||||
// 实例化console
|
||||
$console = new self('Think Console', '0.1');
|
||||
// 读取指令集
|
||||
if (is_file(CONF_PATH . 'command' . EXT)) {
|
||||
$commands = include CONF_PATH . 'command' . EXT;
|
||||
if (is_array($commands)) {
|
||||
foreach ($commands as $command) {
|
||||
if (class_exists($command) && is_subclass_of($command, "\\think\\console\\Command")) {
|
||||
// 注册指令
|
||||
$console->add(new $command());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($run) {
|
||||
// 运行
|
||||
return $console->run();
|
||||
} else {
|
||||
return $console;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $command
|
||||
* @param array $parameters
|
||||
* @param string $driver
|
||||
* @return Output|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);
|
||||
|
||||
$console->setCatchExceptions(false);
|
||||
$console->find($command)->run($input, $output);
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行当前的指令
|
||||
* @return int
|
||||
* @throws \Exception
|
||||
* @api
|
||||
*/
|
||||
public function run()
|
||||
{
|
||||
$input = new Input();
|
||||
$output = new Output();
|
||||
|
||||
$this->configureIO($input, $output);
|
||||
|
||||
try {
|
||||
$exitCode = $this->doRun($input, $output);
|
||||
} catch (\Exception $e) {
|
||||
if (!$this->catchExceptions) {
|
||||
throw $e;
|
||||
}
|
||||
|
||||
$output->renderException($e);
|
||||
|
||||
$exitCode = $e->getCode();
|
||||
if (is_numeric($exitCode)) {
|
||||
$exitCode = (int) $exitCode;
|
||||
if (0 === $exitCode) {
|
||||
$exitCode = 1;
|
||||
}
|
||||
} else {
|
||||
$exitCode = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->autoExit) {
|
||||
if ($exitCode > 255) {
|
||||
$exitCode = 255;
|
||||
}
|
||||
|
||||
exit($exitCode);
|
||||
}
|
||||
|
||||
return $exitCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行指令
|
||||
* @param Input $input
|
||||
* @param Output $output
|
||||
* @return int
|
||||
*/
|
||||
public function doRun(Input $input, Output $output)
|
||||
{
|
||||
if (true === $input->hasParameterOption(['--version', '-V'])) {
|
||||
$output->writeln($this->getLongVersion());
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
$name = $this->getCommandName($input);
|
||||
|
||||
if (true === $input->hasParameterOption(['--help', '-h'])) {
|
||||
if (!$name) {
|
||||
$name = 'help';
|
||||
$input = new Input(['help']);
|
||||
} else {
|
||||
$this->wantHelps = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$name) {
|
||||
$name = $this->defaultCommand;
|
||||
$input = new Input([$this->defaultCommand]);
|
||||
}
|
||||
|
||||
$command = $this->find($name);
|
||||
|
||||
$exitCode = $this->doRunCommand($command, $input, $output);
|
||||
|
||||
return $exitCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置输入参数定义
|
||||
* @param InputDefinition $definition
|
||||
*/
|
||||
public function setDefinition(InputDefinition $definition)
|
||||
{
|
||||
$this->definition = $definition;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取输入参数定义
|
||||
* @return InputDefinition The InputDefinition instance
|
||||
*/
|
||||
public function getDefinition()
|
||||
{
|
||||
return $this->definition;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the help message.
|
||||
* @return string A help message.
|
||||
*/
|
||||
public function getHelp()
|
||||
{
|
||||
return $this->getLongVersion();
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否捕获异常
|
||||
* @param bool $boolean
|
||||
* @api
|
||||
*/
|
||||
public function setCatchExceptions($boolean)
|
||||
{
|
||||
$this->catchExceptions = (bool) $boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否自动退出
|
||||
* @param bool $boolean
|
||||
* @api
|
||||
*/
|
||||
public function setAutoExit($boolean)
|
||||
{
|
||||
$this->autoExit = (bool) $boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取名称
|
||||
* @return string
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置名称
|
||||
* @param string $name
|
||||
*/
|
||||
public function setName($name)
|
||||
{
|
||||
$this->name = $name;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取版本
|
||||
* @return string
|
||||
* @api
|
||||
*/
|
||||
public function getVersion()
|
||||
{
|
||||
return $this->version;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置版本
|
||||
* @param string $version
|
||||
*/
|
||||
public function setVersion($version)
|
||||
{
|
||||
$this->version = $version;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取完整的版本号
|
||||
* @return string
|
||||
*/
|
||||
public function getLongVersion()
|
||||
{
|
||||
if ('UNKNOWN' !== $this->getName() && 'UNKNOWN' !== $this->getVersion()) {
|
||||
return sprintf('<info>%s</info> version <comment>%s</comment>', $this->getName(), $this->getVersion());
|
||||
}
|
||||
|
||||
return '<info>Console Tool</info>';
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册一个指令
|
||||
* @param string $name
|
||||
* @return Command
|
||||
*/
|
||||
public function register($name)
|
||||
{
|
||||
return $this->add(new Command($name));
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加指令
|
||||
* @param Command[] $commands
|
||||
*/
|
||||
public function addCommands(array $commands)
|
||||
{
|
||||
foreach ($commands as $command) {
|
||||
$this->add($command);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加一个指令
|
||||
* @param Command $command
|
||||
* @return Command
|
||||
*/
|
||||
public function add(Command $command)
|
||||
{
|
||||
$command->setConsole($this);
|
||||
|
||||
if (!$command->isEnabled()) {
|
||||
$command->setConsole(null);
|
||||
return;
|
||||
}
|
||||
|
||||
if (null === $command->getDefinition()) {
|
||||
throw new \LogicException(sprintf('Command class "%s" is not correctly initialized. You probably forgot to call the parent constructor.', get_class($command)));
|
||||
}
|
||||
|
||||
$this->commands[$command->getName()] = $command;
|
||||
|
||||
foreach ($command->getAliases() as $alias) {
|
||||
$this->commands[$alias] = $command;
|
||||
}
|
||||
|
||||
return $command;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指令
|
||||
* @param string $name 指令名称
|
||||
* @return Command
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public function get($name)
|
||||
{
|
||||
if (!isset($this->commands[$name])) {
|
||||
throw new \InvalidArgumentException(sprintf('The command "%s" does not exist.', $name));
|
||||
}
|
||||
|
||||
$command = $this->commands[$name];
|
||||
|
||||
if ($this->wantHelps) {
|
||||
$this->wantHelps = false;
|
||||
|
||||
/** @var HelpCommand $helpCommand */
|
||||
$helpCommand = $this->get('help');
|
||||
$helpCommand->setCommand($command);
|
||||
|
||||
return $helpCommand;
|
||||
}
|
||||
|
||||
return $command;
|
||||
}
|
||||
|
||||
/**
|
||||
* 某个指令是否存在
|
||||
* @param string $name 指令名称
|
||||
* @return bool
|
||||
*/
|
||||
public function has($name)
|
||||
{
|
||||
return isset($this->commands[$name]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有的命名空间
|
||||
* @return array
|
||||
*/
|
||||
public function getNamespaces()
|
||||
{
|
||||
$namespaces = [];
|
||||
foreach ($this->commands as $command) {
|
||||
$namespaces = array_merge($namespaces, $this->extractAllNamespaces($command->getName()));
|
||||
|
||||
foreach ($command->getAliases() as $alias) {
|
||||
$namespaces = array_merge($namespaces, $this->extractAllNamespaces($alias));
|
||||
}
|
||||
}
|
||||
|
||||
return array_values(array_unique(array_filter($namespaces)));
|
||||
}
|
||||
|
||||
/**
|
||||
* 查找注册命名空间中的名称或缩写。
|
||||
* @param string $namespace
|
||||
* @return string
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public function findNamespace($namespace)
|
||||
{
|
||||
$allNamespaces = $this->getNamespaces();
|
||||
$expr = preg_replace_callback('{([^:]+|)}', function ($matches) {
|
||||
return preg_quote($matches[1]) . '[^:]*';
|
||||
}, $namespace);
|
||||
$namespaces = preg_grep('{^' . $expr . '}', $allNamespaces);
|
||||
|
||||
if (empty($namespaces)) {
|
||||
$message = sprintf('There are no commands defined in the "%s" namespace.', $namespace);
|
||||
|
||||
if ($alternatives = $this->findAlternatives($namespace, $allNamespaces)) {
|
||||
if (1 == count($alternatives)) {
|
||||
$message .= "\n\nDid you mean this?\n ";
|
||||
} else {
|
||||
$message .= "\n\nDid you mean one of these?\n ";
|
||||
}
|
||||
|
||||
$message .= implode("\n ", $alternatives);
|
||||
}
|
||||
|
||||
throw new \InvalidArgumentException($message);
|
||||
}
|
||||
|
||||
$exact = in_array($namespace, $namespaces, true);
|
||||
if (count($namespaces) > 1 && !$exact) {
|
||||
throw new \InvalidArgumentException(sprintf('The namespace "%s" is ambiguous (%s).', $namespace, $this->getAbbreviationSuggestions(array_values($namespaces))));
|
||||
}
|
||||
|
||||
return $exact ? $namespace : reset($namespaces);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查找指令
|
||||
* @param string $name 名称或者别名
|
||||
* @return Command
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public function find($name)
|
||||
{
|
||||
$allCommands = array_keys($this->commands);
|
||||
$expr = preg_replace_callback('{([^:]+|)}', function ($matches) {
|
||||
return preg_quote($matches[1]) . '[^:]*';
|
||||
}, $name);
|
||||
$commands = preg_grep('{^' . $expr . '}', $allCommands);
|
||||
|
||||
if (empty($commands) || count(preg_grep('{^' . $expr . '$}', $commands)) < 1) {
|
||||
if (false !== $pos = strrpos($name, ':')) {
|
||||
$this->findNamespace(substr($name, 0, $pos));
|
||||
}
|
||||
|
||||
$message = sprintf('Command "%s" is not defined.', $name);
|
||||
|
||||
if ($alternatives = $this->findAlternatives($name, $allCommands)) {
|
||||
if (1 == count($alternatives)) {
|
||||
$message .= "\n\nDid you mean this?\n ";
|
||||
} else {
|
||||
$message .= "\n\nDid you mean one of these?\n ";
|
||||
}
|
||||
$message .= implode("\n ", $alternatives);
|
||||
}
|
||||
|
||||
throw new \InvalidArgumentException($message);
|
||||
}
|
||||
|
||||
if (count($commands) > 1) {
|
||||
$commandList = $this->commands;
|
||||
$commands = array_filter($commands, function ($nameOrAlias) use ($commandList, $commands) {
|
||||
$commandName = $commandList[$nameOrAlias]->getName();
|
||||
|
||||
return $commandName === $nameOrAlias || !in_array($commandName, $commands);
|
||||
});
|
||||
}
|
||||
|
||||
$exact = in_array($name, $commands, true);
|
||||
if (count($commands) > 1 && !$exact) {
|
||||
$suggestions = $this->getAbbreviationSuggestions(array_values($commands));
|
||||
|
||||
throw new \InvalidArgumentException(sprintf('Command "%s" is ambiguous (%s).', $name, $suggestions));
|
||||
}
|
||||
|
||||
return $this->get($exact ? $name : reset($commands));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有的指令
|
||||
* @param string $namespace 命名空间
|
||||
* @return Command[]
|
||||
* @api
|
||||
*/
|
||||
public function all($namespace = null)
|
||||
{
|
||||
if (null === $namespace) {
|
||||
return $this->commands;
|
||||
}
|
||||
|
||||
$commands = [];
|
||||
foreach ($this->commands as $name => $command) {
|
||||
if ($this->extractNamespace($name, substr_count($namespace, ':') + 1) === $namespace) {
|
||||
$commands[$name] = $command;
|
||||
}
|
||||
}
|
||||
|
||||
return $commands;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取可能的指令名
|
||||
* @param array $names
|
||||
* @return array
|
||||
*/
|
||||
public static function getAbbreviations($names)
|
||||
{
|
||||
$abbrevs = [];
|
||||
foreach ($names as $name) {
|
||||
for ($len = strlen($name); $len > 0; --$len) {
|
||||
$abbrev = substr($name, 0, $len);
|
||||
$abbrevs[$abbrev][] = $name;
|
||||
}
|
||||
}
|
||||
|
||||
return $abbrevs;
|
||||
}
|
||||
|
||||
/**
|
||||
* 配置基于用户的参数和选项的输入和输出实例。
|
||||
* @param Input $input 输入实例
|
||||
* @param Output $output 输出实例
|
||||
*/
|
||||
protected function configureIO(Input $input, Output $output)
|
||||
{
|
||||
if (true === $input->hasParameterOption(['--ansi'])) {
|
||||
$output->setDecorated(true);
|
||||
} elseif (true === $input->hasParameterOption(['--no-ansi'])) {
|
||||
$output->setDecorated(false);
|
||||
}
|
||||
|
||||
if (true === $input->hasParameterOption(['--no-interaction', '-n'])) {
|
||||
$input->setInteractive(false);
|
||||
}
|
||||
|
||||
if (true === $input->hasParameterOption(['--quiet', '-q'])) {
|
||||
$output->setVerbosity(Output::VERBOSITY_QUIET);
|
||||
} else {
|
||||
if ($input->hasParameterOption('-vvv') || $input->hasParameterOption('--verbose=3') || $input->getParameterOption('--verbose') === 3) {
|
||||
$output->setVerbosity(Output::VERBOSITY_DEBUG);
|
||||
} elseif ($input->hasParameterOption('-vv') || $input->hasParameterOption('--verbose=2') || $input->getParameterOption('--verbose') === 2) {
|
||||
$output->setVerbosity(Output::VERBOSITY_VERY_VERBOSE);
|
||||
} elseif ($input->hasParameterOption('-v') || $input->hasParameterOption('--verbose=1') || $input->hasParameterOption('--verbose') || $input->getParameterOption('--verbose')) {
|
||||
$output->setVerbosity(Output::VERBOSITY_VERBOSE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行指令
|
||||
* @param Command $command 指令实例
|
||||
* @param Input $input 输入实例
|
||||
* @param Output $output 输出实例
|
||||
* @return int
|
||||
* @throws \Exception
|
||||
*/
|
||||
protected function doRunCommand(Command $command, Input $input, Output $output)
|
||||
{
|
||||
return $command->run($input, $output);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指令的基础名称
|
||||
* @param Input $input
|
||||
* @return string
|
||||
*/
|
||||
protected function getCommandName(Input $input)
|
||||
{
|
||||
return $input->getFirstArgument();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取默认输入定义
|
||||
* @return InputDefinition
|
||||
*/
|
||||
protected function getDefaultInputDefinition()
|
||||
{
|
||||
return new InputDefinition([
|
||||
new InputArgument('command', InputArgument::REQUIRED, 'The command to execute'),
|
||||
new InputOption('--help', '-h', InputOption::VALUE_NONE, 'Display this help message'),
|
||||
new InputOption('--version', '-V', InputOption::VALUE_NONE, 'Display this console version'),
|
||||
new InputOption('--quiet', '-q', InputOption::VALUE_NONE, 'Do not output any message'),
|
||||
new InputOption('--verbose', '-v|vv|vvv', InputOption::VALUE_NONE, 'Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug'),
|
||||
new InputOption('--ansi', '', InputOption::VALUE_NONE, 'Force ANSI output'),
|
||||
new InputOption('--no-ansi', '', InputOption::VALUE_NONE, 'Disable ANSI output'),
|
||||
new InputOption('--no-interaction', '-n', InputOption::VALUE_NONE, 'Do not ask any interactive question'),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置默认命令
|
||||
* @return Command[] An array of default Command instances
|
||||
*/
|
||||
protected function getDefaultCommands()
|
||||
{
|
||||
$defaultCommands = [];
|
||||
|
||||
foreach (self::$defaultCommands as $classname) {
|
||||
if (class_exists($classname) && is_subclass_of($classname, "think\\console\\Command")) {
|
||||
$defaultCommands[] = new $classname();
|
||||
}
|
||||
}
|
||||
|
||||
return $defaultCommands;
|
||||
}
|
||||
|
||||
public static function addDefaultCommands(array $classnames)
|
||||
{
|
||||
self::$defaultCommands = array_merge(self::$defaultCommands, $classnames);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取可能的建议
|
||||
* @param array $abbrevs
|
||||
* @return string
|
||||
*/
|
||||
private function getAbbreviationSuggestions($abbrevs)
|
||||
{
|
||||
return sprintf('%s, %s%s', $abbrevs[0], $abbrevs[1], count($abbrevs) > 2 ? sprintf(' and %d more', count($abbrevs) - 2) : '');
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回命名空间部分
|
||||
* @param string $name 指令
|
||||
* @param string $limit 部分的命名空间的最大数量
|
||||
* @return string
|
||||
*/
|
||||
public function extractNamespace($name, $limit = null)
|
||||
{
|
||||
$parts = explode(':', $name);
|
||||
array_pop($parts);
|
||||
|
||||
return implode(':', null === $limit ? $parts : array_slice($parts, 0, $limit));
|
||||
}
|
||||
|
||||
/**
|
||||
* 查找可替代的建议
|
||||
* @param string $name
|
||||
* @param array|\Traversable $collection
|
||||
* @return array
|
||||
*/
|
||||
private function findAlternatives($name, $collection)
|
||||
{
|
||||
$threshold = 1e3;
|
||||
$alternatives = [];
|
||||
|
||||
$collectionParts = [];
|
||||
foreach ($collection as $item) {
|
||||
$collectionParts[$item] = explode(':', $item);
|
||||
}
|
||||
|
||||
foreach (explode(':', $name) as $i => $subname) {
|
||||
foreach ($collectionParts as $collectionName => $parts) {
|
||||
$exists = isset($alternatives[$collectionName]);
|
||||
if (!isset($parts[$i]) && $exists) {
|
||||
$alternatives[$collectionName] += $threshold;
|
||||
continue;
|
||||
} elseif (!isset($parts[$i])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$lev = levenshtein($subname, $parts[$i]);
|
||||
if ($lev <= strlen($subname) / 3 || '' !== $subname && false !== strpos($parts[$i], $subname)) {
|
||||
$alternatives[$collectionName] = $exists ? $alternatives[$collectionName] + $lev : $lev;
|
||||
} elseif ($exists) {
|
||||
$alternatives[$collectionName] += $threshold;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($collection as $item) {
|
||||
$lev = levenshtein($name, $item);
|
||||
if ($lev <= strlen($name) / 3 || false !== strpos($item, $name)) {
|
||||
$alternatives[$item] = isset($alternatives[$item]) ? $alternatives[$item] - $lev : $lev;
|
||||
}
|
||||
}
|
||||
|
||||
$alternatives = array_filter($alternatives, function ($lev) use ($threshold) {
|
||||
return $lev < 2 * $threshold;
|
||||
});
|
||||
asort($alternatives);
|
||||
|
||||
return array_keys($alternatives);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置默认的指令
|
||||
* @param string $commandName The Command name
|
||||
*/
|
||||
public function setDefaultCommand($commandName)
|
||||
{
|
||||
$this->defaultCommand = $commandName;
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回所有的命名空间
|
||||
* @param string $name
|
||||
* @return array
|
||||
*/
|
||||
private function extractAllNamespaces($name)
|
||||
{
|
||||
$parts = explode(':', $name, -1);
|
||||
$namespaces = [];
|
||||
|
||||
foreach ($parts as $part) {
|
||||
if (count($namespaces)) {
|
||||
$namespaces[] = end($namespaces) . ':' . $part;
|
||||
} else {
|
||||
$namespaces[] = $part;
|
||||
}
|
||||
}
|
||||
|
||||
return $namespaces;
|
||||
}
|
||||
|
||||
}
|
213
thinkphp/library/think/Controller.php
Normal file
213
thinkphp/library/think/Controller.php
Normal file
@ -0,0 +1,213 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2017 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;
|
||||
|
||||
Loader::import('controller/Jump', TRAIT_PATH, EXT);
|
||||
|
||||
class Controller
|
||||
{
|
||||
use Jump;
|
||||
|
||||
/**
|
||||
* @var \think\View 视图类实例
|
||||
*/
|
||||
protected $view;
|
||||
/**
|
||||
* @var \think\Request Request实例
|
||||
*/
|
||||
protected $request;
|
||||
// 验证失败是否抛出异常
|
||||
protected $failException = false;
|
||||
// 是否批量验证
|
||||
protected $batchValidate = false;
|
||||
|
||||
/**
|
||||
* 前置操作方法列表
|
||||
* @var array $beforeActionList
|
||||
* @access protected
|
||||
*/
|
||||
protected $beforeActionList = [];
|
||||
|
||||
/**
|
||||
* 构造方法
|
||||
* @param Request $request Request对象
|
||||
* @access public
|
||||
*/
|
||||
public function __construct(Request $request = null)
|
||||
{
|
||||
if (is_null($request)) {
|
||||
$request = Request::instance();
|
||||
}
|
||||
$this->view = View::instance(Config::get('template'), Config::get('view_replace_str'));
|
||||
$this->request = $request;
|
||||
|
||||
// 控制器初始化
|
||||
$this->_initialize();
|
||||
|
||||
// 前置操作方法
|
||||
if ($this->beforeActionList) {
|
||||
foreach ($this->beforeActionList as $method => $options) {
|
||||
is_numeric($method) ?
|
||||
$this->beforeAction($options) :
|
||||
$this->beforeAction($method, $options);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 初始化
|
||||
protected function _initialize()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* 前置操作
|
||||
* @access protected
|
||||
* @param string $method 前置操作方法名
|
||||
* @param array $options 调用参数 ['only'=>[...]] 或者['except'=>[...]]
|
||||
*/
|
||||
protected function beforeAction($method, $options = [])
|
||||
{
|
||||
if (isset($options['only'])) {
|
||||
if (is_string($options['only'])) {
|
||||
$options['only'] = explode(',', $options['only']);
|
||||
}
|
||||
if (!in_array($this->request->action(), $options['only'])) {
|
||||
return;
|
||||
}
|
||||
} elseif (isset($options['except'])) {
|
||||
if (is_string($options['except'])) {
|
||||
$options['except'] = explode(',', $options['except']);
|
||||
}
|
||||
if (in_array($this->request->action(), $options['except'])) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
call_user_func([$this, $method]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载模板输出
|
||||
* @access protected
|
||||
* @param string $template 模板文件名
|
||||
* @param array $vars 模板输出变量
|
||||
* @param array $replace 模板替换
|
||||
* @param array $config 模板参数
|
||||
* @return mixed
|
||||
*/
|
||||
protected function fetch($template = '', $vars = [], $replace = [], $config = [])
|
||||
{
|
||||
return $this->view->fetch($template, $vars, $replace, $config);
|
||||
}
|
||||
|
||||
/**
|
||||
* 渲染内容输出
|
||||
* @access protected
|
||||
* @param string $content 模板内容
|
||||
* @param array $vars 模板输出变量
|
||||
* @param array $replace 替换内容
|
||||
* @param array $config 模板参数
|
||||
* @return mixed
|
||||
*/
|
||||
protected function display($content = '', $vars = [], $replace = [], $config = [])
|
||||
{
|
||||
return $this->view->display($content, $vars, $replace, $config);
|
||||
}
|
||||
|
||||
/**
|
||||
* 模板变量赋值
|
||||
* @access protected
|
||||
* @param mixed $name 要显示的模板变量
|
||||
* @param mixed $value 变量的值
|
||||
* @return void
|
||||
*/
|
||||
protected function assign($name, $value = '')
|
||||
{
|
||||
$this->view->assign($name, $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化模板引擎
|
||||
* @access protected
|
||||
* @param array|string $engine 引擎参数
|
||||
* @return void
|
||||
*/
|
||||
protected function engine($engine)
|
||||
{
|
||||
$this->view->engine($engine);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置验证失败后是否抛出异常
|
||||
* @access protected
|
||||
* @param bool $fail 是否抛出异常
|
||||
* @return $this
|
||||
*/
|
||||
protected function validateFailException($fail = true)
|
||||
{
|
||||
$this->failException = $fail;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证数据
|
||||
* @access protected
|
||||
* @param array $data 数据
|
||||
* @param string|array $validate 验证器名或者验证规则数组
|
||||
* @param array $message 提示信息
|
||||
* @param bool $batch 是否批量验证
|
||||
* @param mixed $callback 回调方法(闭包)
|
||||
* @return array|string|true
|
||||
* @throws ValidateException
|
||||
*/
|
||||
protected function validate($data, $validate, $message = [], $batch = false, $callback = null)
|
||||
{
|
||||
if (is_array($validate)) {
|
||||
$v = Loader::validate();
|
||||
$v->rule($validate);
|
||||
} else {
|
||||
if (strpos($validate, '.')) {
|
||||
// 支持场景
|
||||
list($validate, $scene) = explode('.', $validate);
|
||||
}
|
||||
$v = Loader::validate($validate);
|
||||
if (!empty($scene)) {
|
||||
$v->scene($scene);
|
||||
}
|
||||
}
|
||||
// 是否批量验证
|
||||
if ($batch || $this->batchValidate) {
|
||||
$v->batch(true);
|
||||
}
|
||||
|
||||
if (is_array($message)) {
|
||||
$v->message($message);
|
||||
}
|
||||
|
||||
if ($callback && is_callable($callback)) {
|
||||
call_user_func_array($callback, [$v, &$data]);
|
||||
}
|
||||
|
||||
if (!$v->check($data)) {
|
||||
if ($this->failException) {
|
||||
throw new ValidateException($v->getError());
|
||||
} else {
|
||||
return $v->getError();
|
||||
}
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
224
thinkphp/library/think/Cookie.php
Normal file
224
thinkphp/library/think/Cookie.php
Normal file
@ -0,0 +1,224 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace think;
|
||||
|
||||
class Cookie
|
||||
{
|
||||
protected static $config = [
|
||||
// cookie 名称前缀
|
||||
'prefix' => '',
|
||||
// cookie 保存时间
|
||||
'expire' => 0,
|
||||
// cookie 保存路径
|
||||
'path' => '/',
|
||||
// cookie 有效域名
|
||||
'domain' => '',
|
||||
// cookie 启用安全传输
|
||||
'secure' => false,
|
||||
// httponly设置
|
||||
'httponly' => '',
|
||||
// 是否使用 setcookie
|
||||
'setcookie' => true,
|
||||
];
|
||||
|
||||
protected static $init;
|
||||
|
||||
/**
|
||||
* Cookie初始化
|
||||
* @param array $config
|
||||
* @return void
|
||||
*/
|
||||
public static function init(array $config = [])
|
||||
{
|
||||
if (empty($config)) {
|
||||
$config = Config::get('cookie');
|
||||
}
|
||||
self::$config = array_merge(self::$config, array_change_key_case($config));
|
||||
if (!empty(self::$config['httponly'])) {
|
||||
ini_set('session.cookie_httponly', 1);
|
||||
}
|
||||
self::$init = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置或者获取cookie作用域(前缀)
|
||||
* @param string $prefix
|
||||
* @return string|void
|
||||
*/
|
||||
public static function prefix($prefix = '')
|
||||
{
|
||||
if (empty($prefix)) {
|
||||
return self::$config['prefix'];
|
||||
}
|
||||
self::$config['prefix'] = $prefix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cookie 设置、获取、删除
|
||||
*
|
||||
* @param string $name cookie名称
|
||||
* @param mixed $value cookie值
|
||||
* @param mixed $option 可选参数 可能会是 null|integer|string
|
||||
*
|
||||
* @return mixed
|
||||
* @internal param mixed $options cookie参数
|
||||
*/
|
||||
public static function set($name, $value = '', $option = null)
|
||||
{
|
||||
!isset(self::$init) && self::init();
|
||||
// 参数设置(会覆盖黙认设置)
|
||||
if (!is_null($option)) {
|
||||
if (is_numeric($option)) {
|
||||
$option = ['expire' => $option];
|
||||
} elseif (is_string($option)) {
|
||||
parse_str($option, $option);
|
||||
}
|
||||
$config = array_merge(self::$config, array_change_key_case($option));
|
||||
} else {
|
||||
$config = self::$config;
|
||||
}
|
||||
$name = $config['prefix'] . $name;
|
||||
// 设置cookie
|
||||
if (is_array($value)) {
|
||||
array_walk_recursive($value, 'self::jsonFormatProtect', 'encode');
|
||||
$value = 'think:' . json_encode($value);
|
||||
}
|
||||
$expire = !empty($config['expire']) ? $_SERVER['REQUEST_TIME'] + intval($config['expire']) : 0;
|
||||
if ($config['setcookie']) {
|
||||
setcookie($name, $value, $expire, $config['path'], $config['domain'], $config['secure'], $config['httponly']);
|
||||
}
|
||||
$_COOKIE[$name] = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* 永久保存Cookie数据
|
||||
* @param string $name cookie名称
|
||||
* @param mixed $value cookie值
|
||||
* @param mixed $option 可选参数 可能会是 null|integer|string
|
||||
* @return void
|
||||
*/
|
||||
public static function forever($name, $value = '', $option = null)
|
||||
{
|
||||
if (is_null($option) || is_numeric($option)) {
|
||||
$option = [];
|
||||
}
|
||||
$option['expire'] = 315360000;
|
||||
self::set($name, $value, $option);
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断Cookie数据
|
||||
* @param string $name cookie名称
|
||||
* @param string|null $prefix cookie前缀
|
||||
* @return bool
|
||||
*/
|
||||
public static function has($name, $prefix = null)
|
||||
{
|
||||
!isset(self::$init) && self::init();
|
||||
$prefix = !is_null($prefix) ? $prefix : self::$config['prefix'];
|
||||
$name = $prefix . $name;
|
||||
return isset($_COOKIE[$name]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Cookie获取
|
||||
* @param string $name cookie名称
|
||||
* @param string|null $prefix cookie前缀
|
||||
* @return mixed
|
||||
*/
|
||||
public static function get($name = '', $prefix = null)
|
||||
{
|
||||
!isset(self::$init) && self::init();
|
||||
$prefix = !is_null($prefix) ? $prefix : self::$config['prefix'];
|
||||
$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, 'self::jsonFormatProtect', 'decode');
|
||||
}
|
||||
} else {
|
||||
$value = null;
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cookie删除
|
||||
* @param string $name cookie名称
|
||||
* @param string|null $prefix cookie前缀
|
||||
* @return mixed
|
||||
*/
|
||||
public static function delete($name, $prefix = null)
|
||||
{
|
||||
!isset(self::$init) && self::init();
|
||||
$config = self::$config;
|
||||
$prefix = !is_null($prefix) ? $prefix : $config['prefix'];
|
||||
$name = $prefix . $name;
|
||||
if ($config['setcookie']) {
|
||||
setcookie($name, '', $_SERVER['REQUEST_TIME'] - 3600, $config['path'], $config['domain'], $config['secure'], $config['httponly']);
|
||||
}
|
||||
// 删除指定cookie
|
||||
unset($_COOKIE[$name]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Cookie清空
|
||||
* @param string|null $prefix cookie前缀
|
||||
* @return mixed
|
||||
*/
|
||||
public static function clear($prefix = null)
|
||||
{
|
||||
// 清除指定前缀的所有cookie
|
||||
if (empty($_COOKIE)) {
|
||||
return;
|
||||
}
|
||||
!isset(self::$init) && self::init();
|
||||
// 要删除的cookie前缀,不指定则删除config设置的指定前缀
|
||||
$config = self::$config;
|
||||
$prefix = !is_null($prefix) ? $prefix : $config['prefix'];
|
||||
if ($prefix) {
|
||||
// 如果前缀为空字符串将不作处理直接返回
|
||||
foreach ($_COOKIE as $key => $val) {
|
||||
if (0 === strpos($key, $prefix)) {
|
||||
if ($config['setcookie']) {
|
||||
setcookie($key, '', $_SERVER['REQUEST_TIME'] - 3600, $config['path'], $config['domain'], $config['secure'], $config['httponly']);
|
||||
}
|
||||
unset($_COOKIE[$key]);
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
private static function jsonFormatProtect(&$val, $key, $type = 'encode')
|
||||
{
|
||||
if (!empty($val) && true !== $val) {
|
||||
$val = 'decode' == $type ? urldecode($val) : urlencode($val);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
156
thinkphp/library/think/Db.php
Normal file
156
thinkphp/library/think/Db.php
Normal file
@ -0,0 +1,156 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace think;
|
||||
|
||||
use think\db\Connection;
|
||||
use think\db\Query;
|
||||
|
||||
/**
|
||||
* Class Db
|
||||
* @package think
|
||||
* @method Query table(string $table) static 指定数据表(含前缀)
|
||||
* @method Query name(string $name) static 指定数据表(不含前缀)
|
||||
* @method Query where(mixed $field, string $op = null, mixed $condition = null) static 查询条件
|
||||
* @method Query join(mixed $join, mixed $condition = null, string $type = 'INNER') static JOIN查询
|
||||
* @method Query union(mixed $union, boolean $all = false) static UNION查询
|
||||
* @method Query limit(mixed $offset, integer $length = null) static 查询LIMIT
|
||||
* @method Query order(mixed $field, string $order = null) static 查询ORDER
|
||||
* @method Query cache(mixed $key = null , integer $expire = null) static 设置查询缓存
|
||||
* @method mixed value(string $field) static 获取某个字段的值
|
||||
* @method array column(string $field, string $key = '') static 获取某个列的值
|
||||
* @method Query view(mixed $join, mixed $field = null, mixed $on = null, string $type = 'INNER') static 视图查询
|
||||
* @method mixed find(mixed $data = 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 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 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 quote(string $str) static SQL指令安全过滤
|
||||
* @method string getLastInsID($sequence = null) static 获取最近插入的ID
|
||||
*/
|
||||
class Db
|
||||
{
|
||||
// 数据库连接实例
|
||||
private static $instance = [];
|
||||
// 查询次数
|
||||
public static $queryTimes = 0;
|
||||
// 执行次数
|
||||
public static $executeTimes = 0;
|
||||
|
||||
/**
|
||||
* 数据库初始化 并取得数据库类实例
|
||||
* @static
|
||||
* @access public
|
||||
* @param mixed $config 连接配置
|
||||
* @param bool|string $name 连接标识 true 强制重新连接
|
||||
* @return Connection
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function connect($config = [], $name = false)
|
||||
{
|
||||
if (false === $name) {
|
||||
$name = md5(serialize($config));
|
||||
}
|
||||
if (true === $name || !isset(self::$instance[$name])) {
|
||||
// 解析连接参数 支持数组和字符串
|
||||
$options = self::parseConfig($config);
|
||||
if (empty($options['type'])) {
|
||||
throw new \InvalidArgumentException('Undefined db type');
|
||||
}
|
||||
$class = false !== strpos($options['type'], '\\') ? $options['type'] : '\\think\\db\\connector\\' . ucwords($options['type']);
|
||||
// 记录初始化信息
|
||||
if (App::$debug) {
|
||||
Log::record('[ DB ] INIT ' . $options['type'], 'info');
|
||||
}
|
||||
if (true === $name) {
|
||||
$name = md5(serialize($config));
|
||||
}
|
||||
self::$instance[$name] = new $class($options);
|
||||
}
|
||||
return self::$instance[$name];
|
||||
}
|
||||
|
||||
public static function clear() {
|
||||
self::$instance = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 数据库连接参数解析
|
||||
* @static
|
||||
* @access private
|
||||
* @param mixed $config
|
||||
* @return array
|
||||
*/
|
||||
private static function parseConfig($config)
|
||||
{
|
||||
if (empty($config)) {
|
||||
$config = Config::get('database');
|
||||
} elseif (is_string($config) && false === strpos($config, '/')) {
|
||||
// 支持读取配置参数
|
||||
$config = Config::get($config);
|
||||
}
|
||||
if (is_string($config)) {
|
||||
return self::parseDsn($config);
|
||||
} else {
|
||||
return $config;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* DSN解析
|
||||
* 格式: mysql://username:passwd@localhost:3306/DbName?param1=val1¶m2=val2#utf8
|
||||
* @static
|
||||
* @access private
|
||||
* @param string $dsnStr
|
||||
* @return array
|
||||
*/
|
||||
private static function parseDsn($dsnStr)
|
||||
{
|
||||
$info = parse_url($dsnStr);
|
||||
if (!$info) {
|
||||
return [];
|
||||
}
|
||||
$dsn = [
|
||||
'type' => $info['scheme'],
|
||||
'username' => isset($info['user']) ? $info['user'] : '',
|
||||
'password' => isset($info['pass']) ? $info['pass'] : '',
|
||||
'hostname' => isset($info['host']) ? $info['host'] : '',
|
||||
'hostport' => isset($info['port']) ? $info['port'] : '',
|
||||
'database' => !empty($info['path']) ? ltrim($info['path'], '/') : '',
|
||||
'charset' => isset($info['fragment']) ? $info['fragment'] : 'utf8',
|
||||
];
|
||||
|
||||
if (isset($info['query'])) {
|
||||
parse_str($info['query'], $dsn['params']);
|
||||
} else {
|
||||
$dsn['params'] = [];
|
||||
}
|
||||
return $dsn;
|
||||
}
|
||||
|
||||
// 调用驱动类的方法
|
||||
public static function __callStatic($method, $params)
|
||||
{
|
||||
// 自动初始化数据库
|
||||
return call_user_func_array([self::connect(), $method], $params);
|
||||
}
|
||||
}
|
212
thinkphp/library/think/Debug.php
Normal file
212
thinkphp/library/think/Debug.php
Normal file
@ -0,0 +1,212 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2017 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\response\Redirect;
|
||||
|
||||
class Debug
|
||||
{
|
||||
// 区间时间信息
|
||||
protected static $info = [];
|
||||
// 区间内存信息
|
||||
protected static $mem = [];
|
||||
|
||||
/**
|
||||
* 记录时间(微秒)和内存使用情况
|
||||
* @param string $name 标记位置
|
||||
* @param mixed $value 标记值 留空则取当前 time 表示仅记录时间 否则同时记录时间和内存
|
||||
* @return mixed
|
||||
*/
|
||||
public static function remark($name, $value = '')
|
||||
{
|
||||
// 记录时间和内存使用
|
||||
self::$info[$name] = is_float($value) ? $value : microtime(true);
|
||||
if ('time' != $value) {
|
||||
self::$mem['mem'][$name] = is_float($value) ? $value : memory_get_usage();
|
||||
self::$mem['peak'][$name] = memory_get_peak_usage();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 统计某个区间的时间(微秒)使用情况 返回值以秒为单位
|
||||
* @param string $start 开始标签
|
||||
* @param string $end 结束标签
|
||||
* @param integer|string $dec 小数位
|
||||
* @return integer
|
||||
*/
|
||||
public static function getRangeTime($start, $end, $dec = 6)
|
||||
{
|
||||
if (!isset(self::$info[$end])) {
|
||||
self::$info[$end] = microtime(true);
|
||||
}
|
||||
return number_format((self::$info[$end] - self::$info[$start]), $dec);
|
||||
}
|
||||
|
||||
/**
|
||||
* 统计从开始到统计时的时间(微秒)使用情况 返回值以秒为单位
|
||||
* @param integer|string $dec 小数位
|
||||
* @return integer
|
||||
*/
|
||||
public static function getUseTime($dec = 6)
|
||||
{
|
||||
return number_format((microtime(true) - THINK_START_TIME), $dec);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前访问的吞吐率情况
|
||||
* @return string
|
||||
*/
|
||||
public static function getThroughputRate()
|
||||
{
|
||||
return number_format(1 / self::getUseTime(), 2) . 'req/s';
|
||||
}
|
||||
|
||||
/**
|
||||
* 记录区间的内存使用情况
|
||||
* @param string $start 开始标签
|
||||
* @param string $end 结束标签
|
||||
* @param integer|string $dec 小数位
|
||||
* @return string
|
||||
*/
|
||||
public static function getRangeMem($start, $end, $dec = 2)
|
||||
{
|
||||
if (!isset(self::$mem['mem'][$end])) {
|
||||
self::$mem['mem'][$end] = memory_get_usage();
|
||||
}
|
||||
$size = self::$mem['mem'][$end] - self::$mem['mem'][$start];
|
||||
$a = ['B', 'KB', 'MB', 'GB', 'TB'];
|
||||
$pos = 0;
|
||||
while ($size >= 1024) {
|
||||
$size /= 1024;
|
||||
$pos++;
|
||||
}
|
||||
return round($size, $dec) . " " . $a[$pos];
|
||||
}
|
||||
|
||||
/**
|
||||
* 统计从开始到统计时的内存使用情况
|
||||
* @param integer|string $dec 小数位
|
||||
* @return string
|
||||
*/
|
||||
public static function getUseMem($dec = 2)
|
||||
{
|
||||
$size = memory_get_usage() - THINK_START_MEM;
|
||||
$a = ['B', 'KB', 'MB', 'GB', 'TB'];
|
||||
$pos = 0;
|
||||
while ($size >= 1024) {
|
||||
$size /= 1024;
|
||||
$pos++;
|
||||
}
|
||||
return round($size, $dec) . " " . $a[$pos];
|
||||
}
|
||||
|
||||
/**
|
||||
* 统计区间的内存峰值情况
|
||||
* @param string $start 开始标签
|
||||
* @param string $end 结束标签
|
||||
* @param integer|string $dec 小数位
|
||||
* @return mixed
|
||||
*/
|
||||
public static function getMemPeak($start, $end, $dec = 2)
|
||||
{
|
||||
if (!isset(self::$mem['peak'][$end])) {
|
||||
self::$mem['peak'][$end] = memory_get_peak_usage();
|
||||
}
|
||||
$size = self::$mem['peak'][$end] - self::$mem['peak'][$start];
|
||||
$a = ['B', 'KB', 'MB', 'GB', 'TB'];
|
||||
$pos = 0;
|
||||
while ($size >= 1024) {
|
||||
$size /= 1024;
|
||||
$pos++;
|
||||
}
|
||||
return round($size, $dec) . " " . $a[$pos];
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文件加载信息
|
||||
* @param bool $detail 是否显示详细
|
||||
* @return integer|array
|
||||
*/
|
||||
public static function getFile($detail = false)
|
||||
{
|
||||
if ($detail) {
|
||||
$files = get_included_files();
|
||||
$info = [];
|
||||
foreach ($files as $key => $file) {
|
||||
$info[] = $file . ' ( ' . number_format(filesize($file) / 1024, 2) . ' KB )';
|
||||
}
|
||||
return $info;
|
||||
}
|
||||
return count(get_included_files());
|
||||
}
|
||||
|
||||
/**
|
||||
* 浏览器友好的变量输出
|
||||
* @param mixed $var 变量
|
||||
* @param boolean $echo 是否输出 默认为true 如果为false 则返回输出字符串
|
||||
* @param string $label 标签 默认为空
|
||||
* @param integer $flags htmlspecialchars flags
|
||||
* @return void|string
|
||||
*/
|
||||
public static function dump($var, $echo = true, $label = null, $flags = ENT_SUBSTITUTE)
|
||||
{
|
||||
$label = (null === $label) ? '' : rtrim($label) . ':';
|
||||
ob_start();
|
||||
var_dump($var);
|
||||
$output = ob_get_clean();
|
||||
$output = preg_replace('/\]\=\>\n(\s+)/m', '] => ', $output);
|
||||
if (IS_CLI) {
|
||||
$output = PHP_EOL . $label . $output . PHP_EOL;
|
||||
} else {
|
||||
if (!extension_loaded('xdebug')) {
|
||||
$output = htmlspecialchars($output, $flags);
|
||||
}
|
||||
$output = '<pre>' . $label . $output . '</pre>';
|
||||
}
|
||||
if ($echo) {
|
||||
echo($output);
|
||||
return;
|
||||
} else {
|
||||
return $output;
|
||||
}
|
||||
}
|
||||
|
||||
public static function inject(Response $response, &$content)
|
||||
{
|
||||
$config = Config::get('trace');
|
||||
$type = isset($config['type']) ? $config['type'] : 'Html';
|
||||
$request = Request::instance();
|
||||
$class = false !== strpos($type, '\\') ? $type : '\\think\\debug\\' . ucwords($type);
|
||||
unset($config['type']);
|
||||
if (class_exists($class)) {
|
||||
$trace = new $class($config);
|
||||
} else {
|
||||
throw new ClassNotFoundException('class not exists:' . $class, $class);
|
||||
}
|
||||
|
||||
if ($response instanceof Redirect) {
|
||||
//TODO 记录
|
||||
} else {
|
||||
$output = $trace->output($response, Log::getLog());
|
||||
if (is_string($output)) {
|
||||
// trace调试信息注入
|
||||
$pos = strripos($content, '</body>');
|
||||
if (false !== $pos) {
|
||||
$content = substr($content, 0, $pos) . $output . substr($content, $pos);
|
||||
} else {
|
||||
$content = $content . $output;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
36
thinkphp/library/think/Env.php
Normal file
36
thinkphp/library/think/Env.php
Normal file
@ -0,0 +1,36 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace think;
|
||||
|
||||
class Env
|
||||
{
|
||||
/**
|
||||
* 获取环境变量值
|
||||
* @param string $name 环境变量名(支持二级 .号分割)
|
||||
* @param string $default 默认值
|
||||
* @return mixed
|
||||
*/
|
||||
public static function get($name, $default = null)
|
||||
{
|
||||
$result = getenv(ENV_PREFIX . strtoupper(str_replace('.', '_', $name)));
|
||||
if (false !== $result) {
|
||||
if ('false' === $result) {
|
||||
$result = false;
|
||||
} elseif ('true' === $result) {
|
||||
$result = true;
|
||||
}
|
||||
return $result;
|
||||
} else {
|
||||
return $default;
|
||||
}
|
||||
}
|
||||
}
|
120
thinkphp/library/think/Error.php
Normal file
120
thinkphp/library/think/Error.php
Normal file
@ -0,0 +1,120 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2017 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
|
||||
{
|
||||
/**
|
||||
* 注册异常处理
|
||||
* @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
|
||||
* @param \Exception|\Throwable $e
|
||||
*/
|
||||
public static function appException($e)
|
||||
{
|
||||
if (!$e instanceof \Exception) {
|
||||
$e = new ThrowableError($e);
|
||||
}
|
||||
|
||||
self::getExceptionHandler()->report($e);
|
||||
if (IS_CLI) {
|
||||
self::getExceptionHandler()->renderForConsole(new ConsoleOutput, $e);
|
||||
} else {
|
||||
self::getExceptionHandler()->render($e)->send();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Error Handler
|
||||
* @param integer $errno 错误编号
|
||||
* @param integer $errstr 详细错误信息
|
||||
* @param string $errfile 出错的文件
|
||||
* @param integer $errline 出错行号
|
||||
* @param array $errcontext
|
||||
* @throws ErrorException
|
||||
*/
|
||||
public static function appError($errno, $errstr, $errfile = '', $errline = 0, $errcontext = [])
|
||||
{
|
||||
$exception = new ErrorException($errno, $errstr, $errfile, $errline, $errcontext);
|
||||
if (error_reporting() & $errno) {
|
||||
// 将错误信息托管至 think\exception\ErrorException
|
||||
throw $exception;
|
||||
} else {
|
||||
self::getExceptionHandler()->report($exception);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Shutdown Handler
|
||||
*/
|
||||
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);
|
||||
}
|
||||
|
||||
// 写入日志
|
||||
Log::save();
|
||||
}
|
||||
|
||||
/**
|
||||
* 确定错误类型是否致命
|
||||
*
|
||||
* @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.
|
||||
*
|
||||
* @return Handle
|
||||
*/
|
||||
public static function getExceptionHandler()
|
||||
{
|
||||
static $handle;
|
||||
if (!$handle) {
|
||||
// 异常处理handle
|
||||
$class = Config::get('exception_handle');
|
||||
if ($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;
|
||||
}
|
||||
}
|
54
thinkphp/library/think/Exception.php
Normal file
54
thinkphp/library/think/Exception.php
Normal file
@ -0,0 +1,54 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2017 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;
|
||||
|
||||
class Exception extends \Exception
|
||||
{
|
||||
|
||||
/**
|
||||
* 保存异常页面显示的额外Debug数据
|
||||
* @var array
|
||||
*/
|
||||
protected $data = [];
|
||||
|
||||
/**
|
||||
* 设置异常额外的Debug数据
|
||||
* 数据将会显示为下面的格式
|
||||
*
|
||||
* Exception Data
|
||||
* --------------------------------------------------
|
||||
* Label 1
|
||||
* key1 value1
|
||||
* key2 value2
|
||||
* Label 2
|
||||
* key1 value1
|
||||
* key2 value2
|
||||
*
|
||||
* @param string $label 数据分类,用于异常页面显示
|
||||
* @param array $data 需要显示的数据,必须为关联数组
|
||||
*/
|
||||
final protected function setData($label, array $data)
|
||||
{
|
||||
$this->data[$label] = $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取异常额外Debug数据
|
||||
* 主要用于输出到异常页面便于调试
|
||||
* @return array 由setData设置的Debug数据
|
||||
*/
|
||||
final public function getData()
|
||||
{
|
||||
return $this->data;
|
||||
}
|
||||
|
||||
}
|
415
thinkphp/library/think/File.php
Normal file
415
thinkphp/library/think/File.php
Normal file
@ -0,0 +1,415 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2017 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 = '';
|
||||
// 当前完整文件名
|
||||
protected $filename;
|
||||
// 上传文件名
|
||||
protected $saveName;
|
||||
// 文件上传命名规则
|
||||
protected $rule = 'date';
|
||||
// 文件上传验证规则
|
||||
protected $validate = [];
|
||||
// 单元测试
|
||||
protected $isTest;
|
||||
// 上传文件信息
|
||||
protected $info;
|
||||
// 文件hash信息
|
||||
protected $hash = [];
|
||||
|
||||
public function __construct($filename, $mode = 'r')
|
||||
{
|
||||
parent::__construct($filename, $mode);
|
||||
$this->filename = $this->getRealPath() ?: $this->getPathname();
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否测试
|
||||
* @param bool $test 是否测试
|
||||
* @return $this
|
||||
*/
|
||||
public function isTest($test = false)
|
||||
{
|
||||
$this->isTest = $test;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置上传信息
|
||||
* @param array $info 上传文件信息
|
||||
* @return $this
|
||||
*/
|
||||
public function setUploadInfo($info)
|
||||
{
|
||||
$this->info = $info;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取上传文件的信息
|
||||
* @param string $name
|
||||
* @return array|string
|
||||
*/
|
||||
public function getInfo($name = '')
|
||||
{
|
||||
return isset($this->info[$name]) ? $this->info[$name] : $this->info;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取上传文件的文件名
|
||||
* @return string
|
||||
*/
|
||||
public function getSaveName()
|
||||
{
|
||||
return $this->saveName;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置上传文件的保存文件名
|
||||
* @param string $saveName
|
||||
* @return $this
|
||||
*/
|
||||
public function setSaveName($saveName)
|
||||
{
|
||||
$this->saveName = $saveName;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文件的哈希散列值
|
||||
* @param string $type
|
||||
* @return mixed $string
|
||||
*/
|
||||
public function hash($type = 'sha1')
|
||||
{
|
||||
if (!isset($this->hash[$type])) {
|
||||
$this->hash[$type] = hash_file($type, $this->filename);
|
||||
}
|
||||
return $this->hash[$type];
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查目录是否可写
|
||||
* @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 = "目录 {$path} 创建失败!";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文件类型信息
|
||||
* @return string
|
||||
*/
|
||||
public function getMime()
|
||||
{
|
||||
$finfo = finfo_open(FILEINFO_MIME_TYPE);
|
||||
return finfo_file($finfo, $this->filename);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置文件的命名规则
|
||||
* @param string $rule 文件命名规则
|
||||
* @return $this
|
||||
*/
|
||||
public function rule($rule)
|
||||
{
|
||||
$this->rule = $rule;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置上传文件的验证规则
|
||||
* @param array $rule 验证规则
|
||||
* @return $this
|
||||
*/
|
||||
public function validate($rule = [])
|
||||
{
|
||||
$this->validate = $rule;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检测是否合法的上传文件
|
||||
* @return bool
|
||||
*/
|
||||
public function isValid()
|
||||
{
|
||||
if ($this->isTest) {
|
||||
return is_file($this->filename);
|
||||
}
|
||||
return is_uploaded_file($this->filename);
|
||||
}
|
||||
|
||||
/**
|
||||
* 检测上传文件
|
||||
* @param array $rule 验证规则
|
||||
* @return bool
|
||||
*/
|
||||
public function check($rule = [])
|
||||
{
|
||||
$rule = $rule ?: $this->validate;
|
||||
|
||||
/* 检查文件大小 */
|
||||
if (isset($rule['size']) && !$this->checkSize($rule['size'])) {
|
||||
$this->error = '上传文件大小不符!';
|
||||
return false;
|
||||
}
|
||||
|
||||
/* 检查文件Mime类型 */
|
||||
if (isset($rule['type']) && !$this->checkMime($rule['type'])) {
|
||||
$this->error = '上传文件MIME类型不允许!';
|
||||
return false;
|
||||
}
|
||||
|
||||
/* 检查文件后缀 */
|
||||
if (isset($rule['ext']) && !$this->checkExt($rule['ext'])) {
|
||||
$this->error = '上传文件后缀不允许';
|
||||
return false;
|
||||
}
|
||||
|
||||
/* 检查图像文件 */
|
||||
if (!$this->checkImg()) {
|
||||
$this->error = '非法图像文件!';
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检测上传文件后缀
|
||||
* @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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检测图像文件
|
||||
* @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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检测上传文件大小
|
||||
* @param integer $size 最大大小
|
||||
* @return bool
|
||||
*/
|
||||
public function checkSize($size)
|
||||
{
|
||||
if ($this->getSize() > $size) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检测上传文件类型
|
||||
* @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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 移动文件
|
||||
* @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 = '非法上传文件';
|
||||
return false;
|
||||
}
|
||||
|
||||
// 验证上传
|
||||
if (!$this->check()) {
|
||||
return false;
|
||||
}
|
||||
$path = rtrim($path, DS) . DS;
|
||||
// 文件保存命名规则
|
||||
$saveName = $this->buildSaveName($savename);
|
||||
$filename = $path . $saveName;
|
||||
|
||||
// 检测目录
|
||||
if (false === $this->checkPath(dirname($filename))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* 不覆盖同名文件 */
|
||||
if (!$replace && is_file($filename)) {
|
||||
$this->error = '存在同名文件' . $filename;
|
||||
return false;
|
||||
}
|
||||
|
||||
/* 移动文件 */
|
||||
if ($this->isTest) {
|
||||
rename($this->filename, $filename);
|
||||
} elseif (!move_uploaded_file($this->filename, $filename)) {
|
||||
$this->error = '文件上传保存错误!';
|
||||
return false;
|
||||
}
|
||||
// 返回 File对象实例
|
||||
$file = new self($filename);
|
||||
$file->setSaveName($saveName);
|
||||
$file->setUploadInfo($this->info);
|
||||
return $file;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取保存文件名
|
||||
* @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') . DS . md5(microtime(true));
|
||||
break;
|
||||
default:
|
||||
if (in_array($this->rule, hash_algos())) {
|
||||
$hash = $this->hash($this->rule);
|
||||
$savename = substr($hash, 0, 2) . DS . substr($hash, 2);
|
||||
} elseif (is_callable($this->rule)) {
|
||||
$savename = call_user_func($this->rule);
|
||||
} else {
|
||||
$savename = date('Ymd') . DS . md5(microtime(true));
|
||||
}
|
||||
}
|
||||
}
|
||||
} elseif ('' === $savename) {
|
||||
$savename = $this->getInfo('name');
|
||||
}
|
||||
if (!strpos($savename, '.')) {
|
||||
$savename .= '.' . pathinfo($this->getInfo('name'), PATHINFO_EXTENSION);
|
||||
}
|
||||
return $savename;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取错误代码信息
|
||||
* @param int $errorNo 错误号
|
||||
*/
|
||||
private function error($errorNo)
|
||||
{
|
||||
switch ($errorNo) {
|
||||
case 1:
|
||||
case 2:
|
||||
$this->error = '上传文件大小超过了最大值!';
|
||||
break;
|
||||
case 3:
|
||||
$this->error = '文件只有部分被上传!';
|
||||
break;
|
||||
case 4:
|
||||
$this->error = '没有文件被上传!';
|
||||
break;
|
||||
case 6:
|
||||
$this->error = '找不到临时文件夹!';
|
||||
break;
|
||||
case 7:
|
||||
$this->error = '文件写入失败!';
|
||||
break;
|
||||
default:
|
||||
$this->error = '未知上传错误!';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取错误信息
|
||||
* @return mixed
|
||||
*/
|
||||
public function getError()
|
||||
{
|
||||
return $this->error;
|
||||
}
|
||||
|
||||
public function __call($method, $args)
|
||||
{
|
||||
return $this->hash($method);
|
||||
}
|
||||
}
|
136
thinkphp/library/think/Hook.php
Normal file
136
thinkphp/library/think/Hook.php
Normal file
@ -0,0 +1,136 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace think;
|
||||
|
||||
class Hook
|
||||
{
|
||||
|
||||
private static $tags = [];
|
||||
|
||||
/**
|
||||
* 动态添加行为扩展到某个标签
|
||||
* @param string $tag 标签名称
|
||||
* @param mixed $behavior 行为名称
|
||||
* @param bool $first 是否放到开头执行
|
||||
* @return void
|
||||
*/
|
||||
public static function add($tag, $behavior, $first = false)
|
||||
{
|
||||
isset(self::$tags[$tag]) || self::$tags[$tag] = [];
|
||||
if (is_array($behavior) && !is_callable($behavior)) {
|
||||
if (!array_key_exists('_overlay', $behavior) || !$behavior['_overlay']) {
|
||||
unset($behavior['_overlay']);
|
||||
self::$tags[$tag] = array_merge(self::$tags[$tag], $behavior);
|
||||
} else {
|
||||
unset($behavior['_overlay']);
|
||||
self::$tags[$tag] = $behavior;
|
||||
}
|
||||
} elseif ($first) {
|
||||
array_unshift(self::$tags[$tag], $behavior);
|
||||
} else {
|
||||
self::$tags[$tag][] = $behavior;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量导入插件
|
||||
* @param array $tags 插件信息
|
||||
* @param boolean $recursive 是否递归合并
|
||||
*/
|
||||
public static function import(array $tags, $recursive = true)
|
||||
{
|
||||
if ($recursive) {
|
||||
foreach ($tags as $tag => $behavior) {
|
||||
self::add($tag, $behavior);
|
||||
}
|
||||
} else {
|
||||
self::$tags = $tags + self::$tags;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取插件信息
|
||||
* @param string $tag 插件位置 留空获取全部
|
||||
* @return array
|
||||
*/
|
||||
public static function get($tag = '')
|
||||
{
|
||||
if (empty($tag)) {
|
||||
//获取全部的插件信息
|
||||
return self::$tags;
|
||||
} else {
|
||||
return array_key_exists($tag, self::$tags) ? self::$tags[$tag] : [];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 监听标签的行为
|
||||
* @param string $tag 标签名称
|
||||
* @param mixed $params 传入参数
|
||||
* @param mixed $extra 额外参数
|
||||
* @param bool $once 只获取一个有效返回值
|
||||
* @return mixed
|
||||
*/
|
||||
public static function listen($tag, &$params = null, $extra = null, $once = false)
|
||||
{
|
||||
$results = [];
|
||||
$tags = static::get($tag);
|
||||
foreach ($tags as $key => $name) {
|
||||
$results[$key] = self::exec($name, $tag, $params, $extra);
|
||||
if (false === $results[$key]) {
|
||||
// 如果返回false 则中断行为执行
|
||||
break;
|
||||
} elseif (!is_null($results[$key]) && $once) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return $once ? end($results) : $results;
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行某个行为
|
||||
* @param mixed $class 要执行的行为
|
||||
* @param string $tag 方法名(标签名)
|
||||
* @param Mixed $params 传人的参数
|
||||
* @param mixed $extra 额外参数
|
||||
* @return mixed
|
||||
*/
|
||||
public static function exec($class, $tag = '', &$params = null, $extra = null)
|
||||
{
|
||||
App::$debug && Debug::remark('behavior_start', 'time');
|
||||
$method = Loader::parseName($tag, 1, false);
|
||||
if ($class instanceof \Closure) {
|
||||
$result = call_user_func_array($class, [ & $params, $extra]);
|
||||
$class = 'Closure';
|
||||
} elseif (is_array($class)) {
|
||||
list($class, $method) = $class;
|
||||
|
||||
$result = (new $class())->$method($params, $extra);
|
||||
$class = $class . '->' . $method;
|
||||
} elseif (is_object($class)) {
|
||||
$result = $class->$method($params, $extra);
|
||||
$class = get_class($class);
|
||||
} elseif (strpos($class, '::')) {
|
||||
$result = call_user_func_array($class, [ & $params, $extra]);
|
||||
} else {
|
||||
$obj = new $class();
|
||||
$method = ($tag && is_callable([$obj, $method])) ? $method : 'run';
|
||||
$result = $obj->$method($params, $extra);
|
||||
}
|
||||
if (App::$debug) {
|
||||
Debug::remark('behavior_end', 'time');
|
||||
Log::record('[ BEHAVIOR ] Run ' . $class . ' @' . $tag . ' [ RunTime:' . Debug::getRangeTime('behavior_start', 'behavior_end') . 's ]', 'info');
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
}
|
223
thinkphp/library/think/Lang.php
Normal file
223
thinkphp/library/think/Lang.php
Normal file
@ -0,0 +1,223 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace think;
|
||||
|
||||
class Lang
|
||||
{
|
||||
// 语言数据
|
||||
private static $lang = [];
|
||||
// 语言作用域
|
||||
private static $range = 'zh-cn';
|
||||
// 语言自动侦测的变量
|
||||
protected static $langDetectVar = 'lang';
|
||||
// 语言Cookie变量
|
||||
protected static $langCookieVar = 'think_var';
|
||||
// 语言Cookie的过期时间
|
||||
protected static $langCookieExpire = 3600;
|
||||
// 允许语言列表
|
||||
protected static $allowLangList = [];
|
||||
// Accept-Language转义为对应语言包名称 系统默认配置
|
||||
protected static $acceptLanguage = [
|
||||
'zh-hans-cn' => 'zh-cn',
|
||||
];
|
||||
|
||||
// 设定当前的语言
|
||||
public static function range($range = '')
|
||||
{
|
||||
if ('' == $range) {
|
||||
return self::$range;
|
||||
} else {
|
||||
self::$range = $range;
|
||||
}
|
||||
return self::$range;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置语言定义(不区分大小写)
|
||||
* @param string|array $name 语言变量
|
||||
* @param string $value 语言值
|
||||
* @param string $range 语言作用域
|
||||
* @return mixed
|
||||
*/
|
||||
public static function set($name, $value = null, $range = '')
|
||||
{
|
||||
$range = $range ?: self::$range;
|
||||
// 批量定义
|
||||
if (!isset(self::$lang[$range])) {
|
||||
self::$lang[$range] = [];
|
||||
}
|
||||
if (is_array($name)) {
|
||||
return self::$lang[$range] = array_change_key_case($name) + self::$lang[$range];
|
||||
} else {
|
||||
return self::$lang[$range][strtolower($name)] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载语言定义(不区分大小写)
|
||||
* @param array|string $file 语言文件
|
||||
* @param string $range 语言作用域
|
||||
* @return mixed
|
||||
*/
|
||||
public static function load($file, $range = '')
|
||||
{
|
||||
$range = $range ?: self::$range;
|
||||
if (!isset(self::$lang[$range])) {
|
||||
self::$lang[$range] = [];
|
||||
}
|
||||
// 批量定义
|
||||
if (is_string($file)) {
|
||||
$file = [$file];
|
||||
}
|
||||
$lang = [];
|
||||
foreach ($file as $_file) {
|
||||
if (is_file($_file)) {
|
||||
// 记录加载信息
|
||||
App::$debug && Log::record('[ LANG ] ' . $_file, 'info');
|
||||
$_lang = include $_file;
|
||||
if (is_array($_lang)) {
|
||||
$lang = array_change_key_case($_lang) + $lang;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!empty($lang)) {
|
||||
self::$lang[$range] = $lang + self::$lang[$range];
|
||||
}
|
||||
return self::$lang[$range];
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取语言定义(不区分大小写)
|
||||
* @param string|null $name 语言变量
|
||||
* @param string $range 语言作用域
|
||||
* @return mixed
|
||||
*/
|
||||
public static function has($name, $range = '')
|
||||
{
|
||||
$range = $range ?: self::$range;
|
||||
return isset(self::$lang[$range][strtolower($name)]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取语言定义(不区分大小写)
|
||||
* @param string|null $name 语言变量
|
||||
* @param array $vars 变量替换
|
||||
* @param string $range 语言作用域
|
||||
* @return mixed
|
||||
*/
|
||||
public static function get($name = null, $vars = [], $range = '')
|
||||
{
|
||||
$range = $range ?: self::$range;
|
||||
// 空参数返回所有定义
|
||||
if (empty($name)) {
|
||||
return self::$lang[$range];
|
||||
}
|
||||
$key = strtolower($name);
|
||||
$value = isset(self::$lang[$range][$key]) ? self::$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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 自动侦测设置获取语言选择
|
||||
* @return string
|
||||
*/
|
||||
public static function detect()
|
||||
{
|
||||
// 自动侦测设置获取语言选择
|
||||
$langSet = '';
|
||||
|
||||
if (isset($_GET[self::$langDetectVar])) {
|
||||
// url中设置了语言变量
|
||||
$langSet = strtolower($_GET[self::$langDetectVar]);
|
||||
} elseif (isset($_COOKIE[self::$langCookieVar])) {
|
||||
// Cookie中设置了语言变量
|
||||
$langSet = strtolower($_COOKIE[self::$langCookieVar]);
|
||||
} elseif (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {
|
||||
// 自动侦测浏览器语言
|
||||
preg_match('/^([a-z\d\-]+)/i', $_SERVER['HTTP_ACCEPT_LANGUAGE'], $matches);
|
||||
$langSet = strtolower($matches[1]);
|
||||
$acceptLangs = Config::get('header_accept_lang');
|
||||
if (isset($acceptLangs[$langSet])) {
|
||||
$langSet = $acceptLangs[$langSet];
|
||||
} elseif (isset(self::$acceptLanguage[$langSet])) {
|
||||
$langSet = self::$acceptLanguage[$langSet];
|
||||
}
|
||||
}
|
||||
if (empty(self::$allowLangList) || in_array($langSet, self::$allowLangList)) {
|
||||
// 合法的语言
|
||||
self::$range = $langSet ?: self::$range;
|
||||
}
|
||||
return self::$range;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置语言自动侦测的变量
|
||||
* @param string $var 变量名称
|
||||
* @return void
|
||||
*/
|
||||
public static function setLangDetectVar($var)
|
||||
{
|
||||
self::$langDetectVar = $var;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置语言的cookie保存变量
|
||||
* @param string $var 变量名称
|
||||
* @return void
|
||||
*/
|
||||
public static function setLangCookieVar($var)
|
||||
{
|
||||
self::$langCookieVar = $var;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置语言的cookie的过期时间
|
||||
* @param string $expire 过期时间
|
||||
* @return void
|
||||
*/
|
||||
public static function setLangCookieExpire($expire)
|
||||
{
|
||||
self::$langCookieExpire = $expire;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置允许的语言列表
|
||||
* @param array $list 语言列表
|
||||
* @return void
|
||||
*/
|
||||
public static function setAllowLangList($list)
|
||||
{
|
||||
self::$allowLangList = $list;
|
||||
}
|
||||
}
|
570
thinkphp/library/think/Loader.php
Normal file
570
thinkphp/library/think/Loader.php
Normal file
@ -0,0 +1,570 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2017 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 Loader
|
||||
{
|
||||
protected static $instance = [];
|
||||
// 类名映射
|
||||
protected static $map = [];
|
||||
|
||||
// 命名空间别名
|
||||
protected static $namespaceAlias = [];
|
||||
|
||||
// PSR-4
|
||||
private static $prefixLengthsPsr4 = [];
|
||||
private static $prefixDirsPsr4 = [];
|
||||
private static $fallbackDirsPsr4 = [];
|
||||
|
||||
// PSR-0
|
||||
private static $prefixesPsr0 = [];
|
||||
private static $fallbackDirsPsr0 = [];
|
||||
|
||||
// 自动加载的文件
|
||||
private static $autoloadFiles = [];
|
||||
|
||||
// 自动加载
|
||||
public static function autoload($class)
|
||||
{
|
||||
// 检测命名空间别名
|
||||
if (!empty(self::$namespaceAlias)) {
|
||||
$namespace = dirname($class);
|
||||
if (isset(self::$namespaceAlias[$namespace])) {
|
||||
$original = self::$namespaceAlias[$namespace] . '\\' . basename($class);
|
||||
if (class_exists($original)) {
|
||||
return class_alias($original, $class, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($file = self::findFile($class)) {
|
||||
|
||||
// Win环境严格区分大小写
|
||||
if (IS_WIN && pathinfo($file, PATHINFO_FILENAME) != pathinfo(realpath($file), PATHINFO_FILENAME)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
__include_file($file);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 查找文件
|
||||
* @param $class
|
||||
* @return bool
|
||||
*/
|
||||
private static function findFile($class)
|
||||
{
|
||||
if (!empty(self::$map[$class])) {
|
||||
// 类库映射
|
||||
return self::$map[$class];
|
||||
}
|
||||
|
||||
// 查找 PSR-4
|
||||
$logicalPathPsr4 = strtr($class, '\\', DS) . EXT;
|
||||
|
||||
$first = $class[0];
|
||||
if (isset(self::$prefixLengthsPsr4[$first])) {
|
||||
foreach (self::$prefixLengthsPsr4[$first] as $prefix => $length) {
|
||||
if (0 === strpos($class, $prefix)) {
|
||||
foreach (self::$prefixDirsPsr4[$prefix] as $dir) {
|
||||
if (is_file($file = $dir . DS . substr($logicalPathPsr4, $length))) {
|
||||
return $file;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 查找 PSR-4 fallback dirs
|
||||
foreach (self::$fallbackDirsPsr4 as $dir) {
|
||||
if (is_file($file = $dir . DS . $logicalPathPsr4)) {
|
||||
return $file;
|
||||
}
|
||||
}
|
||||
|
||||
// 查找 PSR-0
|
||||
if (false !== $pos = strrpos($class, '\\')) {
|
||||
// namespaced class name
|
||||
$logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1)
|
||||
. strtr(substr($logicalPathPsr4, $pos + 1), '_', DS);
|
||||
} else {
|
||||
// PEAR-like class name
|
||||
$logicalPathPsr0 = strtr($class, '_', DS) . EXT;
|
||||
}
|
||||
|
||||
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 . DS . $logicalPathPsr0)) {
|
||||
return $file;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 查找 PSR-0 fallback dirs
|
||||
foreach (self::$fallbackDirsPsr0 as $dir) {
|
||||
if (is_file($file = $dir . DS . $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, DS), true);
|
||||
}
|
||||
} else {
|
||||
self::addPsr4($namespace . '\\', rtrim($path, DS), 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空间
|
||||
private static function addPsr4($prefix, $paths, $prepend = false)
|
||||
{
|
||||
if (!$prefix) {
|
||||
// Register directories for the root namespace.
|
||||
if ($prepend) {
|
||||
self::$fallbackDirsPsr4 = array_merge(
|
||||
(array) $paths,
|
||||
self::$fallbackDirsPsr4
|
||||
);
|
||||
} else {
|
||||
self::$fallbackDirsPsr4 = array_merge(
|
||||
self::$fallbackDirsPsr4,
|
||||
(array) $paths
|
||||
);
|
||||
}
|
||||
} elseif (!isset(self::$prefixDirsPsr4[$prefix])) {
|
||||
// Register directories for a new namespace.
|
||||
$length = strlen($prefix);
|
||||
if ('\\' !== $prefix[$length - 1]) {
|
||||
throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
|
||||
}
|
||||
self::$prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
|
||||
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 addNamespaceAlias($namespace, $original = '')
|
||||
{
|
||||
if (is_array($namespace)) {
|
||||
self::$namespaceAlias = array_merge(self::$namespaceAlias, $namespace);
|
||||
} else {
|
||||
self::$namespaceAlias[$namespace] = $original;
|
||||
}
|
||||
}
|
||||
|
||||
// 注册自动加载机制
|
||||
public static function register($autoload = '')
|
||||
{
|
||||
// 注册系统自动加载
|
||||
spl_autoload_register($autoload ?: 'think\\Loader::autoload', true, true);
|
||||
// 注册命名空间定义
|
||||
self::addNamespace([
|
||||
'think' => LIB_PATH . 'think' . DS,
|
||||
'behavior' => LIB_PATH . 'behavior' . DS,
|
||||
'traits' => LIB_PATH . 'traits' . DS,
|
||||
]);
|
||||
// 加载类库映射文件
|
||||
if (is_file(RUNTIME_PATH . 'classmap' . EXT)) {
|
||||
self::addClassMap(__include_file(RUNTIME_PATH . 'classmap' . EXT));
|
||||
}
|
||||
|
||||
// Composer自动加载支持
|
||||
if (is_dir(VENDOR_PATH . 'composer')) {
|
||||
self::registerComposerLoader();
|
||||
}
|
||||
|
||||
// 自动加载extend目录
|
||||
self::$fallbackDirsPsr4[] = rtrim(EXTEND_PATH, DS);
|
||||
}
|
||||
|
||||
// 注册composer自动加载
|
||||
private static function registerComposerLoader()
|
||||
{
|
||||
if (is_file(VENDOR_PATH . 'composer/autoload_namespaces.php')) {
|
||||
$map = require VENDOR_PATH . 'composer/autoload_namespaces.php';
|
||||
foreach ($map as $namespace => $path) {
|
||||
self::addPsr0($namespace, $path);
|
||||
}
|
||||
}
|
||||
|
||||
if (is_file(VENDOR_PATH . 'composer/autoload_psr4.php')) {
|
||||
$map = require VENDOR_PATH . 'composer/autoload_psr4.php';
|
||||
foreach ($map as $namespace => $path) {
|
||||
self::addPsr4($namespace, $path);
|
||||
}
|
||||
}
|
||||
|
||||
if (is_file(VENDOR_PATH . 'composer/autoload_classmap.php')) {
|
||||
$classMap = require VENDOR_PATH . 'composer/autoload_classmap.php';
|
||||
if ($classMap) {
|
||||
self::addClassMap($classMap);
|
||||
}
|
||||
}
|
||||
|
||||
if (is_file(VENDOR_PATH . 'composer/autoload_files.php')) {
|
||||
$includeFiles = require VENDOR_PATH . 'composer/autoload_files.php';
|
||||
foreach ($includeFiles as $fileIdentifier => $file) {
|
||||
if (empty(self::$autoloadFiles[$fileIdentifier])) {
|
||||
__require_file($file);
|
||||
self::$autoloadFiles[$fileIdentifier] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 导入所需的类库 同java的Import 本函数有缓存功能
|
||||
* @param string $class 类库命名空间字符串
|
||||
* @param string $baseUrl 起始路径
|
||||
* @param string $ext 导入的文件扩展名
|
||||
* @return boolean
|
||||
*/
|
||||
public static function import($class, $baseUrl = '', $ext = EXT)
|
||||
{
|
||||
static $_file = [];
|
||||
$key = $class . $baseUrl;
|
||||
$class = str_replace(['.', '#'], [DS, '.'], $class);
|
||||
if (isset($_file[$key])) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (empty($baseUrl)) {
|
||||
list($name, $class) = explode(DS, $class, 2);
|
||||
|
||||
if (isset(self::$prefixDirsPsr4[$name . '\\'])) {
|
||||
// 注册的命名空间
|
||||
$baseUrl = self::$prefixDirsPsr4[$name . '\\'];
|
||||
} elseif ('@' == $name) {
|
||||
//加载当前模块应用类库
|
||||
$baseUrl = App::$modulePath;
|
||||
} elseif (is_dir(EXTEND_PATH . $name)) {
|
||||
$baseUrl = EXTEND_PATH . $name . DS;
|
||||
} else {
|
||||
// 加载其它模块的类库
|
||||
$baseUrl = APP_PATH . $name . DS;
|
||||
}
|
||||
} elseif (substr($baseUrl, -1) != DS) {
|
||||
$baseUrl .= DS;
|
||||
}
|
||||
// 如果类存在 则导入类库文件
|
||||
if (is_array($baseUrl)) {
|
||||
foreach ($baseUrl as $path) {
|
||||
$filename = $path . DS . $class . $ext;
|
||||
if (is_file($filename)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$filename = $baseUrl . $class . $ext;
|
||||
}
|
||||
|
||||
if (!empty($filename) && is_file($filename)) {
|
||||
// 开启调试模式Win环境严格区分大小写
|
||||
if (IS_WIN && pathinfo($filename, PATHINFO_FILENAME) != pathinfo(realpath($filename), PATHINFO_FILENAME)) {
|
||||
return false;
|
||||
}
|
||||
__include_file($filename);
|
||||
$_file[$key] = true;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 实例化(分层)模型
|
||||
* @param string $name Model名称
|
||||
* @param string $layer 业务层名称
|
||||
* @param bool $appendSuffix 是否添加类名后缀
|
||||
* @param string $common 公共模块名
|
||||
* @return object
|
||||
* @throws ClassNotFoundException
|
||||
*/
|
||||
public static function model($name = '', $layer = 'model', $appendSuffix = false, $common = 'common')
|
||||
{
|
||||
$guid = $name . $layer;
|
||||
if (isset(self::$instance[$guid])) {
|
||||
return self::$instance[$guid];
|
||||
}
|
||||
if (false !== strpos($name, '\\')) {
|
||||
$class = $name;
|
||||
$module = Request::instance()->module();
|
||||
} else {
|
||||
if (strpos($name, '/')) {
|
||||
list($module, $name) = explode('/', $name, 2);
|
||||
} else {
|
||||
$module = Request::instance()->module();
|
||||
}
|
||||
$class = self::parseClass($module, $layer, $name, $appendSuffix);
|
||||
}
|
||||
if (class_exists($class)) {
|
||||
$model = new $class();
|
||||
} else {
|
||||
$class = str_replace('\\' . $module . '\\', '\\' . $common . '\\', $class);
|
||||
if (class_exists($class)) {
|
||||
$model = new $class();
|
||||
} else {
|
||||
throw new ClassNotFoundException('class not exists:' . $class, $class);
|
||||
}
|
||||
}
|
||||
self::$instance[$guid] = $model;
|
||||
return $model;
|
||||
}
|
||||
|
||||
/**
|
||||
* 实例化(分层)控制器 格式:[模块名/]控制器名
|
||||
* @param string $name 资源地址
|
||||
* @param string $layer 控制层名称
|
||||
* @param bool $appendSuffix 是否添加类名后缀
|
||||
* @param string $empty 空控制器名称
|
||||
* @return object
|
||||
* @throws ClassNotFoundException
|
||||
*/
|
||||
public static function controller($name, $layer = 'controller', $appendSuffix = false, $empty = '')
|
||||
{
|
||||
if (false !== strpos($name, '\\')) {
|
||||
$class = $name;
|
||||
$module = Request::instance()->module();
|
||||
} else {
|
||||
if (strpos($name, '/')) {
|
||||
list($module, $name) = explode('/', $name);
|
||||
} else {
|
||||
$module = Request::instance()->module();
|
||||
}
|
||||
$class = self::parseClass($module, $layer, $name, $appendSuffix);
|
||||
}
|
||||
if (class_exists($class)) {
|
||||
return App::invokeClass($class);
|
||||
} elseif ($empty && class_exists($emptyClass = self::parseClass($module, $layer, $empty, $appendSuffix))) {
|
||||
return new $emptyClass(Request::instance());
|
||||
} else {
|
||||
throw new ClassNotFoundException('class not exists:' . $class, $class);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 实例化验证类 格式:[模块名/]验证器名
|
||||
* @param string $name 资源地址
|
||||
* @param string $layer 验证层名称
|
||||
* @param bool $appendSuffix 是否添加类名后缀
|
||||
* @param string $common 公共模块名
|
||||
* @return object|false
|
||||
* @throws ClassNotFoundException
|
||||
*/
|
||||
public static function validate($name = '', $layer = 'validate', $appendSuffix = false, $common = 'common')
|
||||
{
|
||||
$name = $name ?: Config::get('default_validate');
|
||||
if (empty($name)) {
|
||||
return new Validate;
|
||||
}
|
||||
$guid = $name . $layer;
|
||||
if (isset(self::$instance[$guid])) {
|
||||
return self::$instance[$guid];
|
||||
}
|
||||
if (false !== strpos($name, '\\')) {
|
||||
$class = $name;
|
||||
$module = Request::instance()->module();
|
||||
} else {
|
||||
if (strpos($name, '/')) {
|
||||
list($module, $name) = explode('/', $name);
|
||||
} else {
|
||||
$module = Request::instance()->module();
|
||||
}
|
||||
$class = self::parseClass($module, $layer, $name, $appendSuffix);
|
||||
}
|
||||
if (class_exists($class)) {
|
||||
$validate = new $class;
|
||||
} else {
|
||||
$class = str_replace('\\' . $module . '\\', '\\' . $common . '\\', $class);
|
||||
if (class_exists($class)) {
|
||||
$validate = new $class;
|
||||
} else {
|
||||
throw new ClassNotFoundException('class not exists:' . $class, $class);
|
||||
}
|
||||
}
|
||||
self::$instance[$guid] = $validate;
|
||||
return $validate;
|
||||
}
|
||||
|
||||
/**
|
||||
* 数据库初始化 并取得数据库类实例
|
||||
* @param mixed $config 数据库配置
|
||||
* @param bool|string $name 连接标识 true 强制重新连接
|
||||
* @return \think\db\Connection
|
||||
*/
|
||||
public static function db($config = [], $name = false)
|
||||
{
|
||||
return Db::connect($config, $name);
|
||||
}
|
||||
|
||||
/**
|
||||
* 远程调用模块的操作方法 参数格式 [模块/控制器/]操作
|
||||
* @param string $url 调用地址
|
||||
* @param string|array $vars 调用参数 支持字符串和数组
|
||||
* @param string $layer 要调用的控制层名称
|
||||
* @param bool $appendSuffix 是否添加类名后缀
|
||||
* @return mixed
|
||||
*/
|
||||
public static function action($url, $vars = [], $layer = 'controller', $appendSuffix = false)
|
||||
{
|
||||
$info = pathinfo($url);
|
||||
$action = $info['basename'];
|
||||
$module = '.' != $info['dirname'] ? $info['dirname'] : Request::instance()->controller();
|
||||
$class = self::controller($module, $layer, $appendSuffix);
|
||||
if ($class) {
|
||||
if (is_scalar($vars)) {
|
||||
if (strpos($vars, '=')) {
|
||||
parse_str($vars, $vars);
|
||||
} else {
|
||||
$vars = [$vars];
|
||||
}
|
||||
}
|
||||
return App::invokeMethod([$class, $action . Config::get('action_suffix')], $vars);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 字符串命名风格转换
|
||||
* type 0 将Java风格转换为C的风格 1 将C风格转换为Java的风格
|
||||
* @param string $name 字符串
|
||||
* @param integer $type 转换类型
|
||||
* @param bool $ucfirst 首字母是否大写(驼峰规则)
|
||||
* @return string
|
||||
*/
|
||||
public static function parseName($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), "_"));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析应用类的类名
|
||||
* @param string $module 模块名
|
||||
* @param string $layer 层名 controller model ...
|
||||
* @param string $name 类名
|
||||
* @param bool $appendSuffix
|
||||
* @return string
|
||||
*/
|
||||
public static function parseClass($module, $layer, $name, $appendSuffix = false)
|
||||
{
|
||||
$name = str_replace(['/', '.'], '\\', $name);
|
||||
$array = explode('\\', $name);
|
||||
$class = self::parseName(array_pop($array), 1) . (App::$suffix || $appendSuffix ? ucfirst($layer) : '');
|
||||
$path = $array ? implode('\\', $array) . '\\' : '';
|
||||
return App::$namespace . '\\' . ($module ? $module . '\\' : '') . $layer . '\\' . $path . $class;
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化类的实例
|
||||
* @return void
|
||||
*/
|
||||
public static function clearInstance()
|
||||
{
|
||||
self::$instance = [];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 作用范围隔离
|
||||
*
|
||||
* @param $file
|
||||
* @return mixed
|
||||
*/
|
||||
function __include_file($file)
|
||||
{
|
||||
return include $file;
|
||||
}
|
||||
|
||||
function __require_file($file)
|
||||
{
|
||||
return require $file;
|
||||
}
|
213
thinkphp/library/think/Log.php
Normal file
213
thinkphp/library/think/Log.php
Normal file
@ -0,0 +1,213 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2017 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
|
||||
* @package think
|
||||
*
|
||||
* @method void log($msg) static
|
||||
* @method void error($msg) static
|
||||
* @method void info($msg) static
|
||||
* @method void sql($msg) static
|
||||
* @method void notice($msg) static
|
||||
* @method void alert($msg) static
|
||||
*/
|
||||
class Log
|
||||
{
|
||||
const LOG = 'log';
|
||||
const ERROR = 'error';
|
||||
const INFO = 'info';
|
||||
const SQL = 'sql';
|
||||
const NOTICE = 'notice';
|
||||
const ALERT = 'alert';
|
||||
const DEBUG = 'debug';
|
||||
|
||||
// 日志信息
|
||||
protected static $log = [];
|
||||
// 配置参数
|
||||
protected static $config = [];
|
||||
// 日志类型
|
||||
protected static $type = ['log', 'error', 'info', 'sql', 'notice', 'alert', 'debug'];
|
||||
// 日志写入驱动
|
||||
protected static $driver;
|
||||
|
||||
// 当前日志授权key
|
||||
protected static $key;
|
||||
|
||||
/**
|
||||
* 日志初始化
|
||||
* @param array $config
|
||||
*/
|
||||
public static function init($config = [])
|
||||
{
|
||||
$type = isset($config['type']) ? $config['type'] : 'File';
|
||||
$class = false !== strpos($type, '\\') ? $type : '\\think\\log\\driver\\' . ucwords($type);
|
||||
self::$config = $config;
|
||||
unset($config['type']);
|
||||
if (class_exists($class)) {
|
||||
self::$driver = new $class($config);
|
||||
} else {
|
||||
throw new ClassNotFoundException('class not exists:' . $class, $class);
|
||||
}
|
||||
// 记录初始化信息
|
||||
App::$debug && Log::record('[ LOG ] INIT ' . $type, 'info');
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取日志信息
|
||||
* @param string $type 信息类型
|
||||
* @return array
|
||||
*/
|
||||
public static function getLog($type = '')
|
||||
{
|
||||
return $type ? self::$log[$type] : self::$log;
|
||||
}
|
||||
|
||||
/**
|
||||
* 记录调试信息
|
||||
* @param mixed $msg 调试信息
|
||||
* @param string $type 信息类型
|
||||
* @return void
|
||||
*/
|
||||
public static function record($msg, $type = 'log')
|
||||
{
|
||||
self::$log[$type][] = $msg;
|
||||
if (IS_CLI) {
|
||||
// 命令行下面日志写入改进
|
||||
self::save();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 清空日志信息
|
||||
* @return void
|
||||
*/
|
||||
public static function clear()
|
||||
{
|
||||
self::$log = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* 当前日志记录的授权key
|
||||
* @param string $key 授权key
|
||||
* @return void
|
||||
*/
|
||||
public static function key($key)
|
||||
{
|
||||
self::$key = $key;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查日志写入权限
|
||||
* @param array $config 当前日志配置参数
|
||||
* @return bool
|
||||
*/
|
||||
public static function check($config)
|
||||
{
|
||||
if (self::$key && !empty($config['allow_key']) && !in_array(self::$key, $config['allow_key'])) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存调试信息
|
||||
* @return bool
|
||||
*/
|
||||
public static function save()
|
||||
{
|
||||
if (!empty(self::$log)) {
|
||||
if (is_null(self::$driver)) {
|
||||
self::init(Config::get('log'));
|
||||
}
|
||||
|
||||
if (!self::check(self::$config)) {
|
||||
// 检测日志写入权限
|
||||
return false;
|
||||
}
|
||||
|
||||
if (empty(self::$config['level'])) {
|
||||
// 获取全部日志
|
||||
$log = self::$log;
|
||||
if (!App::$debug && isset($log['debug'])) {
|
||||
unset($log['debug']);
|
||||
}
|
||||
} else {
|
||||
// 记录允许级别
|
||||
$log = [];
|
||||
foreach (self::$config['level'] as $level) {
|
||||
if (isset(self::$log[$level])) {
|
||||
$log[$level] = self::$log[$level];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$result = self::$driver->save($log);
|
||||
if ($result) {
|
||||
self::$log = [];
|
||||
}
|
||||
Hook::listen('log_write_done', $log);
|
||||
return $result;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 实时写入日志信息 并支持行为
|
||||
* @param mixed $msg 调试信息
|
||||
* @param string $type 信息类型
|
||||
* @param bool $force 是否强制写入
|
||||
* @return bool
|
||||
*/
|
||||
public static function write($msg, $type = 'log', $force = false)
|
||||
{
|
||||
$log = self::$log;
|
||||
// 封装日志信息
|
||||
if (true === $force || empty(self::$config['level'])) {
|
||||
$log[$type][] = $msg;
|
||||
} elseif (in_array($type, self::$config['level'])) {
|
||||
$log[$type][] = $msg;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 监听log_write
|
||||
Hook::listen('log_write', $log);
|
||||
if (is_null(self::$driver)) {
|
||||
self::init(Config::get('log'));
|
||||
}
|
||||
// 写入日志
|
||||
$result = self::$driver->save($log);
|
||||
if ($result) {
|
||||
self::$log = [];
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 静态调用
|
||||
* @param $method
|
||||
* @param $args
|
||||
* @return mixed
|
||||
*/
|
||||
public static function __callStatic($method, $args)
|
||||
{
|
||||
if (in_array($method, self::$type)) {
|
||||
array_push($args, $method);
|
||||
return call_user_func_array('\\think\\Log::record', $args);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
2212
thinkphp/library/think/Model.php
Normal file
2212
thinkphp/library/think/Model.php
Normal file
File diff suppressed because it is too large
Load Diff
401
thinkphp/library/think/Paginator.php
Normal file
401
thinkphp/library/think/Paginator.php
Normal file
@ -0,0 +1,401 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2017 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;
|
||||
use Traversable;
|
||||
|
||||
abstract class Paginator implements ArrayAccess, Countable, IteratorAggregate, JsonSerializable
|
||||
{
|
||||
/** @var bool 是否为简洁模式 */
|
||||
protected $simple = false;
|
||||
|
||||
/** @var Collection 数据集 */
|
||||
protected $items;
|
||||
|
||||
/** @var integer 当前页 */
|
||||
protected $currentPage;
|
||||
|
||||
/** @var integer 最后一页 */
|
||||
protected $lastPage;
|
||||
|
||||
/** @var integer|null 数据总数 */
|
||||
protected $total;
|
||||
|
||||
/** @var integer 每页的数量 */
|
||||
protected $listRows;
|
||||
|
||||
/** @var bool 是否有下一页 */
|
||||
protected $hasMore;
|
||||
|
||||
/** @var array 一些配置 */
|
||||
protected $options = [
|
||||
'var_page' => 'page',
|
||||
'path' => '/',
|
||||
'query' => [],
|
||||
'fragment' => '',
|
||||
];
|
||||
|
||||
/** @var mixed simple模式下的下个元素 */
|
||||
protected $nextItem;
|
||||
|
||||
public function __construct($items, $listRows, $currentPage = null, $total = null, $simple = false, $options = [])
|
||||
{
|
||||
$this->options = array_merge($this->options, $options);
|
||||
|
||||
$this->options['path'] = '/' != $this->options['path'] ? rtrim($this->options['path'], '/') : $this->options['path'];
|
||||
|
||||
$this->simple = $simple;
|
||||
$this->listRows = $listRows;
|
||||
|
||||
if (!$items instanceof Collection) {
|
||||
$items = Collection::make($items);
|
||||
}
|
||||
|
||||
if ($simple) {
|
||||
$this->currentPage = $this->setCurrentPage($currentPage);
|
||||
$this->hasMore = count($items) > ($this->listRows);
|
||||
if ($this->hasMore) {
|
||||
$this->nextItem = $items->slice($this->listRows, 1);
|
||||
}
|
||||
$items = $items->slice(0, $this->listRows);
|
||||
} else {
|
||||
$this->total = $total;
|
||||
$this->lastPage = (int) ceil($total / $listRows);
|
||||
$this->currentPage = $this->setCurrentPage($currentPage);
|
||||
$this->hasMore = $this->currentPage < $this->lastPage;
|
||||
}
|
||||
$this->items = $items;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $items
|
||||
* @param $listRows
|
||||
* @param null $currentPage
|
||||
* @param bool $simple
|
||||
* @param null $total
|
||||
* @param array $options
|
||||
* @return Paginator
|
||||
*/
|
||||
public static function make($items, $listRows, $currentPage = null, $total = null, $simple = false, $options = [])
|
||||
{
|
||||
return new static($items, $listRows, $currentPage, $total, $simple, $options);
|
||||
}
|
||||
|
||||
protected function setCurrentPage($currentPage)
|
||||
{
|
||||
if (!$this->simple && $currentPage > $this->lastPage) {
|
||||
return $this->lastPage > 0 ? $this->lastPage : 1;
|
||||
}
|
||||
|
||||
return $currentPage;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取页码对应的链接
|
||||
*
|
||||
* @param $page
|
||||
* @return string
|
||||
*/
|
||||
protected function url($page)
|
||||
{
|
||||
if ($page <= 0) {
|
||||
$page = 1;
|
||||
}
|
||||
|
||||
if (strpos($this->options['path'], '[PAGE]') === false) {
|
||||
$parameters = [$this->options['var_page'] => $page];
|
||||
$path = $this->options['path'];
|
||||
} else {
|
||||
$parameters = [];
|
||||
$path = str_replace('[PAGE]', $page, $this->options['path']);
|
||||
}
|
||||
if (count($this->options['query']) > 0) {
|
||||
$parameters = array_merge($this->options['query'], $parameters);
|
||||
}
|
||||
$url = $path;
|
||||
if (!empty($parameters)) {
|
||||
$url .= '?' . urldecode(http_build_query($parameters, null, '&'));
|
||||
}
|
||||
return $url . $this->buildFragment();
|
||||
}
|
||||
|
||||
/**
|
||||
* 自动获取当前页码
|
||||
* @param string $varPage
|
||||
* @param int $default
|
||||
* @return int
|
||||
*/
|
||||
public static function getCurrentPage($varPage = 'page', $default = 1)
|
||||
{
|
||||
$page = (int) Request::instance()->param($varPage);
|
||||
|
||||
if (filter_var($page, FILTER_VALIDATE_INT) !== false && $page >= 1) {
|
||||
return $page;
|
||||
}
|
||||
|
||||
return $default;
|
||||
}
|
||||
|
||||
/**
|
||||
* 自动获取当前的path
|
||||
* @return string
|
||||
*/
|
||||
public static function getCurrentPath()
|
||||
{
|
||||
return Request::instance()->baseUrl();
|
||||
}
|
||||
|
||||
public function total()
|
||||
{
|
||||
if ($this->simple) {
|
||||
throw new \DomainException('not support total');
|
||||
}
|
||||
return $this->total;
|
||||
}
|
||||
|
||||
public function listRows()
|
||||
{
|
||||
return $this->listRows;
|
||||
}
|
||||
|
||||
public function currentPage()
|
||||
{
|
||||
return $this->currentPage;
|
||||
}
|
||||
|
||||
public function lastPage()
|
||||
{
|
||||
if ($this->simple) {
|
||||
throw new \DomainException('not support last');
|
||||
}
|
||||
return $this->lastPage;
|
||||
}
|
||||
|
||||
/**
|
||||
* 数据是否足够分页
|
||||
* @return boolean
|
||||
*/
|
||||
public function hasPages()
|
||||
{
|
||||
return !(1 == $this->currentPage && !$this->hasMore);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建一组分页链接
|
||||
*
|
||||
* @param int $start
|
||||
* @param int $end
|
||||
* @return array
|
||||
*/
|
||||
public function getUrlRange($start, $end)
|
||||
{
|
||||
$urls = [];
|
||||
|
||||
for ($page = $start; $page <= $end; $page++) {
|
||||
$urls[$page] = $this->url($page);
|
||||
}
|
||||
|
||||
return $urls;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置URL锚点
|
||||
*
|
||||
* @param string|null $fragment
|
||||
* @return $this
|
||||
*/
|
||||
public function fragment($fragment)
|
||||
{
|
||||
$this->options['fragment'] = $fragment;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加URL参数
|
||||
*
|
||||
* @param array|string $key
|
||||
* @param string|null $value
|
||||
* @return $this
|
||||
*/
|
||||
public function appends($key, $value = null)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造锚点字符串
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function buildFragment()
|
||||
{
|
||||
return $this->options['fragment'] ? '#' . $this->options['fragment'] : '';
|
||||
}
|
||||
|
||||
/**
|
||||
* 渲染分页html
|
||||
* @return mixed
|
||||
*/
|
||||
abstract public function render();
|
||||
|
||||
public function items()
|
||||
{
|
||||
return $this->items->all();
|
||||
}
|
||||
|
||||
public function getCollection()
|
||||
{
|
||||
return $this->items;
|
||||
}
|
||||
|
||||
public function isEmpty()
|
||||
{
|
||||
return $this->items->isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* 给每个元素执行个回调
|
||||
*
|
||||
* @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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve an external iterator
|
||||
* @return Traversable An instance of an object implementing <b>Iterator</b> or
|
||||
* <b>Traversable</b>
|
||||
*/
|
||||
public function getIterator()
|
||||
{
|
||||
return new ArrayIterator($this->items->all());
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether a offset exists
|
||||
* @param mixed $offset
|
||||
* @return bool
|
||||
*/
|
||||
public function offsetExists($offset)
|
||||
{
|
||||
return $this->items->offsetExists($offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Offset to retrieve
|
||||
* @param mixed $offset
|
||||
* @return mixed
|
||||
*/
|
||||
public function offsetGet($offset)
|
||||
{
|
||||
return $this->items->offsetGet($offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Offset to set
|
||||
* @param mixed $offset
|
||||
* @param mixed $value
|
||||
*/
|
||||
public function offsetSet($offset, $value)
|
||||
{
|
||||
$this->items->offsetSet($offset, $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Offset to unset
|
||||
* @param mixed $offset
|
||||
* @return void
|
||||
* @since 5.0.0
|
||||
*/
|
||||
public function offsetUnset($offset)
|
||||
{
|
||||
$this->items->offsetUnset($offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Count elements of an object
|
||||
*/
|
||||
public function count()
|
||||
{
|
||||
return $this->items->count();
|
||||
}
|
||||
|
||||
public function __toString()
|
||||
{
|
||||
return (string) $this->render();
|
||||
}
|
||||
|
||||
public function toArray()
|
||||
{
|
||||
if ($this->simple) {
|
||||
return [
|
||||
'per_page' => $this->listRows,
|
||||
'current_page' => $this->currentPage,
|
||||
'has_more' => $this->hasMore,
|
||||
'next_item' => $this->nextItem,
|
||||
'data' => $this->items->toArray(),
|
||||
];
|
||||
} else {
|
||||
return [
|
||||
'total' => $this->total,
|
||||
'per_page' => $this->listRows,
|
||||
'current_page' => $this->currentPage,
|
||||
'last_page' => $this->lastPage,
|
||||
'data' => $this->items->toArray(),
|
||||
];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify data which should be serialized to JSON
|
||||
*/
|
||||
public function jsonSerialize()
|
||||
{
|
||||
return $this->toArray();
|
||||
}
|
||||
|
||||
public function __call($name, $arguments)
|
||||
{
|
||||
return call_user_func_array([$this->getCollection(), $name], $arguments);
|
||||
}
|
||||
|
||||
}
|
1205
thinkphp/library/think/Process.php
Normal file
1205
thinkphp/library/think/Process.php
Normal file
File diff suppressed because it is too large
Load Diff
1645
thinkphp/library/think/Request.php
Normal file
1645
thinkphp/library/think/Request.php
Normal file
File diff suppressed because it is too large
Load Diff
334
thinkphp/library/think/Response.php
Normal file
334
thinkphp/library/think/Response.php
Normal file
@ -0,0 +1,334 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace think;
|
||||
|
||||
use think\response\Json as JsonResponse;
|
||||
use think\response\Jsonp as JsonpResponse;
|
||||
use think\response\Redirect as RedirectResponse;
|
||||
use think\response\View as ViewResponse;
|
||||
use think\response\Xml as XmlResponse;
|
||||
|
||||
class Response
|
||||
{
|
||||
// 原始数据
|
||||
protected $data;
|
||||
|
||||
// 当前的contentType
|
||||
protected $contentType = 'text/html';
|
||||
|
||||
// 字符集
|
||||
protected $charset = 'utf-8';
|
||||
|
||||
//状态
|
||||
protected $code = 200;
|
||||
|
||||
// 输出参数
|
||||
protected $options = [];
|
||||
// header参数
|
||||
protected $header = [];
|
||||
|
||||
protected $content = null;
|
||||
|
||||
/**
|
||||
* 构造函数
|
||||
* @access public
|
||||
* @param mixed $data 输出数据
|
||||
* @param int $code
|
||||
* @param array $header
|
||||
* @param array $options 输出参数
|
||||
*/
|
||||
public function __construct($data = '', $code = 200, array $header = [], $options = [])
|
||||
{
|
||||
$this->data($data);
|
||||
if (!empty($options)) {
|
||||
$this->options = array_merge($this->options, $options);
|
||||
}
|
||||
$this->contentType($this->contentType, $this->charset);
|
||||
$this->header = array_merge($this->header, $header);
|
||||
$this->code = $code;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建Response对象
|
||||
* @access public
|
||||
* @param mixed $data 输出数据
|
||||
* @param string $type 输出类型
|
||||
* @param int $code
|
||||
* @param array $header
|
||||
* @param array $options 输出参数
|
||||
* @return Response|JsonResponse|ViewResponse|XmlResponse|RedirectResponse|JsonpResponse
|
||||
*/
|
||||
public static function create($data = '', $type = '', $code = 200, array $header = [], $options = [])
|
||||
{
|
||||
$type = empty($type) ? 'null' : strtolower($type);
|
||||
|
||||
$class = false !== strpos($type, '\\') ? $type : '\\think\\response\\' . ucfirst($type);
|
||||
if (class_exists($class)) {
|
||||
$response = new $class($data, $code, $header, $options);
|
||||
} else {
|
||||
$response = new static($data, $code, $header, $options);
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送数据到客户端
|
||||
* @access public
|
||||
* @return mixed
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public function send()
|
||||
{
|
||||
// 监听response_send
|
||||
Hook::listen('response_send', $this);
|
||||
|
||||
// 处理输出数据
|
||||
$data = $this->getContent();
|
||||
|
||||
// Trace调试注入
|
||||
if (Env::get('app_trace', Config::get('app_trace'))) {
|
||||
Debug::inject($this, $data);
|
||||
}
|
||||
|
||||
if (200 == $this->code) {
|
||||
$cache = Request::instance()->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';
|
||||
Cache::tag($cache[2])->set($cache[0], [$data, $this->header], $cache[1]);
|
||||
}
|
||||
}
|
||||
|
||||
if (!headers_sent() && !empty($this->header)) {
|
||||
// 发送状态码
|
||||
http_response_code($this->code);
|
||||
// 发送头部信息
|
||||
foreach ($this->header as $name => $val) {
|
||||
if (is_null($val)) {
|
||||
header($name);
|
||||
} else {
|
||||
header($name . ':' . $val);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
echo $data;
|
||||
|
||||
if (function_exists('fastcgi_finish_request')) {
|
||||
// 提高页面响应
|
||||
fastcgi_finish_request();
|
||||
}
|
||||
|
||||
// 监听response_end
|
||||
Hook::listen('response_end', $this);
|
||||
|
||||
// 清空当次请求有效的数据
|
||||
if (!($this instanceof RedirectResponse)) {
|
||||
Session::flush();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理数据
|
||||
* @access protected
|
||||
* @param mixed $data 要处理的数据
|
||||
* @return mixed
|
||||
*/
|
||||
protected function output($data)
|
||||
{
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 输出的参数
|
||||
* @access public
|
||||
* @param mixed $options 输出参数
|
||||
* @return $this
|
||||
*/
|
||||
public function options($options = [])
|
||||
{
|
||||
$this->options = array_merge($this->options, $options);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 输出数据设置
|
||||
* @access public
|
||||
* @param mixed $data 输出数据
|
||||
* @return $this
|
||||
*/
|
||||
public function data($data)
|
||||
{
|
||||
$this->data = $data;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置响应头
|
||||
* @access public
|
||||
* @param string|array $name 参数名
|
||||
* @param string $value 参数值
|
||||
* @return $this
|
||||
*/
|
||||
public function header($name, $value = null)
|
||||
{
|
||||
if (is_array($name)) {
|
||||
$this->header = array_merge($this->header, $name);
|
||||
} else {
|
||||
$this->header[$name] = $value;
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置页面输出内容
|
||||
* @param $content
|
||||
* @return $this
|
||||
*/
|
||||
public function content($content)
|
||||
{
|
||||
if (null !== $content && !is_string($content) && !is_numeric($content) && !is_callable([
|
||||
$content,
|
||||
'__toString',
|
||||
])
|
||||
) {
|
||||
throw new \InvalidArgumentException(sprintf('variable type error: %s', gettype($content)));
|
||||
}
|
||||
|
||||
$this->content = (string) $content;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送HTTP状态
|
||||
* @param integer $code 状态码
|
||||
* @return $this
|
||||
*/
|
||||
public function code($code)
|
||||
{
|
||||
$this->code = $code;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* LastModified
|
||||
* @param string $time
|
||||
* @return $this
|
||||
*/
|
||||
public function lastModified($time)
|
||||
{
|
||||
$this->header['Last-Modified'] = $time;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Expires
|
||||
* @param string $time
|
||||
* @return $this
|
||||
*/
|
||||
public function expires($time)
|
||||
{
|
||||
$this->header['Expires'] = $time;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* ETag
|
||||
* @param string $eTag
|
||||
* @return $this
|
||||
*/
|
||||
public function eTag($eTag)
|
||||
{
|
||||
$this->header['ETag'] = $eTag;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 页面缓存控制
|
||||
* @param string $cache 状态码
|
||||
* @return $this
|
||||
*/
|
||||
public function cacheControl($cache)
|
||||
{
|
||||
$this->header['Cache-control'] = $cache;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 页面输出类型
|
||||
* @param string $contentType 输出类型
|
||||
* @param string $charset 输出编码
|
||||
* @return $this
|
||||
*/
|
||||
public function contentType($contentType, $charset = 'utf-8')
|
||||
{
|
||||
$this->header['Content-Type'] = $contentType . '; charset=' . $charset;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取头部信息
|
||||
* @param string $name 头部名称
|
||||
* @return mixed
|
||||
*/
|
||||
public function getHeader($name = '')
|
||||
{
|
||||
if (!empty($name)) {
|
||||
return isset($this->header[$name]) ? $this->header[$name] : null;
|
||||
} else {
|
||||
return $this->header;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取原始数据
|
||||
* @return mixed
|
||||
*/
|
||||
public function getData()
|
||||
{
|
||||
return $this->data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取输出数据
|
||||
* @return mixed
|
||||
*/
|
||||
public function getContent()
|
||||
{
|
||||
if (null == $this->content) {
|
||||
$content = $this->output($this->data);
|
||||
|
||||
if (null !== $content && !is_string($content) && !is_numeric($content) && !is_callable([
|
||||
$content,
|
||||
'__toString',
|
||||
])
|
||||
) {
|
||||
throw new \InvalidArgumentException(sprintf('variable type error: %s', gettype($content)));
|
||||
}
|
||||
|
||||
$this->content = (string) $content;
|
||||
}
|
||||
return $this->content;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取状态码
|
||||
* @return integer
|
||||
*/
|
||||
public function getCode()
|
||||
{
|
||||
return $this->code;
|
||||
}
|
||||
}
|
1603
thinkphp/library/think/Route.php
Normal file
1603
thinkphp/library/think/Route.php
Normal file
File diff suppressed because it is too large
Load Diff
366
thinkphp/library/think/Session.php
Normal file
366
thinkphp/library/think/Session.php
Normal file
@ -0,0 +1,366 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2017 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
|
||||
{
|
||||
protected static $prefix = '';
|
||||
protected static $init = null;
|
||||
|
||||
/**
|
||||
* 设置或者获取session作用域(前缀)
|
||||
* @param string $prefix
|
||||
* @return string|void
|
||||
*/
|
||||
public static function prefix($prefix = '')
|
||||
{
|
||||
empty(self::$init) && self::boot();
|
||||
if (empty($prefix) && null !== $prefix) {
|
||||
return self::$prefix;
|
||||
} else {
|
||||
self::$prefix = $prefix;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* session初始化
|
||||
* @param array $config
|
||||
* @return void
|
||||
* @throws \think\Exception
|
||||
*/
|
||||
public static function init(array $config = [])
|
||||
{
|
||||
if (empty($config)) {
|
||||
$config = Config::get('session');
|
||||
}
|
||||
// 记录初始化信息
|
||||
App::$debug && Log::record('[ SESSION ] INIT ' . var_export($config, true), 'info');
|
||||
$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']) && ('' === self::$prefix || null === self::$prefix)) {
|
||||
self::$prefix = $config['prefix'];
|
||||
}
|
||||
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();
|
||||
self::$init = true;
|
||||
} else {
|
||||
self::$init = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* session自动启动或者初始化
|
||||
* @return void
|
||||
*/
|
||||
public static function boot()
|
||||
{
|
||||
if (is_null(self::$init)) {
|
||||
self::init();
|
||||
} elseif (false === self::$init) {
|
||||
if (PHP_SESSION_ACTIVE != session_status()) {
|
||||
session_start();
|
||||
}
|
||||
self::$init = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* session设置
|
||||
* @param string $name session名称
|
||||
* @param mixed $value session值
|
||||
* @param string|null $prefix 作用域(前缀)
|
||||
* @return void
|
||||
*/
|
||||
public static function set($name, $value = '', $prefix = null)
|
||||
{
|
||||
empty(self::$init) && self::boot();
|
||||
|
||||
$prefix = !is_null($prefix) ? $prefix : self::$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;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* session获取
|
||||
* @param string $name session名称
|
||||
* @param string|null $prefix 作用域(前缀)
|
||||
* @return mixed
|
||||
*/
|
||||
public static function get($name = '', $prefix = null)
|
||||
{
|
||||
empty(self::$init) && self::boot();
|
||||
$prefix = !is_null($prefix) ? $prefix : self::$prefix;
|
||||
if ('' == $name) {
|
||||
// 获取全部的session
|
||||
$value = $prefix ? (!empty($_SESSION[$prefix]) ? $_SESSION[$prefix] : []) : $_SESSION;
|
||||
} elseif ($prefix) {
|
||||
// 获取session
|
||||
if (strpos($name, '.')) {
|
||||
list($name1, $name2) = explode('.', $name);
|
||||
$value = isset($_SESSION[$prefix][$name1][$name2]) ? $_SESSION[$prefix][$name1][$name2] : null;
|
||||
} else {
|
||||
$value = isset($_SESSION[$prefix][$name]) ? $_SESSION[$prefix][$name] : null;
|
||||
}
|
||||
} else {
|
||||
if (strpos($name, '.')) {
|
||||
list($name1, $name2) = explode('.', $name);
|
||||
$value = isset($_SESSION[$name1][$name2]) ? $_SESSION[$name1][$name2] : null;
|
||||
} else {
|
||||
$value = isset($_SESSION[$name]) ? $_SESSION[$name] : null;
|
||||
}
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* session获取并删除
|
||||
* @param string $name session名称
|
||||
* @param string|null $prefix 作用域(前缀)
|
||||
* @return mixed
|
||||
*/
|
||||
public static function pull($name, $prefix = null)
|
||||
{
|
||||
$result = self::get($name, $prefix);
|
||||
if ($result) {
|
||||
self::delete($name, $prefix);
|
||||
return $result;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* session设置 下一次请求有效
|
||||
* @param string $name session名称
|
||||
* @param mixed $value session值
|
||||
* @param string|null $prefix 作用域(前缀)
|
||||
* @return void
|
||||
*/
|
||||
public static function flash($name, $value)
|
||||
{
|
||||
self::set($name, $value);
|
||||
if (!self::has('__flash__.__time__')) {
|
||||
self::set('__flash__.__time__', $_SERVER['REQUEST_TIME_FLOAT']);
|
||||
}
|
||||
self::push('__flash__', $name);
|
||||
}
|
||||
|
||||
/**
|
||||
* 清空当前请求的session数据
|
||||
* @return void
|
||||
*/
|
||||
public static function flush()
|
||||
{
|
||||
if (self::$init) {
|
||||
$item = self::get('__flash__');
|
||||
|
||||
if (!empty($item)) {
|
||||
$time = $item['__time__'];
|
||||
if ($_SERVER['REQUEST_TIME_FLOAT'] > $time) {
|
||||
unset($item['__time__']);
|
||||
self::delete($item);
|
||||
self::set('__flash__', []);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除session数据
|
||||
* @param string|array $name session名称
|
||||
* @param string|null $prefix 作用域(前缀)
|
||||
* @return void
|
||||
*/
|
||||
public static function delete($name, $prefix = null)
|
||||
{
|
||||
empty(self::$init) && self::boot();
|
||||
$prefix = !is_null($prefix) ? $prefix : self::$prefix;
|
||||
if (is_array($name)) {
|
||||
foreach ($name as $key) {
|
||||
self::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数据
|
||||
* @param string|null $prefix 作用域(前缀)
|
||||
* @return void
|
||||
*/
|
||||
public static function clear($prefix = null)
|
||||
{
|
||||
empty(self::$init) && self::boot();
|
||||
$prefix = !is_null($prefix) ? $prefix : self::$prefix;
|
||||
if ($prefix) {
|
||||
unset($_SESSION[$prefix]);
|
||||
} else {
|
||||
$_SESSION = [];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断session数据
|
||||
* @param string $name session名称
|
||||
* @param string|null $prefix
|
||||
* @return bool
|
||||
*/
|
||||
public static function has($name, $prefix = null)
|
||||
{
|
||||
empty(self::$init) && self::boot();
|
||||
$prefix = !is_null($prefix) ? $prefix : self::$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数组
|
||||
* @param string $key
|
||||
* @param mixed $value
|
||||
* @return void
|
||||
*/
|
||||
public static function push($key, $value)
|
||||
{
|
||||
$array = self::get($key);
|
||||
if (is_null($array)) {
|
||||
$array = [];
|
||||
}
|
||||
$array[] = $value;
|
||||
self::set($key, $array);
|
||||
}
|
||||
|
||||
/**
|
||||
* 启动session
|
||||
* @return void
|
||||
*/
|
||||
public static function start()
|
||||
{
|
||||
session_start();
|
||||
self::$init = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 销毁session
|
||||
* @return void
|
||||
*/
|
||||
public static function destroy()
|
||||
{
|
||||
if (!empty($_SESSION)) {
|
||||
$_SESSION = [];
|
||||
}
|
||||
session_unset();
|
||||
session_destroy();
|
||||
self::$init = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 重新生成session_id
|
||||
* @param bool $delete 是否删除关联会话文件
|
||||
* @return void
|
||||
*/
|
||||
public static function regenerate($delete = false)
|
||||
{
|
||||
session_regenerate_id($delete);
|
||||
}
|
||||
|
||||
/**
|
||||
* 暂停session
|
||||
* @return void
|
||||
*/
|
||||
public static function pause()
|
||||
{
|
||||
// 暂停session
|
||||
session_write_close();
|
||||
self::$init = false;
|
||||
}
|
||||
}
|
1147
thinkphp/library/think/Template.php
Normal file
1147
thinkphp/library/think/Template.php
Normal file
File diff suppressed because it is too large
Load Diff
328
thinkphp/library/think/Url.php
Normal file
328
thinkphp/library/think/Url.php
Normal file
@ -0,0 +1,328 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace think;
|
||||
|
||||
class Url
|
||||
{
|
||||
// 生成URL地址的root
|
||||
protected static $root;
|
||||
protected static $bindCheck;
|
||||
|
||||
/**
|
||||
* URL生成 支持路由反射
|
||||
* @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 static function build($url = '', $vars = '', $suffix = true, $domain = false)
|
||||
{
|
||||
if (false === $domain && Route::rules('domain')) {
|
||||
$domain = true;
|
||||
}
|
||||
// 解析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 = Route::name(isset($name) ? $name : $url . (isset($info['query']) ? '?' . $info['query'] : ''));
|
||||
if (is_null($rule) && isset($info['query'])) {
|
||||
$rule = Route::name($url);
|
||||
// 解析地址里面参数 合并到vars
|
||||
parse_str($info['query'], $params);
|
||||
$vars = array_merge($params, $vars);
|
||||
unset($info['query']);
|
||||
}
|
||||
}
|
||||
if (!empty($rule) && $match = self::getRuleUrl($rule, $vars)) {
|
||||
// 匹配路由命名标识
|
||||
$url = $match[0];
|
||||
// 替换可选分隔符
|
||||
$url = preg_replace(['/(\W)\?$/', '/(\W)\?/'], ['', '\1'], $url);
|
||||
if (!empty($match[1])) {
|
||||
$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 = Route::rules('alias');
|
||||
$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 = self::parseUrl($url, $domain);
|
||||
}
|
||||
if (isset($info['query'])) {
|
||||
// 解析地址里面参数 合并到vars
|
||||
parse_str($info['query'], $params);
|
||||
$vars = array_merge($params, $vars);
|
||||
}
|
||||
}
|
||||
|
||||
// 检测URL绑定
|
||||
if (!self::$bindCheck) {
|
||||
$type = Route::getBind('type');
|
||||
if ($type) {
|
||||
$bind = Route::getBind($type);
|
||||
if (0 === strpos($url, $bind)) {
|
||||
$url = substr($url, strlen($bind) + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
// 还原URL分隔符
|
||||
$depr = Config::get('pathinfo_depr');
|
||||
$url = str_replace('/', $depr, $url);
|
||||
|
||||
// URL后缀
|
||||
$suffix = in_array($url, ['/', '']) ? '' : self::parseSuffix($suffix);
|
||||
// 锚点
|
||||
$anchor = !empty($anchor) ? '#' . $anchor : '';
|
||||
// 参数组装
|
||||
if (!empty($vars)) {
|
||||
// 添加参数
|
||||
if (Config::get('url_common_param')) {
|
||||
$vars = urldecode(http_build_query($vars));
|
||||
$url .= $suffix . '?' . $vars . $anchor;
|
||||
} else {
|
||||
$paramType = 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 = self::parseDomain($url, $domain);
|
||||
// URL组装
|
||||
$url = $domain . rtrim(self::$root ?: Request::instance()->root(), '/') . '/' . ltrim($url, '/');
|
||||
|
||||
self::$bindCheck = false;
|
||||
return $url;
|
||||
}
|
||||
|
||||
// 直接解析URL地址
|
||||
protected static function parseUrl($url, &$domain)
|
||||
{
|
||||
$request = Request::instance();
|
||||
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();
|
||||
$domains = Route::rules('domain');
|
||||
if (true === $domain && 2 == substr_count($url, '/')) {
|
||||
$current = $request->host();
|
||||
$match = [];
|
||||
$pos = [];
|
||||
foreach ($domains as $key => $item) {
|
||||
if (isset($item['[bind]']) && 0 === strpos($url, $item['[bind]'][0])) {
|
||||
$pos[$key] = strlen($item['[bind]'][0]) + 1;
|
||||
$match[] = $key;
|
||||
$module = '';
|
||||
}
|
||||
}
|
||||
if ($match) {
|
||||
$domain = current($match);
|
||||
foreach ($match as $item) {
|
||||
if (0 === strpos($current, $item)) {
|
||||
$domain = $item;
|
||||
}
|
||||
}
|
||||
self::$bindCheck = true;
|
||||
$url = substr($url, $pos[$domain]);
|
||||
}
|
||||
} elseif ($domain) {
|
||||
if (isset($domains[$domain]['[bind]'][0])) {
|
||||
$bindModule = $domains[$domain]['[bind]'][0];
|
||||
if ($bindModule && !in_array($bindModule[0], ['\\', '@'])) {
|
||||
$module = '';
|
||||
}
|
||||
}
|
||||
}
|
||||
$module = $module ? $module . '/' : '';
|
||||
|
||||
$controller = Loader::parseName($request->controller());
|
||||
if ('' == $url) {
|
||||
// 空字符串输出当前的 模块/控制器/操作
|
||||
$url = $module . $controller . '/' . $request->action();
|
||||
} else {
|
||||
$path = explode('/', $url);
|
||||
$action = Config::get('url_convert') ? strtolower(array_pop($path)) : array_pop($path);
|
||||
$controller = empty($path) ? $controller : (Config::get('url_convert') ? Loader::parseName(array_pop($path)) : array_pop($path));
|
||||
$module = empty($path) ? $module : array_pop($path) . '/';
|
||||
$url = $module . $controller . '/' . $action;
|
||||
}
|
||||
}
|
||||
return $url;
|
||||
}
|
||||
|
||||
// 检测域名
|
||||
protected static function parseDomain(&$url, $domain)
|
||||
{
|
||||
if (!$domain) {
|
||||
return '';
|
||||
}
|
||||
$request = Request::instance();
|
||||
$rootDomain = Config::get('url_domain_root');
|
||||
if (true === $domain) {
|
||||
// 自动判断域名
|
||||
$domain = Config::get('app_host') ?: $request->host();
|
||||
|
||||
$domains = Route::rules('domain');
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
if (empty($rootDomain)) {
|
||||
$host = Config::get('app_host') ?: $request->host();
|
||||
$rootDomain = substr_count($host, '.') > 1 ? substr(strstr($host, '.'), 1) : $host;
|
||||
}
|
||||
if (substr_count($domain, '.') < 2 && !strpos($domain, $rootDomain)) {
|
||||
$domain .= '.' . $rootDomain;
|
||||
}
|
||||
}
|
||||
if (false !== strpos($domain, '://')) {
|
||||
$scheme = '';
|
||||
} else {
|
||||
$scheme = $request->isSsl() || Config::get('is_https') ? 'https://' : 'http://';
|
||||
}
|
||||
return $scheme . $domain;
|
||||
}
|
||||
|
||||
// 解析URL后缀
|
||||
protected static function parseSuffix($suffix)
|
||||
{
|
||||
if ($suffix) {
|
||||
$suffix = true === $suffix ? Config::get('url_html_suffix') : $suffix;
|
||||
if ($pos = strpos($suffix, '|')) {
|
||||
$suffix = substr($suffix, 0, $pos);
|
||||
}
|
||||
}
|
||||
return (empty($suffix) || 0 === strpos($suffix, '.')) ? $suffix : '.' . $suffix;
|
||||
}
|
||||
|
||||
// 匹配路由地址
|
||||
public static function getRuleUrl($rule, &$vars = [])
|
||||
{
|
||||
foreach ($rule as $item) {
|
||||
list($url, $pattern, $domain, $suffix) = $item;
|
||||
if (empty($pattern)) {
|
||||
return [$url, $domain, $suffix];
|
||||
}
|
||||
foreach ($pattern as $key => $val) {
|
||||
if (isset($vars[$key])) {
|
||||
$url = str_replace(['[:' . $key . ']', '<' . $key . '?>', ':' . $key . '', '<' . $key . '>'], urlencode($vars[$key]), $url);
|
||||
unset($vars[$key]);
|
||||
$result = [$url, $domain, $suffix];
|
||||
} elseif (2 == $val) {
|
||||
$url = str_replace(['/[:' . $key . ']', '[:' . $key . ']', '<' . $key . '?>'], '', $url);
|
||||
$result = [$url, $domain, $suffix];
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (isset($result)) {
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// 指定当前生成URL地址的root
|
||||
public static function root($root)
|
||||
{
|
||||
self::$root = $root;
|
||||
Request::instance()->root($root);
|
||||
}
|
||||
}
|
1292
thinkphp/library/think/Validate.php
Normal file
1292
thinkphp/library/think/Validate.php
Normal file
File diff suppressed because it is too large
Load Diff
236
thinkphp/library/think/View.php
Normal file
236
thinkphp/library/think/View.php
Normal file
@ -0,0 +1,236 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace think;
|
||||
|
||||
class View
|
||||
{
|
||||
// 视图实例
|
||||
protected static $instance;
|
||||
// 模板引擎实例
|
||||
public $engine;
|
||||
// 模板变量
|
||||
protected $data = [];
|
||||
// 用于静态赋值的模板变量
|
||||
protected static $var = [];
|
||||
// 视图输出替换
|
||||
protected $replace = [];
|
||||
|
||||
/**
|
||||
* 构造函数
|
||||
* @access public
|
||||
* @param array $engine 模板引擎参数
|
||||
* @param array $replace 字符串替换参数
|
||||
*/
|
||||
public function __construct($engine = [], $replace = [])
|
||||
{
|
||||
// 初始化模板引擎
|
||||
$this->engine((array) $engine);
|
||||
// 基础替换字符串
|
||||
$request = Request::instance();
|
||||
$base = $request->root();
|
||||
$root = strpos($base, '.') ? ltrim(dirname($base), DS) : $base;
|
||||
if ('' != $root) {
|
||||
$root = '/' . ltrim($root, '/');
|
||||
}
|
||||
$baseReplace = [
|
||||
'__ROOT__' => $root,
|
||||
'__URL__' => $base . '/' . $request->module() . '/' . Loader::parseName($request->controller()),
|
||||
'__STATIC__' => $root . '/static',
|
||||
'__CSS__' => $root . '/static/css',
|
||||
'__JS__' => $root . '/static/js',
|
||||
];
|
||||
$this->replace = array_merge($baseReplace, (array) $replace);
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化视图
|
||||
* @access public
|
||||
* @param array $engine 模板引擎参数
|
||||
* @param array $replace 字符串替换参数
|
||||
* @return object
|
||||
*/
|
||||
public static function instance($engine = [], $replace = [])
|
||||
{
|
||||
if (is_null(self::$instance)) {
|
||||
self::$instance = new self($engine, $replace);
|
||||
}
|
||||
return self::$instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* 模板变量静态赋值
|
||||
* @access public
|
||||
* @param mixed $name 变量名
|
||||
* @param mixed $value 变量值
|
||||
* @return void
|
||||
*/
|
||||
public static function share($name, $value = '')
|
||||
{
|
||||
if (is_array($name)) {
|
||||
self::$var = array_merge(self::$var, $name);
|
||||
} else {
|
||||
self::$var[$name] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 模板变量赋值
|
||||
* @access public
|
||||
* @param mixed $name 变量名
|
||||
* @param mixed $value 变量值
|
||||
* @return $this
|
||||
*/
|
||||
public function assign($name, $value = '')
|
||||
{
|
||||
if (is_array($name)) {
|
||||
$this->data = array_merge($this->data, $name);
|
||||
} else {
|
||||
$this->data[$name] = $value;
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置当前模板解析的引擎
|
||||
* @access public
|
||||
* @param array|string $options 引擎参数
|
||||
* @return $this
|
||||
*/
|
||||
public function engine($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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 配置模板引擎
|
||||
* @access private
|
||||
* @param string|array $name 参数名
|
||||
* @param mixed $value 参数值
|
||||
* @return $this
|
||||
*/
|
||||
public function config($name, $value = null)
|
||||
{
|
||||
$this->engine->config($name, $value);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析和获取模板内容 用于输出
|
||||
* @param string $template 模板文件名或者内容
|
||||
* @param array $vars 模板输出变量
|
||||
* @param array $replace 替换内容
|
||||
* @param array $config 模板参数
|
||||
* @param bool $renderContent 是否渲染内容
|
||||
* @return string
|
||||
* @throws Exception
|
||||
*/
|
||||
public function fetch($template = '', $vars = [], $replace = [], $config = [], $renderContent = false)
|
||||
{
|
||||
// 模板变量
|
||||
$vars = array_merge(self::$var, $this->data, $vars);
|
||||
|
||||
// 页面缓存
|
||||
ob_start();
|
||||
ob_implicit_flush(0);
|
||||
|
||||
// 渲染输出
|
||||
$method = $renderContent ? 'display' : 'fetch';
|
||||
$this->engine->$method($template, $vars, $config);
|
||||
|
||||
// 获取并清空缓存
|
||||
$content = ob_get_clean();
|
||||
// 内容过滤标签
|
||||
Hook::listen('view_filter', $content);
|
||||
// 允许用户自定义模板的字符串替换
|
||||
$replace = array_merge($this->replace, $replace);
|
||||
if (!empty($replace)) {
|
||||
$content = strtr($content, $replace);
|
||||
}
|
||||
return $content;
|
||||
}
|
||||
|
||||
/**
|
||||
* 视图内容替换
|
||||
* @access public
|
||||
* @param string|array $content 被替换内容(支持批量替换)
|
||||
* @param string $replace 替换内容
|
||||
* @return $this
|
||||
*/
|
||||
public function replace($content, $replace = '')
|
||||
{
|
||||
if (is_array($content)) {
|
||||
$this->replace = array_merge($this->replace, $content);
|
||||
} else {
|
||||
$this->replace[$content] = $replace;
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 渲染内容输出
|
||||
* @access public
|
||||
* @param string $content 内容
|
||||
* @param array $vars 模板输出变量
|
||||
* @param array $replace 替换内容
|
||||
* @param array $config 模板参数
|
||||
* @return mixed
|
||||
*/
|
||||
public function display($content, $vars = [], $replace = [], $config = [])
|
||||
{
|
||||
return $this->fetch($content, $vars, $replace, $config, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 模板变量赋值
|
||||
* @access public
|
||||
* @param string $name 变量名
|
||||
* @param mixed $value 变量值
|
||||
*/
|
||||
public function __set($name, $value)
|
||||
{
|
||||
$this->data[$name] = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* 取得模板显示变量的值
|
||||
* @access protected
|
||||
* @param string $name 模板变量
|
||||
* @return mixed
|
||||
*/
|
||||
public function __get($name)
|
||||
{
|
||||
return $this->data[$name];
|
||||
}
|
||||
|
||||
/**
|
||||
* 检测模板变量是否设置
|
||||
* @access public
|
||||
* @param string $name 模板变量名
|
||||
* @return bool
|
||||
*/
|
||||
public function __isset($name)
|
||||
{
|
||||
return isset($this->data[$name]);
|
||||
}
|
||||
}
|
225
thinkphp/library/think/cache/Driver.php
vendored
Normal file
225
thinkphp/library/think/cache/Driver.php
vendored
Normal file
@ -0,0 +1,225 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace think\cache;
|
||||
|
||||
/**
|
||||
* 缓存基础类
|
||||
*/
|
||||
abstract class Driver
|
||||
{
|
||||
protected $handler = null;
|
||||
protected $options = [];
|
||||
protected $tag;
|
||||
|
||||
/**
|
||||
* 判断缓存是否存在
|
||||
* @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 public
|
||||
* @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)) {
|
||||
while ($this->has($name . '_lock')) {
|
||||
// 存在锁定则等待
|
||||
}
|
||||
|
||||
try {
|
||||
// 锁定
|
||||
$this->set($name . '_lock', true);
|
||||
if ($value instanceof \Closure) {
|
||||
$value = call_user_func($value);
|
||||
}
|
||||
$this->set($name, $value, $expire);
|
||||
// 解锁
|
||||
$this->rm($name . '_lock');
|
||||
} catch (\Exception $e) {
|
||||
// 解锁
|
||||
$this->rm($name . '_lock');
|
||||
}
|
||||
} 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 public
|
||||
* @param string $name 缓存标识
|
||||
* @return void
|
||||
*/
|
||||
protected function setTagItem($name)
|
||||
{
|
||||
if ($this->tag) {
|
||||
$key = 'tag_' . md5($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);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取标签包含的缓存标识
|
||||
* @access public
|
||||
* @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 public
|
||||
* @return object
|
||||
*/
|
||||
public function handler()
|
||||
{
|
||||
return $this->handler;
|
||||
}
|
||||
}
|
250
thinkphp/library/think/cache/driver/File.php
vendored
Normal file
250
thinkphp/library/think/cache/driver/File.php
vendored
Normal file
@ -0,0 +1,250 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2017 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 File extends Driver
|
||||
{
|
||||
protected $options = [
|
||||
'expire' => 0,
|
||||
'cache_subdir' => true,
|
||||
'prefix' => '',
|
||||
'path' => CACHE_PATH,
|
||||
'data_compress' => false,
|
||||
];
|
||||
|
||||
/**
|
||||
* 构造函数
|
||||
* @param array $options
|
||||
*/
|
||||
public function __construct($options = [])
|
||||
{
|
||||
if (!empty($options)) {
|
||||
$this->options = array_merge($this->options, $options);
|
||||
}
|
||||
if (substr($this->options['path'], -1) != DS) {
|
||||
$this->options['path'] .= DS;
|
||||
}
|
||||
$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 protected
|
||||
* @param string $name 缓存变量名
|
||||
* @return string
|
||||
*/
|
||||
protected function getCacheKey($name)
|
||||
{
|
||||
$name = md5($name);
|
||||
if ($this->options['cache_subdir']) {
|
||||
// 使用子目录
|
||||
$name = substr($name, 0, 2) . DS . substr($name, 2);
|
||||
}
|
||||
if ($this->options['prefix']) {
|
||||
$name = $this->options['prefix'] . DS . $name;
|
||||
}
|
||||
$filename = $this->options['path'] . $name . '.php';
|
||||
$dir = dirname($filename);
|
||||
if (!is_dir($dir)) {
|
||||
mkdir($dir, 0755, true);
|
||||
}
|
||||
return $filename;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断缓存是否存在
|
||||
* @access public
|
||||
* @param string $name 缓存变量名
|
||||
* @return bool
|
||||
*/
|
||||
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)
|
||||
{
|
||||
$filename = $this->getCacheKey($name);
|
||||
if (!is_file($filename)) {
|
||||
return $default;
|
||||
}
|
||||
$content = file_get_contents($filename);
|
||||
if (false !== $content) {
|
||||
$expire = (int) substr($content, 8, 12);
|
||||
if (0 != $expire && $_SERVER['REQUEST_TIME'] > filemtime($filename) + $expire) {
|
||||
return $default;
|
||||
}
|
||||
$content = substr($content, 32);
|
||||
if ($this->options['data_compress'] && function_exists('gzcompress')) {
|
||||
//启用数据压缩
|
||||
$content = gzuncompress($content);
|
||||
}
|
||||
$content = unserialize($content);
|
||||
return $content;
|
||||
} else {
|
||||
return $default;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 写入缓存
|
||||
* @access public
|
||||
* @param string $name 缓存变量名
|
||||
* @param mixed $value 存储数据
|
||||
* @param integer|\DateTime $expire 有效时间(秒)
|
||||
* @return boolean
|
||||
*/
|
||||
public function set($name, $value, $expire = null)
|
||||
{
|
||||
if (is_null($expire)) {
|
||||
$expire = $this->options['expire'];
|
||||
}
|
||||
if ($expire instanceof \DateTime) {
|
||||
$expire = $expire->getTimestamp() - time();
|
||||
}
|
||||
$filename = $this->getCacheKey($name);
|
||||
if ($this->tag && !is_file($filename)) {
|
||||
$first = true;
|
||||
}
|
||||
$data = serialize($value);
|
||||
if ($this->options['data_compress'] && function_exists('gzcompress')) {
|
||||
//数据压缩
|
||||
$data = gzcompress($data, 3);
|
||||
}
|
||||
$data = "<?php\n//" . sprintf('%012d', $expire) . "\n exit();?>\n" . $data;
|
||||
$result = file_put_contents($filename, $data);
|
||||
if ($result) {
|
||||
isset($first) && $this->setTagItem($filename);
|
||||
clearstatcache();
|
||||
return true;
|
||||
} else {
|
||||
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)
|
||||
{
|
||||
$filename = $this->getCacheKey($name);
|
||||
return $this->unlink($filename);
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除缓存
|
||||
* @access public
|
||||
* @param string $tag 标签名
|
||||
* @return boolean
|
||||
*/
|
||||
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;
|
||||
}
|
||||
$files = (array) glob($this->options['path'] . ($this->options['prefix'] ? $this->options['prefix'] . DS : '') . '*');
|
||||
foreach ($files as $path) {
|
||||
if (is_dir($path)) {
|
||||
array_map('unlink', glob($path . '/*.php'));
|
||||
rmdir($path);
|
||||
} else {
|
||||
unlink($path);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断文件是否存在后,删除
|
||||
* @param $path
|
||||
* @return bool
|
||||
* @author byron sampson <xiaobo.sun@qq.com>
|
||||
* @return boolean
|
||||
*/
|
||||
private function unlink($path)
|
||||
{
|
||||
return is_file($path) && unlink($path);
|
||||
}
|
||||
|
||||
}
|
187
thinkphp/library/think/cache/driver/Lite.php
vendored
Normal file
187
thinkphp/library/think/cache/driver/Lite.php
vendored
Normal file
@ -0,0 +1,187 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2017 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) != DS) {
|
||||
$this->options['path'] .= DS;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 取得变量的存储文件名
|
||||
* @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)
|
||||
{
|
||||
$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 integer|\DateTime $expire 有效时间(秒)
|
||||
* @return bool
|
||||
*/
|
||||
public function set($name, $value, $expire = null)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
array_map("unlink", glob($this->options['path'] . ($this->options['prefix'] ? $this->options['prefix'] . DS : '') . '*.php'));
|
||||
}
|
||||
}
|
177
thinkphp/library/think/cache/driver/Memcache.php
vendored
Normal file
177
thinkphp/library/think/cache/driver/Memcache.php
vendored
Normal file
@ -0,0 +1,177 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2017 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;
|
||||
|
||||
class Memcache extends Driver
|
||||
{
|
||||
protected $options = [
|
||||
'host' => '127.0.0.1',
|
||||
'port' => 11211,
|
||||
'expire' => 0,
|
||||
'timeout' => 0, // 超时时间(单位:毫秒)
|
||||
'persistent' => true,
|
||||
'prefix' => '',
|
||||
];
|
||||
|
||||
/**
|
||||
* 构造函数
|
||||
* @param array $options 缓存参数
|
||||
* @access public
|
||||
* @throws \BadFunctionCallException
|
||||
*/
|
||||
public function __construct($options = [])
|
||||
{
|
||||
if (!extension_loaded('memcache')) {
|
||||
throw new \BadFunctionCallException('not support: memcache');
|
||||
}
|
||||
if (!empty($options)) {
|
||||
$this->options = array_merge($this->options, $options);
|
||||
}
|
||||
$this->handler = new \Memcache;
|
||||
// 支持集群
|
||||
$hosts = explode(',', $this->options['host']);
|
||||
$ports = explode(',', $this->options['port']);
|
||||
if (empty($ports[0])) {
|
||||
$ports[0] = 11211;
|
||||
}
|
||||
// 建立连接
|
||||
foreach ((array) $hosts as $i => $host) {
|
||||
$port = isset($ports[$i]) ? $ports[$i] : $ports[0];
|
||||
$this->options['timeout'] > 0 ?
|
||||
$this->handler->addServer($host, $port, $this->options['persistent'], 1, $this->options['timeout']) :
|
||||
$this->handler->addServer($host, $port, $this->options['persistent'], 1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断缓存
|
||||
* @access public
|
||||
* @param string $name 缓存变量名
|
||||
* @return bool
|
||||
*/
|
||||
public function has($name)
|
||||
{
|
||||
$key = $this->getCacheKey($name);
|
||||
return $this->handler->get($key) ? true : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 读取缓存
|
||||
* @access public
|
||||
* @param string $name 缓存变量名
|
||||
* @param mixed $default 默认值
|
||||
* @return mixed
|
||||
*/
|
||||
public function get($name, $default = false)
|
||||
{
|
||||
$result = $this->handler->get($this->getCacheKey($name));
|
||||
return false !== $result ? $result : $default;
|
||||
}
|
||||
|
||||
/**
|
||||
* 写入缓存
|
||||
* @access public
|
||||
* @param string $name 缓存变量名
|
||||
* @param mixed $value 存储数据
|
||||
* @param integer|\DateTime $expire 有效时间(秒)
|
||||
* @return bool
|
||||
*/
|
||||
public function set($name, $value, $expire = null)
|
||||
{
|
||||
if (is_null($expire)) {
|
||||
$expire = $this->options['expire'];
|
||||
}
|
||||
if ($expire instanceof \DateTime) {
|
||||
$expire = $expire->getTimestamp() - time();
|
||||
}
|
||||
if ($this->tag && !$this->has($name)) {
|
||||
$first = true;
|
||||
}
|
||||
$key = $this->getCacheKey($name);
|
||||
if ($this->handler->set($key, $value, 0, $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)
|
||||
{
|
||||
$key = $this->getCacheKey($name);
|
||||
if ($this->handler->get($key)) {
|
||||
return $this->handler->increment($key, $step);
|
||||
}
|
||||
return $this->handler->set($key, $step);
|
||||
}
|
||||
|
||||
/**
|
||||
* 自减缓存(针对数值缓存)
|
||||
* @access public
|
||||
* @param string $name 缓存变量名
|
||||
* @param int $step 步长
|
||||
* @return false|int
|
||||
*/
|
||||
public function dec($name, $step = 1)
|
||||
{
|
||||
$key = $this->getCacheKey($name);
|
||||
$value = $this->handler->get($key) - $step;
|
||||
$res = $this->handler->set($key, $value);
|
||||
if (!$res) {
|
||||
return false;
|
||||
} else {
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除缓存
|
||||
* @param string $name 缓存变量名
|
||||
* @param bool|false $ttl
|
||||
* @return bool
|
||||
*/
|
||||
public function rm($name, $ttl = false)
|
||||
{
|
||||
$key = $this->getCacheKey($name);
|
||||
return false === $ttl ?
|
||||
$this->handler->delete($key) :
|
||||
$this->handler->delete($key, $ttl);
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除缓存
|
||||
* @access public
|
||||
* @param string $tag 标签名
|
||||
* @return 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;
|
||||
}
|
||||
return $this->handler->flush();
|
||||
}
|
||||
}
|
187
thinkphp/library/think/cache/driver/Memcached.php
vendored
Normal file
187
thinkphp/library/think/cache/driver/Memcached.php
vendored
Normal file
@ -0,0 +1,187 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2017 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;
|
||||
|
||||
class Memcached extends Driver
|
||||
{
|
||||
protected $options = [
|
||||
'host' => '127.0.0.1',
|
||||
'port' => 11211,
|
||||
'expire' => 0,
|
||||
'timeout' => 0, // 超时时间(单位:毫秒)
|
||||
'prefix' => '',
|
||||
'username' => '', //账号
|
||||
'password' => '', //密码
|
||||
'option' => [],
|
||||
];
|
||||
|
||||
/**
|
||||
* 构造函数
|
||||
* @param array $options 缓存参数
|
||||
* @access public
|
||||
*/
|
||||
public function __construct($options = [])
|
||||
{
|
||||
if (!extension_loaded('memcached')) {
|
||||
throw new \BadFunctionCallException('not support: memcached');
|
||||
}
|
||||
if (!empty($options)) {
|
||||
$this->options = array_merge($this->options, $options);
|
||||
}
|
||||
$this->handler = new \Memcached;
|
||||
if (!empty($this->options['option'])) {
|
||||
$this->handler->setOptions($this->options['option']);
|
||||
}
|
||||
// 设置连接超时时间(单位:毫秒)
|
||||
if ($this->options['timeout'] > 0) {
|
||||
$this->handler->setOption(\Memcached::OPT_CONNECT_TIMEOUT, $this->options['timeout']);
|
||||
}
|
||||
// 支持集群
|
||||
$hosts = explode(',', $this->options['host']);
|
||||
$ports = explode(',', $this->options['port']);
|
||||
if (empty($ports[0])) {
|
||||
$ports[0] = 11211;
|
||||
}
|
||||
// 建立连接
|
||||
$servers = [];
|
||||
foreach ((array) $hosts as $i => $host) {
|
||||
$servers[] = [$host, (isset($ports[$i]) ? $ports[$i] : $ports[0]), 1];
|
||||
}
|
||||
$this->handler->addServers($servers);
|
||||
if ('' != $this->options['username']) {
|
||||
$this->handler->setOption(\Memcached::OPT_BINARY_PROTOCOL, true);
|
||||
$this->handler->setSaslAuthData($this->options['username'], $this->options['password']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断缓存
|
||||
* @access public
|
||||
* @param string $name 缓存变量名
|
||||
* @return bool
|
||||
*/
|
||||
public function has($name)
|
||||
{
|
||||
$key = $this->getCacheKey($name);
|
||||
return $this->handler->get($key) ? true : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 读取缓存
|
||||
* @access public
|
||||
* @param string $name 缓存变量名
|
||||
* @param mixed $default 默认值
|
||||
* @return mixed
|
||||
*/
|
||||
public function get($name, $default = false)
|
||||
{
|
||||
$result = $this->handler->get($this->getCacheKey($name));
|
||||
return false !== $result ? $result : $default;
|
||||
}
|
||||
|
||||
/**
|
||||
* 写入缓存
|
||||
* @access public
|
||||
* @param string $name 缓存变量名
|
||||
* @param mixed $value 存储数据
|
||||
* @param integer|\DateTime $expire 有效时间(秒)
|
||||
* @return bool
|
||||
*/
|
||||
public function set($name, $value, $expire = null)
|
||||
{
|
||||
if (is_null($expire)) {
|
||||
$expire = $this->options['expire'];
|
||||
}
|
||||
if ($expire instanceof \DateTime) {
|
||||
$expire = $expire->getTimestamp() - time();
|
||||
}
|
||||
if ($this->tag && !$this->has($name)) {
|
||||
$first = true;
|
||||
}
|
||||
$key = $this->getCacheKey($name);
|
||||
$expire = 0 == $expire ? 0 : $_SERVER['REQUEST_TIME'] + $expire;
|
||||
if ($this->handler->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)
|
||||
{
|
||||
$key = $this->getCacheKey($name);
|
||||
if ($this->handler->get($key)) {
|
||||
return $this->handler->increment($key, $step);
|
||||
}
|
||||
return $this->handler->set($key, $step);
|
||||
}
|
||||
|
||||
/**
|
||||
* 自减缓存(针对数值缓存)
|
||||
* @access public
|
||||
* @param string $name 缓存变量名
|
||||
* @param int $step 步长
|
||||
* @return false|int
|
||||
*/
|
||||
public function dec($name, $step = 1)
|
||||
{
|
||||
$key = $this->getCacheKey($name);
|
||||
$value = $this->handler->get($key) - $step;
|
||||
$res = $this->handler->set($key, $value);
|
||||
if (!$res) {
|
||||
return false;
|
||||
} else {
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除缓存
|
||||
* @param string $name 缓存变量名
|
||||
* @param bool|false $ttl
|
||||
* @return bool
|
||||
*/
|
||||
public function rm($name, $ttl = false)
|
||||
{
|
||||
$key = $this->getCacheKey($name);
|
||||
return false === $ttl ?
|
||||
$this->handler->delete($key) :
|
||||
$this->handler->delete($key, $ttl);
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除缓存
|
||||
* @access public
|
||||
* @param string $tag 标签名
|
||||
* @return bool
|
||||
*/
|
||||
public function clear($tag = null)
|
||||
{
|
||||
if ($tag) {
|
||||
// 指定标签清除
|
||||
$keys = $this->getTagItem($tag);
|
||||
$this->handler->deleteMulti($keys);
|
||||
$this->rm('tag_' . md5($tag));
|
||||
return true;
|
||||
}
|
||||
return $this->handler->flush();
|
||||
}
|
||||
}
|
179
thinkphp/library/think/cache/driver/Redis.php
vendored
Normal file
179
thinkphp/library/think/cache/driver/Redis.php
vendored
Normal file
@ -0,0 +1,179 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2017 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;
|
||||
|
||||
/**
|
||||
* Redis缓存驱动,适合单机部署、有前端代理实现高可用的场景,性能最好
|
||||
* 有需要在业务层实现读写分离、或者使用RedisCluster的需求,请使用Redisd驱动
|
||||
*
|
||||
* 要求安装phpredis扩展:https://github.com/nicolasff/phpredis
|
||||
* @author 尘缘 <130775@qq.com>
|
||||
*/
|
||||
class Redis extends Driver
|
||||
{
|
||||
protected $options = [
|
||||
'host' => '127.0.0.1',
|
||||
'port' => 6379,
|
||||
'password' => '',
|
||||
'select' => 0,
|
||||
'timeout' => 0,
|
||||
'expire' => 0,
|
||||
'persistent' => false,
|
||||
'prefix' => '',
|
||||
];
|
||||
|
||||
/**
|
||||
* 构造函数
|
||||
* @param array $options 缓存参数
|
||||
* @access public
|
||||
*/
|
||||
public function __construct($options = [])
|
||||
{
|
||||
if (!extension_loaded('redis')) {
|
||||
throw new \BadFunctionCallException('not support: redis');
|
||||
}
|
||||
if (!empty($options)) {
|
||||
$this->options = array_merge($this->options, $options);
|
||||
}
|
||||
$func = $this->options['persistent'] ? 'pconnect' : 'connect';
|
||||
$this->handler = new \Redis;
|
||||
$this->handler->$func($this->options['host'], $this->options['port'], $this->options['timeout']);
|
||||
|
||||
if ('' != $this->options['password']) {
|
||||
$this->handler->auth($this->options['password']);
|
||||
}
|
||||
|
||||
if (0 != $this->options['select']) {
|
||||
$this->handler->select($this->options['select']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断缓存
|
||||
* @access public
|
||||
* @param string $name 缓存变量名
|
||||
* @return bool
|
||||
*/
|
||||
public function has($name)
|
||||
{
|
||||
return $this->handler->get($this->getCacheKey($name)) ? true : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 读取缓存
|
||||
* @access public
|
||||
* @param string $name 缓存变量名
|
||||
* @param mixed $default 默认值
|
||||
* @return mixed
|
||||
*/
|
||||
public function get($name, $default = false)
|
||||
{
|
||||
$value = $this->handler->get($this->getCacheKey($name));
|
||||
if (is_null($value)) {
|
||||
return $default;
|
||||
}
|
||||
$jsonData = json_decode($value, true);
|
||||
// 检测是否为JSON数据 true 返回JSON解析数组, false返回源数据 byron sampson<xiaobo.sun@qq.com>
|
||||
return (null === $jsonData) ? $value : $jsonData;
|
||||
}
|
||||
|
||||
/**
|
||||
* 写入缓存
|
||||
* @access public
|
||||
* @param string $name 缓存变量名
|
||||
* @param mixed $value 存储数据
|
||||
* @param integer|\DateTime $expire 有效时间(秒)
|
||||
* @return boolean
|
||||
*/
|
||||
public function set($name, $value, $expire = null)
|
||||
{
|
||||
if (is_null($expire)) {
|
||||
$expire = $this->options['expire'];
|
||||
}
|
||||
if ($expire instanceof \DateTime) {
|
||||
$expire = $expire->getTimestamp() - time();
|
||||
}
|
||||
if ($this->tag && !$this->has($name)) {
|
||||
$first = true;
|
||||
}
|
||||
$key = $this->getCacheKey($name);
|
||||
//对数组/对象数据进行缓存处理,保证数据完整性 byron sampson<xiaobo.sun@qq.com>
|
||||
$value = (is_object($value) || is_array($value)) ? json_encode($value) : $value;
|
||||
if (is_int($expire) && $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 步长
|
||||
* @return false|int
|
||||
*/
|
||||
public function inc($name, $step = 1)
|
||||
{
|
||||
$key = $this->getCacheKey($name);
|
||||
return $this->handler->incrby($key, $step);
|
||||
}
|
||||
|
||||
/**
|
||||
* 自减缓存(针对数值缓存)
|
||||
* @access public
|
||||
* @param string $name 缓存变量名
|
||||
* @param int $step 步长
|
||||
* @return false|int
|
||||
*/
|
||||
public function dec($name, $step = 1)
|
||||
{
|
||||
$key = $this->getCacheKey($name);
|
||||
return $this->handler->decrby($key, $step);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除缓存
|
||||
* @access public
|
||||
* @param string $name 缓存变量名
|
||||
* @return boolean
|
||||
*/
|
||||
public function rm($name)
|
||||
{
|
||||
return $this->handler->delete($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) {
|
||||
$this->handler->delete($key);
|
||||
}
|
||||
$this->rm('tag_' . md5($tag));
|
||||
return true;
|
||||
}
|
||||
return $this->handler->flushDB();
|
||||
}
|
||||
|
||||
}
|
199
thinkphp/library/think/cache/driver/Sqlite.php
vendored
Normal file
199
thinkphp/library/think/cache/driver/Sqlite.php
vendored
Normal file
@ -0,0 +1,199 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2017 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,
|
||||
];
|
||||
|
||||
/**
|
||||
* 构造函数
|
||||
* @param array $options 缓存参数
|
||||
* @throws \BadFunctionCallException
|
||||
* @access public
|
||||
*/
|
||||
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 >' . $_SERVER['REQUEST_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)
|
||||
{
|
||||
$name = $this->getCacheKey($name);
|
||||
$sql = 'SELECT value FROM ' . $this->options['table'] . ' WHERE var=\'' . $name . '\' AND (expire=0 OR expire >' . $_SERVER['REQUEST_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 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)
|
||||
{
|
||||
$name = $this->getCacheKey($name);
|
||||
$value = sqlite_escape_string(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)
|
||||
{
|
||||
$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;
|
||||
}
|
||||
$sql = 'DELETE FROM ' . $this->options['table'];
|
||||
sqlite_query($this->handler, $sql);
|
||||
return true;
|
||||
}
|
||||
}
|
152
thinkphp/library/think/cache/driver/Wincache.php
vendored
Normal file
152
thinkphp/library/think/cache/driver/Wincache.php
vendored
Normal file
@ -0,0 +1,152 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2017 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;
|
||||
|
||||
/**
|
||||
* Wincache缓存驱动
|
||||
* @author liu21st <liu21st@gmail.com>
|
||||
*/
|
||||
class Wincache extends Driver
|
||||
{
|
||||
protected $options = [
|
||||
'prefix' => '',
|
||||
'expire' => 0,
|
||||
];
|
||||
|
||||
/**
|
||||
* 构造函数
|
||||
* @param array $options 缓存参数
|
||||
* @throws \BadFunctionCallException
|
||||
* @access public
|
||||
*/
|
||||
public function __construct($options = [])
|
||||
{
|
||||
if (!function_exists('wincache_ucache_info')) {
|
||||
throw new \BadFunctionCallException('not support: WinCache');
|
||||
}
|
||||
if (!empty($options)) {
|
||||
$this->options = array_merge($this->options, $options);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断缓存
|
||||
* @access public
|
||||
* @param string $name 缓存变量名
|
||||
* @return bool
|
||||
*/
|
||||
public function has($name)
|
||||
{
|
||||
$key = $this->getCacheKey($name);
|
||||
return wincache_ucache_exists($key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 读取缓存
|
||||
* @access public
|
||||
* @param string $name 缓存变量名
|
||||
* @param mixed $default 默认值
|
||||
* @return mixed
|
||||
*/
|
||||
public function get($name, $default = false)
|
||||
{
|
||||
$key = $this->getCacheKey($name);
|
||||
return wincache_ucache_exists($key) ? wincache_ucache_get($key) : $default;
|
||||
}
|
||||
|
||||
/**
|
||||
* 写入缓存
|
||||
* @access public
|
||||
* @param string $name 缓存变量名
|
||||
* @param mixed $value 存储数据
|
||||
* @param integer|\DateTime $expire 有效时间(秒)
|
||||
* @return boolean
|
||||
*/
|
||||
public function set($name, $value, $expire = null)
|
||||
{
|
||||
if (is_null($expire)) {
|
||||
$expire = $this->options['expire'];
|
||||
}
|
||||
if ($expire instanceof \DateTime) {
|
||||
$expire = $expire->getTimestamp() - time();
|
||||
}
|
||||
$key = $this->getCacheKey($name);
|
||||
if ($this->tag && !$this->has($name)) {
|
||||
$first = true;
|
||||
}
|
||||
if (wincache_ucache_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)
|
||||
{
|
||||
$key = $this->getCacheKey($name);
|
||||
return wincache_ucache_inc($key, $step);
|
||||
}
|
||||
|
||||
/**
|
||||
* 自减缓存(针对数值缓存)
|
||||
* @access public
|
||||
* @param string $name 缓存变量名
|
||||
* @param int $step 步长
|
||||
* @return false|int
|
||||
*/
|
||||
public function dec($name, $step = 1)
|
||||
{
|
||||
$key = $this->getCacheKey($name);
|
||||
return wincache_ucache_dec($key, $step);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除缓存
|
||||
* @access public
|
||||
* @param string $name 缓存变量名
|
||||
* @return boolean
|
||||
*/
|
||||
public function rm($name)
|
||||
{
|
||||
return wincache_ucache_delete($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) {
|
||||
wincache_ucache_delete($key);
|
||||
}
|
||||
$this->rm('tag_' . md5($tag));
|
||||
return true;
|
||||
} else {
|
||||
return wincache_ucache_clear();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user