一、故障背景
站点运行于 Movable Type 3.3,历史跨度较长(十年以上)。
在升级服务器环境(Perl 5.3 + 新版 MySQL / MariaDB)后,发现:
- 文章标题、分类、评论、TrackBack 出现乱码(如:安装笔记)
- 数据库表字符集显示为 utf8 / utf8mb3,但内容明显异常
- 后台管理界面:界面菜单正常,但博客各种内容部分都受中文乱码影响
二、问题本质分析(核心结论)
这是一个经典的历史字符集问题:
- 早期 MT 3.x + MySQL 常以
latin1 方式写入数据
- 实际内容是 UTF-8(甚至混有 GBK / GB2312)
- 后期 MySQL / Perl 按 UTF-8 读取,导致“UTF-8 被当 latin1 再显示”
修复原则:
- 不修改程序逻辑:尝试修改mt-config.cgi中配置增加
DBIParams mysql_enable_utf8=0
是没有用的,改用ObjectDriver DBI::MariaDB 但Movable Type 3.3根本不支持MariaDB驱动。
Got an error: Unsupported driver MT::ObjectDriver::DBI::MariaDB: Can't locate MT/ObjectDriver/DBI/MariaDB.pm in @INC (you may need to install the MT::ObjectDriver::DBI::MariaDB module) (@INC contains: /home/path/to/cgi-bin/mt/extlib lib /etc/perl /usr/local/lib/x86_64-linux-gnu/perl/5.34.0 /usr/local/share/perl/5.34.0 /usr/lib/x86_64-linux-gnu/perl5/5.34 /usr/share/perl5 /usr/lib/x86_64-linux-gnu/perl-base /usr/lib/x86_64-linux-gnu/perl/5.34 /usr/share/perl/5.34 /usr/local/lib/site_perl) at (eval 8) line 1. BEGIN failed--compilation aborted at (eval 8) line 1.
- 不整体强制转换数据库字符集
- 仅针对“人类可读字段”做字节级修复
- 修复前使用mysqldump或者phpmyadmin的工具备份数据库:mysqldump database_of_mt > mt_entry.bak.sql
四、通用修复方案(核心 SQL 模式)
统一采用以下安全转换模式:
CONVERT(
CAST(CONVERT(column_name USING latin1) AS BINARY)
USING utf8mb4
)
说明:
- latin1:还原历史错误解码
- BINARY:保留原始字节
- utf8mb4:以现代 UTF-8 重新解释
五、各主要数据表修复脚本
1. mt_entry(文章)
UPDATE mt_entry SET
entry_title = CONVERT(CAST(CONVERT(entry_title USING latin1) AS BINARY) USING utf8mb4),
entry_text = CONVERT(CAST(CONVERT(entry_text USING latin1) AS BINARY) USING utf8mb4),
entry_text_more = CONVERT(CAST(CONVERT(entry_text_more USING latin1) AS BINARY) USING utf8mb4),
entry_excerpt = CONVERT(CAST(CONVERT(entry_excerpt USING latin1) AS BINARY) USING utf8mb4),
entry_keywords = CONVERT(CAST(CONVERT(entry_keywords USING latin1) AS BINARY) USING utf8mb4);
2. mt_comment(评论)
UPDATE mt_comment SET
comment_author = CONVERT(CAST(CONVERT(comment_author USING latin1) AS BINARY) USING utf8mb4),
comment_text = CONVERT(CAST(CONVERT(comment_text USING latin1) AS BINARY) USING utf8mb4);
3. mt_category (分类目录) / mt_tag (标签)
UPDATE mt_category SET
category_label = CONVERT(CAST(CONVERT(category_label USING latin1) AS BINARY) USING utf8mb4),
category_description = CONVERT(CAST(CONVERT(category_description USING latin1) AS BINARY) USING utf8mb4);
UPDATE mt_tag SET
tag_name = CONVERT(CAST(CONVERT(tag_name USING latin1) AS BINARY) USING utf8mb4);
4. mt_template(模板)
UPDATE mt_template SET
template_name = CONVERT(CAST(CONVERT(template_name USING latin1) AS BINARY) USING utf8mb4),
template_text = CONVERT(CAST(CONVERT(template_text USING latin1) AS BINARY) USING utf8mb4);
5. mt_tbping(TrackBack ping)
UPDATE mt_tbping SET
tbping_blog_name = CONVERT(CAST(CONVERT(tbping_blog_name USING latin1) AS BINARY) USING utf8mb4),
tbping_title = CONVERT(CAST(CONVERT(tbping_title USING latin1) AS BINARY) USING utf8mb4),
tbping_excerpt = CONVERT(CAST(CONVERT(tbping_excerpt USING latin1) AS BINARY) USING utf8mb4),
tbping_junk_log = CONVERT(CAST(CONVERT(tbping_junk_log USING latin1) AS BINARY) USING utf8mb4);
6. mt_blog(博客信息)
UPDATE mt_blog SET
blog_name = CONVERT(CAST(CONVERT(blog_name USING latin1) AS BINARY) USING utf8mb4),
blog_description = CONVERT(CAST(CONVERT(blog_description USING latin1) AS BINARY) USING utf8mb4),
blog_welcome_msg = CONVERT(CAST(CONVERT(blog_welcome_msg USING latin1) AS BINARY) USING utf8mb4);
7. mt_author(作者)
仅修以下字段,严禁修改密码 / token 字段:
UPDATE mt_author SET
author_name = CONVERT(CAST(CONVERT(author_name USING latin1) AS BINARY) USING utf8mb4),
author_nickname = CONVERT(CAST(CONVERT(author_nickname USING latin1) AS BINARY) USING utf8mb4),
author_hint = CONVERT(CAST(CONVERT(author_hint USING latin1) AS BINARY) USING utf8mb4);
六、验证与验收
1. 乱码扫描
SELECT entry_id FROM mt_entry
WHERE entry_title REGEXP '[åæçéï]';
返回 0 行表示修复完成。
2. 随机抽样
SELECT entry_id, entry_title FROM mt_entry
ORDER BY RAND() LIMIT 10;
按此阅读全文 "Movable Type 3.3 字符集乱码故障修复记录:" »