vr-shopxo-plugin/plan.md

11 KiB
Raw Permalink Blame History

vr-shopxo-plugin Phase 2 Bugfix — plan.md

版本v1.0 | 日期2026-04-16 | Agentcouncil/FrontendDev 背景Phase 2 后台管理两个致命问题 — 侧栏乱码 + 路由无法渲染


问题总览

# 问题 症状 优先级
P1 插件控制器路由无法渲染 内容区空白,"template not exists"
P2 侧边栏插件名乱码 VR票务(应为 VR票务

P1 — 路由无法渲染问题

已知现象

  • 访问 adminwatekc.php?s=VrTicket/SeatTemplateList → 侧栏正常,主内容区空白
  • ShopXO Plugins/Index 控制器调用插件时有 strtolower+ucfirst 类名匹配问题
  • 当前 SeatTemplate.phpadmin/controller/ 子目录

已知正确模式freightfee/answers

app/plugins/{plugin}/
├── Admin.php              ← 直接在插件根目录,继承 think\Controller
├── Hook.php
├── config.json
└── admin/view/...         ← 视图在 admin/view/ 子目录

当前 vr_ticket 结构(有问题)

app/plugins/vr_ticket/
├── admin/controller/SeatTemplate.php  ← ❌ 在子目录
└── admin/view/seat_template/list.html

任务清单

  • P1-T1: 验证 strtolower+ucfirst 路由匹配机制
    • PluginsService::PluginsControlCall: class = \app\plugins\{plugin}\{group}\{ucfirst(control)}
    • sidebar URL /plugins/vr_ticket/admin/seatTemplateList
    • → pluginsname=vr_ticket, pluginscontrol=admin, pluginsaction=seatTemplateList
    • → class = \app\plugins\vr_ticket\admin\Admin ✓
    • → method = ucfirst('seatTemplateList') = 'SeatTemplateList' ✓
  • P1-T2: 对比 Admin.php 根目录模式 vs 当前 admin/controller/ 子目录模式
    • 根目录 Admin.php (app/plugins/vr_ticket/admin/Admin.php) 可以被正确加载 ✓
    • 旧子目录控制器无法被 PluginsService 找到(类路径不匹配)✗
  • P1-T3: 实施修复 — 创建 admin/Admin.php(注意:不是根目录,是 admin/ 子目录)
    • admin/Admin.php 路径 → 类名 \app\plugins\vr_ticket\admin\Admin
    • 方法使用 camelCaseSeatTemplateList(), TicketList()
    • sidebar URL 必须用 camelCasepluginsaction=seatTemplateList
    • 修复 plugin.json sidebar URL改为 /plugins/vr_ticket/admin/seatTemplateList 格式
  • P1-T4: 验证修复后路由能否正常渲染(需实际访问 URL 截图)

P2 — 侧栏插件名乱码问题

已知现象

  • 侧栏显示:VR票务(应为 VR票务
  • 这是 UTF-8 字符串被当作 Latin1/ISO-8859-1 解码的结果
  • 乱码规律: (E7 A5 8A) → Latin1 解码为 票务

乱码根因假设

假设 可能性 验证方式
数据库 vrt_power 表 name 字段 latin1 编码存储 检查 MySQL SHOW CREATE TABLE vrt_power
数据库连接 charset 不匹配 检查 ShopXO 数据库配置 charset
plugin.json 编码问题 plugin.json 已是正确 UTF-8

任务清单

  • P2-T1: 确认乱码根因 — 检查 vrt_power 表结构
    • SHOW CREATE TABLE vrt_power
    • SHOW FULL COLUMNS FROM vrt_power
    • 确认 name 字段 charset 和 collate
  • P2-T2: 如果是数据库 latin1 问题 — 修复方案
    • 方案AALTER TABLE 转换 latin1 → utf8mb4
    • 方案BMySQL CONVERT/CAST 函数读取时转换
    • 方案CPHP 层以 latin1 读出再转 utf8

视图路径问题Round 5 根因确认 + 修复)

根因BackendArchitect 分析)

