【XiunoX插件】插件市场 1.0.0

管理员组

NavGCN 插件市场

纯后台插件:远程插件市场客户端,数据源在代码内硬编码(Gitee 仓库 + 自建仓库 repo-server),后台一键浏览清单、安装/升级免费插件,无任何后台设置项

  • 类型:后台插件(plugin)

  • 版本:1.0.0

  • 兼容:Xiuno BBS 1.1(bbs_version 1.1)

  • 依赖:PHP 7.4+(推荐 8.x)、ZipArchive 扩展、curlallow_url_fopen

功能

  • 拉取 manifest.json 插件清单(Gitee raw / 自建仓库 api),带文件缓存(6 小时)与源标记。

  • 双源故障转移:主源(Gitee)拉取失败自动切换自建仓库备用源;降级期间页面直接用缓存秒开,降级超过 15 分钟自动重新探测主源,主源恢复即自动切回;也可点「刷新」立即强制探测。双源均失败时回退过期缓存并显示错误原因。

  • 与本地插件比对状态:not_installed / paid / latest / need_upgrade,支持免费/付费筛选、分类筛选与关键词搜索。

  • 免费插件一键安装 / 升级:下载 zip → 魔数与结构校验 → 解压 → 移动 → plugin_install / upgrade.php → 冲突插件自动禁用。

  • 升级全程备份回滚:失败自动恢复旧目录并用 plugin_install 重同步数据库(绝不 plugin_unstall)。

  • 本地已有插件文件但未安装时,支持直接本地安装(无需重新下载 zip)。

  • 已安装插件就地启用/禁用/卸载,支持依赖检查与同类插件互斥自动禁用。

  • 安全:

    • 所有下载请求(与数据源无关)统一执行 URL 安全校验:协议白名单(仅 http/https)、禁止账号密码、主机名校验;私网/回环放行策略便于内网自建仓库部署。

    • zip 校验含魔数、条目数上限、单文件/总大小限流、绝对路径与 .. 穿越拒绝、符号链接条目拒绝,并在解压后全目录递归复查符号链接。

    • 下载限流(50MB),cURL 超时与连接超时双重控制,Gitee raw 302 CDN 跳转采用有界跟随(MAXREDIRS=3)。

  • 来源映射:已安装插件记录其来源仓库(installed_source),便于审计。

数据源(硬编码,修改见 model/NavgcnMarketService.php 顶部常量)

常量

说明

SOURCE_MAIN

gitee

主数据源:gitee | self

GITEE_REPO_URL

https://gitee.com/ywxmz/navgcn

Gitee 仓库完整链接(分支默认 main,链接第 4 段可指定)

SELF_BASE_URL

https://apim.navg.cn

自建仓库根地址(repo-server)

CACHE_TTL

21600

清单缓存有效期(秒)

DOWNLOAD_TIMEOUT

120

插件包下载超时(秒)

ALLOW_PRIVATE_NET

1

SSRF 私网/回环放行(1=放行,便于内网部署)

installed_source(来源映射)为运行时数据,持久化于 setting_get('navgcn_market'),不在后台修改。

与 repo-server 的对接协议

自建源地址为 self_base_url/api/index.php,返回 JSON:

{
    "plugins": [
        {
            "dir": "navgcn_demo",
            "name": "演示插件",
            "version": "1.0.0",
            "type": "plugin",
            "free": 1,
            "brief": "简介",
            "author": "navg.cn",
            "author_homepage": "https://navg.cn",
            "icon_url": "https://.../icon.png",
            "zip_url": "https://.../navgcn_demo_1.0.0.zip",
            "detail_url": "https://.../detail",
            "homepage": "https://..."
        }
    ]
}

Gitee 源清单为仓库根目录 manifest.json(同一格式),raw 地址: https://gitee.com/{owner}/{repo}/raw/{branch}/manifest.json

安装包 zip 需满足:conf.json 位于根目录或唯一子目录;无路径穿越与符号链接条目。

文件结构

plugin/navgcn_market/
├── conf.json                    # 插件配置(hooks_rank)
├── install.php                  # 安装:初始化运行时数据(来源映射)
├── uninstall.php                # 卸载:清除数据与缓存
├── hook/
│   ├── admin_index_route_case_end.php   # 内联编译:路由 case
│   ├── admin_sidebar_end.htm            # 后台侧边栏菜单
│   └── model_inc_file.php               # 内联编译:Service 类注册
├── lang/{zh-cn,zh-tw,en-us}/bbs_admin.php   # 后台语言包
├── model/NavgcnMarketService.php        # 核心服务(静态方法,源配置常量在顶部)
├── route/navgcn_market.php              # 后台路由分发(无设置页)
└── view/htm/market.htm                  # 市场页

自检报告

以下自检基于 xiunox-plugin-dev Skill 硬规则与交付检查表,逐项验证通过。

一、conf.json 配置

检查项

结果

