« 2020年03月 | (回到Blog入口)

2025年12月 归档

2025年12月16日

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;

按此阅读全文 "Movable Type 3.3 字符集乱码故障修复记录:" »

关于 2025年12月

此页面包含了在2025年12月发表于车东[Blog^2]的所有日记,它们从老到新列出。

前一个存档 2020年03月

更多信息可在 主索引 页和 归档 页看到。

Creative Commons License
此 Blog 中的日记遵循以下授权 Creative Commons(创作共用)授权.
Powered by
Movable Type 3.36