找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 52|回复: 1

[维护日志] [2026-07-27] [修复] [插件管理"发现新版"报错] - PHP8下XML解析器字符串下标访问致命错误修复

[复制链接]
  • 打卡等级:本地老炮

9336

威望

6876

金钱

1万

贡献

管理员

自由的灵魂

积分
106811
主题
5597
回帖
26608
注册时间
2003-4-10
最后登录
2026-8-11
发表于 2026-7-27 18:49:25 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×
1、问题缘起

后台插件管理点击"发现新版"时,页面抛出系统致命错误:

  1. Cannot access offset of type type string on string
复制代码


堆栈定位:
  • admin.php:58source/admincp/admincp_plugins.php:1554 (getimportdata()) → source/function/function_admincp.php:1069 (xml2array()) → source/class/class_xml.php:16 (XMLparse->parse()) → open()

根因分析:
应用中心返回的数据并非标准 Discuz XML(可能是 HTML 错误页、网络超时页或 XML 中 <item> 缺失 id 属性),导致 XMLparse 内部引用游标 $this->document 从数组退化为字符串。当解析器继续遇到下一个带 id 的标签时,执行 $this->document = &$this->document[$attributes['id']],在 PHP 8.x 下对字符串使用字符串下标会直接抛出 fatal error(PHP 7 及以下仅 Warning 并返回 null,不会中断页面)。




2、解决方案

(1)简要技术分析
在 XML 解析器的 open() 回调入口处增加 is_array 类型保护:一旦内部游标因异常数据退化为字符串,立即重置为空数组,阻断 fatal error 传播,让解析器继续执行并最终返回空数组,由上层逻辑展示"数据无效"的友好提示。

(2)修改、新增文件列表

类型完整路径
修改source/class/class_xml.php


(3)关键作用代码段全文

source/class/class_xml.php —— open() 方法(第 68 行附近)

  1. function open($parser, $tag, $attributes) {
  2.     $this->data = '';
  3.     $this->failed = FALSE;
  4.    
  5.     /* === 新增:PHP 8 兼容性保护 === */
  6.     if(!is_array($this->document)) {
  7.         $this->document = array();
  8.     }
  9.     /* ============================= */
  10.    
  11.     if(!$this->isnormal) {
  12.         if(isset($attributes['id']) && !(isset($this->document[$attributes['id']]) && is_string($this->document[$attributes['id']]))) {
  13.             $this->document  = &$this->document[$attributes['id']];
  14.         } else {
  15.             $this->failed = TRUE;
  16.         }
  17.     } else {
  18.         if(!isset($this->document[$tag]) || !is_string($this->document[$tag])) {
  19.             $this->document  = &$this->document[$tag];
  20.         } else {
  21.             $this->failed = TRUE;
  22.         }
  23.     }
  24.     $this->stack[] = &$this->document;
  25.     $this->last_opened_tag = $tag;
  26.     $this->attrs = $attributes;
  27. }
复制代码





3、最终实现效果

场景PHP 7.x 行为修复前 PHP 8.x 行为修复后 PHP 8.x 行为
应用中心返回标准 XML正常解析正常解析正常解析(无变化)
应用中心返回 HTML/异常 XMLWarning + 返回空数组Fatal Error 页面中断优雅降级,返回空数组
用户感知提示"导入数据无效"系统报错,无法继续提示"导入数据无效",可继续操作
(实测已经正常无报错,完美解决!)





4、重要技术沉淀

  • PHP 8 字符串下标严格化$string['key'] 在 PHP 8 中不再静默返回 null,而是直接 TypeError fatal。所有旧项目中基于"容错假设"写的数组游标代码都需要审计。
  • Discuz XML 解析器设计缺陷XMLparse 使用全局引用游标 $this->document 作为解析栈指针,一旦某一步异常导致类型退化,后续所有操作都会级联崩溃。防御式编程(入口类型检查)比依赖下游容错更安全。




5、进一步优化的可能性或尚未实现的构想

  • 前置 HTTP 响应校验:在 getimportdata() 调用 xml2array() 之前,先判断返回内容是否以 <?xml 开头,不是则直接提示"应用中心服务异常",避免进入解析器。
  • 解析器现代化替换XMLparse 基于 xml_parser_create 的 SAX 风格手写引用栈已非常古老,可考虑逐步迁移至 SimpleXMLDOMDocument,彻底消除引用游标类型退化风险。
  • 应用中心域名可用性探测:Discuz 应用中心域名偶尔不稳定,可在后台增加连通性检测或超时降级逻辑。

不懂就搜!点此搜点拨论坛。如果本坛没有,请尝试点此问AI,或跟帖提问。
发帖前注意看置顶帖
不定期借助AI对点拨论坛陈年老帖进行挖坟回复,打扰勿怪!
帖中出现了你所不知道的生词怎么办?——先在点拨论坛搜索
  • 打卡等级:本地老炮

73

威望

1万

金钱

165

贡献

超级版主

积分
15111
主题
1306
回帖
3966
注册时间
2010-9-4
最后登录
2026-8-11
发表于 2026-7-27 19:48:05 | 显示全部楼层
支持一下
有任何论坛使用问题,请看论坛帮助
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|手机版|小黑屋|点拨论坛 |网站地图|网站地图

GMT+8, 2026-8-11 22:48 , Processed in 0.044029 second(s), 8 queries , Redis On.

Powered by Discuz! X3.5

© 2001-2026 Discuz! Team.

快速回复 返回顶部 返回列表