必填字段完整(name/brief/version/bbs_version/type

通过

bbs_version1.1(与当前 XIUNOX_VERSION 前两段一致)

通过

不含 id/installed/enable 废弃字段

通过

hooks_rank 键名含扩展名且与 hook 文件完全匹配

通过

插件目录名 navgcn_market 符合两段格式

通过

二、安装/卸载脚本

检查项

结果

install.php!defined('DEBUG') AND exit('Access Denied'); 开头

通过

install.php 使用 setting_set() 初始化运行时数据

通过

install.php 局部变量带插件前缀($_navgcn_market_*

通过

uninstall.php 使用标准拼写(非 unstall.php

通过

uninstall.php 使用 setting_delete() 清理配置

通过

uninstall.php 清理 manifest 缓存文件

通过

三、Hook 规范

检查项

结果

所有 PHP hook 以 <?php exit; 开头

通过

所有 .htm hook 以 <?php 开头(非 <?php exit;

通过

hook 目录下无 return; 语句(闭包内除外)

通过

hook 文件名与源码标记完全匹配

通过

hook 内局部变量带插件前缀,无通用名污染宿主作用域

通过

四、安全规范

检查项

结果

所有 POST 表单包含 CsrfService::input()

通过

所有 POST 处理以 CsrfService::check() 开头

通过

路由文件开头有 $gid != 1 && $gid != 2 权限检查

通过

所有下载请求(与数据源无关)统一执行 URL 安全校验(协议白名单/禁账号密码/主机名校验)

通过

安装/升级前做 zip 校验(魔数、条目数、单文件/总大小、路径穿越、符号链接)

通过

解压后全目录递归复查符号链接(纵深防御)

通过

下载限流(CURLOPT_MAXFILESIZE 50MB,已知超限传输不启动)

通过

升级流程含备份回滚(失败自动恢复旧目录 + 重同步 DB,绝不 plugin_unstall

通过

五、输出转义

检查项

结果

esc_textarea() 调用

通过

无裸 htmlspecialchars(全部使用 esc_html/esc_attr/esc_js

通过

远端 manifest 数据注入 URL 属性时使用 esc_attr 转义

通过

JS 内嵌语言串使用 json_encode(防引号破坏)

通过

确认弹窗中远端数据先经 XN.escapeHtml 转义(防 DOM XSS)

通过

innerHTML 拼接变量字符串(仅静态字符串与恢复已保存可信 HTML)

通过

六、前端框架

检查项

结果

无 jQuery($().on().ajax()$.fn.*

通过

无 Alpine.js(x-datax-showx-bindx-model

通过

无 htmx 2.x 旧事件名

通过

无独立 static/*.js 文件(页面内联原生 JS,无 <?php 注入)

通过

七、命名规范

检查项

结果

语言键带前缀 navgcn_market_*

通过

setting 键为 navgcn_market

通过

模板/hook 内局部变量带前缀($_navgcn_market_* / $_navgcn_*

通过

xn_ / xnx_ 前缀冲突

通过

八、URL 与路由

检查项

结果

后台 URL 使用 url() / route_url() 生成

通过

无硬编码 .htm/.html 后缀

通过

路由 case 值不含 -(多段参数经 param(1)/param(2)/param(3) 逐段取)

通过

后台 URL 保持 ./?xxx.htm 格式

通过

分页/筛选 URL 首个分隔符动态适配 url_rewrite_on

通过

九、Service 与核心类

检查项

结果

Service 通过 hook/model_inc_file.php 注册(编译加载)

通过

路由层含 class_exists 兜底加载(独立入口防御)

通过

调用核心插件函数(plugin_install/plugin_unstall/plugin_disable/plugin_find_conflicts)前做依赖检查

通过

安装/升级/本地安装/切换/卸载操作使用并发锁(生命周期对齐操作时长)

通过

锁内操作使用 try/finally 保证释放,错误路径不遗留锁文件

通过

依赖检查为只读操作,在锁外执行

通过

admin_log_create 参数语义正确($target_type 为目标类型、$target_ids 为目标目录、$detail 为业务信息)

通过

十、模板规范

检查项

结果

后台模板 include ADMIN_PATH . 'view/htm/header.inc.htm'/footer.inc.htm

通过

Card 组件使用 x-card + card 组合

通过

使用 Tabler Icons(ti ti-*)图标体系

通过

十一、其他规则

检查项

结果

单行注释无 ?> 字符

通过

无覆盖核心路径

通过

无调试代码(console.log/var_dump/error_log

通过

无数据表依赖(纯配置型插件,无 DB 表)

通过

PHP 语法检查通过(php -l

通过

十二、多语言

检查项

结果

简体中文 lang/zh-cn/bbs_admin.php 完整

通过

繁体中文 lang/zh-tw/bbs_admin.php 同步

通过

英文 lang/en-us/bbs_admin.php 同步

通过

语言包使用 return array(...) 格式(与 admin/index.php 直接 include 加载方式匹配)

通过


自检结论:全部检查项通过。

最新回复

请先登录后再回复 登录

uid:1 管理员组
关注
这个人很懒,什么都没留下来...
发帖 13
评论 48
粉丝 0
关注 2
发新帖
目录
【XiunoX插件】插件市场 1.0.0