From ae59f756ca2ba016293482bf7e037d8c2111c5ff Mon Sep 17 00:00:00 2001 From: dsh Date: Fri, 28 Aug 2026 20:22:35 +0800 Subject: [PATCH] =?UTF-8?q?chore:=20=E5=AD=98=E9=87=8F=E5=A4=B4=E5=83=8F?= =?UTF-8?q?=E8=BF=81=E7=A7=BB=E8=84=9A=E6=9C=AC=E2=80=94=E2=80=94=E6=97=A7?= =?UTF-8?q?=E5=91=BD=E5=90=8D=20.jpg=20=E8=BF=81=E5=85=A5=E7=BB=9F?= =?UTF-8?q?=E4=B8=80=20files=20=E8=A1=A8=EF=BC=88type=3Davatars=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 其他部署升级到统一上传引擎后,历史头像仍以 .jpg 命名且未在 files 表 登记,直到所有者下次换头像才被清理。本脚本提供一次性迁移: 内容字节不变,以 SHA-256 哈希命名复制到 avatars/,登记 files 行 (type=avatars),更新 users.avatar,删除旧文件。 幂等:已为 64 位哈希名的用户自动跳过;无遗留文件时无操作。 已在线上库实测(2 个用户全部跳过)。 --- scripts/migrate_legacy_avatars.sh | 72 +++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100755 scripts/migrate_legacy_avatars.sh diff --git a/scripts/migrate_legacy_avatars.sh b/scripts/migrate_legacy_avatars.sh new file mode 100755 index 0000000..7ed854e --- /dev/null +++ b/scripts/migrate_legacy_avatars.sh @@ -0,0 +1,72 @@ +#!/usr/bin/env bash +# 存量头像迁移:把旧命名(.jpg,历史方案)的用户头像迁入统一 files 表 +# (type='avatars')并用 SHA-256 哈希命名(公开链接 /uploads/avatars/<哈希>)。 +# +# 背景:头像上传自 2026-08 起走统一上传引擎(files 表 + 内容寻址);历史头像 +# 文件仍以 .jpg 命名、未被 files 表登记。本脚本按用户逐个迁移: +# 1. 取头像文件内容 SHA-256 作为新存储名(内容字节不变,不重新编码); +# 2. 复制为 avatars/<哈希> 并登记 files 行(type=avatars); +# 3. 更新 users.avatar; +# 4. 删除旧的 .jpg。 +# 幂等:已是 64 位十六进制哈希名的用户自动跳过;无遗留文件时无操作。 +# +# 用法: +# MYSQL_HOST=127.0.0.1 MYSQL_PORT=3306 MYSQL_USER=blog_go MYSQL_PASSWORD=xxx \ +# MYSQL_DB=blog_go STORAGE_DIR=/srv/blog_go [SVC_USER=blog_go] \ +# bash scripts/migrate_legacy_avatars.sh +set -euo pipefail + +: "${MYSQL_HOST:=127.0.0.1}" +: "${MYSQL_PORT:=3306}" +: "${MYSQL_USER:?请设置 MYSQL_USER}" +: "${MYSQL_PASSWORD:?请设置 MYSQL_PASSWORD}" +: "${MYSQL_DB:?请设置 MYSQL_DB}" +: "${STORAGE_DIR:?请设置 STORAGE_DIR(存储根目录,头像位于其 avatars/ 子目录)}" +: "${SVC_USER:=blog_go}" + +AVATAR_DIR="$STORAGE_DIR/avatars" + +mysqlq() { mysql -h"$MYSQL_HOST" -P"$MYSQL_PORT" -u"$MYSQL_USER" -p"$MYSQL_PASSWORD" "$MYSQL_DB" -N -B -e "$1"; } + +# 前置检查:files 表与头像目录必须存在。 +if ! mysqlq "SHOW TABLES LIKE 'files'" | grep -q files; then + echo "错误:数据库 $MYSQL_DB 中不存在 files 表(需先部署 files 表版本)" >&2 + exit 1 +fi +if [ ! -d "$AVATAR_DIR" ]; then + echo "错误:头像目录不存在:$AVATAR_DIR" >&2 + exit 1 +fi + +migrated=0 +skipped=0 +while IFS=$'\t' read -r uid avatar; do + [ -n "$avatar" ] || continue + if [[ "$avatar" =~ ^[0-9a-f]{64}$ ]]; then + echo "跳过 $uid:已是哈希命名($avatar)" + skipped=$((skipped + 1)) + continue + fi + src="$AVATAR_DIR/$avatar" + if [ ! -f "$src" ]; then + echo "跳过 $uid:磁盘文件缺失 $src(不影响 URL,仅提示)" + skipped=$((skipped + 1)) + continue + fi + hash=$(sha256sum "$src" | awk '{print $1}') + dst="$AVATAR_DIR/$hash" + if [ ! -f "$dst" ]; then + cp "$src" "$dst" + chown "$SVC_USER:$SVC_USER" "$dst" + fi + # 登记 files 行(幂等:同类型同哈希已存在则跳过)。 + mysqlq "INSERT INTO files (type, article_id, session_token, uploader_id, filename, stored_name, ext, mime, size, category, created_at, updated_at, deleted_at) + SELECT 'avatars', 0, '', $uid, '$avatar', '$hash', '.jpg', 'image/jpeg', $(stat -c%s "$src"), 'image', NOW(3), NOW(3), NULL + WHERE NOT EXISTS (SELECT 1 FROM files WHERE type='avatars' AND stored_name='$hash')" + mysqlq "UPDATE users SET avatar='$hash' WHERE id=$uid AND avatar='$avatar'" + rm -f "$src" + echo "迁移 $uid:$avatar -> $hash" + migrated=$((migrated + 1)) +done < <(mysqlq "SELECT id, avatar FROM users WHERE avatar <> ''") + +echo "完成:迁移 $migrated 个,跳过 $skipped 个。" -- 2.47.3