Python修复WordPress站点迁移后中文名附件无法显示问题的小工具
在上一片帖子中,我向 V 友们请教了如何解决压缩文档导致文件名编码错误,从而使 WordPress 中文名附件无法正常被加载的问题(当时我在站点迁移之后出现站内图片大量 404 的情况)。
大家的建议都很好: 不应该使用中文附件名;压缩站点应该使用 tar 而不是 zip 等等,我受益匪浅。但站点图片 404 的问题一直都没能够解决。
之后有一天在 Google 上找到一片文章( Git 上有原文链接,这里就不放了),通过修改文件名以及数据库中文件名记录来修复这个问题。作者也提供了一个工具,但是很遗憾,我试了 4 台电脑,都没能成功运行(运行中出错)。
于是今天闲下来就用 Python 重写了一遍这个工具,并且发到了 Git 上。希望对大家能有用。同时也感谢原作者 WP 大学的 @木子 提供的思路。
Github 地址: https://github.com/guiqiqi/WPChineseAttachFix
祝大家使用愉快 O(∩_∩)O~~
Python修复WordPress站点迁移后中文名附件无法显示问题的小工具
这个问题我遇到过,WordPress迁移后中文附件不显示,主要是因为文件名编码问题。Windows服务器用GBK,Linux用UTF-8,迁移时文件名没正确转换就会404。
核心解决思路:遍历数据库附件记录,把中文文件名从UTF-8转成GBK(或反向),同时重命名服务器上的实际文件。
下面这个工具直接拿去用:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
WordPress中文附件修复工具
用于解决站点从Windows迁移到Linux(或反向)后中文名附件无法访问的问题
"""
import pymysql
import os
import sys
from urllib.parse import unquote
class WordPressAttachmentFixer:
def __init__(self, db_config):
"""
初始化数据库连接
:param db_config: 字典,包含host, user, password, database
"""
self.conn = pymysql.connect(**db_config)
self.cursor = self.conn.cursor()
def get_attachments_with_chinese(self):
"""获取所有包含中文字符的附件记录"""
query = """
SELECT post_id, meta_value
FROM wp_postmeta
WHERE meta_key = '_wp_attached_file'
AND meta_value REGEXP '[\\x{4e00}-\\x{9fa5}]'
"""
self.cursor.execute(query)
return self.cursor.fetchall()
def convert_filename_encoding(self, filename, from_encoding='utf-8', to_encoding='gbk'):
"""
转换文件名编码
:param filename: 原始文件名(URL解码后的)
:param from_encoding: 当前编码
:param to_encoding: 目标编码
:return: (转换后的文件名, 是否需要重命名文件)
"""
try:
# URL解码
decoded = unquote(filename)
# 如果已经是目标编码,直接返回
try:
decoded.encode(to_encoding)
return decoded, False
except:
pass
# 转换编码
if from_encoding.lower() == 'utf-8' and to_encoding.lower() == 'gbk':
# UTF-8 -> GBK
converted = decoded.encode('utf-8').decode('gbk', errors='ignore')
elif from_encoding.lower() == 'gbk' and to_encoding.lower() == 'utf-8':
# GBK -> UTF-8
converted = decoded.encode('gbk').decode('utf-8', errors='ignore')
else:
return decoded, False
return converted, converted != decoded
except Exception as e:
print(f"编码转换失败 {filename}: {e}")
return filename, False
def update_database_record(self, post_id, new_filename):
"""更新数据库中的附件记录"""
update_query = """
UPDATE wp_postmeta
SET meta_value = %s
WHERE meta_key = '_wp_attached_file'
AND post_id = %s
"""
self.cursor.execute(update_query, (new_filename, post_id))
self.conn.commit()
def rename_physical_file(self, wp_content_path, old_path, new_path):
"""重命名服务器上的物理文件"""
old_full = os.path.join(wp_content_path, 'uploads', old_path)
new_full = os.path.join(wp_content_path, 'uploads', new_path)
# 创建目标目录(如果需要)
os.makedirs(os.path.dirname(new_full), exist_ok=True)
if os.path.exists(old_full):
os.rename(old_full, new_full)
print(f"文件重命名: {old_path} -> {new_path}")
return True
else:
print(f"文件不存在: {old_full}")
return False
def fix_attachments(self, wp_content_path, from_encoding='utf-8', to_encoding='gbk'):
"""
主修复函数
:param wp_content_path: WordPress的wp-content目录绝对路径
:param from_encoding: 当前文件名编码
:param to_encoding: 目标编码
"""
attachments = self.get_attachments_with_chinese()
print(f"找到 {len(attachments)} 个中文附件需要处理")
fixed_count = 0
for post_id, filepath in attachments:
print(f"\n处理附件 ID {post_id}: {filepath}")
# 转换文件名编码
new_filename, need_rename = self.convert_filename_encoding(
filepath, from_encoding, to_encoding
)
if need_rename:
# 更新数据库
self.update_database_record(post_id, new_filename)
# 重命名物理文件
if self.rename_physical_file(wp_content_path, filepath, new_filename):
fixed_count += 1
print(f"✓ 已修复: {filepath}")
else:
print(f"✗ 文件重命名失败")
else:
print(f"- 无需处理")
print(f"\n处理完成!共修复 {fixed_count} 个附件")
def close(self):
"""关闭数据库连接"""
self.cursor.close()
self.conn.close()
# 使用示例
if __name__ == "__main__":
# 配置参数(根据实际情况修改)
DB_CONFIG = {
'host': 'localhost',
'user': 'your_db_user',
'password': 'your_db_password',
'database': 'your_db_name',
'charset': 'utf8mb4'
}
# WordPress的wp-content目录绝对路径
WP_CONTENT_PATH = '/var/www/html/wp-content'
# 编码转换方向(根据迁移方向选择)
# 从Linux迁移到Windows: from_encoding='utf-8', to_encoding='gbk'
# 从Windows迁移到Linux: from_encoding='gbk', to_encoding='utf-8'
fixer = WordPressAttachmentFixer(DB_CONFIG)
try:
# 示例:从Windows迁移到Linux(GBK -> UTF-8)
fixer.fix_attachments(
wp_content_path=WP_CONTENT_PATH,
from_encoding='gbk',
to_encoding='utf-8'
)
finally:
fixer.close()
使用步骤:
- 修改脚本中的数据库配置和wp-content路径
- 根据迁移方向设置编码转换方向
- 先备份数据库和wp-content/uploads目录
- 运行脚本:
python fix_attachments.py
注意: 如果附件在媒体库有多个尺寸,还需要处理_wp_attachment_metadata中的记录,上面的脚本可以扩展这个功能。
一句话建议:先备份再操作,根据迁移方向选对编码转换参数。

