php不原生支持RTF字体解析,需手动提取fonttbl中fN定义及分号前的字体名,注意编码转换与Unicode转义,或使用rtf-html-php等现成解析器。

PHP 本身不原生支持 RTF 文件解析,更不会直接提取字体信息;要读取 RTF 中的字体(如 f0fswiss Helvetica、f1froman Times New Roman),需手动解析 RTF 控制字。核心思路是:**跳过控制符和组结构,提取 fN 定义及后续的字体名称声明(fNfname 或 fNfroman 等)**。
理解 RTF 字体定义的基本结构
RTF 中字体通过 fonttbl 控制字定义,格式类似:
{fonttbl{f0fswissfcharset0 Helvetica;}{f1fromanfcharset0 Times New Roman;}}
关键点:
-
f0、f1是字体 ID,用于正文中标记(如f0fs24 Hello) -
fswiss、froman是字体族标识(非名称),实际名称在分号前,如Helvetica、Times New Roman - 字体名可能含空格、括号或 Unicode 转义(如
'e9表示 é),需按 RTF 规则解码
用正则 + 状态机粗略提取字体表
适用于格式规范、无嵌套错误的 RTF(如 word 生成的基础文档)。不依赖外部库,轻量可行:
立即学习“PHP免费学习笔记(深入)”;
- 先用
file_get_contents()读取文件,确保编码为 ANSI 或 UTF-8(RTF 头部ansicpg936等提示代码页) - 用正则定位
fonttbl{...}区域(注意大括号嵌套,建议用简单匹配+栈模拟,或用preg_match('/\\fonttbl{([^}]*)}/i', $rtf, $matches)初筛) - 对匹配内容逐字符解析:识别
fd+后紧跟的f[swiss|roman|modern|...]或直接字体名(直到分号或空格) - 示例片段提取逻辑:
$pattern = '/\\f(d+)\\f[^;]+?\\fcharsetd+s+([^;]+);/i'; preg_match_all($pattern, $fonttbl_content, $fonts); $fontMap = array_combine($fonts[1], array_map('trim', $fonts[2])); // ['0'=>'Helvetica', '1'=>'Times New Roman']
处理中文与编码问题
中文 RTF 常用 ansicpg936(GBK)或 uc1 + Unicode 转义('e4')。PHP 读取后需:
- 检查 RTF 头部
ansicpg值,用mb_convert_encoding($text, 'UTF-8', 'GBK')转换(若为 936) - 替换 Unicode 转义:
preg_replace_callback("/'([0-9a-fA-F]{2})/", function($m) { return mb_chr(hexdec($m[1]), 'UTF-8'); }, $str) - 字体名中若含
'(撇号)或,需在正则中转义或预清理
更稳方案:用现成解析器(推荐)
手工解析易出错,尤其面对复杂格式。可考虑:
- rtf-html–php(gitHub 开源):将 RTF 转 HTML,再用 dom 解析
或内联样式 - PHPWord:支持读取部分 RTF(需开启扩展),通过
PhpWordReaderRTF获取段落样式,间接推断字体 - 调用系统命令(linux/macOS):
unrtf --text或catdoc提取纯文本,但会丢失字体信息——仅适合不需要字体的场景