- 框架初始化
 - 安装插件
 - 修复PHP8.4报错
This commit is contained in:
2025-04-19 17:21:20 +08:00
commit c6a4e1f5f6
5306 changed files with 967782 additions and 0 deletions

View File

@@ -0,0 +1,296 @@
<?php
// +----------------------------------------------------------------------
// | thinkphp5 Addons [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016 http://www.zzstudio.net All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: Byron Sampson <xiaobo.sun@qq.com>
// +----------------------------------------------------------------------
namespace think;
use think\Config;
use think\View;
/**
* 插件基类
* Class Addons
* @author Byron Sampson <xiaobo.sun@qq.com>
* @package think\addons
*/
abstract class Addons
{
// 视图实例对象
protected $view = null;
// 当前错误信息
protected $error;
// 插件目录
public $addons_path = '';
public $addonPath = '';
// 插件标识
protected $addonName = '';
// 插件配置作用域
protected $configRange = 'addonconfig';
// 插件信息作用域
protected $infoRange = 'addoninfo';
/**
* 架构函数
* @access public
*/
public function __construct($name = null)
{
$name = is_null($name) ? $this->getName() : $name;
//设置插件标识
$this->addonName = $name;
// 获取当前插件目录
$this->addonPath = ADDON_PATH . $name . DS;
$this->addons_path = $this->addonPath;
// 初始化视图模型
$config = ['view_path' => $this->addonPath];
$config = array_merge(Config::get('template'), $config);
$this->view = new View($config, Config::get('view_replace_str'));
// 控制器初始化
if (method_exists($this, '_initialize')) {
$this->_initialize();
}
}
/**
* 读取基础配置信息
* @param string $name
* @return array
*/
final public function getInfo($name = '', $force = false)
{
if (empty($name)) {
$name = $this->getName();
}
if (!$force) {
$info = Config::get($name, $this->infoRange);
if ($info) {
return $info;
}
}
$info = [];
$infoFile = $this->addonPath . 'info.ini';
if (is_file($infoFile)) {
$info = Config::parse($infoFile, '', $name, $this->infoRange);
$info['url'] = addon_url($name);
}
Config::set($name, $info, $this->infoRange);
return $info ? $info : [];
}
/**
* 获取插件的配置数组
* @param string $name 可选模块名
* @return array
*/
final public function getConfig($name = '', $force = false)
{
if (empty($name)) {
$name = $this->getName();
}
if (!$force) {
$config = Config::get($name, $this->configRange);
if ($config) {
return $config;
}
}
$config = [];
$configFile = $this->addonPath . 'config.php';
if (is_file($configFile)) {
$configArr = include $configFile;
if (is_array($configArr)) {
foreach ($configArr as $key => $value) {
$config[$value['name']] = $value['value'];
}
unset($configArr);
}
}
Config::set($name, $config, $this->configRange);
return $config;
}
/**
* 设置配置数据
* @param $name
* @param array $value
* @return array
*/
final public function setConfig($name = '', $value = [])
{
if (empty($name)) {
$name = $this->getName();
}
$config = $this->getConfig($name);
$config = array_merge($config, $value);
Config::set($name, $config, $this->configRange);
return $config;
}
/**
* 设置插件信息数据
* @param $name
* @param array $value
* @return array
*/
final public function setInfo($name = '', $value = [])
{
if (empty($name)) {
$name = $this->getName();
}
$info = $this->getInfo($name);
$info = array_merge($info, $value);
Config::set($name, $info, $this->infoRange);
return $info;
}
/**
* 获取完整配置列表
* @param string $name
* @return array
*/
final public function getFullConfig($name = '')
{
$fullConfigArr = [];
if (empty($name)) {
$name = $this->getName();
}
$configFile = $this->addonPath . 'config.php';
if (is_file($configFile)) {
$fullConfigArr = include $configFile;
}
return $fullConfigArr;
}
/**
* 获取当前模块名
* @return string
*/
final public function getName()
{
if ($this->addonName) {
return $this->addonName;
}
$data = explode('\\', get_class($this));
return strtolower(array_pop($data));
}
/**
* 设置插件标识
* @param $name
*/
final public function setName($name)
{
$this->addonName = $name;
}
/**
* 检查基础配置信息是否完整
* @return bool
*/
final public function checkInfo()
{
$info = $this->getInfo();
$info_check_keys = ['name', 'title', 'intro', 'author', 'version', 'state'];
foreach ($info_check_keys as $value) {
if (!array_key_exists($value, $info)) {
return false;
}
}
return true;
}
/**
* 加载模板和页面输出 可以返回输出内容
* @access public
* @param string $template 模板文件名或者内容
* @param array $vars 模板输出变量
* @param array $replace 替换内容
* @param array $config 模板参数
* @return mixed
* @throws \Exception
*/
public function fetch($template = '', $vars = [], $replace = [], $config = [])
{
if (!is_file($template)) {
$template = '/' . $template;
}
// 关闭模板布局
$this->view->engine->layout(false);
echo $this->view->fetch($template, $vars, $replace, $config);
}
/**
* 渲染内容输出
* @access public
* @param string $content 内容
* @param array $vars 模板输出变量
* @param array $replace 替换内容
* @param array $config 模板参数
* @return mixed
*/
public function display($content, $vars = [], $replace = [], $config = [])
{
// 关闭模板布局
$this->view->engine->layout(false);
echo $this->view->display($content, $vars, $replace, $config);
}
/**
* 渲染内容输出
* @access public
* @param string $content 内容
* @param array $vars 模板输出变量
* @return mixed
*/
public function show($content, $vars = [])
{
// 关闭模板布局
$this->view->engine->layout(false);
echo $this->view->fetch($content, $vars, [], [], true);
}
/**
* 模板变量赋值
* @access protected
* @param mixed $name 要显示的模板变量
* @param mixed $value 变量的值
* @return void
*/
public function assign($name, $value = '')
{
$this->view->assign($name, $value);
}
/**
* 获取当前错误信息
* @return mixed
*/
public function getError()
{
return $this->error;
}
//必须实现安装
abstract public function install();
//必须卸载插件方法
abstract public function uninstall();
}

