Movable Type 3.3 字符集乱码故障修复记录:


一、故障背景

站点运行于 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

三、诊断方法

1. 典型乱码特征

å  æ  ç  é  ï  ï¼š

以上字符几乎可以 100% 判定为 UTF-8 被当作 latin1 显示。

2. 抽样检测 SQL

SELECT entry_id, entry_title
FROM mt_entry
WHERE entry_title REGEXP '[åæçéï]';

返回结果即为待修复数据。

四、通用修复方案(核心 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;

七、关于 Warning #1300 的说明

修复过程中可能出现大量:

Warning: #1300 Invalid utf8mb4 character string

这通常意味着:

  • 历史数据中混有 GBK / GB2312 或垃圾字节
  • 不影响前台显示
  • 可安全忽略

八、最终建议

  • 不要再次整体转换表字符集
  • 不要尝试一键 CONVERT DATABASE
  • 完成修复后立即做完整备份

至此,Movable Type 3.3 字符集乱码问题修复完成。

作者:车东 发表于:2025-12-16 11:12 最后更新于:2025-12-16 12:12
版权声明:可以转载,转载时请务必以超链接形式标明文章 的原始出处和作者信息及本版权声明

发表一个评论

(如果你此前从未在此 Blog 上发表过评论,则你的评论必须在 Blog 主人验证后才能显示,请你耐心等候。)