Xiuno BBS 审计之问题:全局变量滥用,状态混乱

简介: 本文揭示Xiuno BBS 4.0.4中131处global变量滥用问题:状态共享混乱、函数副作用不可控、单元测试难、并发易串态、重构成本高。XIUNOX版已通过依赖注入与单例封装优化修复,供二次开发参考。(239字)

此文章为XIUNOX版本重构审计时发现问题,XIUNOX版本已优化修复此问题。分享出来方便后续想基于xiuno bbs4.0.4版本制作维护版本或插件模板等需求的开发者和站长参考。

现象
Xiuno BBS 4.0.4 大量使用 global $var 在函数间共享状态,全站共 131 处 global $ 声明分布在 28 个 PHP 文件中。配置 $conf、数据库 $db、缓存 $cache、运行时 $time、用户 $uid、错误 $errno/$errstr、会话 $g_session、插件 $plugins 等核心状态均通过 global 共享,部分关键变量还被同时写入 $_SERVER 超全局变量作"备份"。这种模式导致函数副作用不可预测、单元测试无法隔离、并发请求在单进程内可能串状态、重命名/重构成本极高。

源码证据

  1. 全局变量声明统计(Grep count 模式)

global $ → 131 处 / 28 个文件
重灾区文件(部分):

model/plugin.func.php 19 处
model/user.func.php 17 处
model/post.func.php 7 处 / model/thread.func.php 8 处
model/session.func.php 7 处
xiunophp/xiunophp.min.php 6 处
model/runtime.func.php 6 处

  1. plugin.func.php 中 19 处 global 声明,函数副作用不可预测

文件:xiunobbs_4.0.4/model/plugin.func.php 第 54-101 行

function plugin_init() {
global $plugin_srcfiles, $plugin_paths, $plugins, $official_plugins; // 4 个 global
// ...
$plugin_paths = glob(APP_PATH.'plugin/*', GLOB_ONLYDIR);
if(is_array($plugin_paths)) {
foreach($plugin_paths as $path) {
$dir = file_name($path);
$conffile = $path."/conf.json";
if(!is_file($conffile)) continue;
$arr = xn_json_decode(file_get_contents($conffile));
if(empty($arr)) continue;
$plugins[$dir] = $arr;
$plugins[$dir]['hooks'] = array();
// ...
}
}
}
文件:xiunobbs_4.0.4/model/plugin.func.php 第 145-188 行

function plugin_enable($dir) {
global $plugins; // 改全局状态
if(!isset($plugins[$dir])) return FALSE;
$plugins[$dir]['enable'] = 1;
file_replace_var(APP_PATH."plugin/$dir/conf.json", array('enable'=>1), TRUE);
plugin_clear_tmp_dir();
return TRUE;
}
function plugin_disable($dir) {
global $plugins;
if(!isset($plugins[$dir])) return FALSE;
$plugins[$dir]['enable'] = 0;
file_replace_var(APP_PATH."plugin/$dir/conf.json", array('enable'=>0), TRUE);
plugin_clear_tmp_dir();
return TRUE;
}

  1. session.func.php 直接修改全局 $g_session,sess_write 又读 global

文件:xiunobbs_4.0.4/model/session.func.php 第 29-52 行

function sess_read($sid) {
global $g_session, $longip, $time; // 3 个 global
if(empty($sid)) {
$sid = session_id();
sess_new($sid);
return '';
}
$arr = db_find_one('session', array('sid'=>$sid));
// ...
$g_session = $arr; // 写全局
return $arr ? $arr['data'] : '';
}
第 106-167 行:

function sess_write($sid, $data) {
global $g_session, $time, $longip, $g_session_invalid, $conf; // 5 个 global
$uid = _SESSION('uid');
$fid = _SESSION('fid');
// ...
$update = array_diff_value($arr, $g_session); // 读全局
db_update('session', array('sid'=>$sid), $update);
}

  1. xiunophp.php 把核心对象同时塞 global 和 $_SERVER,双轨制

文件:xiunobbs_4.0.4/xiunophp/xiunophp.php 第 100-130 行

$_SERVER['starttime'] = $starttime;
$_SERVER['time'] = $time;
$_SERVER['ip'] = $ip;
$_SERVER['longip'] = $longip;
$_SERVER['useragent'] = $useragent;
$_SERVER['conf'] = $conf;
$_SERVER['lang'] = $lang;
$_SERVER['errno'] = $errno;
$_SERVER['errstr'] = $errstr;
$_SERVER['method'] = $method;
$_SERVER['ajax'] = $ajax;
// ...
$_SERVER['db'] = $db;
$_SERVER['cache'] = $cache;
第 1-3 行的 db.func.php 函数则反过来读 $_SERVER['db']:

