From 0365098fa4dd060691ff6483ffb1b95c0ac480fb Mon Sep 17 00:00:00 2001 From: Yongquan Date: Mon, 2 Nov 2026 10:42:03 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=EF=BC=9A=E7=A9=BA=E6=A0=BC?= =?UTF-8?q?=E5=BC=8F=E7=99=BD=E5=90=8D=E5=8D=95=E5=8F=8D=E8=80=8C=E6=8B=92?= =?UTF-8?q?=E7=BB=9D=E4=B8=80=E5=88=87=E6=96=87=E4=BB=B6=EF=BC=9B=E5=AE=9A?= =?UTF-8?q?=E4=BD=8D=E3=80=8C=E5=A1=AB=200=20=E6=97=B6=E6=AD=A3=E6=96=87?= =?UTF-8?q?=E5=9B=BE=E4=BC=A0=E4=B8=8D=E4=B8=8A=E3=80=8D=E7=9C=9F=E5=9B=A0?= =?UTF-8?q?=20(#4)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## 一、定位用户报的「提交反馈里图片不显示」 用户先说正文图不显示、回复的却显示,随后反馈「现在可以了,但之前确实不行」。 真因在 #4 已修掉,但当时没写清楚机制: for (var i = 0; i < files.length; i++) { if (countOf(kind) >= maxCount) { alert("最多上传 " + maxCount + " 个"); break; // ← 整批文件一个都不传 } } 数量上限填 0(本意不限)时,countOf 是 0、maxCount 是 0, `0 >= 0` 为真 ⇒ 弹「最多上传 0 个」⇒ break 跳出整个循环 ⇒ 选中几张就全部丢弃。上传区看起来"正常"(只是弹了个框), 提交后正文自然没有图。 已在线上核实用户新发的那条:aid=2 tid=2 reply_id=NULL, 附件正确挂在主题正文,详情页 .atts 渲染出 1 个 img,media.php 返回 200 / 225KB。 ## 二、顺带修同一段里的第二个同类陷阱 var allowed = (box.getAttribute("data-accept") || "").split(","); if (allowed.length && allowed.indexOf(file.type) < 0) { ... 拒绝 ... } `"".split(",")` 返回 `[""]`,长度是 1 不是 0。 所以「未配置格式白名单」时,allowed.length 判真、indexOf 永远 -1 ⇒ 空列表反而拒绝一切文件,这与"没配置=不限格式"的意图相反。 修法:split 后 filter 掉空项。实测: normal : allowed=["image/jpeg","image/png"] len=2 blocked=false empty : allowed=[""] len=1 blocked=true ← 旧代码 当前 UI 没有清空 mimes 的入口,现网触发不到,但属于同一类 「空/0 被当成最严格限制」的坑,一并修掉。 ## 三、资源版本 14 → 15 🔴 上一轮就是改了 app.js 却忘升版本,浏览器一直用缓存旧 JS, 导致修复看起来"没生效"。这次改完立刻升,三处引用 (layout.php 的 css/js、install.php 的 css)都走 FB_ASSET_V 常量。 ## 四、新增专项与反向验证 `_tooling/feedlite/fb_attach_zero_js.py`:19 项。 关键设计:数量判断条件**从源码正则抽取**后注入 node harness, 不在测试里硬编码正确写法 —— 否则修复被回退时测试照旧全过,成了假通过。 反向验证(故意把修复回退): - 正常版本 19/19 - 回退版本 12/19,B1/B2/B4/B6/B9 全部 FAIL,能准确定位 ⚠️ 第一版 harness 的 countOf 返回固定值,导致 B3/B8("传着传着到上限") 假通过。改成动态读递增计数后才是真验证。 回归:全新安装 33/33、附件 22/22、老基线 25/25、约束检查 20/20。 --- assets/app.js | 9 ++++++++- lib/bootstrap.php | 2 +- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/assets/app.js b/assets/app.js index e3dae10..c69fce8 100644 --- a/assets/app.js +++ b/assets/app.js @@ -288,11 +288,18 @@ var maxBytes = parseInt(box.getAttribute('data-max-bytes') || '0', 10); var maxSide = parseInt(box.getAttribute('data-max-side') || '1600', 10); var label = box.getAttribute('data-label') || '附件'; - var allowed = (box.getAttribute('data-accept') || '').split(','); + // ⚠️ ''.split(',') 返回 [""](长度 1),不是空数组。 + // 直接用 allowed.length 判「有没有配置白名单」是错的 —— + // 空列表会被当成「白名单只有空串」,于是拒绝一切文件。 + // 本意应是:没配置 = 不限格式。所以先滤掉空项。 + var allowed = (box.getAttribute('data-accept') || '') + .split(',') + .filter(function (t) { return t.trim() !== ''; }); for (var i = 0; i < files.length; i++) { var file = files[i]; + // allowed 为空 = 后台没限制格式,放行 if (allowed.length && allowed.indexOf(file.type) < 0) { alert('「' + file.name + '」格式不支持,请选择:' + allowed.join(' / ')); continue; diff --git a/lib/bootstrap.php b/lib/bootstrap.php index 2383ada..d9ae99f 100644 --- a/lib/bootstrap.php +++ b/lib/bootstrap.php @@ -8,7 +8,7 @@ if (!defined('FB_ROOT')) { define('FB_ROOT', dirname(__DIR__)); // 静态资源版本号:改 assets/ 下的 css/js 后把这个数字 +1, // 让浏览器与 CDN 缓存失效。全站只此一处,别再往页面里写死数字。 - if (!defined('FB_ASSET_V')) { define('FB_ASSET_V', 14); } + if (!defined('FB_ASSET_V')) { define('FB_ASSET_V', 15); } } /* ------------------------------------------------------------------