Discuz X3.5 上传图片按钮不显示完整修复指南:WebUploader 替换 SWFUpload 与多模板批量改造
Discuz X3.5 把图片上传组件从 Flash 时代的 SWFUpload 切到了 HTML5 WebUploader,旧自定义模板还引用着已被删除的 upload.js 导致按钮消失。本文按为什么消失、怎么找病灶、三种修复方案、X3.4/X3.5/X4 演进对照、移动端关照、9 项 FAQ 全展开,附 sed 批量改造脚本与 30 分钟复查清单。
Discuz X3.5 推出后,论坛运营圈里出现了一类高频报修:"我把模板从 X3.4 升级过来,发主题或回帖时上传图片那个按钮没了。" 装回 default 主题按钮就回来,切到自家定制主题又消失。这件事本身在 Discuz X3.5 的 changelog 里其实有一行字提到:上传组件从 SWFUpload 全面切换到 WebUploader,旧模板里引用的 upload.js 不再被打包发布。本文按"为什么消失 → 怎么找到病灶 → 怎么修最稳 → 修完还要做什么"的顺序展开,并在结尾给出 X3.4 / X3.5 / X4 三个版本的上传组件演进对照、Flash 弃用后的浏览器兼容性、移动端实测结果,以及发现按钮回不来的进阶排查路径。
Discuz X3.5 为什么换掉 Flash 上传
SWFUpload 的历史地位
Discuz 早在 X1 时代就用 SWFUpload 做图片上传——这是一个 2009 年开源的、基于 Flash 的批量上传组件。它在那个年代解决了原生表单 input[type=file] 的三大痛点:不支持多选、不显示上传进度、单文件大小受 PHP 配置限制。SWFUpload 通过 Flash 调起本地文件选择器、用 ActionScript 切片上传、把进度通过 ExternalInterface 回调到 JS 显示——一整套体验远超原生表单。
Discuz X1 到 X3.4 期间这个组件几乎没改,所有版本里的上传 UI 都是它在跑。模板开发者把它当成了"一个永远存在的全局组件",写自定义模板时直接在 upload.htm 里写 <script src="static/js/upload.js"></script>,没有任何兼容性考虑。
2020 年 Flash 全面退役
Adobe 在 2020 年 12 月正式停止 Flash Player 的支持和分发,主流浏览器(Chrome、Firefox、Edge、Safari)在 2021 年上半年陆续移除 Flash 运行时。SWFUpload 失去了底层运行环境,所有还在用它的网站上传按钮都会"显示存在但点击无效"——按钮本身是 div + flash
很多 X3.4 用户在 2021 年发现"上传按钮点了没反应"就是这个原因。Discuz 官方在 X3.5(2022 年正式版)里彻底废弃 SWFUpload,改用 WebUploader。
WebUploader 的技术栈
WebUploader 是百度 FEX 团队开源的 HTML5 上传组件(GitHub: fex-team/webuploader),本质上是 input[type=file] + FileReader API + XHR2 的组合:
- 多选:通过 input[type=file multiple]。
- 分片上传:通过 File.slice() + FormData + XHR2 异步发送。
- 进度显示:通过 XHR2 的 progress 事件。
- 断点续传:通过服务端校验 chunk_md5 + 客户端跳过已传分片。
- 降级:在不支持 HTML5 的旧浏览器上回退到 Flash(保留旧 Uploader.swf 作为兜底,但 X3.5 里把这部分降级链路拆掉了)。
WebUploader 已经停止维护多年,但作为静态文件继续可用。Discuz X3.5 直接把这套静态文件打包到 static/js/webuploader/ 目录下,引用方式和 SWFUpload 完全不同——这就是模板出问题的根。
"按钮消失"具体是怎么消失的
X3.4 模板里的上传引用
典型 X3.4 自定义模板的 upload.htm(位置:template/your_theme/common/upload.htm)会有这么一行:
<script type="text/javascript" src="{$_G[setting][jspath]}upload.js?{VERHASH}"></script>这里 $_G[setting][jspath] 是 Discuz 的 JS 路径常量(默认 static/js/),VERHASH 是版本哈希(用于缓存破坏)。X3.4 时代 static/js/upload.js 是 SWFUpload 包装层,会在页面加载后查找一组特定 ID 的 div(如 #attachbody)并把上传按钮注入进去。
X3.5 把 upload.js 删了但 default 模板有新引用
X3.5 升级包里:
- static/js/upload.js — 已删除。
- static/js/webuploader/ — 新增目录,里面是 webuploader.css、webuploader.min.js 等。
- template/default/common/upload.htm — 已更新,引用了新的 webuploader 文件。
- template/your_theme/common/upload.htm — 你的自定义模板没有被官方碰过,还引用着已经被删除的 upload.js。
结果:浏览器请求 static/js/upload.js?VERHASH 返回 404,自定义模板里没有任何 WebUploader 的初始化代码——上传按钮自然没法被注入到页面,"消失了"。
排查的第一步:F12 看 Network 标签
验证上述判断只需 30 秒:在出问题的发帖页打开浏览器 DevTools → Network → 重新加载页面 → 看是否有请求 upload.js 返回 404。如果有,就是这个问题。如果没有 404 但 webuploader 系列文件全部 404,说明你的服务器静态资源路径还没切到 X3.5 的目录结构(升级时 static 目录没完整覆盖)。
修复方案对照
方案 A:替换自定义模板的 upload.htm 引用
这是最小改动的修法。打开 template/your_theme/common/upload.htm,找到旧版引用:
<script type="text/javascript" src="{$_G[setting][jspath]}upload.js?{VERHASH}"></script>替换为四行新引用:
<link rel="stylesheet" type="text/css" href="{STATICURL}js/webuploader/webuploader.css?{VERHASH}">
<script src="{STATICURL}js/mobile/jquery.min.js?{VERHASH}"></script>
<script src="{STATICURL}js/webuploader/webuploader.min.js?{VERHASH}"></script>
<script type="text/javascript" src="{$_G[setting][jspath]}webuploader.js?{VERHASH}"></script>四行各自的作用:
- WebUploader 的样式表,包含上传按钮、进度条、缩略图的视觉样式。
- jQuery 移动端版本——WebUploader 的依赖之一,X3.5 在 mobile 子目录下保留了一个轻量 jQuery。
- WebUploader 的核心 JS,提供 WebUploader.create() 等 API。
- Discuz 的 webuploader.js 包装层(位置:static/js/webuploader.js),在 WebUploader 之上调用 Discuz 的上传接口(misc.php?mod=swfupload)和把进度回调到 attachbody。
方案 B:直接覆盖 default 模板的 upload.htm
如果方案 A 改完仍有问题,或者你的自定义模板 upload.htm 改动很大不方便人肉 diff,最快的兜底是把官方 default 模板的 upload.htm 整文件覆盖到自定义模板对应位置:
cp template/default/common/upload.htm template/your_theme/common/upload.htm这样能立刻恢复功能。代价是你之前在 upload.htm 里做的样式定制和 hook 都会丢——所以执行前先 git diff 一下记下修改点,再二次注入到覆盖后的文件。
方案 C:在自定义模板里 include 官方默认 upload.htm
更优雅的折中:在自定义模板的 upload.htm 顶部用 Discuz 模板语法 include 官方文件:
<!--{template common/upload}-->这样未来 Discuz 升级官方 default 模板的 upload.htm,你的模板自动跟随。但这种写法只在自定义模板没有覆盖式重写 upload.htm 时才优雅;如果你必须在 upload.htm 里做大幅改动,还是回方案 A 直接改更直观。
升级路径里的隐藏雷
多个模板同时引用 upload.htm 的连锁
Discuz 模板里 upload.htm 不只在发帖页用,还会被引用到:
- 个人空间相册上传(home/space_uchome.htm 链上)
- 论坛主题快速回复
- 群组发帖
- 门户文章发布(portal/portalcp_post.htm)
- 编辑器 toolbar 里的图片按钮(editor/htmlmode.htm)
修了发帖页可能群组上传还是坏的——这些页面要么共享同一个 upload.htm(修一处全好),要么各自有独立 upload.htm(一个个修)。具体取决于模板是怎么组织的。建议改完后把上面 5 个场景挨个测一遍。
缓存:模板编译目录的 .tpl.php 不会自动重建
Discuz 把模板文件编译成 PHP 缓存(位置:data/template/...tpl.php)。改了 upload.htm 但没清缓存的话,前端拿到的还是旧版编译结果。修完后必做:
- 后台 → 工具 → 更新缓存 → 全选执行。
- 或者直接删除 data/template/ 目录所有 .tpl.php 文件让 Discuz 自动重新编译。
- 用浏览器无痕窗口或 Ctrl+F5 测试,避免本地缓存干扰。
权限和文件大小限制
WebUploader 切到了浏览器原生 input[type=file],意味着以前 SWFUpload 时代靠 Flash 绕过 PHP upload_max_filesize 的"骚操作"全部失效,文件大小完全受 PHP 配置约束:
upload_max_filesize:单文件上限。post_max_size:整个 POST 请求上限(必须 ≥ upload_max_filesize)。max_file_uploads:单次请求最大上传文件数。memory_limit:处理上传时 PHP 的内存上限。
Discuz 后台 → 全局 → 上传设置里也有一组限制(按用户组分),生效逻辑是 PHP 限制和 Discuz 限制取较小值。X3.4 升 X3.5 后如果用户反馈"以前能传 50MB 的视频现在不能",先查 PHP php.ini 是不是被运维改回了 8M 默认值。
HTTPS 站点的混合内容问题
WebUploader 的某些静态资源默认走相对路径,但 Discuz 的 STATICURL 常量在某些配置下可能输出 HTTP 协议而非 HTTPS。结果:HTTPS 站点加载 webuploader.css 时被浏览器拦截为混合内容警告,样式没生效,按钮显示但样式异常。修法:
- 确认 Discuz 后台 → 全局 → 域名设置里"统计资源域名"配的是 HTTPS。
- config/config_global.php 里
$_config['site']['url']必须是 https://。 - 必要时强制 STATICURL 输出绝对 HTTPS 路径,hard code 到 upload.htm。
X3.4 / X3.5 / X4 三个版本的上传组件演进对照
X3.4 及以前
SWFUpload + ActionScript + Flash Player。优势:跨浏览器一致、断点续传成熟、不受 PHP 限制(Flash 直接 POST 到服务端)。劣势:Flash 退役。
X3.5(2022)
WebUploader(HTML5)+ jQuery + 兜底没保留 SWFUpload。优势:不依赖 Flash、移动端可用。劣势:受 PHP upload_max_filesize 约束、断点续传逻辑变弱、WebUploader 本身停更。
X4(2024+ 内测版本)
有传闻官方在试验切到 vue-uploader 或自研组件,更现代化。但截至 2026 年初,X4 还没正式发布,X3.5 仍是主流稳定版。
升级 SOP 建议
从 X3.4 跳 X3.5 时把以下事项写进升级 checklist:
- 升级前打 tar.gz 备份 template/、static/、data/ 三个目录。
- 用 diff 工具对比 template/default/common/upload.htm 升级前后的内容,记下改动点。
- 把改动点应用到所有自定义模板的同名文件。
- 清模板缓存。
- 测发帖、回帖、相册上传、群组发帖、门户发布、编辑器图片按钮 6 个场景。
- HTTPS 站点额外测:DevTools 里有没有 mixed content 警告。
- 移动端测:iOS Safari、Android Chrome、微信内置浏览器三个环境上传是否正常。
移动端的特别关照
iOS Safari 的特殊性
iOS Safari 对 input[type=file] 的支持有几个坑:
- iOS 10 以前不支持多选。
- iOS 14 之前 multiple 属性可能被忽略,要用 capture 属性触发相机。
- iOS 微信内置浏览器对图片选择器的支持时好时坏,建议在用户代理判断里检测微信并提示用户切换至外部浏览器。
X3.5 的 mobile 子目录有专门的移动端 upload 模板(template/default/mobile/common/upload.htm),路径不一样要单独修。
移动端按钮不见的另一种原因:CSS 隐藏
有时候按钮没消失,只是被 CSS 隐藏了。WebUploader 默认用一个 div 模拟按钮样式(包了一个透明 input[type=file])。如果你的自定义模板 CSS 把 div.uploadbutton 设置了 display:none 或者 z-index 让它被其他元素盖住,就会出现"按钮的位置看不到"的现象。F12 查看元素:找到 div 的 computed style 排查。
WeChat 内置浏览器的限制
微信浏览器对图片上传支持是阉割的:iOS 上 input[type=file] 只能选择"拍照"或"相册"二选一不能多选;Android 上勉强支持但分片上传不稳定。如果你的论坛主要靠微信流量,建议在 upload.htm 里检测 navigator.userAgent 包含 MicroMessenger,给出"建议在外部浏览器中打开发帖"的提示。
常见问题解答
替换了 upload.htm 但按钮还是不出现怎么办
F12 → Console 看有没有 JS 报错。常见三类:(1) jQuery 未加载——检查 mobile/jquery.min.js 路径是否正确;(2) WebUploader.create is not a function——webuploader.min.js 没加载,检查 STATICURL 是否正确解析;(3) Discuz 的 webuploader.js 包装层报错——通常是 Discuz 升级不完整,static/js/webuploader.js 文件版本不匹配,从官方 X3.5 安装包里拷一份覆盖即可。
Discuz X3.5 还能用回 SWFUpload 吗
技术上可以——把 X3.4 的 static/js/upload.js 和 swfupload.swf 拷过来、模板改回旧引用——但代价大于收益:所有现代浏览器都不再加载 Flash,按钮等于"空架子"。回滚仅在你的用户群体集中在企业内网装了 Flash 调试版或 Pale Moon 等小众浏览器才有意义。常规情况老老实实换 WebUploader。
WebUploader 已停止维护,会不会有安全问题
WebUploader 是纯前端组件,安全风险主要看上传后端。前端代码层面 WebUploader 已经多年没更新但功能稳定无已知严重漏洞。后端 misc.php?mod=swfupload 的处理逻辑由 Discuz 维护,安全补丁随 Discuz 主版本走。建议定期升级 Discuz 主版本,前端组件本身可以暂时不动。
能不能把 WebUploader 换成更现代的 Filepond 或 Uppy
可以,但工程量大。Filepond / Uppy 的 API 设计与 WebUploader 不同,要重写 Discuz 的 webuploader.js 包装层,把上传成功后的 attachbody 注入逻辑、缩略图生成回调、附件 ID 拿到后写入隐藏字段等流程重新对接一遍。除非你做长期维护的二开版本,否则不建议折腾。
静态资源用 CDN 后 webuploader.css 加载失败怎么办
CDN 缓存了旧路径或没把 static/js/webuploader/ 整个目录推上去。解决:(1) 在 CDN 控制台清缓存;(2) 检查 CDN 回源规则是否覆盖 /static/js/webuploader/* 路径;(3) Discuz 后台 → 全局 → 域名设置 → 统计资源域名填的是 CDN 域名时,确保所有 webuploader 文件都在 CDN 上能取到。可以用 curl 直接测:curl -I https://cdn.example.com/static/js/webuploader/webuploader.css 看返回 200 还是 404。
升级后管理员能上传普通用户传不了,是什么原因
大概率是用户组上传权限。Discuz 后台 → 用户 → 用户组 → 编辑某个组 → 论坛相关 → 是否允许上传附件 / 单附件大小 / 每帖最多附件数。X3.5 升级时这些权限设置不会重置,但如果你的模板替换过程中影响了 group_id 的判断逻辑(极少见),就要查 source/include/post/post_newthread.php 里 checkupload 的调用链。
多模板共存时怎么批量修
shell 脚本:
cd /path/to/discuz/template
for theme in */; do
f="$theme/common/upload.htm"
if [ -f "$f" ] && grep -q '/upload.js?' "$f"; then
cp "$f" "$f.bak"
sed -i 's|<script type="text/javascript" src="{$_G\[setting\]\[jspath\]}upload.js?{VERHASH}"></script>|<link rel="stylesheet" type="text/css" href="{STATICURL}js/webuploader/webuploader.css?{VERHASH}"\>\n<script src="{STATICURL}js/mobile/jquery.min.js?{VERHASH}"></script>\n<script src="{STATICURL}js/webuploader/webuploader.min.js?{VERHASH}"></script>\n<script type="text/javascript" src="{$_G[setting][jspath]}webuploader.js?{VERHASH}"></script>|g' "$f"
fi
done跑完后清模板缓存测试每个模板。
修完后还要做哪些验收测试
5 个场景必测:(1) 论坛发新帖上传图片;(2) 主题回复上传图片;(3) 个人相册上传;(4) 门户文章后台发布上传;(5) 编辑器工具栏点击图片按钮。每个场景测:单图、多图、超大图(接近 PHP 限制)、超时大图(应正确报错而非静默失败)、HTTPS/HTTP 混合、移动端、微信浏览器。全部通过算迁移完成。
HTTPS 强制后 webuploader 还有什么坑
主要两个:(1) STATICURL 必须输出 https://,否则混合内容警告;(2) WebUploader 如果保留了 Flash 兜底(X3.5 默认没保留,但有些二次魔改版本会留),swf 文件加载也必须 HTTPS 不然被拦。建议直接禁用 Flash 降级链路,全部走 HTML5。
事后检查的优先级
修完 upload.htm 之后我习惯按这个顺序复查 30 分钟:
- 核心场景:发新帖能传图(最基本)。
- 缓存:DevTools 里 webuploader 系列文件状态码全 200,没有 304 的旧 hash。
- 移动端:手机浏览器测一次,截图存档。
- 性能:DevTools Network → Disable cache → 刷新发帖页,看 webuploader.js 加载时间不要超过 500ms(CDN 不正确时常常卡几秒)。
- SEO 影响:发帖页是否被 noindex(应是的,发帖页本来就不该收录),如果 robots.txt 没禁,X3.5 升级时再加上。
- 错误日志:服务器 PHP error_log 是否新增 misc.php 相关报错——正常应该没有。
这套修复流程我给十几个客户跑过,X3.5 上传按钮的 case 几乎都是"修 upload.htm + 清模板缓存"这一对操作就能解决。真正花时间的是排查为什么自定义模板没在升级时被 diff 出来——这是模板维护流程问题,不是技术问题。建议把"每次主版本升级前对模板和官方 default 做一次 diff"列成 SOP,避免下次升 X4 时又踩同一类坑。
本文标题:《Discuz X3.5 上传图片按钮不显示完整修复指南:WebUploader 替换 SWFUpload 与多模板批量改造》
本文链接:https://zhangwenbao.com/discuz-x3-5-webuploader.html
版权声明:本文原创,转载请注明出处和链接。许可协议: CC BY-NC-SA 4.0