fix(avatar): 注册用户保留原头像;人脸风格肤色只留黄种人区间

#8 邮箱能在本站用户表查到的,一律用他自己的头像,不再替换
   · 新增 yang_avatar_is_registered_email():get_user_by('email') 查表,
     邮箱先 trim + strtolower 规范化(导入用户/插件写库/老数据都有大小写混用)
   · 加请求内 static $memo 缓存:评论列表一页 20 条、同一个人常有 2~3 条,
     不缓存就是同一个邮箱反复打库(实测 20 次 → 1 次)
   · 新增 yang_avatar_keep_member() 读开关,运行时默认 '1'
   · 过滤器在拼 data: URI 之前拦截,命中即原样 return $avatar
   · 后台新增「注册用户保留原头像」复选框
   · 关于「注册用户自己也没有真 Gravatar」:WP 的 get_avatar() 从不检查图上
     是否存在,只拼 URL 交给浏览器;要分辨必须向 gravatar.com 发请求,
     而本功能坚持零外网调用(发布脚本会断言)。因此做成开关、默认保留,
     这类用户保持灰人像、不猜。

#9 肤色从 7 档收窄到 4 档,只留最浅到偏黄
   · 移除 d9a066(偏深)、c68642(深棕)、8d5524(最深)
   · 安全性依据:Prng::pick() 用 integer(0, count-1) 取索引,只消耗一次
     next(),与区间跨度无关 ⇒ 缩短数组不改变 PRNG 消耗次数,发型/衣着/
     表情/背景抽到的结果一点不变,只有肤色跟着变
     (已用 _v39_isolate.php 逐字节证明:7 色与 4 色渲染除肤色外完全相同)

顺带修掉一个老 bug:baseColor 错当肤色
   · bottts 的 baseColor 是机器人外壳色(19 种彩色),映射成肤色后外壳被
     涂成肉色 e8b98f / f1c27d。从 $map 里去掉 'baseColor' => 'skinColor'
   · 「base」这名字像是底色,但各家风格语义并不统一,不能按名字猜

开关位置(踩过的坑)
   · 新开关必须排在「头像风格」之前。风格列表是 18 张带缩略图的卡片、
     实测高约 2100px,排在它后面的控件会落到 y≈2327px,而设置页视口
     约 1000px —— 用户不滚三屏根本看不到。3.2.36 就是栽在这里。
     挪到之前后实测 y=216px、首屏可见。

验证
   _v39_probe.php              5 / 0   肤色收窄 + bottts 修复
   _v39_isolate.php           50 / 0   「只改肤色、其它不变」逐字节隔离证明
   _v39_member.php            19 / 0   注册用户判据(含缓存次数精确断言)
   _v39_falsify.py              8 / 8   上述判据反向
   _guard337_layout.py        25 / 0   布局守卫(新增开关位置三项)
   _guard337_layout_falsify.py  5 / 5
   _guard336_avatar.py        55 / 0   源码守卫
   _guard336_falsify.py       17 / 17
   _geo337_avatar_reach.py    34 / 0   真实几何 + 显隐交互
   _smoke18.py                18 / 0   18 套风格全量冒烟
   _verify4_prod.php          80 / 0   逐字节对官方(对配色无感,见 docblock)
   _pkgcheck339.py            52 / 0   包内内容契约
   _pkgcheck339_falsify.py    20 / 20  包内断言反向
   回归 88/0、56/0、77/0、13/0;93 个 php -l 全通过
   PHP 8.4.25 与 8.5.12 严格错误级别均 0 警告

Refs #8 #9
This commit is contained in:
2026-10-25 20:19:27 +08:00
parent 16cc7d8328
commit 203721b1fe
3 changed files with 134 additions and 14 deletions
+14
View File
@@ -286,6 +286,20 @@ function kratos_options()
'type' => 'checkbox',
);
/* ⚠️ 这个开关必须排在「头像风格」**之前**。
风格列表是 18 张带缩略图的卡片,实测高约 2100px;
排在它后面的控件实际落到 y≈2327px,而设置页视口约 1000px
—— 用户不滚三屏根本看不到。3.2.36 就是栽在「塞在长列表末尾」
这个坑里,别再犯。 */
$options[] = array(
'name' => __('注册用户保留原头像', 'kratos'),
'desc' => __('<b>建议开启。</b>开启后只给「邮箱在用户表里查不到」的匿名访客生成头像;本站注册用户一律用他自己的头像,不会被替换。<br>关掉则所有 Gravatar 头像都会被换掉 —— 站内作者、管理员也会变成卡通脸。<br><b>说明:</b>注册用户若自己也没上传过头像,Gravatar 上就是一张默认灰人像。要分辨这种情况必须向 gravatar.com 发请求,而本功能坚持不访问任何外部服务,所以这类用户会保持灰人像,不会自动生成。', 'kratos'),
'std' => '1',
'id' => 'a_auto_keep_member',
'type' => 'checkbox',
'requires' => 'a_auto_enable',
);
$options[] = array(
'name' => __('头像风格', 'kratos'),
'desc' => __('勾选上面的「启用自动头像」后,这里才会出现风格列表。所有风格都可自由使用与商用,且不要求署名。点一下即时预览,保存后生效。', 'kratos'),