- 后端
【免费下载链接】PHPWord
A pure PHP library for reading and writing word processing documents
本指南围绕 PHPWord 官方docs/howto.md的五大高频实战场景展开,为读者提供可直接复制运行的完整代码方案:让图片在段落中实现“左浮动”、将生成的 Word 文档直接输出到浏览器下载、为多级标题自动编号、在标题中嵌入超链接,以及移除 MS Word 标题栏中恼人的“[兼容模式]”提示。每个方案均结合当前仓库源码说明底层实现原理与参数细节,帮助读者在业务中快速落地。
1. 创建左浮动图片(Create float left image)
在文档正文中插入图片并让文字环绕其周围,是排版中的常见需求。PHPWord 通过设置图片样式中的定位与环绕属性来实现,核心思路是:水平方向采用“绝对定位、相对页边距”,垂直方向采用“相对当前行”定位,再配合square(正方形环绕)文字环绕方式。
<?php $imageStyle = array( 'width' => 40, 'height' => 40, 'wrappingStyle' => 'square', 'positioning' => 'absolute', 'posHorizontalRel' => 'margin', 'posVerticalRel' => 'line', ); $textrun->addImage(__DIR__ . '/resources/_earth.jpg', $imageStyle);其中$textrun是TextRun(文本运行)容器,可通过$section->addTextRun()创建;示例图片路径resources/_earth.jpg需替换为你实际的文件路径。
1.1 参数含义与可选值
在源码中,图片样式由 src/PhpWord/Style/Image.php 定义,其父类 src/PhpWord/Style/Frame.php 提供了完整的枚举常量,各参数可选值如下:
| 参数 | 作用 | 可选值(源码常量) |
|---|---|---|
width/height | 图片显示尺寸,单位为 pt(默认)或 px | 数值 |
wrappingStyle | 文字环绕方式 | inline、square、tight、through、topAndBottom、behind、infront |
positioning | 定位类型 | absolute、relative |
posHorizontalRel | 水平位置参考基准 | margin、page、column、char、left-margin-area、right-margin-area、inner-margin-area、outer-margin-area |
posVerticalRel | 垂直位置参考基准 | margin、page、text、line、top-margin-area、bottom-margin-area、inner-margin-area、outer-margin-area |
从 src/PhpWord/Style/Image.php 的构造函数可见,图片样式默认值为inline环绕、水平定位left(相对字符char)、垂直定位top(相对行line)。上面的示例正是通过覆盖这些默认值,实现“相对页边距水平绝对定位 + 相对行垂直定位”的左浮动效果。
1.2 其他可用定位参数
除文档给出的参数外,Frame 样式还支持以下高级选项,可组合出更精确的排版:
posHorizontal:水平对齐,取left、center、right、inside、outside或absolute;posVertical:垂直对齐,取top、center、bottom、inside、outside或absolute;marginTop/marginLeft:图片与其环绕文字的间距;wrapDistanceTop/wrapDistanceBottom/wrapDistanceLeft/wrapDistanceRight:四个方向上的文字环绕距离。
这些 setter 均定义于 src/PhpWord/Style/Frame.php,并通过setStyleByArray以数组键值方式批量传入,因此直接在$imageStyle数组中追加键即可。
2. 自动下载生成的文档(Download the produced file automatically)
当需要让用户直接下载 PHPWord 生成的文件(而非保存到服务器磁盘)时,将输出目标指定为 PHP 内置输出流php://output,配合 HTTP 响应头即可触发浏览器下载。
<?php $phpWord = new \PhpOffice\PhpWord\PhpWord(); $section = $phpWord->addSection(); $section->addText('Hello World!'); $file = 'HelloWorld.docx'; header("Content-Description: File Transfer"); header('Content-Disposition: attachment; filename="' . $file . '"'); header('Content-Type: application/vnd.openxmlformats-officedocument.wordprocessingml.document'); header('Content-Transfer-Encoding: binary'); header('Cache-Control: must-revalidate, post-check=0, pre-check=0'); header('Expires: 0'); $xmlWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, 'Word2007'); $xmlWriter->save("php://output");2.1 原理说明
IOFactory::createWriter($phpWord, 'Word2007')创建 Word 2007(OOXML .docx)格式的写入器,save("php://output")将生成的 ZIP 包直接写入输出缓冲区,不经由磁盘中转;- 五个
header()按 HTTP 规范告知浏览器这是一个名为HelloWorld.docx的二进制附件,其中Content-Type对应 OOXML 文档的官方 MIME 类型; - 完整的 MIME 类型列表可参考 src/PhpWord/Writer/Word2007/Part/ContentTypes.php。
2.2 应用前提与注意事项
- 该方案适用于任何由
IOFactory::createWriter支持的写入器,将Word2007替换为ODText、RTF、HTML、PDF或EPub3等即可输出对应格式(详见 docs/usage/writers.md); - 脚本中任何输出(包括 BOM、空行、调试信息)都必须出现在
header()之前,否则会触发“headers already sent”错误; - 内存中一次性生成文档对超大文档不友好,超大规模文档建议改用
$xmlWriter->save($path)保存到临时文件后配合readfile()输出。
3. 创建带编号的多级标题(Create numbered headings)
利用 PHPWord 的样式系统,可让文档标题自动带上“1”、“1.1”、“1.1.1”式的多级编号。实现分为三步:定义编号样式 → 定义各层级标题样式 → 将编号样式关联到标题样式。
<?php $phpWord->addNumberingStyle( 'hNum', array('type' => 'multilevel', 'levels' => array( array('pStyle' => 'Heading1', 'format' => 'decimal', 'text' => '%1'), array('pStyle' => 'Heading2', 'format' => 'decimal', 'text' => '%1.%2'), array('pStyle' => 'Heading3', 'format' => 'decimal', 'text' => '%1.%2.%3'), ) ) ); $phpWord->addTitleStyle(1, array('size' => 16), array('numStyle' => 'hNum', 'numLevel' => 0)); $phpWord->addTitleStyle(2, array('size' => 14), array('numStyle' => 'hNum', 'numLevel' => 1)); $phpWord->addTitleStyle(3, array('size' => 12), array('numStyle' => 'hNum', 'numLevel' => 2)); $section->addTitle('Heading 1', 1); $section->addTitle('Heading 2', 2); $section->addTitle('Heading 3', 3);3.1 参数拆解
addNumberingStyle('hNum', …):注册名为hNum的编号样式,type为multilevel(多级),levels数组中的每个元素对应一个层级:pStyle:该编号层级绑定的段落样式名(此处即标题样式Heading1/Heading2/Heading3);format:编号格式,decimal表示阿拉伯数字;src/PhpWord/SimpleType/NumberFormat.php 还定义了upperRoman、lowerRoman、upperLetter、lowerLetter、bullet等格式;text:编号的显示模板,%1、%2、%3分别代表第 1、2、3 级编号,组合%1.%2.%3即可呈现“1.1.1”式层级。
addTitleStyle(层级, 字体样式, 段落样式):注册标题样式,第三个参数中的numStyle指定上文编号样式名hNum,numLevel指定该标题对应编号层级(从 0 开始,因此 Heading1 为 0、Heading2 为 1、Heading3 为 2)。$section->addTitle('Heading 1', 1):以深度 1 添加标题元素,深度对应addTitleStyle的第一个参数。
3.2 底层原理
- 标题与编号的绑定最终体现在段落 XML 中。在 src/PhpWord/Writer/Word2007/Style/Paragraph.php 的
writeNumbering()方法中,numStyle与numLevel被转换为<w:numPr>节点中的<w:numId>与<w:ilvl>属性,并同时写出<w:outlineLvl>大纲级别; - 编号层级细节定义在 src/PhpWord/Style/NumberingLevel.php,每个层级支持
level(0~8,共 9 级)、start(起始值,默认 1)、format、restart等属性,可用addNumberingStyle的levels数组继续扩展; - 文档中所有
addTitleStyle、addNumberingStyle、addFontStyle等“add…Style”方法经由 src/PhpWord/PhpWord.php 的__call魔术方法分发到Style类统一注册,样式名在文档内全局唯一。
4. 在标题中加入超链接(Add a link within a title)
标题中直接嵌入可点击的超链接,做法是给链接所在的段落应用HeadingN段落样式。PHPWord 提供两种写法:在 TextRun 中混合文本与链接,以及直接添加链接元素并指定标题样式。
<?php $phpWord = new \PhpOffice\PhpWord\PhpWord(); $phpWord->addTitleStyle(1, array('size' => 16, 'bold' => true)); $phpWord->addTitleStyle(2, array('size' => 14, 'bold' => true)); $phpWord->addFontStyle('Link', array('color' => '0000FF', 'underline' => 'single')); $section = $phpWord->addSection(); // Textrun 方式:标题内混合普通文本与链接 $textrun = $section->addTextRun('Heading1'); $textrun->addText('The '); $textrun->addLink('https://github.com/PHPOffice/PHPWord', 'PHPWord', 'Link'); // Link 方式:链接元素直接使用标题样式 $section->addLink('https://github.com/', 'GitHub', 'Link', 'Heading2');4.1 两种写法对比
- TextRun 方式:
$section->addTextRun('Heading1')创建一个应用Heading1段落样式的文本运行容器,随后在容器内先addText加普通文本,再addLink加链接。链接的字体样式通过第三个参数指定为'Link',即上一步用addFontStyle('Link', …)注册的“蓝色 + 单下划线”样式; - Link 方式:
$section->addLink($target, $text, $fStyle, $pStyle)的第 4 个参数直接传入'Heading2',表示该链接段落套用二级标题样式,整行即成为一个可点击的标题。
两种方式可得到同样效果——标题层级由段落样式决定,而段落中的文字是否可点击由链接元素决定。
4.2 相关 API 签名
上述方法的参数签名定义于 src/PhpWord/Element/AbstractContainer.php 的 docblock:
addTextRun(mixed $pStyle = null):创建文本运行,参数为段落样式;addLink(string $target, string $text = null, mixed $fStyle = null, mixed $pStyle = null, boolean $internal = false):创建链接,第 5 个参数为true时表示文档内部链接(配合书签使用);addTitle(mixed $text, int $depth = 1, int $pageNumber = null):创建标题,depth对应标题层级。
5. 移除 MS Word 标题栏中的“[兼容模式]”提示(Remove [Compatibility Mode] text)
当用第三方库生成的 docx 以兼容模式打开时,MS Word 标题栏会显示“[兼容模式]”字样,观感不佳。PHPWord 通过Metadata\Compatibility对象设置文档的 OOXML 版本号,让 Word 以对应版本的完整模式打开文档。
<?php $phpWord->getCompatibility()->setOoxmlVersion(15);5.1 版本号与 Office 版本对照
setOoxmlVersion($n)的参数n对应文档目标 OOXML 版本:
| 值 | 对应 Office 版本 |
|---|---|
| 12 | Office 2007(默认) |
| 14 | Office 2010 |
| 15 | Office 2013 |
注:原始文档只列出 14(2010)与 15(2013);从 src/PhpWord/Metadata/Compatibility.php 源码可见其默认值为
12(Office 2007),可一并参考。
5.2 底层实现
Compatibility类位于 src/PhpWord/Metadata/Compatibility.php,setOoxmlVersion()仅做整型赋值,不校验取值范围,写入的值会直接体现在最终文档的兼容性设置中;$phpWord->getCompatibility()通过 src/PhpWord/PhpWord.php 返回PhpWord构造时预置的Compatibility实例(见 src/PhpWord/PhpWord.php),该对象与DocInfo、Settings一并作为文档元数据管理;- 实际写出时,该版本号由 src/PhpWord/Writer/Word2007/Part/Settings.php 渲染进
settings.xml中的兼容性节。设置合适的高版本号后,Word 将以对应版本的完整功能模式打开文档,从而消除“[兼容模式]”提示。
6. 实战组合示例
将上述技巧串联,可快速生成一个带编号标题、含浮动图片与链接、并能被浏览器直接下载的完整文档:
<?php require_once 'vendor/autoload.php'; use PhpOffice\PhpWord\PhpWord; use PhpOffice\PhpWord\IOFactory; $phpWord = new PhpWord(); $phpWord->getCompatibility()->setOoxmlVersion(15); // 多级编号标题 $phpWord->addNumberingStyle('hNum', [ 'type' => 'multilevel', 'levels' => [ ['pStyle' => 'Heading1', 'format' => 'decimal', 'text' => '%1'], ['pStyle' => 'Heading2', 'format' => 'decimal', 'text' => '%1.%2'], ['pStyle' => 'Heading3', 'format' => 'decimal', 'text' => '%1.%2.%3'], ], ]); $phpWord->addTitleStyle(1, ['size' => 16], ['numStyle' => 'hNum', 'numLevel' => 0]); $phpWord->addTitleStyle(2, ['size' => 14], ['numStyle' => 'hNum', 'numLevel' => 1]); $phpWord->addTitleStyle(3, ['size' => 12], ['numStyle' => 'hNum', 'numLevel' => 2]); $section = $phpWord->addSection(); $section->addTitle('Introduction', 1); $textrun = $section->addTextRun('Heading2'); $textrun->addText('The '); $textrun->addLink('https://github.com/PHPOffice/PHPWord', 'PHPWord', 'Link'); // 左浮动图片 $imageStyle = [ 'width' => 40, 'height' => 40, 'wrappingStyle' => 'square', 'positioning' => 'absolute', 'posHorizontalRel' => 'margin', 'posVerticalRel' => 'line', ]; $textrun->addImage(__DIR__ . '/earth.jpg', $imageStyle); // 输出下载 header('Content-Type: application/vnd.openxmlformats-officedocument.wordprocessingml.document'); header('Content-Disposition: attachment; filename="demo.docx"'); $writer = IOFactory::createWriter($phpWord, 'Word2007'); $writer->save('php://output');更完整的可运行示例还可参考仓库中的 samples/Sample_04_Textrun.php(文本运行与图片)、samples/Sample_13_Images.php(图片定位)、samples/Sample_15_Link.php(链接)与 samples/Sample_17_TitleTOC.php(标题与编号)。
总结
本文覆盖了docs/howto.md的五个高频场景:浮动图片的关键在于positioning+posHorizontalRel+posVerticalRel的组合定位;浏览器下载的关键在于php://output与正确的响应头;多级编号的关键在于addNumberingStyle与addTitleStyle之间通过numStyle/numLevel建立关联;标题内链接的关键在于让链接段落套用HeadingN样式;消除“[兼容模式]”的关键在于通过Metadata\Compatibility::setOoxmlVersion()声明目标 Office 版本。结合 src/PhpWord 源码中样式类、写入器与元数据类的实现,读者可依据本文示例直接落地到自己的业务代码中。
- 后端
【免费下载链接】PHPWord
A pure PHP library for reading and writing word processing documents
相关推荐
Minimal Mistakes 文章图片排版实战:用 `<figure>` + `capture` 实现"链接 + 标题"图片
Minimal Mistakes 文章图片排版实战:用 <figure + capture 实现"链接 + 标题"图片 导读 在 Minimal Mistake
前端静态站点【免费下载】 Obsidian 自动编号标题插件教程
Obsidian 自动编号标题插件教程 项目介绍 number headings obsidian 是一个为 Obsidian 笔记应用设计的插件,旨在自动为文
知识管理chezmoi `cat` 命令完全指南:将目标文件、脚本与符号链接内容输出到标准输出
chezmoi cat 命令完全指南:将目标文件、脚本与符号链接内容输出到标准输出 chezmoi cat 是 chezmoi 点文件管理器中最常用的预览命令之
开发工具CLI配置管理
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考