View File

@@ -0,0 +1,21 @@
<?php
namespace think\addons;
use think\Exception;
/**
* 插件异常处理类
* @package think\addons
*/
class AddonException extends Exception
{
public function __construct($message, $code = 0, $data = '')
{
$this->message = $message;
$this->code = $code;
$this->data = $data;
}
}

View File

@@ -0,0 +1,220 @@
<?php
// +----------------------------------------------------------------------
// | thinkphp5 Addons [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016 http://www.zzstudio.net All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: Byron Sampson <xiaobo.sun@qq.com>
// +----------------------------------------------------------------------
namespace think\addons;
use app\common\library\Auth;
use think\Config;
use think\Hook;
use think\Lang;
use think\Loader;
use think\Request;
use think\Validate;
/**
* 插件基类控制器
* @package think\addons
*/
class Controller extends \think\Controller
{
// 当前插件操作
protected $addon = null;
protected $controller = null;
protected $action = null;
// 当前template
protected $template;
/**
* 无需登录的方法,同时也就不需要鉴权了
* @var array
*/
protected $noNeedLogin = ['*'];
/**
* 无需鉴权的方法,但需要登录
* @var array
*/
protected $noNeedRight = ['*'];
/**
* 权限Auth
* @var Auth
*/
protected $auth = null;
/**
* 布局模板
* @var string
*/
protected $layout = null;
/**
* 架构函数
* @param Request $request Request对象
* @access public
*/
public function __construct(Request $request = null)
{
if (is_null($request)) {
$request = Request::instance();
}
// 生成request对象
$this->request = $request;
//移除HTML标签
$this->request->filter('trim,strip_tags,htmlspecialchars');
// 是否自动转换控制器和操作名
$convert = Config::get('url_convert');
$filter = $convert ? 'strtolower' : 'trim';
// 处理路由参数
$param = $this->request->param();
$dispatch = $this->request->dispatch();
$var = isset($dispatch['var']) ? $dispatch['var'] : [];
$var = array_merge($param, $var);
if (isset($dispatch['method']) && substr($dispatch['method'][0], 0, 7) == "\\addons") {
$arr = explode("\\", $dispatch['method'][0]);
$addon = strtolower($arr[2]);
$controller = strtolower(end($arr));
$action = $dispatch['method'][1];
} else {
$addon = isset($var['addon']) ? $var['addon'] : '';
$controller = isset($var['controller']) ? $var['controller'] : '';
$action = isset($var['action']) ? $var['action'] : '';
}
$this->addon = $addon ? call_user_func($filter, $addon) : '';
$this->controller = $controller ? call_user_func($filter, $controller) : 'index';
$this->action = $action ? call_user_func($filter, $action) : 'index';
// 重置配置
Config::set('template.view_path', ADDON_PATH . $this->addon . DS . 'view' . DS);
// 父类的调用必须放在设置模板路径之后
parent::__construct($this->request);
}
protected function _initialize()
{
// 检测IP是否允许
if (function_exists("check_ip_allowed")) {
check_ip_allowed();
}
// 渲染配置到视图中
$config = get_addon_config($this->addon);
$this->view->assign("config", $config);
$lang = $this->request->langset();
$lang = preg_match("/^([a-zA-Z\-_]{2,10})\$/i", $lang) ? $lang : 'zh-cn';
// 加载系统语言包
Lang::load([
ADDON_PATH . $this->addon . DS . 'lang' . DS . $lang . EXT,
]);
// 设置替换字符串
$cdnurl = Config::get('site.cdnurl');
$this->view->replace('__ADDON__', $cdnurl . "/assets/addons/" . $this->addon);
$this->auth = Auth::instance();
// token
$token = $this->request->server('HTTP_TOKEN', $this->request->request('token', \think\Cookie::get('token')));
$path = 'addons/' . $this->addon . '/' . str_replace('.', '/', $this->controller) . '/' . $this->action;
// 设置当前请求的URI
$this->auth->setRequestUri($path);
// 检测是否需要验证登录
if (!$this->auth->match($this->noNeedLogin)) {
//初始化
$this->auth->init($token);
//检测是否登录
if (!$this->auth->isLogin()) {
$this->error(__('Please login first'), 'index/user/login');
}
// 判断是否需要验证权限
if (!$this->auth->match($this->noNeedRight)) {
// 判断控制器和方法判断是否有对应权限
if (!$this->auth->check($path)) {
$this->error(__('You have no permission'));
}
}
} else {
// 如果有传递token才验证是否登录状态
if ($token) {
$this->auth->init($token);
}
}
// 如果有使用模板布局
if ($this->layout) {
$this->view->engine->layout('layout/' . $this->layout);
}
$this->view->assign('user', $this->auth->getUser());
$site = Config::get("site");
$upload = \app\common\model\Config::upload();
// 上传信息配置后
Hook::listen("upload_config_init", $upload);
Config::set('upload', array_merge(Config::get('upload'), $upload));
// 加载当前控制器语言包
$this->assign('site', $site);
}
/**
* 加载模板输出
* @access protected
* @param string $template 模板文件名
* @param array $vars 模板输出变量
* @param array $replace 模板替换
* @param array $config 模板参数
* @return mixed
*/
protected function fetch($template = '', $vars = [], $replace = [], $config = [])
{
$controller = Loader::parseName($this->controller);
if ('think' == strtolower(Config::get('template.type')) && $controller && 0 !== strpos($template, '/')) {
$depr = Config::get('template.view_depr');
$template = str_replace(['/', ':'], $depr, $template);
if ('' == $template) {
// 如果模板文件名为空 按照默认规则定位
$template = str_replace('.', DS, $controller) . $depr . $this->action;
} elseif (false === strpos($template, $depr)) {
$template = str_replace('.', DS, $controller) . $depr . $template;
}
}
return parent::fetch($template, $vars, $replace, $config);
}
/**
* 刷新Token
*/
protected function token()
{
$token = $this->request->param('__token__');
//验证Token
if (!Validate::make()->check(['__token__' => $token], ['__token__' => 'require|token'])) {
$this->error(__('Token verification error'), '', ['__token__' => $this->request->token()]);
}
//刷新Token
$this->request->token();
}
}

