
在 php 中操作 rtf 文件时,直接插入 utf-8 编码的波兰语字符(如 `częstochowa`)会导致乱码,因为 rtf 格式不原生支持 utf-8;需将 unicode 字符转换为 rtf 兼容的 `\un?` 控制字格式,并确保文档声明正确的字符集。
RTF(Rich Text Format)是一种历史悠久的文档格式,其原生编码机制基于 ANSI(如 Windows-1252),不直接支持 UTF-8 字节流。当 PHP 以 UTF-8 读取并写入 RTF 内容时,若未按 RTF 规范对 Unicode 字符进行转义,Word 等编辑器会错误解析字节序列,表现为 CzÄ™stochowa 或 Czêstochowa 等乱码——这本质是编码映射失配所致。
✅ 正确做法:将 Unicode 字符转为 RTF 的 \uN? 格式
RTF 2.0+ 支持 Unicode 字符嵌入,语法为:
\uN?
其中 N 是该字符的 Unicode 码点十进制值(如 ę 的 Unicode 是 U+0142 → 十进制 322),? 是一个占位 ASCII 字符(通常用空格或 .,用于兼容旧解析器)。
因此,Częstochowa 中的 ę(U+0142)应写作 \u322?,完整字符串需逐字符转换。
立即学习“PHP免费学习笔记(深入)”;
但手动编码繁琐且易错。推荐使用以下健壮方案:
function utf8ToRtfUnicode($utf8String) {
$result = '';
for ($i = 0; $i < mb_strlen($utf8String, 'UTF-8'); $i++) {
$char = mb_substr($utf8String, $i, 1, 'UTF-8');
$code = mb_ord($char, 'UTF-8'); // PHP 7.2+,获取 Unicode 码点
if ($code <= 0xFFFF) {
$result .= sprintf('\u%d?', $code);
} else {
// 处理代理对(超出 BMP 的字符,如 emoji),此处可选
$result .= $char; // 或跳过/替换
}
}
return $result;
}
// 使用示例
$content = file_get_contents('template.rtf');
// 关键:确保原始 RTF 文件头部已声明 \ansicpg65001(UTF-8)或 \uc1 + \udff
// 若无,建议在 RTF 开头插入:{\rtf1\ansi\ansicpg65001\uc1\udff ...
$replaced = str_replace(
'[company_address]',
utf8ToRtfUnicode('Częstochowa'),
$content
);
file_put_contents('uploads/test.rtf', $replaced);⚠️ 重要前提:RTF 文件头部必须包含 \ansicpg65001(声明 UTF-8)和 \uc1(表示后续 \uN? 序列存在)、\udff(指定 Unicode 默认字体)。否则 Word 仍按 ANSI 解析。若原始 RTF 由 Word 保存,通常已含这些标记;若为手写 RTF,请检查并补全:{\rtf1\ansi\ansicpg65001\uc1\udff\deff0...
❌ 为什么原答案 mb_convert_encoding('Częstochowa', 'html') 不可靠?
原回答中:
$string = str_replace('', "\\u", mb_convert_encoding('Częstochowa', 'html'));该方法依赖 HTML 实体(如 ę → ł),再替换为 \u322?。但 mb_convert_encoding($str, 'HTML') 并非标准用法(PHP 文档未定义 'HTML' 为目标编码),实际行为因环境而异,不可移植、不推荐用于生产。且未处理多字节边界与 RTF 上下文,易引入额外转义错误。
✅ 最佳实践总结
- ✅ 始终以二进制模式读取 RTF(file_get_contents 默认满足);
- ✅ 使用 mb_ord() + sprintf('\u%d?', $code) 生成标准 \uN? 序列;
- ✅ 确保 RTF 头部含 \ansicpg65001\uc1\udff;
- ✅ 避免 mb_convert_encoding($str, 'UTF-8') 对 RTF 内容盲目转码——RTF 是混合文本/控制字格式,整体转 UTF-8 会破坏 \fonttbl 等 ANSI 结构;
- ✅ 替换后,用 Word 或 LibreOffice 验证渲染效果,而非仅看源码。
遵循以上步骤,即可稳定、准确地在 RTF 模板中注入含波兰语、捷克语等扩展拉丁字符的动态内容。











