【插件】at8_media_library - 媒体库 · 相册式附件管理

应用开发者 漫步白月光 1月前 1474

各位审核员好,本人申请入驻 Z-Blog 应用中心开发者,以下是我的作品介绍,请审核。

说明:本插件原名 media_library,v1.2.0 起统一 at8_ 前缀更名为 at8_media_library(避免与其他插件命名冲突),应用 ID 与目录名同步更新,以下为本帖最新内容,替代此前版本。

一、开发者信息

个人信息

二、作品简介

  • 作品名称:媒体库 · 相册式附件管理
  • 应用 ID / 目录名:at8_media_library
  • 当前版本:1.4.0

以相册(网格)形式集中管理 Z-BlogPHP 的全部附件(图片、视频、音频、文档、压缩包等),提供比系统默认附件管理更完善的查找、复用与账实核对体验,适合素材量大、需要频繁找图和清理冗余附件的站点。

主要功能

  • 网格 / 列表两种视图自由切换,缩略图直达;图片、视频、音频均有预览,其余格式显示类型图标卡片;
  • 全类型附件支持:上传、替换、删除、关联、插入正文对图片与各类文件一视同仁(不局限于图片);
  • 按文章分类筛选:附件通过所属文章自动关联分类,一键筛出某分类下的全部附件;
  • 多维筛选:文件类型(图片 / 视频 / 音频 / 文档 / 压缩包 / 其他)、上传月份、上传者、是否已关联文章、未关联附件虚拟分类;
  • 关键词搜索(文件名 / 原始文件名 / 标题 / 说明);
  • 拖拽或多选上传,实时进度;同名文件可整体替换更新(保留原附件地址不变);
  • 详情侧栏:大图预览、视频/音频在线播放、尺寸与大小统计,一键复制 URL / HTML / Markdown 代码(非图片自动生成为链接代码);
  • 可编辑标题、说明、图片 Alt(存于附件自定义域,不改动原表结构);
  • 引用检测:检测「已关联文章」的正文里是否真的引用了该附件,区分「✅ 已在正文引用 / ⚠️ 仅关联未引用 / 关联文章不存在」,消除账实不符;
  • 取消关联:已关联文章的附件可一键解除关联;
  • 批量选择、批量删除(分批请求,单批失败不中断)、批量关联到指定文章;
  • 文章 / 页面编辑页右栏「文章附件」面板:列出本文关联的全部附件,图片一键插入正文、其他附件一键插入下载链接(经 editor_api 官方插入接口,兼容各编辑器);
  • 灯箱大图浏览,支持键盘左右切换与 Esc 关闭;
  • 统计概览:附件总数、图片数、占用空间、未关联文章数一目了然。

技术要点(对照上架规范)

  • 数据查询全部使用系统自带 SQL 构造器与对象接口,条件数组参数化,不直接拼接 SQL;不建表、不修改系统文件;
  • 兼容 MySQL / SQLite / PostgreSQL;
  • 权限分层:查看要求管理员或 UploadMng 权限,上传 / 替换 / 删除 / 编辑等写操作要求 UploadAll 或 root,并统一校验 CSRF 令牌;
  • 上传安全:硬拒绝可执行 / 服务端脚本扩展名(php、phar、exe、js、htaccess 等),硬排除可内嵌脚本格式(svg、svgz、xml、swf 等,防同源 XSS,系统自带上传不受影响);扩展名白名单跟随站点「允许上传的文件类型」设置;图片额外做内容双重校验(getimagesize + MIME 探测);文件名净化防 \0 与路径穿越;体积上限取 upload_max_filesize 与 post_max_size 较小值;
  • 路径安全:所有磁盘操作经 realpath 归一化并限定在附件目录内,防路径穿越;替换附件时校验目标文件真实存在且类型与原附件一致;
  • 性能:汇总统计多级缓存,自动探测 Redis(ext/redis)→ APCu → Opcache 文件缓存,装了对应组件即自动启用,无组件时逐级降级;文件缓存原子写入、目录附 .htaccess 拒绝直接访问、不使用 unserialize;
  • 前端输出全部转义,防存储型 XSS;
  • 附件存储对齐系统 Upload 类标准($u->Url / $u->Dir / $u->FullFile),URL 走系统 hook,自动兼容云存储接管类插件;删除走系统 DelFile();
  • 无任何加密代码、无混淆、不引用外站资源(CDN / 远程 JS / 远程字体一律没有);
  • 卸载插件不删除任何已上传的附件文件与数据库记录。