View File

@@ -0,0 +1,94 @@
<?php
// +----------------------------------------------------------------------
// | thinkphp5 Addons [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016 http://www.zzstudio.net All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: Byron Sampson <xiaobo.sun@qq.com>
// +----------------------------------------------------------------------
namespace think\addons;
use think\Config;
use think\exception\HttpException;
use think\exception\HttpResponseException;
use think\Hook;
use think\Loader;
use think\Request;
use think\Response;
/**
* 插件执行默认控制器
* @package think\addons
*/
class Route
{
/**
* 插件执行
*/
public function execute($addon = null, $controller = null, $action = null)
{
$request = Request::instance();
// 是否自动转换控制器和操作名
$convert = Config::get('url_convert');
$filter = $convert ? 'strtolower' : 'trim';
$addon = $addon ? trim(call_user_func($filter, $addon)) : '';
$controller = $controller ? trim(call_user_func($filter, $controller)) : 'index';
$action = $action ? trim(call_user_func($filter, $action)) : 'index';
Hook::listen('addon_begin', $request);
if (!empty($addon) && !empty($controller) && !empty($action)) {
$info = get_addon_info($addon);
if (!$info) {
throw new HttpException(404, __('addon %s not found', $addon));
}
if (!$info['state']) {
throw new HttpException(500, __('addon %s is disabled', $addon));
}
$dispatch = $request->dispatch();
if (isset($dispatch['var']) && $dispatch['var']) {
$request->route(array_diff_key($dispatch['var'], array_flip(['addon', 'controller', 'action'])));
}
// 设置当前请求的控制器、操作
$request->controller($controller)->action($action);
// 监听addon_module_init
Hook::listen('addon_module_init', $request);
// 兼容旧版本行为,即将移除,不建议使用
Hook::listen('addons_init', $request);
$class = get_addon_class($addon, 'controller', $controller);
if (!$class) {
throw new HttpException(404, __('addon controller %s not found', Loader::parseName($controller, 1)));
}
$instance = new $class($request);
$vars = [];
if (is_callable([$instance, $action])) {
// 执行操作方法
$call = [$instance, $action];
} elseif (is_callable([$instance, '_empty'])) {
// 空操作
$call = [$instance, '_empty'];
$vars = [$action];
} else {
// 操作不存在
throw new HttpException(404, __('addon action %s not found', get_class($instance) . '->' . $action . '()'));
}
Hook::listen('addon_action_begin', $call);
return call_user_func_array($call, $vars);
} else {
abort(500, lang('addon can not be empty'));
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,530 @@
<?php
// +----------------------------------------------------------------------
// | thinkphp5 Addons [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016 http://www.zzstudio.net All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: Byron Sampson <xiaobo.sun@qq.com>
// +----------------------------------------------------------------------
use Symfony\Component\VarExporter\VarExporter;
use think\addons\Service;
use think\App;
use think\Cache;
use think\Config;
use think\Exception;
use think\exception\HttpException;
use think\exception\HttpResponseException;
use think\Hook;
use think\Loader;
use think\Response;
use think\Route;
// 插件目录
define('ADDON_PATH', ROOT_PATH . 'addons' . DS);
// 定义路由
Route::any('addons/:addon/[:controller]/[:action]', "\\think\\addons\\Route@execute");
// 如果插件目录不存在则创建
if (!is_dir(ADDON_PATH)) {
@mkdir(ADDON_PATH, 0755, true);
}
// 注册类的根命名空间
Loader::addNamespace('addons', ADDON_PATH);
// 监听addon_init
Hook::listen('addon_init');
// 闭包自动识别插件目录配置
Hook::add('app_init', function () {
// 获取开关
$autoload = (bool)Config::get('addons.autoload', false);
// 非正是返回
if (!$autoload) {
return;
}
// 当debug时不缓存配置
$config = App::$debug ? [] : Cache::get('addons', []);
if (empty($config)) {
$config = get_addon_autoload_config();
Cache::set('addons', $config);
}
});
// 闭包初始化行为
Hook::add('app_init', function () {
//注册路由
$routeArr = (array)Config::get('addons.route');
$domains = [];
$rules = [];
$execute = "\\think\\addons\\Route@execute?addon=%s&controller=%s&action=%s";
foreach ($routeArr as $k => $v) {
if (is_array($v)) {
$addon = $v['addon'];
$domain = $v['domain'];
$drules = [];
foreach ($v['rule'] as $m => $n) {
$urlArr = explode('/', $n);
if (count($urlArr) < 3) {
continue;
}
list($addon, $controller, $action) = $urlArr;
$drules[$m] = sprintf($execute . '&indomain=1', $addon, $controller, $action);
}
//$domains[$domain] = $drules ? $drules : "\\addons\\{$k}\\controller";
$domains[$domain] = $drules ? $drules : [];
$domains[$domain][':controller/[:action]'] = sprintf($execute . '&indomain=1', $addon, ":controller", ":action");
} else {
if (!$v) {
continue;
}
$urlArr = explode('/', $v);
if (count($urlArr) < 3) {
continue;
}
list($addon, $controller, $action) = $urlArr;
$rules[$k] = sprintf($execute, $addon, $controller, $action);
}
}
Route::rule($rules);
if ($domains) {
Route::domain($domains);
}
// 获取系统配置
$hooks = App::$debug ? [] : Cache::get('hooks', []);
if (empty($hooks)) {
$hooks = (array)Config::get('addons.hooks');
// 初始化钩子
foreach ($hooks as $key => $values) {
$values = is_string($values) ? explode(',', $values) : (array)$values;
$values = array_filter($values);
$hooks[$key] = array_filter(array_map('get_addon_class', $values));
}
Cache::set('hooks', $hooks);
}
//如果在插件中有定义app_init则直接执行
if (isset($hooks['app_init'])) {
foreach ($hooks['app_init'] as $k => $v) {
Hook::exec($v, 'app_init');
}
}
Hook::import($hooks, true);
});
/**
* 处理插件钩子
* @param string $hook 钩子名称
* @param mixed $params 传入参数
* @return void
*/
function hook($hook, $params = [])
{
Hook::listen($hook, $params);
}
/**
* 移除空目录
* @param string $dir 目录
*/
function remove_empty_folder($dir)
{
try {
$isDirEmpty = !(new \FilesystemIterator($dir))->valid();
if ($isDirEmpty) {
@rmdir($dir);
remove_empty_folder(dirname($dir));
}
} catch (\UnexpectedValueException $e) {
} catch (\Exception $e) {
}
}
/**
* 获得插件列表
* @return array
*/
function get_addon_list()
{
$results = scandir(ADDON_PATH);
$list = [];
foreach ($results as $name) {
if ($name === '.' or $name === '..') {
continue;
}
if (is_file(ADDON_PATH . $name)) {
continue;
}
$addonDir = ADDON_PATH . $name . DS;
if (!is_dir($addonDir)) {
continue;
}
if (!is_file($addonDir . ucfirst($name) . '.php')) {
continue;
}
//这里不采用get_addon_info是因为会有缓存
//$info = get_addon_info($name);
$info_file = $addonDir . 'info.ini';
if (!is_file($info_file)) {
continue;
}
$info = Config::parse($info_file, '', "addon-info-{$name}");
if (!isset($info['name'])) {
continue;
}
$info['url'] = addon_url($name);
$list[$name] = $info;
}
return $list;
}
/**
* 获得插件自动加载的配置
* @param bool $truncate 是否清除手动配置的钩子
* @return array
*/
function get_addon_autoload_config($truncate = false)
{
// 读取addons的配置
$config = (array)Config::get('addons');
if ($truncate) {
// 清空手动配置的钩子
$config['hooks'] = [];
}
// 伪静态优先级
$priority = isset($config['priority']) && $config['priority'] ? is_array($config['priority']) ? $config['priority'] : explode(',', $config['priority']) : [];
$route = [];
// 读取插件目录及钩子列表
$base = get_class_methods("\\think\\Addons");
$base = array_merge($base, ['install', 'uninstall', 'enable', 'disable']);
$url_domain_deploy = Config::get('url_domain_deploy');
$addons = get_addon_list();
$domain = [];
$priority = array_merge($priority, array_keys($addons));
$orderedAddons = array();
foreach ($priority as $key) {
if (!isset($addons[$key])) {
continue;
}
$orderedAddons[$key] = $addons[$key];
}
foreach ($orderedAddons as $name => $addon) {
if (!$addon['state']) {
continue;
}
// 读取出所有公共方法
$methods = (array)get_class_methods("\\addons\\" . $name . "\\" . ucfirst($name));
// 跟插件基类方法做比对,得到差异结果
$hooks = array_diff($methods, $base);
// 循环将钩子方法写入配置中
foreach ($hooks as $hook) {
$hook = Loader::parseName($hook, 0, false);
if (!isset($config['hooks'][$hook])) {
$config['hooks'][$hook] = [];
}
// 兼容手动配置项
if (is_string($config['hooks'][$hook])) {
$config['hooks'][$hook] = explode(',', $config['hooks'][$hook]);
}
if (!in_array($name, $config['hooks'][$hook])) {
$config['hooks'][$hook][] = $name;
}
}
$conf = get_addon_config($addon['name']);
if ($conf) {
$conf['rewrite'] = isset($conf['rewrite']) && is_array($conf['rewrite']) ? $conf['rewrite'] : [];
$rule = array_map(function ($value) use ($addon) {
return "{$addon['name']}/{$value}";
}, array_flip($conf['rewrite']));
if ($url_domain_deploy && isset($conf['domain']) && $conf['domain']) {
$domain[] = [
'addon' => $addon['name'],
'domain' => $conf['domain'],
'rule' => $rule
];
} else {
$route = array_merge($route, $rule);
}
}
}
$config['route'] = $route;
$config['route'] = array_merge($config['route'], $domain);
return $config;
}
/**
* 获取插件类的类名
* @param string $name 插件名
* @param string $type 返回命名空间类型
* @param string $class 当前类名
* @return string
*/
function get_addon_class($name, $type = 'hook', $class = null)
{
$name = Loader::parseName($name);
// 处理多级控制器情况
if (!is_null($class) && strpos($class, '.')) {
$class = explode('.', $class);
$class[count($class) - 1] = Loader::parseName(end($class), 1);
$class = implode('\\', $class);
} else {
$class = Loader::parseName(is_null($class) ? $name : $class, 1);
}
switch ($type) {
case 'controller':
$namespace = "\\addons\\" . $name . "\\controller\\" . $class;
break;
default:
$namespace = "\\addons\\" . $name . "\\" . $class;
}
return class_exists($namespace) ? $namespace : '';
}
/**
* 读取插件的基础信息
* @param string $name 插件名
* @return array
*/
function get_addon_info($name)
{
$addon = get_addon_instance($name);
if (!$addon) {
return [];
}
return $addon->getInfo($name);
}
/**
* 获取插件类的配置数组
* @param string $name 插件名
* @return array
*/
function get_addon_fullconfig($name)
{
$addon = get_addon_instance($name);
if (!$addon) {
return [];
}
return $addon->getFullConfig($name);
}
/**
* 获取插件类的配置值值
* @param string $name 插件名
* @return array
*/
function get_addon_config($name)
{
$addon = get_addon_instance($name);
if (!$addon) {
return [];
}
return $addon->getConfig($name);
}
/**
* 获取插件的单例
* @param string $name 插件名
* @return mixed|null
*/
function get_addon_instance($name)
{
static $_addons = [];
if (isset($_addons[$name])) {
return $_addons[$name];
}
$class = get_addon_class($name);
if (class_exists($class)) {
$_addons[$name] = new $class();
return $_addons[$name];
} else {
return null;
}
}
/**
* 获取插件创建的表
* @param string $name 插件名
* @return array
*/
function get_addon_tables($name)
{
$addonInfo = get_addon_info($name);
if (!$addonInfo) {
return [];
}
$regex = "/^CREATE\s+TABLE\s+(IF\s+NOT\s+EXISTS\s+)?`?([a-zA-Z_]+)`?/mi";
$sqlFile = ADDON_PATH . $name . DS . 'install.sql';
$tables = [];
if (is_file($sqlFile)) {
preg_match_all($regex, file_get_contents($sqlFile), $matches);
if ($matches && isset($matches[2]) && $matches[2]) {
$prefix = config('database.prefix');
$tables = array_map(function ($item) use ($prefix) {
return str_replace("__PREFIX__", $prefix, $item);
}, $matches[2]);
}
}
return $tables;
}
/**
* 插件显示内容里生成访问插件的url
* @param string $url 地址 格式:插件名/控制器/方法
* @param array $vars 变量参数
* @param bool|string $suffix 生成的URL后缀
* @param bool|string $domain 域名
* @return bool|string
*/
function addon_url($url, $vars = [], $suffix = true, $domain = false)
{
$url = ltrim($url, '/');
$addon = substr($url, 0, stripos($url, '/'));
if (!is_array($vars)) {
parse_str($vars, $params);
$vars = $params;
}
$params = [];
foreach ($vars as $k => $v) {
if (substr($k, 0, 1) === ':') {
$params[$k] = $v;
unset($vars[$k]);
}
}
$val = "@addons/{$url}";
$config = get_addon_config($addon);
$dispatch = think\Request::instance()->dispatch();
$indomain = isset($dispatch['var']['indomain']) && $dispatch['var']['indomain'] && $dispatch['var']['addon'] == $addon ? true : false;
//优先取插件配置中的domain没有的情况下取全局的域名前缀配置
$domainprefix = $config && isset($config['domain']) && $config['domain'] ? $config['domain'] : Config::get('addons.domain');
$domain = $domainprefix && Config::get('url_domain_deploy') ? $domainprefix : $domain;
$rewrite = $config && isset($config['rewrite']) && $config['rewrite'] ? $config['rewrite'] : [];
if ($rewrite) {
$path = substr($url, stripos($url, '/') + 1);
if (isset($rewrite[$path]) && $rewrite[$path]) {
$val = $rewrite[$path];
array_walk($params, function ($value, $key) use (&$val) {
$val = str_replace("[{$key}]", $value, $val);
});
$val = str_replace(['^', '$'], '', $val);
if (substr($val, -1) === '/') {
$suffix = false;
}
} else {
// 如果采用了域名部署,则需要去掉前两段
if ($indomain && $domainprefix) {
$arr = explode("/", $val);
$val = implode("/", array_slice($arr, 2));
}
}
} else {
// 如果采用了域名部署,则需要去掉前两段
if ($indomain && $domainprefix) {
$arr = explode("/", $val);
$val = implode("/", array_slice($arr, 2));
}
foreach ($params as $k => $v) {
$vars[substr($k, 1)] = $v;
}
}
$url = url($val, [], $suffix, $domain) . ($vars ? '?' . http_build_query($vars) : '');
$url = preg_replace("/\/((?!index)[\w]+)\.php\//i", "/", $url);
return $url;
}
/**
* 设置基础配置信息
* @param string $name 插件名
* @param array $array 配置数据
* @return boolean
* @throws Exception
*/
function set_addon_info($name, $array)
{
$file = ADDON_PATH . $name . DS . 'info.ini';
$addon = get_addon_instance($name);
$array = $addon->setInfo($name, $array);
if (!isset($array['name']) || !isset($array['title']) || !isset($array['version'])) {
throw new Exception("插件配置写入失败");
}
$res = array();
foreach ($array as $key => $val) {
if (is_array($val)) {
$res[] = "[$key]";
foreach ($val as $skey => $sval) {
$res[] = "$skey = " . (is_numeric($sval) ? $sval : $sval);
}
} else {
$res[] = "$key = " . (is_numeric($val) ? $val : $val);
}
}
if (file_put_contents($file, implode("\n", $res) . "\n", LOCK_EX)) {
//清空当前配置缓存
Config::set($name, null, 'addoninfo');
} else {
throw new Exception("文件没有写入权限");
}
return true;
}
/**
* 写入配置文件
* @param string $name 插件名
* @param array $config 配置数据
* @param boolean $writefile 是否写入配置文件
* @return bool
* @throws Exception
*/
function set_addon_config($name, $config, $writefile = true)
{
$addon = get_addon_instance($name);
$addon->setConfig($name, $config);
$fullconfig = get_addon_fullconfig($name);
foreach ($fullconfig as $k => &$v) {
if (isset($config[$v['name']])) {
$value = $v['type'] !== 'array' && is_array($config[$v['name']]) ? implode(',', $config[$v['name']]) : $config[$v['name']];
$v['value'] = $value;
}
}
if ($writefile) {
// 写入配置文件
set_addon_fullconfig($name, $fullconfig);
}
return true;
}
/**
* 写入配置文件
*
* @param string $name 插件名
* @param array $array 配置数据
* @return boolean
* @throws Exception
*/
function set_addon_fullconfig($name, $array)
{
$file = ADDON_PATH . $name . DS . 'config.php';
$ret = file_put_contents($file, "<?php\n\n" . "return " . VarExporter::export($array) . ";\n", LOCK_EX);
if (!$ret) {
throw new Exception("配置写入失败");
}
return true;
}

View File

@@ -0,0 +1,15 @@
<?php
// +----------------------------------------------------------------------
// | thinkphp5 Addons [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016 http://www.zzstudio.net All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: Byron Sampson <xiaobo.sun@qq.com>
// +----------------------------------------------------------------------
return [
'addons_on' => true,
];