[开发]site_stats 插件功能增强建议(v2)

👑Lv.11 元老 🌞 骨干会员
2026-10-25 01:25:32

本文由 FlintHub 开发文档归档发布。原始文档日期见标题前缀,来源:WWW/docs/site_stats插件功能增强建议_2026-09-24.md。

site_stats 插件功能增强建议(v2)

  • 日期:2026-09-24
  • 配套文档:site_stats插件审计报告_2026-09-24.md(2 项 P0)
  • v2 修订:① 修正「加列」的表述(实测后确认比 v1 说的简单得多);② 功能建议从 18 项扩充到 34 项,并从「按技术分层」改为「按运营场景」组织。

一、先回答:加列只靠幂等行不行?

行,但 SQLite 有个坑。实测(SQLite 3.39.2,内存库):

方案实测结果
ALTER TABLE t ADD COLUMN IF NOT EXISTS x❌ 语法错误 near "EXISTS" —— SQLite 不支持(MySQL/MariaDB 才有)
裸 ADD COLUMN 重复执行❌ duplicate column name: ref_host
PRAGMA table_info 先检测再 ALTER✅ 真幂等(第 2 次不再执行 ALTER,无异常)
try/catch 吞掉 duplicate 错误✅ 也可行(但把真实错误一起吞了,不如前者干净)

所以正确写法就是 3 行:

$cols = array_column($pdo->query('PRAGMA table_info(ss_views)')->fetchAll(PDO::FETCH_ASSOC), 'name');
if (!in_array('ref_host', $cols, true)) {
    $pdo->exec("ALTER TABLE ss_views ADD COLUMN ref_host TEXT NOT NULL DEFAULT ''");
}

另外实测确认两件事,说明加列风险比我 v1 说的低得多:

  1. 加列向后兼容:加完列后,老 INSERT 语句(不含新列)照样成功,新列自动取 DEFAULT。

→ 不需要「加列和改代码必须原子上线」。

  1. 回填也是幂等的:UPDATE ... WHERE ref_host = '' 第 1 次影响 2 行、第 2 次影响 0 行。

→ 重复跑不会重复劳动。

修正 v1 的表述:v1 写「加列必须写迁移,否则存量库静默不加列」—— 这句本身没错

(ensureSchema 只跑 CREATE TABLE IF NOT EXISTS,确实不补列),但说重了,

听起来像大工程。实际就是上面 3 行检测 + 1 句 ALTER。

真正需要「版本号门控」的只有回填:回填虽幂等,但每次请求都跑一次全表 UPDATE 是浪费

(10 万行约几十 ms,且写在每页触发的路径上会撞 §11.4 的查询预算)。

→ 只在 SCHEMA_VERSION 变化时跑一次。这才是 P2-1 版本号的价值所在。


二、再回答:功能不止外链

v1 其实列了 18 项,但外链那条太显眼,把别的盖住了。这版重新组织成 5 个运营场景、34 项,

并按「你每天真正会看什么」排优先级。


三、现状盘点:一半字段是「白采集」

字段采集率被统计使用结论
path / created_at / ip_hash100%✅在用
user_id100%❌ 仅 INSERT白采集
ua100%❌ 仅 INSERT白采集
referer14/15(93%)❌ 仅 INSERT白采集

getStats() 从头到尾没查过 referer、ua、user_id。

⚠️ 同一站点实测有 p.zgzjw.top + localhost 两个访问入口 → 内链判定需要「本站域名白名单」,

否则站内跳转会被误判成外链。


四、referer 的能力边界(决定哪些是画饼)

场景浏览器实际发送能做吗
同源跳转完整 URL 含 query✅ 最完整(实测 ?q=统计)
跨域跳转只有 origin(strict-origin-when-cross-origin)✅ 域名可做,路径/关键词不可
直接访问 / 书签 / App空⚠️ 归入「直接访问」

结论:

  • ✅ 来源域名完全可做
  • ⚠️ 跨域搜索关键词做不到(百度/Google 早已剥离 query)→ 别设计这个字段
  • ✅ 站内搜索词可做(同源带 query)

