mirror of
https://gitee.com/zoujingli/ThinkAdmin.git
synced 2025-05-22 14:59:14 +08:00
ComposerUpdate
This commit is contained in:
parent
9704c64d13
commit
27dd871878
@ -16,7 +16,6 @@
|
|||||||
namespace app\admin\controller\api;
|
namespace app\admin\controller\api;
|
||||||
|
|
||||||
use think\admin\Controller;
|
use think\admin\Controller;
|
||||||
use think\admin\service\InstallService;
|
|
||||||
use think\admin\service\ModuleService;
|
use think\admin\service\ModuleService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -50,7 +49,7 @@ class Update extends Controller
|
|||||||
*/
|
*/
|
||||||
public function node()
|
public function node()
|
||||||
{
|
{
|
||||||
$this->success('获取文件列表成功!', InstallService::instance()->getList(
|
$this->success('获取文件列表成功!', ModuleService::instance()->getChanges(
|
||||||
json_decode($this->request->post('rules', '[]', ''), true),
|
json_decode($this->request->post('rules', '[]', ''), true),
|
||||||
json_decode($this->request->post('ignore', '[]', ''), true)
|
json_decode($this->request->post('ignore', '[]', ''), true)
|
||||||
));
|
));
|
||||||
|
1
vendor/composer/autoload_classmap.php
vendored
1
vendor/composer/autoload_classmap.php
vendored
@ -299,7 +299,6 @@ return array(
|
|||||||
'think\\admin\\service\\AdminService' => $vendorDir . '/zoujingli/think-library/src/service/AdminService.php',
|
'think\\admin\\service\\AdminService' => $vendorDir . '/zoujingli/think-library/src/service/AdminService.php',
|
||||||
'think\\admin\\service\\CaptchaService' => $vendorDir . '/zoujingli/think-library/src/service/CaptchaService.php',
|
'think\\admin\\service\\CaptchaService' => $vendorDir . '/zoujingli/think-library/src/service/CaptchaService.php',
|
||||||
'think\\admin\\service\\ExpressService' => $vendorDir . '/zoujingli/think-library/src/service/ExpressService.php',
|
'think\\admin\\service\\ExpressService' => $vendorDir . '/zoujingli/think-library/src/service/ExpressService.php',
|
||||||
'think\\admin\\service\\InstallService' => $vendorDir . '/zoujingli/think-library/src/service/InstallService.php',
|
|
||||||
'think\\admin\\service\\InterfaceService' => $vendorDir . '/zoujingli/think-library/src/service/InterfaceService.php',
|
'think\\admin\\service\\InterfaceService' => $vendorDir . '/zoujingli/think-library/src/service/InterfaceService.php',
|
||||||
'think\\admin\\service\\MenuService' => $vendorDir . '/zoujingli/think-library/src/service/MenuService.php',
|
'think\\admin\\service\\MenuService' => $vendorDir . '/zoujingli/think-library/src/service/MenuService.php',
|
||||||
'think\\admin\\service\\MessageService' => $vendorDir . '/zoujingli/think-library/src/service/MessageService.php',
|
'think\\admin\\service\\MessageService' => $vendorDir . '/zoujingli/think-library/src/service/MessageService.php',
|
||||||
|
1
vendor/composer/autoload_static.php
vendored
1
vendor/composer/autoload_static.php
vendored
@ -436,7 +436,6 @@ class ComposerStaticInitb55556af42203bcef68382c66bc39c70
|
|||||||
'think\\admin\\service\\AdminService' => __DIR__ . '/..' . '/zoujingli/think-library/src/service/AdminService.php',
|
'think\\admin\\service\\AdminService' => __DIR__ . '/..' . '/zoujingli/think-library/src/service/AdminService.php',
|
||||||
'think\\admin\\service\\CaptchaService' => __DIR__ . '/..' . '/zoujingli/think-library/src/service/CaptchaService.php',
|
'think\\admin\\service\\CaptchaService' => __DIR__ . '/..' . '/zoujingli/think-library/src/service/CaptchaService.php',
|
||||||
'think\\admin\\service\\ExpressService' => __DIR__ . '/..' . '/zoujingli/think-library/src/service/ExpressService.php',
|
'think\\admin\\service\\ExpressService' => __DIR__ . '/..' . '/zoujingli/think-library/src/service/ExpressService.php',
|
||||||
'think\\admin\\service\\InstallService' => __DIR__ . '/..' . '/zoujingli/think-library/src/service/InstallService.php',
|
|
||||||
'think\\admin\\service\\InterfaceService' => __DIR__ . '/..' . '/zoujingli/think-library/src/service/InterfaceService.php',
|
'think\\admin\\service\\InterfaceService' => __DIR__ . '/..' . '/zoujingli/think-library/src/service/InterfaceService.php',
|
||||||
'think\\admin\\service\\MenuService' => __DIR__ . '/..' . '/zoujingli/think-library/src/service/MenuService.php',
|
'think\\admin\\service\\MenuService' => __DIR__ . '/..' . '/zoujingli/think-library/src/service/MenuService.php',
|
||||||
'think\\admin\\service\\MessageService' => __DIR__ . '/..' . '/zoujingli/think-library/src/service/MessageService.php',
|
'think\\admin\\service\\MessageService' => __DIR__ . '/..' . '/zoujingli/think-library/src/service/MessageService.php',
|
||||||
|
16
vendor/composer/installed.json
vendored
16
vendor/composer/installed.json
vendored
@ -573,8 +573,8 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/options-resolver",
|
"name": "symfony/options-resolver",
|
||||||
"version": "v3.4.43",
|
"version": "v3.4.44",
|
||||||
"version_normalized": "3.4.43.0",
|
"version_normalized": "3.4.44.0",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/symfony/options-resolver.git",
|
"url": "https://github.com/symfony/options-resolver.git",
|
||||||
@ -958,17 +958,17 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "zoujingli/think-library",
|
"name": "zoujingli/think-library",
|
||||||
"version": "v6.0.1",
|
"version": "v6.0.2",
|
||||||
"version_normalized": "6.0.1.0",
|
"version_normalized": "6.0.2.0",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/zoujingli/ThinkLibrary.git",
|
"url": "https://github.com/zoujingli/ThinkLibrary.git",
|
||||||
"reference": "a5c1e18d0e57dd0a83174793f09cca5ba592b773"
|
"reference": "a498595d637568481601091985ae22d5cd05a057"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/zoujingli/ThinkLibrary/zipball/a5c1e18d0e57dd0a83174793f09cca5ba592b773",
|
"url": "https://api.github.com/repos/zoujingli/ThinkLibrary/zipball/a498595d637568481601091985ae22d5cd05a057",
|
||||||
"reference": "a5c1e18d0e57dd0a83174793f09cca5ba592b773",
|
"reference": "a498595d637568481601091985ae22d5cd05a057",
|
||||||
"shasum": "",
|
"shasum": "",
|
||||||
"mirrors": [
|
"mirrors": [
|
||||||
{
|
{
|
||||||
@ -985,7 +985,7 @@
|
|||||||
"ext-mbstring": "*",
|
"ext-mbstring": "*",
|
||||||
"topthink/framework": "^6.0"
|
"topthink/framework": "^6.0"
|
||||||
},
|
},
|
||||||
"time": "2020-08-28T11:32:28+00:00",
|
"time": "2020-08-31T11:59:58+00:00",
|
||||||
"type": "library",
|
"type": "library",
|
||||||
"extra": {
|
"extra": {
|
||||||
"think": {
|
"think": {
|
||||||
|
2
vendor/services.php
vendored
2
vendor/services.php
vendored
@ -1,5 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
// This file is automatically generated at:2020-08-28 19:49:26
|
// This file is automatically generated at:2020-08-31 20:25:48
|
||||||
declare (strict_types = 1);
|
declare (strict_types = 1);
|
||||||
return array (
|
return array (
|
||||||
0 => 'think\\admin\\Library',
|
0 => 'think\\admin\\Library',
|
||||||
|
@ -38,6 +38,11 @@ use function Composer\Autoload\includeFile;
|
|||||||
*/
|
*/
|
||||||
class Library extends Service
|
class Library extends Service
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* 扩展库版本号
|
||||||
|
*/
|
||||||
|
const VERSION = '6.0.2';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 启动服务
|
* 启动服务
|
||||||
*/
|
*/
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
namespace think\admin\command;
|
namespace think\admin\command;
|
||||||
|
|
||||||
use think\admin\Command;
|
use think\admin\Command;
|
||||||
use think\admin\service\InstallService;
|
use think\admin\service\ModuleService;
|
||||||
use think\console\Input;
|
use think\console\Input;
|
||||||
use think\console\input\Argument;
|
use think\console\input\Argument;
|
||||||
use think\console\Output;
|
use think\console\Output;
|
||||||
@ -114,10 +114,10 @@ class Install extends Command
|
|||||||
|
|
||||||
protected function installFile()
|
protected function installFile()
|
||||||
{
|
{
|
||||||
$data = InstallService::instance()->grenerateDifference($this->rules, $this->ignore);
|
$data = ModuleService::instance()->grenerateDifference($this->rules, $this->ignore);
|
||||||
if (empty($data)) $this->output->writeln('No need to update the file if the file comparison is consistent');
|
if (empty($data)) $this->output->writeln('No need to update the file if the file comparison is consistent');
|
||||||
else foreach ($data as $file) {
|
else foreach ($data as $file) {
|
||||||
[$state, $mode, $name] = InstallService::instance()->updateFileByDownload($file);
|
[$state, $mode, $name] = ModuleService::instance()->updateFileByDownload($file);
|
||||||
if ($state) {
|
if ($state) {
|
||||||
if ($mode === 'add') $this->output->writeln("--- {$name} add successfully");
|
if ($mode === 'add') $this->output->writeln("--- {$name} add successfully");
|
||||||
if ($mode === 'mod') $this->output->writeln("--- {$name} update successfully");
|
if ($mode === 'mod') $this->output->writeln("--- {$name} update successfully");
|
||||||
|
@ -74,6 +74,7 @@ class AdminService extends Service
|
|||||||
if ($this->isSuper()) return true;
|
if ($this->isSuper()) return true;
|
||||||
$service = NodeService::instance();
|
$service = NodeService::instance();
|
||||||
[$real, $nodes] = [$service->fullnode($node), $service->getMethods()];
|
[$real, $nodes] = [$service->fullnode($node), $service->getMethods()];
|
||||||
|
// 以下代码为兼容 win 控制器不区分大小写的验证问题
|
||||||
foreach ($nodes as $key => $rule) {
|
foreach ($nodes as $key => $rule) {
|
||||||
if (strpos($key, '_') !== false && strpos($key, '/') !== false) {
|
if (strpos($key, '_') !== false && strpos($key, '/') !== false) {
|
||||||
$attr = explode('/', $key);
|
$attr = explode('/', $key);
|
||||||
|
@ -1,196 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
// +----------------------------------------------------------------------
|
|
||||||
// | Library for ThinkAdmin
|
|
||||||
// +----------------------------------------------------------------------
|
|
||||||
// | 版权所有 2014~2020 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
|
|
||||||
// +----------------------------------------------------------------------
|
|
||||||
// | 官方网站: https://gitee.com/zoujingli/ThinkLibrary
|
|
||||||
// +----------------------------------------------------------------------
|
|
||||||
// | 开源协议 ( https://mit-license.org )
|
|
||||||
// +----------------------------------------------------------------------
|
|
||||||
// | gitee 仓库地址 :https://gitee.com/zoujingli/ThinkLibrary
|
|
||||||
// | github 仓库地址 :https://github.com/zoujingli/ThinkLibrary
|
|
||||||
// +----------------------------------------------------------------------
|
|
||||||
|
|
||||||
namespace think\admin\service;
|
|
||||||
|
|
||||||
use think\admin\extend\HttpExtend;
|
|
||||||
use think\admin\Service;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 模块安装服务管理
|
|
||||||
* Class InstallService
|
|
||||||
* @package think\admin\service
|
|
||||||
*/
|
|
||||||
class InstallService extends Service
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* 项目根目录
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
private $root;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 线上服务器地址
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
private $server;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 初始化服务
|
|
||||||
*/
|
|
||||||
protected function initialize()
|
|
||||||
{
|
|
||||||
$this->root = strtr($this->app->getRootPath(), '\\', '/');
|
|
||||||
$this->server = ModuleService::instance()->getServer();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取文件信息列表
|
|
||||||
* @param array $rules 文件规则
|
|
||||||
* @param array $ignore 忽略规则
|
|
||||||
* @param array $data 扫描结果列表
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function getList(array $rules, array $ignore = [], array $data = []): array
|
|
||||||
{
|
|
||||||
// 扫描规则文件
|
|
||||||
foreach ($rules as $key => $rule) {
|
|
||||||
$name = strtr(trim($rule, '\\/'), '\\', '/');
|
|
||||||
$data = array_merge($data, $this->_scanList($this->root . $name));
|
|
||||||
}
|
|
||||||
// 清除忽略文件
|
|
||||||
foreach ($data as $key => $item) foreach ($ignore as $ign) {
|
|
||||||
if (stripos($item['name'], $ign) === 0) unset($data[$key]);
|
|
||||||
}
|
|
||||||
// 返回文件数据
|
|
||||||
return ['rules' => $rules, 'ignore' => $ignore, 'list' => $data];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取文件差异数据
|
|
||||||
* @param array $rules 文件规则
|
|
||||||
* @param array $ignore 忽略规则
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function grenerateDifference(array $rules = [], array $ignore = []): array
|
|
||||||
{
|
|
||||||
[$rules1, $ignore1, $data] = [$rules, $ignore, []];
|
|
||||||
$result = json_decode(HttpExtend::post($this->server . '/admin/api.update/node', [
|
|
||||||
'rules' => json_encode($rules1), 'ignore' => json_encode($ignore1),
|
|
||||||
]), true);
|
|
||||||
if (!empty($result['code'])) {
|
|
||||||
$new = $this->getList($result['data']['rules'], $result['data']['ignore']);
|
|
||||||
foreach ($this->_grenerateDifferenceContrast($result['data']['list'], $new['list']) as $file) {
|
|
||||||
if (in_array($file['type'], ['add', 'del', 'mod'])) foreach ($rules1 as $rule) {
|
|
||||||
if (stripos($file['name'], $rule) === 0) $data[] = $file;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return $data;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 下载并更新文件
|
|
||||||
* @param array $file 文件信息
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function updateFileByDownload(array $file): array
|
|
||||||
{
|
|
||||||
if (in_array($file['type'], ['add', 'mod'])) {
|
|
||||||
if ($this->_downloadFile(encode($file['name']))) {
|
|
||||||
return [true, $file['type'], $file['name']];
|
|
||||||
} else {
|
|
||||||
return [false, $file['type'], $file['name']];
|
|
||||||
}
|
|
||||||
} elseif (in_array($file['type'], ['del'])) {
|
|
||||||
$real = $this->root . $file['name'];
|
|
||||||
if (is_file($real) && unlink($real)) {
|
|
||||||
$this->_removeEmptyDirectory(dirname($real));
|
|
||||||
return [true, $file['type'], $file['name']];
|
|
||||||
} else {
|
|
||||||
return [false, $file['type'], $file['name']];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 下载更新文件内容
|
|
||||||
* @param string $encode
|
|
||||||
* @return boolean|integer
|
|
||||||
*/
|
|
||||||
private function _downloadFile($encode)
|
|
||||||
{
|
|
||||||
$source = $this->server . '/admin/api.update/get?encode=' . $encode;
|
|
||||||
$result = json_decode(HttpExtend::get($source), true);
|
|
||||||
if (empty($result['code'])) return false;
|
|
||||||
$filename = $this->root . decode($encode);
|
|
||||||
file_exists(dirname($filename)) || mkdir(dirname($filename), 0755, true);
|
|
||||||
return file_put_contents($filename, base64_decode($result['data']['content']));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 清理空目录
|
|
||||||
* @param string $path
|
|
||||||
*/
|
|
||||||
private function _removeEmptyDirectory($path)
|
|
||||||
{
|
|
||||||
if (is_dir($path) && count(scandir($path)) === 2 && rmdir($path)) {
|
|
||||||
$this->_removeEmptyDirectory(dirname($path));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 两二维数组对比
|
|
||||||
* @param array $serve 线上文件列表信息
|
|
||||||
* @param array $local 本地文件列表信息
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
private function _grenerateDifferenceContrast(array $serve = [], array $local = []): array
|
|
||||||
{
|
|
||||||
// 数据扁平化
|
|
||||||
[$_serve, $_local, $_diffy] = [[], [], []];
|
|
||||||
foreach ($serve as $t) $_serve[$t['name']] = $t;
|
|
||||||
foreach ($local as $t) $_local[$t['name']] = $t;
|
|
||||||
unset($serve, $local);
|
|
||||||
// 线上数据差异计算
|
|
||||||
foreach ($_serve as $t) isset($_local[$t['name']]) ? array_push($_diffy, [
|
|
||||||
'type' => $t['hash'] === $_local[$t['name']]['hash'] ? null : 'mod', 'name' => $t['name'],
|
|
||||||
]) : array_push($_diffy, ['type' => 'add', 'name' => $t['name']]);
|
|
||||||
// 本地数据增量计算
|
|
||||||
foreach ($_local as $t) if (!isset($_serve[$t['name']])) array_push($_diffy, ['type' => 'del', 'name' => $t['name']]);
|
|
||||||
unset($_serve, $_local);
|
|
||||||
usort($_diffy, function ($a, $b) {
|
|
||||||
return $a['name'] !== $b['name'] ? ($a['name'] > $b['name'] ? 1 : -1) : 0;
|
|
||||||
});
|
|
||||||
return $_diffy;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取指定文件信息
|
|
||||||
* @param string $path 文件路径
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
private function _getInfo($path): array
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
'name' => str_replace($this->root, '', $path),
|
|
||||||
'hash' => md5(preg_replace('/\s+/', '', file_get_contents($path))),
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取目录文件列表
|
|
||||||
* @param string $path 待扫描目录
|
|
||||||
* @param array $data 扫描结果
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
private function _scanList($path, $data = []): array
|
|
||||||
{
|
|
||||||
foreach (NodeService::instance()->scanDirectory($path, [], null) as $file) {
|
|
||||||
$data[] = $this->_getInfo(strtr($file, '\\', '/'));
|
|
||||||
}
|
|
||||||
return $data;
|
|
||||||
}
|
|
||||||
}
|
|
@ -17,6 +17,7 @@ namespace think\admin\service;
|
|||||||
|
|
||||||
use think\admin\extend\HttpExtend;
|
use think\admin\extend\HttpExtend;
|
||||||
use think\admin\extend\Parsedown;
|
use think\admin\extend\Parsedown;
|
||||||
|
use think\admin\Library;
|
||||||
use think\admin\Service;
|
use think\admin\Service;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -26,6 +27,12 @@ use think\admin\Service;
|
|||||||
*/
|
*/
|
||||||
class ModuleService extends Service
|
class ModuleService extends Service
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* 代码根目录
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $root;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 官方应用地址
|
* 官方应用地址
|
||||||
* @var string
|
* @var string
|
||||||
@ -39,14 +46,14 @@ class ModuleService extends Service
|
|||||||
protected $version;
|
protected $version;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 服务初始化
|
* 模块服务初始化
|
||||||
*/
|
*/
|
||||||
public function initialize()
|
public function initialize()
|
||||||
{
|
{
|
||||||
$full = $this->app->config->get('app.thinkadmin_ver', 'v4.0.0');
|
$this->root = $this->app->getRootPath();
|
||||||
$this->version = trim($full, 'v');
|
$this->version = trim(Library::VERSION, 'v');
|
||||||
$version = strstr($full . '.', '.', true);
|
$maxver = strstr($this->version, '.', true);
|
||||||
$this->server = "https://{$version}.thinkadmin.top";
|
$this->server = "https://v{$maxver}.thinkadmin.top";
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -115,13 +122,12 @@ class ModuleService extends Service
|
|||||||
*/
|
*/
|
||||||
public function install($name): array
|
public function install($name): array
|
||||||
{
|
{
|
||||||
$install = InstallService::instance();
|
|
||||||
$this->app->cache->set('moduleOnlineData', []);
|
$this->app->cache->set('moduleOnlineData', []);
|
||||||
$data = $install->grenerateDifference(['app' . '/' . $name]);
|
$data = $this->grenerateDifference(['app' . '/' . $name]);
|
||||||
if (empty($data)) return [0, '没有需要安装的文件', []];
|
if (empty($data)) return [0, '没有需要安装的文件', []];
|
||||||
$lines = [];
|
$lines = [];
|
||||||
foreach ($data as $file) {
|
foreach ($data as $file) {
|
||||||
[$state, $mode, $name] = $install->updateFileByDownload($file);
|
[$state, $mode, $name] = $this->updateFileByDownload($file);
|
||||||
if ($state) {
|
if ($state) {
|
||||||
if ($mode === 'add') $lines[] = "add {$name} successed";
|
if ($mode === 'add') $lines[] = "add {$name} successed";
|
||||||
if ($mode === 'mod') $lines[] = "modify {$name} successed";
|
if ($mode === 'mod') $lines[] = "modify {$name} successed";
|
||||||
@ -147,7 +153,7 @@ class ModuleService extends Service
|
|||||||
$vars = $this->_getModuleVersion($name);
|
$vars = $this->_getModuleVersion($name);
|
||||||
if (is_array($vars) && isset($vars['version']) && preg_match('|^\d{4}\.\d{2}\.\d{2}\.\d{2}$|', $vars['version'])) {
|
if (is_array($vars) && isset($vars['version']) && preg_match('|^\d{4}\.\d{2}\.\d{2}\.\d{2}$|', $vars['version'])) {
|
||||||
$data[$name] = array_merge($vars, ['change' => []]);
|
$data[$name] = array_merge($vars, ['change' => []]);
|
||||||
foreach ($service->scanDirectory($this->_getModulePath($name) . 'change', [], 'md') as $file) {
|
foreach ($service->scanDirectory($this->_getModuleInfoPath($name) . 'change', [], 'md') as $file) {
|
||||||
$data[$name]['change'][pathinfo($file, PATHINFO_FILENAME)] = Parsedown::instance()->parse(file_get_contents($file));
|
$data[$name]['change'][pathinfo($file, PATHINFO_FILENAME)] = Parsedown::instance()->parse(file_get_contents($file));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -156,17 +162,25 @@ class ModuleService extends Service
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取允许下载的规则
|
* 获取文件信息列表
|
||||||
|
* @param array $rules 文件规则
|
||||||
|
* @param array $ignore 忽略规则
|
||||||
|
* @param array $data 扫描结果列表
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
public function getAllowDownloadRule(): array
|
public function getChanges(array $rules, array $ignore = [], array $data = []): array
|
||||||
{
|
{
|
||||||
$data = $this->app->cache->get('moduleAllowRule', []);
|
// 扫描规则文件
|
||||||
if (is_array($data) && count($data) > 0) return $data;
|
foreach ($rules as $key => $rule) {
|
||||||
$data = ['config', 'public/static', 'public/router.php', 'public/index.php'];
|
$name = strtr(trim($rule, '\\/'), '\\', '/');
|
||||||
foreach (array_keys($this->getModules()) as $name) $data[] = "app/{$name}";
|
$data = array_merge($data, $this->_scanLocalFileHashList($this->root . $name));
|
||||||
$this->app->cache->set('moduleAllowRule', $data, 30);
|
}
|
||||||
return $data;
|
// 清除忽略文件
|
||||||
|
foreach ($data as $key => $item) foreach ($ignore as $ign) {
|
||||||
|
if (stripos($item['name'], $ign) === 0) unset($data[$key]);
|
||||||
|
}
|
||||||
|
// 返回文件数据
|
||||||
|
return ['rules' => $rules, 'ignore' => $ignore, 'list' => $data];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -174,28 +188,89 @@ class ModuleService extends Service
|
|||||||
* @param string $name 文件名称
|
* @param string $name 文件名称
|
||||||
* @return boolean
|
* @return boolean
|
||||||
*/
|
*/
|
||||||
public function checkAllowDownload($name): bool
|
public function checkAllowDownload(string $name): bool
|
||||||
{
|
{
|
||||||
// 禁止下载数据库配置文件
|
// 禁止下载数据库配置文件
|
||||||
if (stripos($name, 'database.php') !== false) {
|
if (stripos($name, 'database.php') !== false) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// 检查允许下载的文件规则
|
// 检查允许下载的文件规则
|
||||||
foreach ($this->getAllowDownloadRule() as $rule) {
|
foreach ($this->_getAllowDownloadRule() as $rule) {
|
||||||
if (stripos($name, $rule) !== false) return true;
|
if (stripos($name, $rule) !== false) return true;
|
||||||
}
|
}
|
||||||
// 不在允许下载的文件规则
|
// 不在允许下载的文件规则
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取文件差异数据
|
||||||
|
* @param array $rules 文件规则
|
||||||
|
* @param array $ignore 忽略规则
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function grenerateDifference(array $rules = [], array $ignore = []): array
|
||||||
|
{
|
||||||
|
[$rules1, $ignore1, $data] = [$rules, $ignore, []];
|
||||||
|
$result = json_decode(HttpExtend::post($this->server . '/admin/api.update/node', [
|
||||||
|
'rules' => json_encode($rules1), 'ignore' => json_encode($ignore1),
|
||||||
|
]), true);
|
||||||
|
if (!empty($result['code'])) {
|
||||||
|
$new = $this->getChanges($result['data']['rules'], $result['data']['ignore']);
|
||||||
|
foreach ($this->_grenerateDifferenceContrast($result['data']['list'], $new['list']) as $file) {
|
||||||
|
if (in_array($file['type'], ['add', 'del', 'mod'])) foreach ($rules1 as $rule) {
|
||||||
|
if (stripos($file['name'], $rule) === 0) $data[] = $file;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 尝试下载并更新文件
|
||||||
|
* @param array $file 文件信息
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function updateFileByDownload(array $file): array
|
||||||
|
{
|
||||||
|
if (in_array($file['type'], ['add', 'mod'])) {
|
||||||
|
if ($this->_downloadUpdateFile(encode($file['name']))) {
|
||||||
|
return [true, $file['type'], $file['name']];
|
||||||
|
} else {
|
||||||
|
return [false, $file['type'], $file['name']];
|
||||||
|
}
|
||||||
|
} elseif (in_array($file['type'], ['del'])) {
|
||||||
|
$real = $this->root . $file['name'];
|
||||||
|
if (is_file($real) && unlink($real)) {
|
||||||
|
$this->_removeEmptyDirectory(dirname($real));
|
||||||
|
return [true, $file['type'], $file['name']];
|
||||||
|
} else {
|
||||||
|
return [false, $file['type'], $file['name']];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取允许下载的规则
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
private function _getAllowDownloadRule(): array
|
||||||
|
{
|
||||||
|
$data = $this->app->cache->get('moduleAllowRule', []);
|
||||||
|
if (is_array($data) && count($data) > 0) return $data;
|
||||||
|
$data = ['think', 'config', 'public/static', 'public/router.php', 'public/index.php'];
|
||||||
|
foreach (array_keys($this->getModules()) as $name) $data[] = 'app/' . $name;
|
||||||
|
$this->app->cache->set('moduleAllowRule', $data, 30);
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取模块版本信息
|
* 获取模块版本信息
|
||||||
* @param string $name 模块名称
|
* @param string $name 模块名称
|
||||||
* @return bool|array|null
|
* @return bool|array|null
|
||||||
*/
|
*/
|
||||||
private function _getModuleVersion($name)
|
private function _getModuleVersion(string $name)
|
||||||
{
|
{
|
||||||
$filename = $this->_getModulePath($name) . 'module.json';
|
$filename = $this->_getModuleInfoPath($name) . 'module.json';
|
||||||
if (file_exists($filename) && is_file($filename) && is_readable($filename)) {
|
if (file_exists($filename) && is_file($filename) && is_readable($filename)) {
|
||||||
$vars = json_decode(file_get_contents($filename), true);
|
$vars = json_decode(file_get_contents($filename), true);
|
||||||
return isset($vars['name']) && isset($vars['version']) ? $vars : null;
|
return isset($vars['name']) && isset($vars['version']) ? $vars : null;
|
||||||
@ -204,14 +279,81 @@ class ModuleService extends Service
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 下载更新文件内容
|
||||||
|
* @param string $encode
|
||||||
|
* @return boolean|integer
|
||||||
|
*/
|
||||||
|
private function _downloadUpdateFile(string $encode)
|
||||||
|
{
|
||||||
|
$source = $this->server . '/admin/api.update/get?encode=' . $encode;
|
||||||
|
$result = json_decode(HttpExtend::get($source), true);
|
||||||
|
if (empty($result['code'])) return false;
|
||||||
|
$filename = $this->root . decode($encode);
|
||||||
|
file_exists(dirname($filename)) || mkdir(dirname($filename), 0755, true);
|
||||||
|
return file_put_contents($filename, base64_decode($result['data']['content']));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 清理空目录
|
||||||
|
* @param string $path
|
||||||
|
*/
|
||||||
|
private function _removeEmptyDirectory(string $path)
|
||||||
|
{
|
||||||
|
if (is_dir($path) && count(scandir($path)) === 2 && rmdir($path)) {
|
||||||
|
$this->_removeEmptyDirectory(dirname($path));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取模块信息路径
|
* 获取模块信息路径
|
||||||
* @param string $name
|
* @param string $name 模块名称
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
private function _getModulePath($name)
|
private function _getModuleInfoPath(string $name): string
|
||||||
{
|
{
|
||||||
$appdir = $this->app->getBasePath() . $name;
|
$appdir = $this->app->getBasePath() . $name;
|
||||||
return $appdir . DIRECTORY_SEPARATOR . 'module' . DIRECTORY_SEPARATOR;
|
return $appdir . DIRECTORY_SEPARATOR . 'module' . DIRECTORY_SEPARATOR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据线上线下生成操作数组
|
||||||
|
* @param array $serve 线上文件列表信息
|
||||||
|
* @param array $local 本地文件列表信息
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
private function _grenerateDifferenceContrast(array $serve = [], array $local = []): array
|
||||||
|
{
|
||||||
|
// 数据扁平化
|
||||||
|
[$_serve, $_local, $_diffy] = [[], [], []];
|
||||||
|
foreach ($serve as $t) $_serve[$t['name']] = $t;
|
||||||
|
foreach ($local as $t) $_local[$t['name']] = $t;
|
||||||
|
unset($serve, $local);
|
||||||
|
// 线上数据差异计算
|
||||||
|
foreach ($_serve as $t) isset($_local[$t['name']]) ? array_push($_diffy, [
|
||||||
|
'type' => $t['hash'] === $_local[$t['name']]['hash'] ? null : 'mod', 'name' => $t['name'],
|
||||||
|
]) : array_push($_diffy, ['type' => 'add', 'name' => $t['name']]);
|
||||||
|
// 本地数据增量计算
|
||||||
|
foreach ($_local as $t) if (!isset($_serve[$t['name']])) array_push($_diffy, ['type' => 'del', 'name' => $t['name']]);
|
||||||
|
unset($_serve, $_local);
|
||||||
|
usort($_diffy, function ($a, $b) {
|
||||||
|
return $a['name'] !== $b['name'] ? ($a['name'] > $b['name'] ? 1 : -1) : 0;
|
||||||
|
});
|
||||||
|
return $_diffy;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取目录文件列表
|
||||||
|
* @param mixed $path 扫描目录
|
||||||
|
* @param array $data 扫描结果
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
private function _scanLocalFileHashList(string $path, array $data = []): array
|
||||||
|
{
|
||||||
|
foreach (NodeService::instance()->scanDirectory($path, [], null) as $file) $data[] = [
|
||||||
|
'name' => str_replace(strtr($this->root, '\\', '/'), '', $file),
|
||||||
|
'hash' => md5(preg_replace('/\s+/', '', file_get_contents($file))),
|
||||||
|
];
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
}
|
}
|
Loading…
x
Reference in New Issue
Block a user