3.2.36 新增「自动头像」:按邮箱本地生成,14 套 CC0/MIT 风格可选 #5
为没有头像的访客按邮箱确定性地生成一张 SVG 头像,替代 Gravatar 那个灰底"神秘人"(cn.gravatar.com 在国内已超时,不勾加速时头像 干脆是空白)。全程纯 PHP,零外网请求、零落盘。 后台「主题设置」新增「自动头像」复选框 + 风格列表:勾上之后才 出现 14 套风格,点一下即时换 16 格预览,保存后全站生效。 实现要点(都是踩出来的): - PRNG 必须与 DiceBear 9.x 逐位一致:xorshift + hashSeed 全程跑在 JS 的 int32 语义里,PHP 64 位整数要逐步 i32() 归一; charCodeAt 按 UTF-16 码元取值,emoji 必须真做代理对拆分。 - pickComponent 有简繁两版:只有 glass/rings/shapes/thumbs 额外取 三次整数(rotation/offsetX/offsetY)。给简版也补三次 ⇒ PRNG 多走 3N 步 ⇒ 31 套里 27 套全错。编译期算 pc_has_ints 才治得住。 - 自带人类调色板:官方默认配色几乎全单值,30 个邮箱只出 2 种配色, 那才是"默认头像丑"的真因,光换画风解决不了。 - 只收录 CC0/MIT(13 CC0 + 1 MIT),CC BY 那 13 套要求署名,一律不收—— 主题装给用户用,用户不会维护署名,收进来等于转嫁合规义务。 接入 get_avatar 的两个关键修正: - 必须先看原 src 是不是 Gravatar 家族域名再决定是否替换。原先无条件 替换会把媒体库头像、外链头像、别的插件处理过的 data: 头像一起盖掉。 - 必须删 srcset。只改 src 留着 srcset,浏览器优先用 srcset, 生成的图根本不会被加载(现象是"代码明明换了,页面还是老样子"), 且不能重建 <img> 标签(会丢掉评论头像 CSS 依赖的 class)。 后台三处必须这么做: - body class 由 PHP 输出(admin_body_class),否则每次进设置页/保存后 重载都会先显示风格列表再藏起来,闪一下。 - 事件监听 radio 的 change,不能监听 label 的 click —— label 会把 click 转发给关联 input,冒泡回来再触发一次 ⇒ 同一风格发两次请求 (实测 hits 2→4)。 - 首屏已渲染的 16 格写进 JS 缓存,否则点一圈回到默认风格会白请求一次。 不依赖任何可选扩展:不用 mbstring(未安装时 mb_substr 是 Fatal error, 整站白屏)、不用 gd/imagick。UTF-8 切分/截断/大写全部自己实现。 PHP 7.0 语法,PHP 8.5 下 E_ALL 无任何 warning。 验证: - 14 套 × 6 种子 = 84 个用例与 DiceBear 官方 Node 输出逐字节一致, PHP 8.4 / 8.5 / 无 mbstring(php -n)三种环境均 84/0。 - 静态守卫 55/0;反向验证 17 项注入全部被捕获。 - 后台面板浏览器验证 26/0(显隐、几何、点选、缓存、连点、零报错)。 - 包内内容契约 24/0;包校验反向验证 6 项注入全部被捕获。 - 单次渲染稳态 0.047~0.105ms,峰值内存 2~4MB。
This commit is contained in:
+33
-1
@@ -229,12 +229,44 @@ function kratos_options()
|
||||
|
||||
$options[] = array(
|
||||
'name' => __('Gravatar 加速', 'kratos'),
|
||||
'desc' => __('把评论头像的请求转发到国内可访问的镜像,改善加载速度', 'kratos'),
|
||||
'desc' => __('把评论头像的请求转发到国内可访问的镜像,改善加载速度。若开启了下面的「自动头像」,未上传头像的访客不再需要这张图。', 'kratos'),
|
||||
'std' => '0',
|
||||
'id' => 'g_gravatar',
|
||||
'type' => 'checkbox',
|
||||
);
|
||||
|
||||
/* ── 自动头像 ────────────────────────────────────────────────
|
||||
*
|
||||
* 总开关与风格选择拆成两个字段,但**风格列表只在开关打开后才显示**。
|
||||
* 这是用户明确要求的形式:先勾选,再出现列表。
|
||||
*
|
||||
* 为什么不是一个字段直接存风格名(留空=关闭):
|
||||
* 用户「关闭功能」和「还没选过风格」在库里会变成同一种状态(都空),
|
||||
* 以后想恢复默认值时就分不清该填什么。两个字段各管一件事更清楚。
|
||||
*
|
||||
* ⚠️ std 只在后台预填和「恢复默认」时起作用,运行时 kratos_option()
|
||||
* 完全不看它。所以运行时默认值必须在这里同步给一份:
|
||||
* 开关默认关('0'),风格默认 lorelei(见 yang_avatar_style())。
|
||||
*/
|
||||
$options[] = array(
|
||||
'name' => __('自动头像', 'kratos'),
|
||||
'desc' => __('访客没注册、也没上传头像时,按他的邮箱生成一张头像。<b>全程本地生成,不请求任何外部服务</b>,同一个邮箱永远得到同一张。若访客已经上传过真实头像,不受影响。', 'kratos'),
|
||||
'std' => '0',
|
||||
'id' => 'a_auto_enable',
|
||||
'type' => 'checkbox',
|
||||
);
|
||||
|
||||
$options[] = array(
|
||||
'name' => __('头像风格', 'kratos'),
|
||||
'desc' => __('勾选上面的「自动头像」后,这里才会出现风格列表。所有风格都是 CC0 或 MIT 许可,可自由使用与商用。点一下即时预览,保存后生效。', 'kratos'),
|
||||
'std' => 'lorelei',
|
||||
'id' => 'a_auto_style',
|
||||
'type' => 'avatar_style',
|
||||
/* 只有开关打开时才渲染这个控件;关着的时候后台完全看不到它,
|
||||
避免用户在关闭状态下改了风格却不知道为什么没生效。 */
|
||||
'requires' => 'a_auto_enable',
|
||||
);
|
||||
|
||||
$options[] = array(
|
||||
'name' => __('禁止生成缩略图', 'kratos'),
|
||||
'desc' => __('上传图片时不再额外生成多种尺寸的副本,节省磁盘空间', 'kratos'),
|
||||
|
||||
Reference in New Issue
Block a user