[开发]FlintHub 下版本待办清单

👑Lv.11 元老 🌞 骨干会员
2026-10-24 00:32:18

本文由 FlintHub 开发文档归档发布。原始文档日期见标题前缀,来源:WWW/待办事宜/FlintHub_下版本待办清单.md。

FlintHub 下版本待办清单

来源:2026-09-14 全面体检(黑盒渗透 + 白盒静态审计 + 竞品对比 + 写入并发核实)

状态:V1.0.0 已发布,以下条目统一下版本处理

说明:每条含「位置 / 问题 / 改法 / 验证」,可直接作为开发工单使用


目录


一、建议的版本切分

按「风险 × 收益」把待办分成三批,避免一次性改动过大:

批次内容特点
V1.0.1(可随时发)性能优化 2 项 + 安全加固 5 项 + 打磨 4 项改动小、风险低、收益明确,适合做补丁版
V1.1.0前端资源优化、CSP 收紧、反代适配需改动模板/构建/配置,需回归测试
V1.2.0最小测试集、文档改进需持续投入,非一次性工作

如果只挑一件先做:先做第二章的性能优化——改两处代码,回帖路径直接少 4 次全表 COUNT。


二、性能优化(新发现,收益最高)

P-1 统计刷新不对称:新增走全量 COUNT,而增量机制已存在

项内容
位置app/Models/Post.php:104、app/Models/Thread.php:116
问题sync 模式下,发帖/回帖调用 Settings::runtimeBuild(),它会执行 4 次全量 COUNT(reply_index / topic_index / users / blogs)并写 4 次 settings 表。<br>但删除方向(Post.php:347、Thread.php:632)用的却是 Settings::runtimeIncr() 增量机制——便宜的那条路已经写好了,只是没用在新增方向。
影响每次回帖额外产生 4 次 COUNT + 4 次写,且全挤在 main_index.sqlite / business.sqlite 两个全局单点上。

| 改法 | ```php

// Post.php:104

  • \app\Helpers\Settings::runtimeBuild();

+ \app\Helpers\Settings::runtimeIncr('total_posts');

// Thread.php:116

  • \app\Helpers\Settings::runtimeBuild();

+ \app\Helpers\Settings::runtimeIncr('total_threads');

| **漂移风险** | 原设计用全量重建来校正漂移(见 `Post.php:316` 注释)。改用增量后,建议:
① 保留后台维护页的「重建统计」按钮作为人工校准入口(**该按钮已存在**,无需新增);
② 可在 `cron_trigger.php` 里挂一个低频(如每日一次)的 `runtimeBuild()` 兜底校准。 | | **验证** | 用 `bench_write.php` 跑改前/改后对比,看 P95 与吞吐变化。 | ### P-2 `reply_index` 缺 `status` 单列索引 | 项 | 内容 | |:---|:---| | **位置** | `app/SplitDB/Schema.php:733-746`(`ensureMainIndex()`) | | **问题** | `reply_index` 目前只有 `idx_reply_index_pid(pid)` 与 `idx_reply_index_uid(uid, status)`。而 `Settings::runtimeBuildSingle('total_posts')` 执行的是 `SELECT COUNT(*) FROM reply_index WHERE status = 0` —— **首列是 uid 的复合索引用不上**,退化为全表扫描。 | | **影响** | 16 万行量级的全表扫描,且发生在 `main_index.sqlite` 上,与写入串行。 | | **改法** | 在 `ensureMainIndex()` 内追加(放在 `CREATE TABLE` 之后,注意该文件已有「索引顺序红线」的注释):
```sql CREATE INDEX IF NOT EXISTS idx_reply_index_status ON reply_index (status);

| 备注 | 即使做了 P-1,本项仍建议保留——后台「重建统计」按钮和 cli/worker.php 仍会走 runtimeBuildSingle(),索引能让它们快起来。 |

| 验证 | 执行 EXPLAIN QUERY PLAN SELECT COUNT(*) FROM reply_index WHERE status = 0;,确认由 SCAN 变为 SEARCH ... USING COVERING INDEX。 |


三、发布阻断项(4 项)

B-1 前端静态资源零优化