三、效果截图

  1. 相册网格总览——顶部实时统计(全部附件 / 图片数 / 占用空间 / 未关联文章),类型、分类、月份、上传者、使用状态多维筛选,缩略图卡片带尺寸徽章与分类标签,PDF 等文档显示类型卡片

  1. 按文章分类筛选——选择分类后一键筛出该分类下的全部附件,底部显示结果计数

  1. 附件详情与引用状态检测——右侧详情抽屉:大图预览、URL / HTML / Markdown 一键复制、类型 / 尺寸 / 上传信息、文件状态、关联文章数与引用状态实时检测(⚠️ 仅关联未引用等异常状态高亮提示)、替换文件与删除操作

  1. 文章编辑页「文章附件」面板——编辑文章 / 页面时右栏「管理 / 插入附件」一键打开弹窗,列出本文全部关联附件,卡片显示大小与引用状态(未引用黄色警示),图片点击「插入正文」直达编辑器

四、代码仓库

https://github.com/361611074/at8_media_library

五、更新记录(节选)

  • 2026-09-18(v1.4.0)
    • 按审核建议完成速查表规范项:58 个自定义函数与常量前缀统一为 at8_media_library_(对齐应用 ID);前端 JS 全部放弃 var 改用 let;编辑页面板内联 <style> / <script> 外置为 css/edit.css、script/edit.js(CSRF 令牌经 data 属性注入),动态渲染的内联 style 收敛为 class
    • 优化 4 项:realpath 前缀判断补目录分隔符(防 /upload2 相邻目录误判);卸载清理运行时 cache/;API 未知操作提示去除双重转义;图片尺寸 getimagesize() 请求内缓存(key 含 mtime)
  • 2026-09-18(v1.3.2)
    • 修复审核反馈 A.01 项:debug 插件(开发模式)下 API 响应被错误页 HTML 污染——JSON 输出前的缓冲清理改为对齐官方 ApiResponse() 的 @ob_clean() 思路:只清空缓冲内容、不删除任何缓冲层(保留 debug 插件等输出捕获工具层),输出 JSON 后逐层推送给客户端;debug 插件收尾时缓冲层仍在但已空,不再产生「无缓冲可删」E_WARNING,JSON 也不会被收尾清理连带丢弃(已模拟双层缓冲验证:响应为纯 JSON、零告警)

  • 2026-09-18(v1.3.1)
    • 安全修复:文章搜索接口(关联下拉)增加状态过滤,非管理员仅可见「已发布 + 自己的」文章 / 页面,防草稿标题枚举;上传硬拒绝补充 .ini / .env(防 .user.ini 落盘利用);单次上传上限 30 个;编辑页面板插入正文 URL / Alt 二次转义;批量关联补审计日志
  • 2026-09-18(v1.3.0)
    • 修复 GetPostList() 误用官方签名导致媒体库页打开报错;版本号规则调整为十进制进位(原 1.2.10 更名发布为 1.3.0)
  • 2026-09-18(v1.2.9)
    • 按审核规范五条自查后重构复用官方能力:上传落盘改用系统官方 Upload::SaveFile()(含云存储接管接口)、分类查询改用系统常驻 $zbp->categories、文章搜索改用官方 $zbp->GetPostList()、CSRF 优先官方 CheckCSRFTokenValid()
    • 修复配置项 perpage 已定义未读取;移除未使用的 version 配置
    • 修复 GetPostList() 误用官方签名导致媒体库页打开报错
  • 2026-09-18(v1.2.8)
    • 编辑页「文章配图」面板升级为「文章附件」:不再只展示图片,全部附件类型均可查看;图片一键插入正文,视频 / 音频 / 文档 / 压缩包等一键插入下载链接,卡片带类型图标与引用状态
    • 修复类别筛选与统计口径不一致:.svg 在 MIME 缺失时图片筛选漏算
  • 2026-09-17(v1.2.7):编辑页面板按钮靠右对齐,与右栏布局一致
  • 2026-09-17(v1.2.6):精简编辑页面板,移除「上传图片」按钮(上传走编辑器自带功能)
  • 2026-09-17(v1.2.5):修复编辑页弹窗被编辑器工具条 / 页面内容压住的层叠问题(遮罩挂载到 body 顶层 + z-index 拉满 + 弹窗期间隐藏工具条,三重保证)
  • 2026-09-17(v1.2.4):弹窗样式改为独立作用域(不依赖后台环境,任何编辑器 / 主题下均正确居中遮罩显示,支持 Esc 关闭);面板按钮美化;列表勾选框缩小为 12px;修复「引用状态」未关联时语义错误,引用检测失败给出重试提示;统计缓存升级为 Redis / APCu / Opcache 多级缓存
  • 2026-09-16(v1.2.3):新增详情抽屉「引用状态」检测;新增文章 / 页面编辑页右栏面板,可一键插入编辑器正文;按文章筛选时附带引用状态(单次查询,无 N+1)
  • 2026-09-15(v1.2.2):修复编辑保存与批量关联后「未关联文章」统计未同步刷新;列表勾选框 20px → 16px
  • 2026-09-15(v1.2.1):修复替换文件错误更新 PostTime 导致已发布文章附件链接 404 / 跨月替换文件缺失;批量关联弹窗重复弹出;批量删除单批失败中断后续批次;视频缩略图去冗余元素
  • 2026-09-14(v1.2.0):应用 ID 与目录更名为 at8_media_library,统一 at8_ 前缀;新增「取消关联」按钮;新增「未关联附件」虚拟分类;批量删除可靠性修复(前端分批 20 个、后端单次 IN 查询消除 N+1、修复只删记录不删文件、不再误报「登录已失效」)
  • 2026-09-15(v1.1.5):附件存储对齐系统 Upload 类(Url / Dir / FullFile),删除走系统 DelFile(),恢复替换文件扩展名一致性校验,统计缓存改 JSON 存储
  • 2026-09-13(v1.1.4):上传类型跟随站点「允许上传的文件类型」设置,兼容多种附件路径存储格式,汇总统计增加缓存
  • 2026-09-12(v1.1.3):安全加固——上传白名单排除可内嵌脚本格式、替换文件归属校验、文件名净化加强、接口统一要求登录 + 权限 + CSRF
  • v1.1.2:修复按文章分类筛选报错,写操作安全校验完善
  • v1.1.0:数据查询改为系统 SQL 构造器与对象接口,符合上架规范;统计与列表合并单次扫描,3 万+附件自动降级
  • v1.0.0:首个版本