ThinkPHP 5 视图路径解析规则:

  1. 相对路径(如 'seat_template/list'):相对于控制器 namespace 对应的默认视图目录
  2. namespace app\plugins\vr_ticket\admin → 默认视图目录 app/plugins/vr_ticket/admin/view/
  3. 实际文件在 app/admin/view/default/plugins/view/vr_ticket/admin/view/ ← 路径不匹配!

实际文件位置

app/admin/view/default/plugins/view/vr_ticket/admin/view/
├── seat_template/
│   ├── list.html
│   └── save.html
├── ticket/
│   ├── list.html
│   └── detail.html
├── venue/
│   ├── list.html
│   └── save.html
├── verifier/
│   ├── list.html
│   └── save.html
└── verification/
    └── list.html

修复方案

ThinkPHP 5 以 / 开头的视图路径为绝对路径,相对于配置的视图根目录(app/admin/view/default/)解析。

修复前(错误):

return view('seat_template/list', $data);  // 解析到 app/plugins/vr_ticket/admin/view/ ← 不存在

修复后(正确):

return view('/plugins/view/vr_ticket/admin/view/seat_template/list', $data);
// → app/admin/view/default/plugins/view/vr_ticket/admin/view/seat_template/list.html ✓

所有 9 个 view() 调用已全部修复为绝对路径格式。

Vrticket.php 的参考价值

shopxo/app/admin/controller/Vrticket.php 使用 MyView('../../../plugins/vr_ticket/admin/' . $template) 手动处理路径。 Admin.php 使用 ThinkPHP view() 函数,以 / 开头则由 ThinkPHP 自动解析到 app/admin/view/default/


阶段划分

阶段 内容 负责
Round 1规划 分析根因,制定修复方案 FrontendDev
Round 2执行 实施 admin/Admin.php + plugin.json 修复 FrontendDev
Round 3综合 合并到 main完整验证 所有成员

依赖关系

  • P1-T3 和 P1-T4 需要实际访问 URL 验证(无法在 CLI 环境截图)
  • P2-T1 需要连接数据库检查编码

交付物

  1. 修复后的 shopxo/app/plugins/vr_ticket/admin/Admin.php(路由正确)
  2. 修复后的 shopxo/app/plugins/vr_ticket/plugin.jsonsidebar URL 使用 camelCase
  3. 乱码问题修复(需数据库层修复)

状态

任务 状态 备注
P1-T1 [Done] PluginsService 路由机制已分析
P1-T2 [Done] admin/Admin.php 模式正确
P1-T3 [Done] admin/Admin.php 已创建 + plugin.json 已修复
P1-T4 [Pending] 需实际访问 URL 截图验证
P2-T1 [Done] 根因plugins.name 字段 Latin1 存储
P2-T2 [Done] SQL 修复脚本见 docs/SQL_FIX_garbled_plugin_name.md
P1-视图路径 [Done] 所有 9 个 view() 改为绝对路径 /plugins/view/vr_ticket/admin/view/...

BackendArchitect Round 5 实现

交付物

  1. shopxo/app/plugins/vr_ticket/admin/Admin.php — 9 个 view() 调用全部改为 /plugins/view/vr_ticket/admin/view/... 绝对路径
  2. docs/SQL_FIX_garbled_plugin_name.md — 乱码修复 SQL 脚本
  3. plan.md — 更新根因分析

P1 乱码 DB 根因(最终确认)

  • plugins.name 字段 = VR票务Latin1 解码的 UTF-8 字节)
  • 安装时 plugin.jsontitle: "VR票务" 被以 Latin1 编码存入 MySQL
  • 读取时 MySQL 连接 charset 是 utf8mb4所以 Latin1 字节被错误解码为乱码
  • 修复:执行 UPDATE sx_plugins SET name = 'VR票务' WHERE plugins = 'vr_ticket'

乱码字节分析

UTF-8: E7 A5 8A → Latin1 解读为: 票务 UTF-8: E5 8A B1 → (in VR票务 combined string)


SecurityEngineer Round 5 补充