项内容
位置assets/css/modern.css(75KB)、assets/js/editor.js(83KB)、assets/css/admin.css(45KB);nginx-server.conf
问题自研 CSS/JS 全部未压缩;静态资源响应既无 Cache-Control/Expires,也未 gzip(仅 HTML 开了 gzip)。
影响访客唯一能肉眼感知的性能问题。后端做到 3~10ms 渲染,却可能被 200KB+ 未压缩资源拖慢首屏;缺 Cache-Control 导致回访用户重复下载。
改法① Nginx 对 css/js/svg 开 gzip 或 gzip_static;<br>② 加 expires 30d; + Cache-Control: public, immutable(现有 ?v=filemtime 版本参数已具备缓存击穿能力);<br>③ 对自研 CSS/JS 产出 .min 版本。
验证curl -I 检查 Content-Encoding: gzip 与 Cache-Control;Lighthouse 看首屏指标。

B-2 无自动化测试

项内容
位置全库无 tests/、无 PHPUnit
问题55,662 行 / 390 文件,升级策略为「完整包覆盖 + 7 个 migrate_* 脚本」,任何改动都缺安全网。
影响数据迁移脚本一旦有误,损失不可逆 —— 这是发布后最大的实际风险。
改法不要求全覆盖,优先给「改了就会出事」的部分补最小测试集:<br>① ShardRouter 的桶计算与 32→64 扩容路由;<br>② migrate_ / rebuild_ CLI 脚本的幂等性与回滚;<br>③ Permission::canView / canAttach 权限判定;<br>④ Content::sanitizeHtml 的 XSS 用例。<br>可用无 Composer 依赖的手写断言脚本,接入现有 cli/ 体系即可。

B-3 HTTPS 判定不支持反向代理

项内容
位置共 5 处:app/Core/Controller.php:79、app/Controllers/AuthController.php:539、app/Helpers/RememberMe.php:97、app/Helpers/PageCache.php:81、install.php:45,215
问题统一写作 isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on',不识别 X-Forwarded-Proto。
影响部署在 Nginx / 宝塔 / 隧道 / CDN 之后(TLS 在反代层终止)时:Session Cookie 与 remember_token 的 Secure 标志失效、HSTS 头不发送 → 会话凭据可能在明文 HTTP 下泄露。
佐证app/Helpers/AuditLog.php:76 已实现 X-Forwarded-For + isTrustedProxy(),说明系统具备反代意识,此处属实现不一致。

| 改法 | 封装统一入口,替换 5 处调用:<br>```php

final class Request {

public static function isSecure(): bool {

if (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') return true;

$remote = $_SERVER['REMOTE_ADDR'] ?? '';

if (AuditLog::isTrustedProxy($remote)) {

$proto = strtolower(trim(explode(',', $_SERVER['HTTP_X_FORWARDED_PROTO'] ?? '')[0]));

if ($proto === 'https') return true;

}

return false;

}

}


### B-4 CSP 形同虚设 + 版本信息外泄

| 项 | 内容 |
|:---|:---|
| **位置** | `app/Core/Controller.php:77`;Nginx `server_tokens`;PHP `expose_php` |
| **问题** | `script-src 'self' 'unsafe-eval' 'unsafe-inline'` —— 两个指令使 CSP 对脚本注入的拦截能力归零;响应头暴露 `Server: nginx/1.29.8` 与 `X-Powered-By: PHP/8.2.30`。 |
| **改法** | ① 脚本标签加 `nonce`,移除 `unsafe-eval`(Alpine.js 换 build 版即可无 eval);
② Nginx `server_tokens off;`;
③ `php.ini` 设 `expose_php = Off`。 | | **备注** | 需同步改造模板中的 `

干跑:只打印将要写入的数据量与桶命中分布,不落盘

php cli/bench_write.php --mode=hot --thread=测试帖ID --concurrency=32 --per=20

正式执行(必须显式 --yes)

php cli/bench_write.php --mode=hot --thread=测试帖ID --concurrency=32 --per=20 --yes

php cli/bench_write.php --mode=spread --thread=测试帖ID --concurrency=32 --per=20 --yes

php cli/bench_write.php --mode=id --concurrency=64 --per=100 --yes

清理压测数据

php cli/bench_write.php --cleanup --thread=测试帖ID

轻量级、高性能、零 MySQL 依赖的PHP社区系统。
| Views 3 | Replies 0

All Replies (0)

No replies yet

Please Log in