五、功能建议(按运营场景,34 项)

场景 1|站点健康度 —— 一眼知道在涨还是在跌

#功能说明代价
1环比对比今天 vs 昨天、本周 vs 上周,带涨跌箭头/百分比极低(纯 SQL)
2异常提示流量较基准骤降/骤升时高亮低
3概览卡增强现有 6 个卡片加一行环比小字极低

⚠️ 这是全清单性价比最高的一项:现在只有绝对值,站长看不出站点在涨还是在跌。

纯 SQL 可实现,零表结构改动。

场景 2|流量来源

#功能说明依赖
4外链来源 Top N你点名的(referer 已采集)域名 / PV / UV无
5来源类型分布直接 / 站内 / 搜索引擎 / 社交 / 其他外链无
6外链落地页哪个页面引流最多无
7爬虫访问统计⚠️ 现在爬虫被直接丢弃(route_after_dispatch.php:36 直接 return)→ SEO 视角的抓取频率数据白白浪费加列 is_bot
8搜索引擎细分百度 / Google / 必应 各自多少无
9站内搜索词用户在站内搜什么(同源 referer 带 ?q=)无
10站内跳转路径站内 A → B 的流转(同源 referer 完整可用)无

场景 3|内容运营

#功能说明依赖
11热门页面已有—
12单页 UV 排行现在只有 PV 排序,UV 维度更有意义无
13高浏览低回复帖内容诊断:有人看没人聊 → 需要读 topic_index(必须走 Model,§10.1)跨库读
14版块活跃对比从 path 解析版块 ID,看哪个版块在衰退加列 entity_id
15内容衰减老帖访问量随时间变化无
16内容类型对比帖子 / 博客 / 问答 的流量占比path 解析

场景 4|用户运营

#功能说明依赖
17会员 vs 游客登录用户占比(user_id 已有)无
18新老访客比ip_hash 首次出现时间无
19时段活跃分布24 根柱,定位活跃时段无
20星期 × 小时热力图24×7 矩阵,视觉效果好无
21留存曲线D1 / D7 / D30无(近似)
22设备分布PC / 移动 / 平板无(SQL LIKE)
23浏览器 / OS 分布同上加列 device 更准
24访问深度单次会话访问了几个页面需 C2 会话表
25回访周期用户平均多久回来一次无
26沉默用户注册后 N 天未回访(跨库读 users.created_at)跨库读

场景 5|技术健康

#功能说明依赖
27慢页面排行microtime(true) - $_SERVER['REQUEST_TIME_FLOAT'] 在 route_after_dispatch 可拿到加列 elapsed_ms
28404 死链排行哪些不存在的 URL 被访问(排查失效链接)加列 status
29接口错误率5xx 占比加列 status
30异常流量识别单 IP 短时高频(核心已有 RateLimiter,这里是事后统计)无
31静态资源命中现在被排除了,可单独统计 CDN 效果无

场景 6|数据出口

#功能说明
32CSV 导出一键导出原始明细
33保留策略可视化当前行数 / 最早记录 / 预计清理量
34每日摘要定时推送到通知(可复用核心通知)


六、新增列汇总

列服务功能备注
ref_host TEXT4/5/6/8免去全表扫 URL 解析(见 §七 阈值)
ref_type TEXT5来源分类落库
device TEXT22/23UA 解析结果
status INTEGER28/29响应码 → 404 统计
elapsed_ms INTEGER27响应耗时 → 慢页面排行
is_bot INTEGER7把现在丢弃的爬虫数据留下来
entity_type / entity_id14/16path 结构化

加列方式:§一 的 3 行 PRAGMA 检测,逐个加。索引用 CREATE INDEX IF NOT EXISTS(本身幂等)。


七、性能阈值(实测)

「外链来源」两种实现对比(内存库,3 次取最优):