关键发现VenueList() 方法缺失Critical Bug

plugin.json sidebar URL /plugins/vr_ticket/admin/venueList 链接到 VenueList() 方法,但 admin/Admin.php 中该方法不存在 → 点击"场馆配置"菜单会导致 500 错误。

已修复:在 admin/Admin.php 中添加:

  • VenueList() — 场馆列表(含 v3.0 seat_map 解析)
  • VenueSave() — 场馆创建/编辑(含 v3.0 JSON 构建和验证)
  • VenueDelete() — 场馆软删除(含审计日志)
  • countSeatsV2() — v2 格式(数组)座位计数辅助方法

安全审计结论

安全项 风险等级 结论
SQL 注入 LOW 所有查询使用 ThinkPHP query builder + 参数绑定
XSS LOW ThinkPHP 模板引擎自动转义,无 |raw 输出
路径遍历 LOW 所有视图路径为硬编码方法名,无用户输入
CSRF MEDIUM ShopXO 框架级缺失,插件层面无法单独修复
数据编码P1乱码 LOW DB latin1 存储导致乱码,非安全漏洞

P1 乱码 DB 修复 SQL

-- 1. 诊断
SELECT id, name, title, LENGTH(name), HEX(name) FROM shx_plugins WHERE name LIKE '%vr%';

-- 2. 修复 plugins 表
UPDATE shx_plugins SET name = 'vr_ticket', title = 'VR票务' WHERE name = 'vr_ticket';

-- 3. 修复 vrt_power 表(如果存在乱码)
SELECT id, name, LENGTH(name), HEX(name) FROM vrt_power WHERE name LIKE '%票%';
UPDATE vrt_power SET name = 'VR票务' WHERE HEX(name) LIKE '%E7A58A%';

详细安全分析见:reviews/SecurityEngineer-round5-review.md


SecurityEngineer Round 6 — 文档评审

任务:对 Phase 2 相关 3 份文档进行评审 规则:只读文档,不读代码文件;不修改任何文件;不 push

待评审文档

# 文档 评审重点
D1 docs/14_TEMPLATE_RENDER_INVESTIGATION.md 数据流表名是否正确、Think驱动结论是否有效、解决方案是否合理
D2 docs/PHASE2_PLAN.md 任务优先级、风险评估、决策点清晰度
D3 docs/DEVELOPMENT_LOG.md(第十一+十二章) 事实准确性、时间线一致性、遗漏的关键信息

评审维度(每份文档覆盖)

  1. 准确性 — 技术描述、数据流、表名是否正确
  2. 完整性 — 是否遗漏边界条件/安全考量/依赖项
  3. 可操作性 — 下一步行动是否清晰可执行
  4. 一致性 — 各文档之间表名/文件路径/状态描述是否一致
  5. 误导风险 — 是否有表述易让接手者误解

任务清单

  • D1-T1: 评审 docs/14_TEMPLATE_RENDER_INVESTIGATION.md → 输出到 reviews/SecurityEngineer-on-docs-review.md
  • D1-T2: 评审 docs/PHASE2_PLAN.md → 追加到 reviews/SecurityEngineer-on-docs-review.md
  • D1-T3: 评审 docs/DEVELOPMENT_LOG.md(第十一+十二章)→ 追加到 reviews/SecurityEngineer-on-docs-review.md
  • D1-T4: 综合建议 + Top 3 最需要修正的问题 → 追加到 reviews/SecurityEngineer-on-docs-review.md
  • D1-T5: 合并评审结果到 reviews/SecurityEngineer-on-docs-review.md 并提交到 main

交付物

reviews/SecurityEngineer-on-docs-review.md — 三份文档各自的评分5维度+ 总体评价 + Top 3 修正建议

状态

  • D1-T1 [Claimed: council/SecurityEngineer]
  • D1-T2 [Claimed: council/SecurityEngineer]
  • D1-T3 [Claimed: council/SecurityEngineer]
  • D1-T4 [Claimed: council/SecurityEngineer]
  • D1-T5 [Claimed: council/SecurityEngineer]