六、申请说明

  • 已对照《注意事项速查表》完成自查:插件无加密、无混淆、无外站资源引用,接口有登录 + 权限 + CSRF 鉴权;
  • 应用 ID 与目录名已统一为 at8_media_library,仓库名同步更新;
  • 已按平台要求完成实名认证相关绑定(手机号、微信);
  • 此前审核员提出的意见已逐条修改完毕(详见更新记录 v1.2.0 与 v1.2.1);
  • 后续将根据审核员反馈继续逐条修改,并在本帖更新时附 Changelog。

请审核,谢谢!

最后于 1月前 被唐朝编辑 ,原因:
最新回复 (2)
全部楼主
  • 应用开发者 bloggo 1月前 0
    引用 1楼

    媒体库 · 相册式附件管理 1.5.1 审核意见

    审核结果

    当前版本不建议上架,请修改后重新提交审核。

    本次发现 4 个必须修改的问题,其中“越权读取附件”和“对象存储兼容问题”会影响用户数据安全或主要功能,属于阻断上架的问题。

    审核信息

    • 插件 ID:at8_media_library
    • 插件版本:1.5.1
    • 审核日期:2026-09-21
    • 参考环境:Z-BlogPHP 1.7.5.3540 Optimus
    • 对象存储兼容性参考插件:fui_oss

    必须修改的问题

    1. 插件兼容版本填写不正确

    plugin.xml 中的 <adapted> 填写了 1.7.0,但这里应该填写 Z-BlogPHP 的内部版本号。如果最低支持版本是 1.7.0,应填写 172900。

    插件还没有填写最低 PHP 版本,可能导致用户在不兼容的 PHP 环境中安装并启用插件,严重时会使网站直接报错。

    另外,dependency、rewritefunctions、existsfunctions、conflict 等字段应放在 <advanced> 节点内,否则 Z-Blog 无法正确读取。

    审核意见:

    • 正确填写 Z-BlogPHP 内部版本号;
    • 根据实际测试结果填写最低 PHP 版本;
    • 调整 <advanced> 内的字段结构;
    • 修改后实际验证安装和启用时的兼容性检查是否生效。

    2. 普通附件管理员可以查看其他用户的附件

    插件只检查用户是否拥有附件管理权限,没有继续判断用户是否拥有“管理全部附件”的权限。

    因此,一个只能管理自己附件的后台账号,也可以通过插件查看其他用户上传的附件,包括:

    • 文件名、附件地址、文件类型和大小;
    • 上传者、上传时间和关联文章;
    • 全站附件数量、容量及分类统计;
    • 其他用户附件的引用情况。

    这与 Z-Blog 官方附件管理的权限规则不一致,属于越权读取。

    审核意见:

    • 拥有 UploadAll 权限的用户可以查看全部附件;
    • 没有 UploadAll 权限的用户只能查看自己的附件;
    • 这个限制必须同时用于列表、统计、筛选、引用检查和文章编辑页附件面板;
    • 不能依靠前端传入的上传者 ID 控制权限,必须在服务端强制限制。

    3. 对象存储附件会被误报为丢失,替换文件也不能正确同步

    插件获取附件地址时使用了 Z-Blog 官方的 $upload->Url,因此复制 URL、新窗口打开和文章编辑页插入附件,能够兼容 fui_oss 的云端地址和代理地址。

    但是,插件判断附件是否存在时,只检查服务器本地文件。

    当 fui_oss 已经把文件上传到对象存储,并按设置删除本地文件后,远端文件仍然可以正常访问,但媒体库会把它显示为“文件缺失”,并出现以下问题:

    • 图片列表不显示云端缩略图;
    • 图片、视频和音频不能在详情中预览;
    • 图片宽高显示为 0;
    • 同一个附件可以复制和打开 URL,却又被插件提示为文件缺失。

    替换附件时,插件直接覆盖本地文件,没有经过 Z-Blog 官方附件保存流程:

    • 本地文件已被删除时,附件完全无法替换;
    • 保留本地文件时,只会替换本地文件,不会更新对象存储中的文件;
    • 数据库可能已经显示新的大小和类型,但用户访问到的仍是云端旧文件。

    新上传已经调用官方 SaveFile()。对于当前版本的 fui_oss,文件会先保存到本地,再在请求结束时上传到对象存储,因此新上传通常可以完成。但插件仍然把“本地文件存在”当作上传成功的必要条件,无法兼容完全不保存本地文件的其他存储插件。

    审核意见:

    • 不要再用本地文件是否存在判断对象存储附件是否丢失;
    • 缩略图和图片、视频、音频预览应直接使用官方附件 URL;
    • 替换附件必须经过能够触发对象存储 Hook 的官方流程;
    • 如果暂时无法安全替换对象存储附件,应明确禁止该操作,不能只修改本地文件和数据库;
    • 至少测试 fui_oss 的直接地址、代理地址、保留本地文件和删除本地文件四种组合。

    4. 上传和删除没有完整使用 Z-Blog 官方权限及处理流程

    插件把上传、删除等写操作都绑定到了 UploadAll,没有分别使用 Z-Blog 的上传权限 UploadPst 和删除权限 UploadDel。

    这会造成两类问题:

    • 某些自定义角色本来可以上传或删除自己的附件,却被插件错误拒绝;
    • 权限插件对 UploadPst、UploadDel 的单独设置可能失效。

    插件保存或删除附件后,也没有完整执行 Z-Blog 官方流程,例如:

    • 没有正确更新用户的附件数量;
    • 没有触发官方上传成功 Hook;
    • 删除文件失败时,仍可能删除数据库记录并向前端返回成功;
    • 依赖官方 Hook 的缩略图、同步、日志或审计插件可能无法正常工作。

    审核意见:

    • 上传使用 UploadPst,删除使用 UploadDel;
    • UploadAll 只用于判断用户能否操作其他人的附件;
    • 上传和删除应优先复用 Z-Blog 官方业务流程;
    • 正确更新附件缓存和用户附件数量,并触发官方 Hook;
    • 只有文件、对象存储和数据库都处理成功后,才能向前端返回成功;
    • 批量删除需要分别返回成功、失败和跳过的数量。

    重新提交时重点检查

    1. plugin.xml 中的 Z-BlogPHP 和 PHP 兼容版本是否填写正确;
    2. 没有 UploadAll 权限的账号是否只能看到自己的附件;
    3. fui_oss 删除本地文件后,云端图片、视频和音频能否正常显示和预览;
    4. 替换对象存储附件后,远端内容和数据库信息是否一致;
    5. 不同的 UploadPst、UploadDel、UploadAll 权限组合是否按预期工作;
    6. 上传和删除后,用户附件数量、官方 Hook、文件及数据库状态是否一致。

    其他检查结果

    以下项目没有发现需要阻止上架的重大问题:

    • 插件自定义 PHP 函数均使用了 at8_media_library 前缀;
    • 没有发现函数重名或明显的全局命名冲突;
    • 重复使用 require_once 不会重复加载函数文件或重复注册 Hook;
    • 没有发现插件功能挂载到网站前台高频 Hook,正常前台访问不会执行附件统计或远程请求;
    • 标准附件 URL 和标准附件删除入口使用了 Z-Blog 官方接口;
    • 没有发现明显的 SQL 注入、目录穿越、未登录写入、任意文件覆盖或存储型 XSS;
    • PHP、XML 和 JavaScript 语法检查均已通过。
    最后于 28天前 被沉冰浮水编辑 ,原因:
  • 应用开发者 bloggo 1月前 0
    引用 2楼
    关于我提到的对象存储插件 fui_oss,它只是本次审核中用来说明问题的一个例子,并不是要求插件必须专门适配 fui_oss。你在修改和测试时,可以使用任意一款通过 Z-Blog 官方附件接口接管上传、访问和删除的对象存储插件。

    之所以强调必须配合对象存储插件进行测试,是因为现在很多网站会把附件保存到 OSS、COS 等对象存储中,并在上传成功后删除服务器上的本地文件。媒体库插件不能只根据本地文件是否存在来判断附件是否丢失,也不能在替换文件时绕过 Z-Blog 官方附件接口,否则就会出现云端文件明明存在,却被提示“文件缺失”、无法预览,或者替换后云端仍然是旧文件等问题。

    需要兼容的不是某一个具体插件,而是 Z-Blog 官方提供的附件 Hook 和处理流程。只要对象存储插件按照官方接口开发,媒体库就应该能够正常读取、预览、替换和删除附件。
    • Z-Blog 开发者社区
      4 楼
        丨  
返回