XIUNOX 更新记录贴 202600725

管理

  • [权限错误] 修复 API 上传附件非管理员用户返回 403:api/v1/attach.php 未加载 $grouplist,PermissionService::check(‘allowattach’) 对非管理员回退查 $grouplist 时为空返回 false

    • 必测: 非管理员用户通过 API(Bearer Token)上传附件,应正常返回 200 而非 403

  • [逻辑错误] 修复 API 发帖/回帖带附件时图片显示 broken:api_attach_assoc_post 只更新 message 未更新 message_fmt,前台显示用 message_fmt 仍指向已移走的 upload/tmp/ 临时文件

    • 必测: API 发主题/回复带图片附件,前台帖子详情页图片正常显示

  • [健壮性] 修复 api/v1/attach.php 未创建 upload/tmp/ 目录导致首次上传失败

    • 必测: 删除 upload/tmp/ 目录后通过 API 上传附件

  • [健壮性] 修复 api_attach_assoc_post 中 xn_copy 失败仍创建 attach 记录的孤儿附件问题

    • 必测: 模拟磁盘满或权限不足场景,检查不产生无物理文件的 attach 记录

  • [安全/清理] api/v1/attach.php 的 .meta.json 不再写入 path 物理路径字段;api_attach_assoc_post 新增孤儿附件清理(message 中未引用的图片/视频)

  • [清理] 移除上线版本不需要的调试代码:admin/route/group.php group-update xn_log、xnx_maintenance saveSettings xn_log、xnx_ai_reply markReplied xn_log、xnx_appcenter createForumThread 入口/成功/失败 error_log;admin htm 模板(group_list/forum_list/other_cache_setting)与 view/js(xiuno-modern.js/editor-paste-markdown.js)大量 console.log 调试输出;保留所有 catch 异常日志、安全日志与 console.warn/error

    • 必测: 后台用户组列表/版块列表/缓存设置页/编辑器粘贴 Markdown 功能正常,浏览器控制台无多余 [xxx] 调试输出

  • [架构优化] 彻底废弃 model.min.php 文件合并机制,改为始终逐文件 include + 依赖 OPcache 字节码缓存

    • 根因: PHP 8 + OPcache 时代文件合并收益可忽略,但带来加载顺序不确定、单插件语法错误全站白屏、并发重建损坏、缓存陈旧等大量稳定性问题

    • 修改: model.inc.php 删除整个 if/else 合并分支,统一走 foreach include _include() 循环

    • 清理: 核心 + 61 个插件文件中所有 model.min.php 相关清理代码、自愈代码、注释引用全部移除

    • 收益: 彻底杜绝所有 model.min.php 相关问题,函数/类加载顺序确定可控,单个插件故障不影响全站

  • [新功能] xnx_tag 插件新增版块推荐话题功能

    • 后台版块编辑页增加推荐话题设置项(支持搜索已有话题+创建新话题)

    • 前台发帖表单展示当前版块的专属推荐话题,版块切换时 AJAX 动态刷新

    • 新增 xnx_forum_recommend_tags 关联表,支持缓存

    • 版本升级至 1.1.0,需在后台插件管理页点击升级

  • [改进] 插件互相卸载机制改进:从「静默卸载」改为「禁用+前端提示」,保留配置便于切换

    • 新增 plugin_find_conflicts($dir) 函数(model/plugin.func.php),匹配规则:最后一段为 theme → 主题类互斥;其他按第二段功能名匹配(符合 Xiuno4 命名规范)

    • admin/route/plugin.php install/enable 分支:plugin_unstall 改为 plugin_disable(保留配置),主题与非主题逻辑统一

    • admin/route/plugin_scanner.php preinstall 返回 conflicts 字段

    • admin/view/htm/plugin_list.htm 安装前弹窗渲染冲突提示,列出将被禁用的同类插件

    • 新增语言键 plugin_conflict_title/desc/item_disabled/item_enabled(zh-cn/zh-tw/en-us)

    • 必测: 安装 xnx_moments_theme 时提示将禁用 xnx_cyber_theme,安装后 xnx_cyber_theme 配置保留

  • [文档] 更新插件互斥机制相关文档:plugindev/01-architecture.md 更新 install/enable 分支描述(卸载→禁用+前端提示)、plugindev/02-plugin-structure.md 新增第8节命名规范与互斥规则、xiunox-plugin-dev/SKILL.md 新增 2 条禁止规则 + 2 条交付检查项

  • [逻辑错误] 修复「插件重编译」流程读 conf.json enable/installed 强制启用已禁用插件:lib/UpgradeService.php recompilePlugins() 删除 foreach 循环(读 conf.json enable+installed 调 plugin_enable),改为只清 tmp + plugin_init();lib/PluginScanner.php scanSingleByDir() 返回的 installed/enable 字段改为读 db 权威(plugin_db_get + try-catch + function_exists 守卫,db 异常/未加载时回退 conf.json);更新 NavService.php/PluginScanner.php 陈旧注释(conf.json → db 权威)

    • 根因: conf.json 是静态配置,installed/enable 是运行时状态唯一权威源为 db bbs_plugin 表,读 conf.json 决定启用状态会让存量 conf.json 带 enable=1/installed=1 的插件在「插件重编译」时被强制重新启用(即使用户禁用了)

    • 必测: 后台系统工具→插件重编译,禁用的插件保持禁用状态不被重新启用

  • [逻辑错误] 彻底切断 conf.json enable/installed 读取链路:plugin_init() 在 xn_json_decode(conf.json) 后立即 unset enable/installed 丢弃脏数据;plugin_paths_enabled() 删除 db 异常回退 conf.json 分支,db 异常/无记录统一默认 false;PluginScanner::scanSingleByDir() 同步删除回退分支;plugin_init() db 异常时跳过整个 db 覆盖 foreach 避免 plugin_db_init fatal(原注释「db 异常时跳过保留 conf.json 值避免白屏」实际代码未跳过会 fatal,现已真正跳过)

    • 根因: 用户指出「既然规则说已忽略不读,那留 db 异常回退 conf.json 的兜底就是自相矛盾」——存量 conf.json 带 enable=1/installed=1 是脏数据,db 异常时回退读它会重现「禁用的插件被启用」bug

    • 必测: 后台插件列表页正常加载;模拟 db 异常(停 db)后访问后台不白屏,所有插件显示未安装

  • [逻辑错误] 彻底切断 conf.json enable/installed 读取链路并同步文档:lib/ErrorHandler.php autoDisableCrashedPlugin 删除「写 conf.json enable=0」步骤(conf.json 不再被读,写了无意义),只保留 db_update + 清 tmp + 清 OPcache;docs/plugindev/01-architecture.md、02-plugin-structure.md07-runtime-safety.mdREADME.md、docs/xiunox-plugin-dev/SKILL.md、README.md 同步更新「db 异常时回退 conf.json 兜底」→「不回退 conf.json,db 异常/无记录默认 false」

    • 根因: 用户指出「既然规则说已忽略不读,那留 db 异常回退 conf.json 的兜底就是自相矛盾」,与「彻底不读」的规则冲突

    • 必测: 模拟 db 异常(停 db)后访问后台不白屏,所有插件显示未安装;插件崩溃自愈禁用流程仍能正常工作

  • [功能完善] xnx_appcenter 应用审核页展示用户上传的安装包:审核列表版本号列增加下载图标按钮(点击直接下载最新版本包),新增 AppCenterService::getLatestVersionsByAppIds 批量查询方法避免 N+1,管理员审核下载非已发布应用不计数避免虚增开发者下载数

    • 必测: admin/?plugin-setting-xnx_appcenter.htm&tab=app_audit 各状态应用版本号列出现下载图标,点击下载到最新版本包

  • [逻辑错误] 修复 xnx_appcenter 拒绝后重新提交审核页显示旧版本包:原流程 updateApp(重置 status=0、清空 reject_reason)在前、addVersion(实际写入新包)在后,addVersion 失败时应用卡在"待审但旧版本号、旧包"脏状态;改为前置校验+上传提升+addVersion 全部在 updateApp 之前完成

    • 必测: 拒绝应用后开发者重新上传新包提交,审核页版本号列显示新版本号+下载到新包

  • [逻辑错误] 整体检查修复 conf.json enable/installed 残留:api/v1/my.php GET /my/feed 端点原直接读 conf.json installed/enable 判断 xnx_feeds 启用状态(存量脏数据会导致已禁用插件被误判启用),改用 plugin_db_get("xnx_feeds") 查 db;lib/NavService.php:209 修正过时注释("db 异常时回退 conf.json 兜底"→"db 异常时返回空数组,不回退 conf.json");docs/plugindev/07-runtime-safety.md L10/L647 本章覆盖摘要与小结从旧三步(写 conf.json + db + tmp)改为新三步(db + tmp + OPcache);docs/xiunox-plugin-dev/SKILL.md:1117 交付检查表措辞强化为"代码层任何情况下都不读"并补充 API 端点用 plugin_db_get($dir)

    • 根因: 整体排查发现 api/v1/my.php 仍残留直接读 conf.json 的旧代码(之前未覆盖到 API 层),以及文档摘要/小结与新规则自相矛盾

    • 必测: GET /api/v1/my/feed 端点在 xnx_feeds 禁用时返回空列表;后台插件扫描器页面正常加载

  • [发帖页错误处理优化] post.htm 补齐 htmx 错误事件处理、30s 超时兜底、htmx 未加载兜底

    • 必测: thread-create 发帖页/post-update 编辑页/post-create 回复页,分别测试网络断开/服务器 500/服务器卡死 30s/htmx.js 加载失败四种场景

  • [逻辑错误] 修复 xnx_appcenter 编辑应用提交时误报"请先阅读上架前必看文档"或"请上传下载包":edit 路由 POST 中 guide_read 校验未跳过编辑模式(模板不渲染 guide_read hidden input 导致始终为 0);递增 static_version 强制浏览器加载最新 appcenter_publish.js(旧版 JS 缺少 isEdit 条件导致编辑模式也校验下载包必填)

    • 必测: 应用详情页点击编辑应用,仅修改介绍文字不上传新包,提交成功

  • [快速回复错误处理优化] thread_main.inc.htm + thread_js.inc.htm 修复 htmx 事件名错误 + 补齐超时/错误事件处理

    • 必测: 帖子详情页底部快速回复框,分别测试网络断开/服务器 500/服务器卡死 30s/htmx.js 加载失败四种场景

    • 回归: 验证正常回复/楼中楼回复/待审回复/积分扣减确认/验证码刷新仍正常

  • [编译缓存未清理修复] 删除 tmp/ 下 view_htm_post/thread_js/thread_main 和 lang_*_bbs 编译缓存,确保上次修改生效;快速回复框补齐 code=-1002 频率限制倒计时逻辑

    • 必测: 发帖页/快速回复框触发频率限制(连续发帖触发10秒间隔),按钮应显示倒计时而非卡在提交中

    • 回归: 验证网络断开/服务器500/超时/htmx加载失败场景仍正常

  • [发帖错误处理bugfix] 修复 htmx 4 ctx.response 结构误用导致成功请求也被误判为错误 + 频率限制倒计时逻辑未执行

    • 根因: htmx 4 中 event.detail.ctx.response 是 {raw, status} 包装对象无 .ok 属性, response.ok 永远 undefined 导致 !response.ok 恒为 true

    • 根因: 频率限制 code=-1002 的倒计时逻辑放在 after:request 的 !response.ok 分支后被 return 跳过

    • 修复: after:request 仅处理 HTTP 4xx/5xx (用 ctx.response.status>=400), 业务错误统一由 after:swap 检查 data-code 处理

    • 必测: 发帖成功(无错误提示)/发帖失败(显示具体错误如内容太短)/频率限制(按钮倒计时)/验证码错误/网络断开/服务器500

  • [发帖频率限制UI优化] 频率限制(code=-1002)时清空 #post-msg alert 框,只保留 toast 提示 + 按钮倒计时

    • 必测: 触发频率限制后页面无红色 alert 框,只有 toast + 按钮倒计时

  • [发帖错误处理bugfix] 修复 htmx:after:swap 的 event.detail.target 误用导致所有业务错误处理逻辑被跳过

    • 根因: htmx 4 中 htmx:after:swap 的 event.detail 只有 {ctx} 没有 target 属性, event.detail.target 永远 undefined, if(!target) return 直接跳过所有错误处理

    • 修复: 改用 document.getElementById(“post-msg”) 直接获取目标元素

    • 必测: 频率限制(按钮倒计时+toast+无alert框)/内容太短(保留alert框+toast)/验证码错误/发帖成功(无错误提示)

  • [重构] lib/avatar_component.php 重构为三层嵌套头像组件(L1 avatar-wrap / L2 position-relative / L3 group-icon),支持 6 档尺寸(xs~xxl)、avatar_shape 配置(rounded/circle/square)、两个 hook 点(avatar_component_frame.php 头像框 / avatar_component_badges.php 角标)、$options 选项(extra_class/link_uid/show_group_icon/show_hooks/lazy/badge_position/_uid)

    • 必测: 前台帖子列表/详情页头像正常显示,用户组角标位置正确

    • 必测: 后台设置页切换 avatar_shape 为 circle,前台头像变圆形

    • 必测: 程序构造内容场景调用 avatar_component_from_data 传 skip_attach_assoc 无关(本组件不涉及附件)

  • [头像组件迁移] 5 个插件原生 img 头像迁移到 avatar_component_from_data()

    • xnx_checkin: checkin_rank.htm PC/移动端 40px→md + index_site_brief_stats_after.htm 28px→xs 叠放 + checkin_index.htm JS class 对齐 avatar-xs

    • xnx_invite: invite_center.htm 邀请记录 32px→sm(16px 侧栏保留原生)

    • xnx_fusers: fusers_block.htm 版块成员 32px→sm + link_uid

    • xnx_lottery: lottery_card.htm 参与者 22px→xs + 移除首字母兜底

    • xnx_status: status_admin.htm 后台贡献者 32px→sm + show_hooks=false

    • 必测: 签到排行榜/首页签到叠放/邀请中心/版块成员/抽奖卡片/后台贡献者页

  • [清理] 删除 xnx_medal 插件头像角标功能(avatar badge):删除 hook/avatar_component_badges.php(勋章 icon 作为头像角标显示)、hook/header_link_after.htm(引入 medal.css)、static/css/medal.css(.xnx-medal-badge 样式);conf.json 从 hooks_rank 移除 avatar_component_badges.php 和 header_link_after.htm 两个 key,version 1.0.5→1.0.6

    • 必测: 前台帖子列表/详情页头像不再显示勋章角标,用户组角标正常显示;后台插件管理页 xnx_medal 显示需升级至 1.0.6

  • [功能增强] xnx_verify 头像角标支持后台配置位置/图标/颜色/启用开关 (v1.0.5)

    • 必测: admin/?plugin-setting-xnx_verify-config.htm 头像角标设置区块保存后生效

    • 必测: 前台帖子列表/详情页认证用户头像角标按配置显示

    • 必测: badge_enabled=0 时角标不显示;badge_position 切换位置;badge_icon/badge_color 自定义生效

  • [新功能] xnx_avatar_frame 前台页面:创建商店路由+模板(frame_shop.php/htm)和我的头像框路由+模板(my_frame.php/htm)

    • 必测: ?frame-shop.htm 商店列表分页/购买按钮交互

    • 必测: ?my-frame.htm 我的头像框佩戴/取消佩戴交互

  • [URL Bug] 修复使用默认固定链接(url_rewrite_on=0)时 more 发现页插件项 URL 出现两个 ?? 的问题

    • 必测: 访问 /?more.htm 发现页,点击插件注册的发现项(如猜题对决 duel),URL 应为 /?duel.htm 而非 /??duel.htm

    • 根因: NavService::normalize() 先剥离前导 ? 再 ltrim /,导致 /?duel.htm 中 ? 不在位置 0 漏剥离,normalize 返回 ?duel,url(?duel) 生成 /??duel.htm

    • 修复: 调整 normalize 顺序为 ltrim / → 剥离 ? → ltrim /;同时优化 DiscoverService::getPluginDiscoverItems() 前台保留原始路由名避免双重 url() 转换

  • [Hook失效] 修复签到动态未出现在 xnx_feeds:CheckinService 用 include_once 直接加载不经过 _include() 编译,// hook xnx_checkin_do_checkin_end.php 注释未处理,FeedsService::create 永不调用

    • 必测: 签到后查看动态流侧边栏 toast 或 feeds 列表,应出现"签到获得"动态

    • 根因: 缺少 hook/model_inc_file.php,CheckinService 未注册到 model 加载列表,源文件中的 hook 注释只是普通 PHP 注释

    • 修复: 新增 xnx_checkin/hook/model_inc_file.php 注册 CheckinService;删除 8 处 include_once(api/index/admin/setting/calendar/rank/2 个 hook htm);conf.json hooks_rank 注册 + 版本号 1.0.2→1.0.3;static_version ?1.4.39→?1.4.40

  • [显示缺陷] 修复签到动态只显示「贰先生签到获得了」缺少积分数:footer_js_after.htm 未拼接 extra.credits;同时 hook 写入时缺少 credits_name 字段

    • 必测: 签到后查看动态流 toast,应显示「XX签到获得 10 积分」(含积分数+积分类型名)

    • 根因: footer_js_after.htm 第 68 行 action_text 仅用 lang 固定文案;hook extra 只有 credits/continuous 缺积分类型名

    • 修复: ①xnx_checkin_do_checkin_end.php extra 增加 credits_name(通过 $this->getRewardCreditsTypeName() 获取);②footer_js_after.htm checkin 类型拼接「积分数 积分名」到 action_text;③static_version ?1.4.40→?1.4.41

  • [显示缺陷] 修复其他 5 种动态类型未显示积分奖励数额:悬赏被采纳/帖子被标记奖励/PK 对决获胜/骰子中奖/邀请成功

    • 必测: 触发上述 5 种动态后查看 toast 文案,应显示「悬赏被采纳 50 积分」「PK 对决获胜 100 金币」「成功邀请好友 100 积分 + 10 金币」等含积分数的文案

    • 根因: footer_js_after.htm 原仅对 checkin 类型拼接积分数,其他 5 种类型的 extra 中的 amount/reward_amount/prize/win_amount/reward_credits 字段未被读取渲染

    • 修复: footer_js_after.htm 扩展为通用 helper,按 action_type 读取对应数值字段 + 按 credits_type 反查全局配置 $conf[‘{type}_name’] 获取显示名(向后兼容老数据);3 个语言包补 xnx_feeds_golds/xnx_feeds_rmbs key;static_version ?1.4.41→?1.4.42

最新回复

请先登录后再回复 登录