function db_sql_find_one($sql, $d = NULL) {
$db = $_SERVER['db'];
$d = $d ? $d : $db;
// ...
}
而 model/*.func.php 中又用 global $conf 读同一份数据,三轨并存。

  1. user.func.php 中 17 处 global,包含 $g_static_users 进程内缓存

文件:xiunobbs_4.0.4/model/user.func.php 第 54-75 行

function user_update($uid, $arr) {
global $conf, $g_static_users; // 2 个 global
$r = userupdate($uid, $arr);
$conf['cache']['type'] != 'mysql' AND cache_delete("user-$uid");
isset($g_static_users[$uid]) AND $g_static_users[$uid] = array_merge($g_static_users[$uid], $arr);
return $r;
}
function user_read($uid) {
global $g_static_users;
if(empty($uid)) return array();
$uid = intval($uid);
$user = user
read($uid);
user_format($user);
$g_static_users[$uid] = $user; // 进程内缓存写全局
return $user;
}
风险等级与结论
架构缺陷(严重)

危害:

131 处 global 声明使函数行为依赖隐式外部状态,调用顺序敏感、不可单元测试
$conf、$db、$cache 同时通过 global 与 $_SERVER 双轨暴露,命名空间污染严重
$g_static_users 等进程内缓存与 global 绑定,长生命周期进程(如 php-fpm 复用 worker)可能跨请求串数据
错误状态 $errno/$errstr 为全局变量,嵌套调用会被覆盖,错误追溯困难
重构成本极高:改名任何一个全局变量需同步修改 N 个文件
与"无依赖注入容器"缺陷叠加,无法 mock 替换依赖
修复建议:

引入依赖注入容器(如 Container::get('db')),函数通过参数接收依赖而非 global
将 $conf、$db、$cache 封装为 Config/DB/Cache 类的静态方法或单例
$g_static_users 等 request 级缓存改为 Request 上下文对象属性,请求结束自动释放
$errno/$errstr 改为异常或 Result 对象,杜绝全局状态污染

目录
相关文章
人工智能 缓存 前端开发
5897 14
人工智能 JavaScript 开发工具
2453 2
|
11天前
|
存储 弹性计算 缓存
阿里云服务器租赁费用:新版租赁收费标准及活动报价参考
本文更新了2026年阿里云全系列云服务器租赁活动报价,所有特惠资源均可前往阿里云活动中心选购,整体覆盖从个人入门到企业级高性能场景的全梯度需求。其中轻量应用服务器主打极致性价比,2核2G峰值200M带宽配置每日10点、15点限时抢购价仅38元/年,2核4G配置379元/年起;高性价比的经济型e实例、通用算力型u2i实例覆盖2核4G至4核32G全档位,适配开发测试与中小型企业业务;搭载英特尔至强6处理器的第九代c9i企业级实例算力较上代提升20%,支撑高并发生产环境,不同实例规格价差清晰,用户可根据自身业务负载与预算灵活选型。
2027 121
阿里云服务器租赁费用:新版租赁收费标准及活动报价参考
缓存 JavaScript Shell
1022 1
|
12天前
|
人工智能 程序员 API
Codex 接入 DeepSeek-V4-Flash:还能补上识图,提供两套方案
Codex 接入 DeepSeek-V4-Flash 怎么配?本文覆盖 CLI 与桌面端,再用 qwen3-vl-flash 补识图,两套方案可直接照做
1577 13
|
9天前
|
编解码 弹性计算 云计算
MiniMax-H3 视频生成模型 — 一键部署与使用指南
MiniMax-H3是MiniMax开源的33B全模态视频生成模型,支持文生视频、图生视频、参考生视频三种模式,原生输出2K/15秒带立体声音频视频,已原生适配ComfyUI,并可通过阿里云计算巢一键部署。(239字)
缓存 人工智能 算法
572 0
|
18天前
|
云安全 人工智能 运维
阿里云联动百位企业安全专家,共识Agent防御最佳实践
当Agent成为新员工,你的安全边界在哪里?
1979 10
阿里云联动百位企业安全专家,共识Agent防御最佳实践
|
10天前
|
人工智能 API 开发工具
2026 零基础本地 AI 漫剧完整实操教程(8G 笔记本显卡可用|附可直接复制命令与代码)
本方案提供完全离线、本地运行的漫剧全自动制作流程:RTX3060/4050 8G显卡即可驱动,涵盖Qwen写分镜→ComfyUI统一角色绘图→LTX2.3图生微动画→Qwen3-TTS本地配音→FFmpeg自动合成,全程无水印、免API、不限次。专为低显存优化,解决变脸、闪烁、爆内存三大痛点。(239字)