数据量纯 SQL 解析(无索引)加 `ref_host` 列 + 索引
1 万行12.47 ms1.43 ms
10 万行146.42 ms15.12 ms
50 万行725.51 ms76.03 ms

  • < 5 万行:纯 SQL 够用 → A 级先做,零改动
  • > 10 万行:必须加列(约 10 倍差距)
  • 日均千级 PV → 一年约 36 万行 → 大概率要加列

另外:getStats() 现有 6 次 COUNT(DISTINCT) + 2 次 GROUP BY 也是全表扫,

数据量上来后 C1(日表)比 A1 的优化优先级更高。


八、与本次修复的整合

整合点说明
加列检测 ≡ P2-1 版本号门控把 SCHEMA_VERSION 常量、加列检测、回填绑在一起:版本变了 → 重跑建表 + 补列 + 回填一次。一次设计两处受益。
P2-3(XFF 可伪造)必须先修ip_hash 不可信 → 「来源 × UV」的 UV 失真
P0-1 必须先修后台页现在任何登录用户都能看,加来源分析会放大信息泄露面
加列不加剧 P2-2INSERT 加几列成本可忽略(主体开销是 fsync,实测 21ms)


九、不建议做

不做理由
❌ 访客地理分布 / 地图需 GeoIP 库;且只存 IP 哈希,拿不到位置
❌ 跨域搜索关键词浏览器策略决定拿不到(§四)
❌ 前端图表库无 Chromium 测试环境;CSP script-src 'self' 需放行。纯 CSS 柱状图 + SVG 够用
❌ 明文存 IP破坏现有隐私设计;退一步可只存 /24
❌ 实时在线人数核心已有 online_users 表,别重复造
❌ 不建会话表硬算跳出率ss_views 粒度不够,误差大,等 C2


十、落地顺序(重排)

进度(2026-09-24 12:30):第 1 批 6 项全部交付并验证,见 site_stats插件审计报告_2026-09-24.md §九。第 2 批未开始。

第 1 批|与 P0 修复同批(做完停下来验)—— ✅ 已完成

  1. ✅ 修 P0-1 鉴权 + P0-2 CSRF + P1-1 二次验证 ← 前置
  2. ✅ 修 P2-3(XFF),保证 UV 可信
  3. ✅ 设计 SCHEMA_VERSION 门控(合并 P2-1)+ 幂等加列 ref_host
  4. ✅ 环比对比(#1) ← 最便宜的体验提升
  5. ✅ 外链三件套(#4/#5/#6) ← 你点名的
  6. ✅ 修 P1-2(CRLF)
  • 额外:域名白名单(解决「站内跳转被误判外链」)+ 后台 UI 改造(tab + 左侧导航)

第 2 批|把白采集的字段用起来(未开始)

  1. 会员 vs 游客(#17)、时段分布(#19)、新老访客(#18)、设备(#22)
  2. 爬虫统计(#7)—— 把现在丢弃的数据捡回来
  3. ss_daily 日表

第 3 批|进阶(未开始)

  1. 星期×小时热力图(#20)、留存曲线(#21)
  2. 404 + 慢页面(#27/#28)
  3. ss_sessions 会话表 → 跳出率 / 停留时长 / 访问深度

附:验证方式

  • 来源解析正确性:SQL 提取 host 与 PHP parse_url() 逐项交叉比对(已执行,15 行全一致)
  • 性能阈值:内存库造数实测(1 万 / 10 万 / 50 万行),非估算
  • 加列幂等:内存库实测 4 种方案 + 向后兼容验证 + 回填幂等验证
  • 上线验收:外链区块需真实外链流量才能验收 —— 当前 15 行全是站内跳转,会显示为空
  • 第 1 批交付后:i18n 三语键集合断言(53 键零差异)+ 零内联复扫 + 双主题渲染对比(.ss-admin 块 sha256 一致)—— 已执行,见审计报告 §9.3
轻量级、高性能、零 MySQL 依赖的PHP社区系统。
| 浏览 1 次 | 回复 0 次

全部回复 (0)

暂无回复

请 登录