Files
go_blog/scripts/migrate_legacy_avatars.sh
T
dsh ae59f756ca chore: 存量头像迁移脚本——旧命名 <uid>.jpg 迁入统一 files 表(type=avatars)
其他部署升级到统一上传引擎后,历史头像仍以 <uid>.jpg 命名且未在 files 表
登记,直到所有者下次换头像才被清理。本脚本提供一次性迁移:
内容字节不变,以 SHA-256 哈希命名复制到 avatars/,登记 files 行
(type=avatars),更新 users.avatar,删除旧文件。
幂等:已为 64 位哈希名的用户自动跳过;无遗留文件时无操作。
已在线上库实测(2 个用户全部跳过)。
2026-08-28 20:22:35 +08:00

73 lines
3.0 KiB
Bash
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env bash
# 存量头像迁移:把旧命名(<uid>.jpg,历史方案)的用户头像迁入统一 files 表
# type='avatars')并用 SHA-256 哈希命名(公开链接 /uploads/avatars/<哈希>)。
#
# 背景:头像上传自 2026-08 起走统一上传引擎(files 表 + 内容寻址);历史头像
# 文件仍以 <uid>.jpg 命名、未被 files 表登记。本脚本按用户逐个迁移:
# 1. 取头像文件内容 SHA-256 作为新存储名(内容字节不变,不重新编码);
# 2. 复制为 avatars/<哈希> 并登记 files 行(type=avatars);
# 3. 更新 users.avatar
# 4. 删除旧的 <uid>.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 个。"