From acb42e8eb8cc82050fad99d83d0f3fbba9800f98 Mon Sep 17 00:00:00 2001 From: Karson Date: Thu, 24 Sep 2020 15:15:24 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E6=97=A5=E5=BF=97=E8=BF=87?= =?UTF-8?q?=E6=BB=A4=20=E6=96=B0=E5=A2=9E=E5=AE=89=E8=A3=85=E6=9C=AA?= =?UTF-8?q?=E7=9F=A5=E6=9D=A5=E6=BA=90=E6=8F=92=E4=BB=B6=E5=BC=80=E5=85=B3?= =?UTF-8?q?=20=E6=96=B0=E5=A2=9E=E6=8F=92=E4=BB=B6=E7=BA=AF=E5=87=80?= =?UTF-8?q?=E6=A8=A1=E5=BC=8F=20=E4=BF=AE=E5=A4=8D=E5=88=86=E7=89=87?= =?UTF-8?q?=E5=90=88=E5=B9=B6=E6=9C=AA=E5=88=9B=E5=BB=BA=E6=96=87=E4=BB=B6?= =?UTF-8?q?=E5=A4=B9BUG=20=E4=BC=98=E5=8C=96=E6=8F=92=E4=BB=B6=E7=AE=A1?= =?UTF-8?q?=E7=90=86=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- application/admin/behavior/AdminLog.php | 3 +- application/admin/command/Addon.php | 4 +- application/admin/command/Install.php | 2 +- .../admin/command/Install/install.html | 8 +- application/admin/controller/Addon.php | 108 +++++----------- .../admin/controller/general/Config.php | 2 +- application/admin/lang/zh-cn/addon.php | 23 ++-- application/admin/model/AdminLog.php | 65 ++++++++-- application/admin/view/addon/index.html | 18 +-- .../admin/view/auth/adminlog/detail.html | 27 ++-- application/admin/view/auth/rule/index.html | 8 +- application/common.php | 25 +--- application/common/controller/Backend.php | 2 +- application/common/library/Menu.php | 118 ++++++++++++------ application/common/library/Upload.php | 3 + application/config.php | 8 ++ application/extra/addons.php | 18 +-- application/extra/site.php | 69 +++++----- composer.json | 4 +- public/assets/css/backend.css | 4 +- public/assets/css/backend.min.css | 2 +- public/assets/js/addons.js | 37 +----- public/assets/js/backend/addon.js | 47 +++++-- public/assets/js/backend/index.js | 3 +- public/assets/js/require-backend.min.js | 4 +- public/assets/less/backend.less | 2 +- 26 files changed, 323 insertions(+), 291 deletions(-) diff --git a/application/admin/behavior/AdminLog.php b/application/admin/behavior/AdminLog.php index b6154b37..f5bcd3c9 100644 --- a/application/admin/behavior/AdminLog.php +++ b/application/admin/behavior/AdminLog.php @@ -6,7 +6,8 @@ class AdminLog { public function run(&$params) { - if (request()->isPost()) { + //只记录POST请求的日志 + if (request()->isPost() && config('fastadmin.auto_record_log')) { \app\admin\model\AdminLog::record(); } } diff --git a/application/admin/command/Addon.php b/application/admin/command/Addon.php index a33e1b7c..aaba93a8 100644 --- a/application/admin/command/Addon.php +++ b/application/admin/command/Addon.php @@ -88,7 +88,7 @@ class Addon extends Command 'name' => $name, 'addon' => $name, 'addonClassName' => ucfirst($name), - 'addonInstallMenu' => $createMenu ? "\$menu = " . var_export_short($createMenu, "\t") . ";\n\tMenu::create(\$menu);" : '', + 'addonInstallMenu' => $createMenu ? "\$menu = " . var_export_short($createMenu) . ";\n\tMenu::create(\$menu);" : '', 'addonUninstallMenu' => $menuList ? 'Menu::delete("' . $name . '");' : '', 'addonEnableMenu' => $menuList ? 'Menu::enable("' . $name . '");' : '', 'addonDisableMenu' => $menuList ? 'Menu::disable("' . $name . '");' : '', @@ -379,5 +379,5 @@ class Addon extends Command { return __DIR__ . '/Addon/stubs/' . $name . '.stub'; } - + } diff --git a/application/admin/command/Install.php b/application/admin/command/Install.php index 835269de..52968111 100644 --- a/application/admin/command/Install.php +++ b/application/admin/command/Install.php @@ -245,7 +245,7 @@ class Install extends Command $config[$value['name']] = $value['value']; } $config['name'] = $siteName; - file_put_contents($configFile, ' body { - background: #fff; + background: #f1f6fd; margin: 0; padding: 0; line-height: 1.5; @@ -71,8 +71,8 @@ } .form-field input { - background: #EDF2F7; - margin: 0 0 1px; + background: #fff; + margin: 0 0 2px; border: 2px solid transparent; transition: background 0.2s, border-color 0.2s, color 0.2s; width: 100%; @@ -313,4 +313,4 @@ - \ No newline at end of file + diff --git a/application/admin/controller/Addon.php b/application/admin/controller/Addon.php index b27f9149..a0bc0562 100644 --- a/application/admin/controller/Addon.php +++ b/application/admin/controller/Addon.php @@ -116,6 +116,8 @@ class Addon extends Backend if (!preg_match("/^[a-zA-Z0-9]+$/", $name)) { $this->error(__('Addon name incorrect')); } + + $info = []; try { $uid = $this->request->post("uid"); $token = $this->request->post("token"); @@ -127,16 +129,13 @@ class Addon extends Backend 'version' => $version, 'faversion' => $faversion ]; - Service::install($name, $force, $extend); - $info = get_addon_info($name); - $info['config'] = get_addon_config($name) ? 1 : 0; - $info['state'] = 1; - $this->success(__('Install successful'), null, ['addon' => $info]); + $info = Service::install($name, $force, $extend); } catch (AddonException $e) { $this->result($e->getData(), $e->getCode(), __($e->getMessage())); } catch (Exception $e) { $this->error(__($e->getMessage()), $e->getCode()); } + $this->success(__('Install successful'), '', ['addon' => $info]); } /** @@ -171,12 +170,12 @@ class Addon extends Backend Db::execute("DROP TABLE IF EXISTS `{$table}`"); } } - $this->success(__('Uninstall successful')); } catch (AddonException $e) { $this->result($e->getData(), $e->getCode(), __($e->getMessage())); } catch (Exception $e) { $this->error(__($e->getMessage())); } + $this->success(__('Uninstall successful')); } /** @@ -198,12 +197,12 @@ class Addon extends Backend //调用启用、禁用的方法 Service::$action($name, $force); Cache::rm('__menu__'); - $this->success(__('Operate successful')); } catch (AddonException $e) { $this->result($e->getData(), $e->getCode(), __($e->getMessage())); } catch (Exception $e) { $this->error(__($e->getMessage())); } + $this->success(__('Operate successful')); } /** @@ -213,75 +212,27 @@ class Addon extends Backend { Config::set('default_return_type', 'json'); + $info = []; $file = $this->request->file('file'); - $addonTmpDir = RUNTIME_PATH . 'addons' . DS; - if (!is_dir($addonTmpDir)) { - @mkdir($addonTmpDir, 0755, true); - } - $info = $file->rule('uniqid')->validate(['size' => 10240000, 'ext' => 'zip'])->move($addonTmpDir); - if ($info) { - $tmpName = substr($info->getFilename(), 0, stripos($info->getFilename(), '.')); - $tmpAddonDir = ADDON_PATH . $tmpName . DS; - $tmpFile = $addonTmpDir . $info->getSaveName(); - try { - Service::unzip($tmpName); - unset($info); - @unlink($tmpFile); - $infoFile = $tmpAddonDir . 'info.ini'; - if (!is_file($infoFile)) { - throw new Exception(__('Addon info file was not found')); - } - - $config = Config::parse($infoFile, '', $tmpName); - $name = isset($config['name']) ? $config['name'] : ''; - if (!$name) { - throw new Exception(__('Addon info file data incorrect')); - } - if (!preg_match("/^[a-zA-Z0-9]+$/", $name)) { - throw new Exception(__('Addon name incorrect')); - } - - $newAddonDir = ADDON_PATH . $name . DS; - if (is_dir($newAddonDir)) { - throw new Exception(__('Addon already exists')); - } - - //重命名插件文件夹 - rename($tmpAddonDir, $newAddonDir); - try { - //默认禁用该插件 - $info = get_addon_info($name); - if ($info['state']) { - $info['state'] = 0; - set_addon_info($name, $info); - } - - //执行插件的安装方法 - $class = get_addon_class($name); - if (class_exists($class)) { - $addon = new $class(); - $addon->install(); - } - - //导入SQL - Service::importsql($name); - - $info['config'] = get_addon_config($name) ? 1 : 0; - $this->success(__('Offline installed tips'), null, ['addon' => $info]); - } catch (Exception $e) { - @rmdirs($newAddonDir); - throw new Exception(__($e->getMessage())); - } - } catch (Exception $e) { - unset($info); - @unlink($tmpFile); - @rmdirs($tmpAddonDir); - $this->error(__($e->getMessage())); + try { + $uid = $this->request->post("uid"); + $token = $this->request->post("token"); + $faversion = $this->request->post("faversion"); + if (!$uid || !$token) { + throw new Exception(__('Please login and try to install')); } - } else { - // 上传失败获取错误信息 - $this->error(__($file->getError())); + $extend = [ + 'uid' => $uid, + 'token' => $token, + 'faversion' => $faversion + ]; + $info = Service::local($file, $extend); + } catch (AddonException $e) { + $this->result($e->getData(), $e->getCode(), __($e->getMessage())); + } catch (Exception $e) { + $this->error(__($e->getMessage())); } + $this->success(__('Offline installed tips'), '', ['addon' => $info]); } /** @@ -300,6 +251,8 @@ class Addon extends Backend if (!is_dir($addonTmpDir)) { @mkdir($addonTmpDir, 0755, true); } + + $info = []; try { $uid = $this->request->post("uid"); $token = $this->request->post("token"); @@ -312,14 +265,14 @@ class Addon extends Backend 'faversion' => $faversion ]; //调用更新的方法 - Service::upgrade($name, $extend); + $info = Service::upgrade($name, $extend); Cache::rm('__menu__'); - $this->success(__('Operate successful')); } catch (AddonException $e) { $this->result($e->getData(), $e->getCode(), __($e->getMessage())); } catch (Exception $e) { $this->error(__($e->getMessage())); } + $this->success(__('Operate successful'), '', ['addon' => $info]); } /** @@ -352,7 +305,7 @@ class Addon extends Backend $addons = get_addon_list(); $list = []; foreach ($addons as $k => $v) { - if ($search && stripos($v['name'], $search) === false && stripos($v['intro'], $search) === false) { + if ($search && stripos($v['name'], $search) === false && stripos($v['title'], $search) === false && stripos($v['intro'], $search) === false) { continue; } @@ -393,6 +346,9 @@ class Addon extends Backend public function get_table_list() { $name = $this->request->post("name"); + if (!preg_match("/^[a-zA-Z0-9]+$/", $name)) { + $this->error(__('Addon name incorrect')); + } $tables = get_addon_tables($name); $prefix = Config::get('database.prefix'); foreach ($tables as $index => $table) { diff --git a/application/admin/controller/general/Config.php b/application/admin/controller/general/Config.php index eb1739d8..edc859af 100644 --- a/application/admin/controller/general/Config.php +++ b/application/admin/controller/general/Config.php @@ -190,7 +190,7 @@ class Config extends Backend } file_put_contents( APP_PATH . 'extra' . DS . 'site.php', - ' '扫码支付后如果仍然无法立即下载,请不要重复支付,请稍后再重试安装!', 'Pay click tips' => '请点击这里在新窗口中进行支付!', 'Pay new window tips' => '请在新弹出的窗口中进行支付,支付完成后再重新点击安装按钮进行安装!', - 'Upgrade tips' => '确认升级[%s]

升级后可能出现部分冗余数据记录,请根据需要移除即可!!!

如有重要数据请备份后再操作!', - 'Offline installed tips' => '插件安装成功!清除浏览器缓存和框架缓存后生效!', - 'Online installed tips' => '插件安装成功!清除浏览器缓存和框架缓存后生效!', + 'Upgrade tips' => '确认升级《%s》

1、请务必做好代码和数据库备份!备份!备份!
2、升级后如出现冗余数据,请根据需要移除即可!
3、不建议在生产环境升级,请在本地完成升级测试

如有重要数据请备份后再操作!', + 'Offline installed tips' => '安装成功!清除浏览器缓存和框架缓存后生效!', + 'Online installed tips' => '安装成功!清除浏览器缓存和框架缓存后生效!', 'Not login tips' => '你当前未登录FastAdmin,登录后将同步已购买的记录,下载时无需二次付费!', + 'Please login and try to install' => '请登录后再进行离线安装!', 'Not installed tips' => '请安装后再访问插件前台页面!', 'Not enabled tips' => '插件已经禁用,请启用后再访问插件前台页面!', 'New version tips' => '发现新版本:%s 点击查看更新日志', 'Store now available tips' => '插件市场暂不可用,是否切换到本地插件?', 'Switch to the local' => '切换到本地插件', 'try to reload' => '重新尝试加载', - 'Please disable addon first' => '请先禁用插件再进行升级', + 'Please disable the add before trying to upgrade' => '请先禁用插件再进行升级', + 'Please disable the add before trying to uninstall' => '请先禁用插件再进行卸载', 'Login now' => '立即登录', - 'Continue install' => '不登录,继续安装', + 'Continue install' => '继续安装', 'View addon home page' => '查看插件介绍和帮助', 'View addon index page' => '查看插件前台首页', 'View addon screenshots' => '点击查看插件截图', @@ -85,10 +87,17 @@ return [ 'Addon name incorrect' => '插件名称不正确', 'Addon info file was not found' => '插件配置文件未找到', 'Addon info file data incorrect' => '插件配置信息不正确', - 'Addon already exists' => '上传的插件已经存在', + 'Addon already exists' => '插件已经存在', + 'Addon package download failed' => '插件下载失败', + 'Conflicting file found' => '发现冲突文件', + 'Invalid addon package' => '未验证的插件', + 'No permission to write temporary files' => '没有权限写入临时文件', + 'The addon file does not exist' => '插件主启动程序不存在', + 'The configuration file content is incorrect' => '配置文件不完整', 'Unable to open the zip file' => '无法打开ZIP文件', 'Unable to extract the file' => '无法解压ZIP文件', - 'Are you sure you want to unstall %s?' => '确认卸载插件《%s》?', + 'Unable to open file \'%s\' for writing' => '文件(%s)没有写入权限', + 'Are you sure you want to unstall %s?' => '确认卸载《%s》?', 'Delete all the addon file and cannot be recovered!' => '卸载将会删除所有插件文件且不可找回!!!', 'Delete all the addon database and cannot be recovered!' => '删除所有插件相关数据表且不可找回!!!', 'Please backup important data manually before uninstall!' => '如有重要数据请备份后再操作!!!', diff --git a/application/admin/model/AdminLog.php b/application/admin/model/AdminLog.php index 2fbb688e..faf7e562 100644 --- a/application/admin/model/AdminLog.php +++ b/application/admin/model/AdminLog.php @@ -18,6 +18,10 @@ class AdminLog extends Model protected static $title = ''; //自定义日志内容 protected static $content = ''; + //忽略的链接正则列表 + protected static $ignoreRegex = [ + '/^(.*)\/(selectpage|index)$/i', + ]; public static function setTitle($title) { @@ -29,26 +33,41 @@ class AdminLog extends Model self::$content = $content; } - public static function record($title = '') + public static function setIgnoreRegex($regex = []) + { + $regex = is_array($regex) ? $regex : [$regex]; + self::$ignoreRegex = array_merge(self::$ignoreRegex, $regex); + } + + /** + * 记录日志 + * @param string $title + * @param string $content + */ + public static function record($title = '', $content = '') { $auth = Auth::instance(); $admin_id = $auth->isLogin() ? $auth->id : 0; $username = $auth->isLogin() ? $auth->username : __('Unknown'); - $content = self::$content; - if (!$content) { - $content = request()->param('', null, 'trim,strip_tags,htmlspecialchars'); - foreach ($content as $k => $v) { - if (is_string($v) && strlen($v) > 200 || stripos($k, 'password') !== false) { - unset($content[$k]); + + $controllername = Loader::parseName(request()->controller()); + $actionname = strtolower(request()->action()); + $path = str_replace('.', '/', $controllername) . '/' . $actionname; + if (self::$ignoreRegex) { + foreach (self::$ignoreRegex as $index => $item) { + if (preg_match($item, $path)) { + return; } } } - $title = self::$title; + $content = $content ? $content : self::$content; + if (!$content) { + $content = request()->param('', null, 'trim,strip_tags,htmlspecialchars'); + $content = self::getPureContent($content); + } + $title = $title ? $title : self::$title; if (!$title) { $title = []; - $controllername = Loader::parseName(request()->controller()); - $actionname = strtolower(request()->action()); - $path = str_replace('.', '/', $controllername) . '/' . $actionname; $breadcrumb = Auth::instance()->getBreadcrumb($path); foreach ($breadcrumb as $k => $v) { $title[] = $v['title']; @@ -57,7 +76,7 @@ class AdminLog extends Model } self::create([ 'title' => $title, - 'content' => !is_scalar($content) ? json_encode($content) : $content, + 'content' => !is_scalar($content) ? json_encode($content, JSON_UNESCAPED_UNICODE) : $content, 'url' => substr(request()->url(), 0, 1500), 'admin_id' => $admin_id, 'username' => $username, @@ -66,6 +85,28 @@ class AdminLog extends Model ]); } + /** + * 获取已屏蔽关键信息的数据 + * @param $content + * @return false|string + */ + protected static function getPureContent($content) + { + if (!is_array($content)) { + return $content; + } + foreach ($content as $index => &$item) { + if (preg_match("/(password|salt|token)/i", $index)) { + $item = "***"; + } else { + if (is_array($item)) { + $item = self::getPureContent($item); + } + } + } + return $content; + } + public function admin() { return $this->belongsTo('Admin', 'admin_id')->setEagerlyType(0); diff --git a/application/admin/view/addon/index.html b/application/admin/view/addon/index.html index 6f0d93a1..770fdc2a 100644 --- a/application/admin/view/addon/index.html +++ b/application/admin/view/addon/index.html @@ -78,18 +78,18 @@
- {:build_toolbar('refresh')} - - {if $Think.config.fastadmin.api_url} - {:__('Userinfo')} + {:__('Userinfo')} {/if}
@@ -208,7 +208,7 @@