- 后端
【免费下载链接】PHPWord
A pure PHP library for reading and writing word processing documents
导读
PHPWord 是一套纯 PHP 读写 Word 文档的库,图片是其最常用的元素之一。本文以 docs/usage/elements/image.md 为核心,系统讲解addImage方法的五个参数、四种图像来源(本地文件、远程 URL、字符串二进制数据、压缩包内图像)、图像样式配置(尺寸、边距、环绕方式与定位),并结合仓库源码揭示其底层实现原理与安全边界。读完本文,你将能够在 Section、页眉、页脚、TextRun 和表格单元格中正确插入图片,并掌握防止文件读取与 SSRF 攻击的安全实践。
addImage 方法签名与五种参数
PHPWord 通过容器抽象类统一提供addImage方法,可用于Section(节)、Header(页眉)、Footer(页脚)、TextRun(文本流)、Cell(表格单元格)等容器。方法声明见 src/PhpWord/Element/AbstractContainer.php 的@method注解:
<?php $section->addImage($src, [$style], [$isWatermark], [$name], [$altText]);各参数含义如下:
| 参数 | 类型 | 说明 |
|---|---|---|
$src | string | 本地图片路径、远程图片 URL,或图片二进制数据(字符串)。安全警告:切勿传入用户可控的字符串,否则攻击者可通过传入文件路径或 URL 读取任意文件或发起服务端请求伪造(SSRF)。 |
$style | array | 图片样式数组,详见下文"图片样式选项",完整定义参见 docs/usage/styles/image.md。 |
$isWatermark | bool | 是否作为水印(页背景图)使用,由 Elements > Watermark 文档配套使用。 |
$name | string | 图片名称。 |
$altText | string | 图片的替代描述文本,供屏幕阅读器(无障碍访问)使用。 |
addImage最终通过容器基类的__call魔术方法与addElement反射机制实例化 src/PhpWord/Element/Image.php 中定义的Image元素(构造签名与上述五个参数一一对应),并校验容器合法性:Image被允许出现在Section、Header、Footer、Footnote、Endnote、Cell、TextRun、TextBox、ListItemRun、TrackChange等通用容器中(见 src/PhpWord/Element/AbstractContainer.php 的$validContainers定义)。
官方文档示例
<?php $section = $phpWord->addSection(); $section->addImage( 'mars.jpg', array( 'width' => 100, 'height' => 100, 'marginTop' => -1, 'marginLeft' => -1, 'wrappingStyle' => 'behind' ) ); $footer = $section->addFooter(); $footer->addImage('http://example.com/image.php'); $textrun = $section->addTextRun(); $textrun->addImage('http://php.net/logo.jpg', null, false, null, 'PHP logo'); $source = file_get_contents('/path/to/my/images/earth.jpg'); $image = $textrun->addImage($source);上述示例演示了三种典型用法:本地文件加环绕样式、页脚远程图片、TextRun 中的远程图片(带altText)以及字符串二进制数据。注意$textrun->addImage('http://php.net/logo.jpg', null, false, null, 'PHP logo')的传参顺序:$style=null、$isWatermark=false、$name=null、$altText='PHP logo'。
图像来源的四种类型与自动识别
在 src/PhpWord/Element/Image.php 的setSourceType()中,PHPWord 会根据$src内容自动判定图像来源类型,共四种:
| 来源类型 | 常量 | 触发条件 |
|---|---|---|
| 本地文件 | SOURCE_LOCAL | 字符串以.php结尾且非 GD 内存图时,字符串中不含空字符(chr(0))且file_exists()为真 |
| GD 内存图像 | SOURCE_GD | 字符串以.php结尾(通常是 PHP 脚本动态输出图片),或 URL 非 HTTPS 时按 GD 处理 |
| 压缩包内图像 | SOURCE_ARCHIVE | 字符串包含zip://前缀,格式为zip://$archive#$image |
| 字符串二进制数据 | SOURCE_STRING | 其他情况,包括file_get_contents()读取的二进制内容、HTTPS 远程图片内容等 |
其中 HTTPS URL 会被file_get_contents()拉取内容后转存为字符串数据(SOURCE_STRING),普通 HTTP URL 则走 GD 内存图像路径(SOURCE_GD),该分支需要 PHP 的GD 扩展支持(代码中显式检查extension_loaded('gd'),否则抛出RuntimeException,见 src/PhpWord/Element/Image.php)。
支持格式与校验流程
checkImage()方法(src/PhpWord/Element/Image.php)在构造时执行:
- 调用
getimagesize()/getimagesizefromstring()读取真实宽高与类型,失败则抛出InvalidImageException; - 校验类型:GD/字符串来源支持 JPEG、GIF、PNG;本地文件与压缩包来源额外支持 BMP、TIFF(
IMAGETYPE_TIFF_II/IMAGETYPE_TIFF_MM),其他格式抛出UnsupportedImageTypeException; - 按类型设置 MIME 类型、图像处理函数与扩展名(PNG 保留 alpha 通道,JPEG 默认质量 100,见
setFunctions())。
自动等比缩放
setProportionalSize()(src/PhpWord/Element/Image.php)实现比例补偿:若样式只指定了width或只指定了height,则按原图宽高比自动计算另一维;两者都未指定时使用原图实际尺寸。因此你通常只需给宽度即可保持图片不变形。
图片样式选项详解
图片样式的全部可用选项定义在 docs/usage/styles/image.md,底层由 src/PhpWord/Style/Image.php 继承自 src/PhpWord/Style/Frame.php 实现:
| 样式键 | 单位 | 说明 |
|---|---|---|
alignment | - | 水平对齐方式,取值见\PhpOffice\PhpWord\SimpleType\Jc类(src/PhpWord/SimpleType/Jc.php),如'center'、'left'、'right'、'both'等 |
width | pt | 宽度,单位为磅(pt) |
height | pt | 高度,单位为磅(pt) |
marginLeft | inch | 左边距,单位为英寸,可为负值 |
marginTop | inch | 上边距,单位为英寸,可为负值 |
wrappingStyle | - | 环绕方式:inline、square、tight、behind、infront |
wrapDistanceTop | px | 顶部文字环绕间距,单位为像素 |
wrapDistanceBottom | px | 底部文字环绕间距,单位为像素 |
wrapDistanceLeft | px | 左侧文字环绕间距,单位为像素 |
wrapDistanceRight | px | 右侧文字环绕间距,单位为像素 |
样式底层实现要点
从源码看,图片样式并非独立定义,而是对Frame框架样式的包装与向后兼容映射:
setMarginTop/setMarginLeft实际代理到Frame的top/left(见 src/PhpWord/Style/Image.php);setWrappingStyle代理到setWrap(src/PhpWord/Style/Image.php),合法的环绕值完整枚举在 src/PhpWord/Style/Frame.php:除文档列出的inline、square、tight、behind、infront外,源码还支持through(穿越)与topAndBottom(上下型)——但 docs/usage/styles/image.md 仅列出前五种,其余按未文档化特性对待;- 图片样式的默认单位是磅(
UNIT_PT),构造时默认inline环绕、水平左对齐(相对字符)、垂直顶端对齐(相对行),见 src/PhpWord/Style/Image.php; alignment通过Jc::isValid()校验后才写入(src/PhpWord/Style/Frame.php)。
环绕与定位在 OOXML 中的落地
Word2007 写入器将上述样式转换为 DrawingML 的style属性与w10:wrap节点(src/PhpWord/Writer/Word2007/Style/Frame.php):
- 尺寸与边距映射为
width、height、margin-left、margin-top(带单位后缀); - 环绕距离映射为
mso-wrap-distance-top/bottom/left/right; behind环绕被转换为 z-index 为-2147483647,infront转换为+2147483647,以实现置底/置顶分层;- 定位映射为
position、mso-position-horizontal、mso-position-vertical及其 relative 系列; w10:wrap节点还会根据positioning(absolute/relative)写出anchorx/anchory锚点属性。
当图片作为水印时($element->isWatermark()),写入器强制设置positioning=absolute并走独立的水印段落分支(见 src/PhpWord/Writer/Word2007/Element/Image.php)。
完整可运行示例
结合仓库自带的官方示例 samples/Sample_13_Images.php,可看到更贴近实战的写法。该示例覆盖:无样式本地图片、带宽度/高度/居中对齐的本地图片、远程图片、字符串图片、五种环绕样式对比、绝对定位与相对定位。其关键代码片段:
<?php use PhpOffice\PhpWord\Shared\Converter; // 本地图片 + 样式 $section->addImage(__DIR__ . '/resources/_earth.jpg', ['width' => 210, 'height' => 210, 'alignment' => PhpOffice\PhpWord\SimpleType\Jc::CENTER]); // 远程图片 $section->addImage('http://php.net/images/logos/php-med-trans-light.gif'); // 字符串图片 $fileContent = file_get_contents(__DIR__ . '/resources/_mars.jpg'); $section->addImage($fileContent); // 环绕样式 + 厘米转磅 $section->addImage( __DIR__ . '/resources/_earth.jpg', [ 'positioning' => 'relative', 'marginTop' => -1, 'marginLeft' => 1, 'width' => 80, 'height' => 80, 'wrappingStyle' => $wrappingStyle, // inline / behind / infront / square / tight 'wrapDistanceRight' => Converter::cmToPoint(1), 'wrapDistanceBottom' => Converter::cmToPoint(1), ] ); // 绝对定位到页面右上角 $section->addImage( __DIR__ . '/resources/_mars.jpg', [ 'width' => Converter::cmToPixel(3), 'height' => Converter::cmToPixel(3), 'positioning' => PhpOffice\PhpWord\Style\Image::POSITION_ABSOLUTE, 'posHorizontal' => PhpOffice\PhpWord\Style\Image::POSITION_HORIZONTAL_RIGHT, 'posHorizontalRel' => PhpOffice\PhpWord\Style\Image::POSITION_RELATIVE_TO_PAGE, 'posVerticalRel' => PhpOffice\PhpWord\Style\Image::POSITION_RELATIVE_TO_PAGE, 'marginLeft' => Converter::cmToPixel(15.5), 'marginTop' => Converter::cmToPixel(1.55), ] );示例中使用PhpOffice\PhpWord\Shared\Converter完成厘米到磅/像素的单位换算(cmToPoint、cmToPixel),也说明marginTop/marginLeft可以取负值实现图片微调位移。定位相关的常量定义在 src/PhpWord/Style/Image.php 的向后兼容常量中(如POSITION_ABSOLUTE、POSITION_HORIZONTAL_RIGHT、POSITION_RELATIVE_TO_PAGE、POSITION_VERTICAL_TOP、POSITION_RELATIVE_TO_LINE等),完整的定位取值与"相对于"枚举可参见 src/PhpWord/Style/Frame.php。
水印图片:isWatermark 参数
当$isWatermark为true时,图片被当作页背景水印处理。使用前提是Section 必须先有页眉引用,然后通过Header的addWatermark快捷方法添加(src/PhpWord/Element/Header.php 内部即调用addImage($src, $style, true)):
<?php $section = $phpWord->addSection(); $header = $section->addHeader(); $header->addWatermark('resources/_earth.jpg', array('marginTop' => 200, 'marginLeft' => 55));完整说明见 Elements > Watermark。写入 ODText 时,水印图被保留在节的主页眉(master page header)中,作为页锚定的绘图框(drawing frame),并携带其尺寸与边距;ODF 主页面页眉提供类似原生背景的放置效果,但 WordprocessingML 的分层语义无法在 ODF 消费者之间完全移植。
安全注意事项与最佳实践
文档在$src参数处给出了明确的安全警告:不要将用户生成的字符串直接传给addImage。其风险链条可以从源码推演:
setSourceType()会执行file_exists($this->source)与filter_var($this->source, FILTER_VALIDATE_URL)判定(src/PhpWord/Element/Image.php);- 若攻击者传入
/etc/passwd之类的路径,图片会被当成本地文件读取;若传入http://内网地址/之类的 URL,会触发服务端请求伪造(SSRF)——HTTPS URL 会被file_get_contents()直接拉取,GD 分支也会对资源发起请求。
因此实践上应遵循:
- 只接受经你校验过的受信来源(如应用上传目录内、经
getimagesize()校验过的文件),而非直接透传用户输入; - 若必须接受用户上传,先解码并验证 MIME 类型与文件内容,再存入受控目录,之后以服务器端路径调用
addImage; - 不要构造以用户输入拼接的
zip://路径(该来源会将压缩包内条目解压到临时目录后读取)。
读写联动:图片如何被保存
图片的媒体资源在文档保存时统一处理。Image元素实现了getImageString()(src/PhpWord/Element/Image.php)来提取图片二进制:本地/字符串来源直接读二进制,GD 来源通过imagepng/imagejpeg/imagegif回调输出,压缩包来源则先从zip://解压到Settings::getTempDir()临时目录再读取。getImageStringData($base64)提供 hex 或 base64 两种编码输出(src/PhpWord/Element/Image.php)。此外,getMediaId()返回md5($source)作为媒体去重标识(src/PhpWord/Element/Image.php),写入时会通过关系 ID(rId)把图片关联到文档包内。
相关文档导航
- 样式完整参考:Styles > Image
- 水印场景:Elements > Watermark
- 文字环绕示例与更多元素:samples/Sample_13_Images.php
- 图片元素测试:tests/PhpWordTests/Element/ImageTest.php
- 从 Word2007 读取图片的实现参考:src/PhpWord/Reader/Word2007/AbstractPart.php
- 后端
【免费下载链接】PHPWord
A pure PHP library for reading and writing word processing documents
相关推荐
实战指南:如何用Google Generative AI构建智能餐饮解决方案的三大核心模块
实战指南:如何用Google Generative AI构建智能餐饮解决方案的三大核心模块 在数字化转型浪潮中,餐饮行业面临着菜单设计效率低下、客户服务体验不足
示例工程人工智能大模型Duende.IdentityServer.Admin高级技巧:自定义主题、审计日志与数据保护
Duende.IdentityServer.Admin高级技巧:自定义主题、审计日志与数据保护 Duende.IdentityServer.Admin是一款强大
后端前端认证鉴权单点登录Sunshine游戏串流服务器:打造你的终极跨平台游戏娱乐系统
Sunshine游戏串流服务器:打造你的终极跨平台游戏娱乐系统 你是否曾经希望将高性能PC游戏带到家中的任何角落?无论是客厅的智能电视、卧室的平板电脑,还是出差
后端
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考