phpword 模板替换文字和图片
个人建议使用composer下载phpword
找到phpword/src/PhpWord/TemplateProcessor.php 修改为
<?php /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. * * PHPWord is free software distributed under the terms of the GNU Lesser * General Public License version 3 as published by the Free Software Foundation. * * For the full copyright and license information, please read the LICENSE * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord; use PhpOffice\PhpWord\Escaper\RegExp; use PhpOffice\PhpWord\Escaper\Xml; use PhpOffice\PhpWord\Exception\CopyFileException; use PhpOffice\PhpWord\Exception\CreateTemporaryFileException; use PhpOffice\PhpWord\Exception\Exception; use PhpOffice\PhpWord\Shared\ZipArchive; use Zend\Stdlib\StringUtils; class TemplateProcessor { const MAXIMUM_REPLACEMENTS_DEFAULT = -1; /** * ZipArchive object. * * @var mixed */ protected $zipClass; /** * @var string Temporary document filename (with path). */ protected $tempDocumentFilename; /** * Content of main document part (in XML format) of the temporary document. * * @var string */ protected $tempDocumentMainPart; /** * Content of headers (in XML format) of the temporary document. * * @var string[] */ protected $tempDocumentHeaders = array(); /** * Content of footers (in XML format) of the temporary document. * * @var string[] */ protected $tempDocumentFooters = array(); protected $_rels; protected $_types; /** * @since 0.12.0 Throws CreateTemporaryFileException and CopyFileException instead of Exception. * * @param string $documentTemplate The fully qualified template filename. * * @throws \PhpOffice\PhpWord\Exception\CreateTemporaryFileException * @throws \PhpOffice\PhpWord\Exception\CopyFileException */ public function __construct($documentTemplate) { $this->_countRels=100; // Temporary document filename initialization $this->tempDocumentFilename = tempnam(Settings::getTempDir(), 'PhpWord'); if (false === $this->tempDocumentFilename) { throw new CreateTemporaryFileException(); } // Template file cloning if (false === copy($documentTemplate, $this->tempDocumentFilename)) { throw new CopyFileException($documentTemplate, $this->tempDocumentFilename); } // Temporary document content extraction $this->zipClass = new ZipArchive(); $this->zipClass->open($this->tempDocumentFilename); $index = 1; while (false !== $this->zipClass->locateName($this->getHeaderName($index))) { $this->tempDocumentHeaders[$index] = $this->fixBrokenMacros( $this->zipClass->getFromName($this->getHeaderName($index)) ); $index++; } $index = 1; while (false !== $this->zipClass->locateName($this->getFooterName($index))) { $this->tempDocumentFooters[$index] = $this->fixBrokenMacros( $this->zipClass->getFromName($this->getFooterName($index)) ); $index++; } $this->tempDocumentMainPart = $this->fixBrokenMacros($this->zipClass->getFromName($this->getMainPartName())); } /** * @param string $xml * @param \XSLTProcessor $xsltProcessor * * @return string * * @throws \PhpOffice\PhpWord\Exception\Exception */ protected function transformSingleXml($xml, $xsltProcessor) { $domDocument = new \DOMDocument(); if (false === $domDocument->loadXML($xml)) { throw new Exception('Could not load the given XML document.'); } $transformedXml = $xsltProcessor->transformToXml($domDocument); if (false === $transformedXml) { throw new Exception('Could not transform the given XML document.'); } return $transformedXml; } /** * @param mixed $xml * @param \XSLTProcessor $xsltProcessor * * @return mixed */ protected function transformXml($xml, $xsltProcessor) { if (is_array($xml)) { foreach ($xml as &$item) { $item = $this->transformSingleXml($item, $xsltProcessor); } } else { $xml = $this->transformSingleXml($xml, $xsltProcessor); } return $xml; } /** * Applies XSL style sheet to template's parts. * * Note: since the method doesn't make any guess on logic of the provided XSL style sheet, * make sure that output is correctly escaped. Otherwise you may get broken document. * * @param \DOMDocument $xslDomDocument * @param array $xslOptions * @param string $xslOptionsUri * * @return void * * @throws \PhpOffice\PhpWord\Exception\Exception */ public function applyXslStyleSheet($xslDomDocument, $xslOptions = array(), $xslOptionsUri = '') { $xsltProcessor = new \XSLTProcessor(); $xsltProcessor->importStylesheet($xslDomDocument); if (false === $xsltProcessor->setParameter($xslOptionsUri, $xslOptions)) { throw new Exception('Could not set values for the given XSL style sheet parameters.'); } $this->tempDocumentHeaders = $this->transformXml($this->tempDocumentHeaders, $xsltProcessor); $this->tempDocumentMainPart = $this->transformXml($this->tempDocumentMainPart, $xsltProcessor); $this->tempDocumentFooters = $this->transformXml($this->tempDocumentFooters, $xsltProcessor); } /** * @param string $macro * * @return string */ protected static function ensureMacroCompleted($macro) { if (substr($macro, 0, 2) !== '${' && substr($macro, -1) !== '}') { $macro = '${' . $macro . '}'; } return $macro; } /** * @param string $subject * * @return string */ protected static function ensureUtf8Encoded($subject) { if (!StringUtils::isValidUtf8($subject)) { $subject = utf8_encode($subject); } return $subject; } /** * @param mixed $search * @param mixed $replace * @param integer $limit * * @return void */ public function setValue($search, $replace, $limit = self::MAXIMUM_REPLACEMENTS_DEFAULT) { if (is_array($search)) { foreach ($search as &$item) { $item = self::ensureMacroCompleted($item); } } else { $search = self::ensureMacroCompleted($search); } if (is_array($replace)) { foreach ($replace as &$item) { $item = self::ensureUtf8Encoded($item); } } else { $replace = self::ensureUtf8Encoded($replace); } if (Settings::isOutputEscapingEnabled()) { $xmlEscaper = new Xml(); $replace = $xmlEscaper->escape($replace); } $this->tempDocumentHeaders = $this->setValueForPart($search, $replace, $this->tempDocumentHeaders, $limit); $this->tempDocumentMainPart = $this->setValueForPart($search, $replace, $this->tempDocumentMainPart, $limit); $this->tempDocumentFooters = $this->setValueForPart($search, $replace, $this->tempDocumentFooters, $limit); } /** * Returns array of all variables in template. * * @return string[] */ public function getVariables() { $variables = $this->getVariablesForPart($this->tempDocumentMainPart); foreach ($this->tempDocumentHeaders as $headerXML) { $variables = array_merge($variables, $this->getVariablesForPart($headerXML)); } foreach ($this->tempDocumentFooters as $footerXML) { $variables = array_merge($variables, $this->getVariablesForPart($footerXML)); } return array_unique($variables); } /** * Clone a table row in a template document. * * @param string $search * @param integer $numberOfClones * * @return void * * @throws \PhpOffice\PhpWord\Exception\Exception */ public function cloneRow($search, $numberOfClones) { if ('${' !== substr($search, 0, 2) && '}' !== substr($search, -1)) { $search = '${' . $search . '}'; } $tagPos = strpos($this->tempDocumentMainPart, $search); if (!$tagPos) { throw new Exception("Can not clone row, template variable not found or variable contains markup."); } $rowStart = $this->findRowStart($tagPos); $rowEnd = $this->findRowEnd($tagPos); $xmlRow = $this->getSlice($rowStart, $rowEnd); // Check if there's a cell spanning multiple rows. if (preg_match('#<w:vMerge w:val="restart"/>#', $xmlRow)) { // $extraRowStart = $rowEnd; $extraRowEnd = $rowEnd; while (true) { $extraRowStart = $this->findRowStart($extraRowEnd + 1); $extraRowEnd = $this->findRowEnd($extraRowEnd + 1); // If extraRowEnd is lower then 7, there was no next row found. if ($extraRowEnd < 7) { break; } // If tmpXmlRow doesn't contain continue, this row is no longer part of the spanned row. $tmpXmlRow = $this->getSlice($extraRowStart, $extraRowEnd); if (!preg_match('#<w:vMerge/>#', $tmpXmlRow) && !preg_match('#<w:vMerge w:val="continue" />#', $tmpXmlRow)) { break; } // This row was a spanned row, update $rowEnd and search for the next row. $rowEnd = $extraRowEnd; } $xmlRow = $this->getSlice($rowStart, $rowEnd); } $result = $this->getSlice(0, $rowStart); for ($i = 1; $i <= $numberOfClones; $i++) { $result .= preg_replace('/\$\{(.*?)\}/', '\${\\1#' . $i . '}', $xmlRow); } $result .= $this->getSlice($rowEnd); $this->tempDocumentMainPart = $result; } /** * Clone a block. * * @param string $blockname * @param integer $clones * @param boolean $replace * * @return string|null */ public function cloneBlock($blockname, $clones = 1, $replace = true) { $xmlBlock = null; preg_match( '/(<\?xml.*)(<w:p.*>\${' . $blockname . '}<\/w:.*?p>)(.*)(<w:p.*\${\/' . $blockname . '}<\/w:.*?p>)/is', $this->tempDocumentMainPart, $matches ); if (isset($matches[3])) { $xmlBlock = $matches[3]; $cloned = array(); for ($i = 1; $i <= $clones; $i++) { $cloned[] = $xmlBlock; } if ($replace) { $this->tempDocumentMainPart = str_replace( $matches[2] . $matches[3] . $matches[4], implode('', $cloned), $this->tempDocumentMainPart ); } } return $xmlBlock; } /** * Replace a block. * * @param string $blockname * @param string $replacement * * @return void */ public function replaceBlock($blockname, $replacement) { preg_match( '/(<\?xml.*)(<w:p.*>\${' . $blockname . '}<\/w:.*?p>)(.*)(<w:p.*\${\/' . $blockname . '}<\/w:.*?p>)/is', $this->tempDocumentMainPart, $matches ); if (isset($matches[3])) { $this->tempDocumentMainPart = str_replace( $matches[2] . $matches[3] . $matches[4], $replacement, $this->tempDocumentMainPart ); } } /** * Delete a block of text. * * @param string $blockname * * @return void */ public function deleteBlock($blockname) { $this->replaceBlock($blockname, ''); } /** * Saves the result document. * * @return string * * @throws \PhpOffice\PhpWord\Exception\Exception */ public function save() { foreach ($this->tempDocumentHeaders as $index => $xml) { $this->zipClass->addFromString($this->getHeaderName($index), $xml); } $this->zipClass->addFromString($this->getMainPartName(), $this->tempDocumentMainPart); if($this->_rels!="") { $this->zipClass->addFromString('word/_rels/document.xml.rels', $this->_rels); } if($this->_types!="") { $this->zipClass->addFromString('[Content_Types].xml', $this->_types); } foreach ($this->tempDocumentFooters as $index => $xml) { $this->zipClass->addFromString($this->getFooterName($index), $xml); } // Close zip file if (false === $this->zipClass->close()) { throw new Exception('Could not close zip file.'); } return $this->tempDocumentFilename; } /** * Saves the result document to the user defined file. * * @since 0.8.0 * * @param string $fileName * * @return void */ public function saveAs($fileName) { $tempFileName = $this->save(); if (file_exists($fileName)) { unlink($fileName); } /* * Note: we do not use `rename` function here, because it looses file ownership data on Windows platform. * As a result, user cannot open the file directly getting "Access denied" message. * * @see https://github.com/PHPOffice/PHPWord/issues/532 */ copy($tempFileName, $fileName); unlink($tempFileName); } /** * Finds parts of broken macros and sticks them together. * Macros, while being edited, could be implicitly broken by some of the word processors. * * @param string $documentPart The document part in XML representation. * * @return string */ protected function fixBrokenMacros($documentPart) { $fixedDocumentPart = $documentPart; $fixedDocumentPart = preg_replace_callback( '|\$[^{]*\{[^}]*\}|U', function ($match) { return strip_tags($match[0]); }, $fixedDocumentPart ); return $fixedDocumentPart; } /** * Find and replace macros in the given XML section. * * @param mixed $search * @param mixed $replace * @param string $documentPartXML * @param integer $limit * * @return string */ protected function setValueForPart($search, $replace, $documentPartXML, $limit) { // Note: we can't use the same function for both cases here, because of performance considerations. if (self::MAXIMUM_REPLACEMENTS_DEFAULT === $limit) { return str_replace($search, $replace, $documentPartXML); } else { $regExpEscaper = new RegExp(); return preg_replace($regExpEscaper->escape($search), $replace, $documentPartXML, $limit); } } /** * Find all variables in $documentPartXML. * * @param string $documentPartXML * * @return string[] */ protected function getVariablesForPart($documentPartXML) { preg_match_all('/\$\{(.*?)}/i', $documentPartXML, $matches); return $matches[1]; } /** * Get the name of the header file for $index. * * @param integer $index * * @return string */ protected function getHeaderName($index) { return sprintf('word/header%d.xml', $index); } /** * @return string */ protected function getMainPartName() { return 'word/document.xml'; } /** * Get the name of the footer file for $index. * * @param integer $index * * @return string */ protected function getFooterName($index) { return sprintf('word/footer%d.xml', $index); } /** * Find the start position of the nearest table row before $offset. * * @param integer $offset * * @return integer * * @throws \PhpOffice\PhpWord\Exception\Exception */ protected function findRowStart($offset) { $rowStart = strrpos($this->tempDocumentMainPart, '<w:tr ', ((strlen($this->tempDocumentMainPart) - $offset) * -1)); if (!$rowStart) { $rowStart = strrpos($this->tempDocumentMainPart, '<w:tr>', ((strlen($this->tempDocumentMainPart) - $offset) * -1)); } if (!$rowStart) { throw new Exception('Can not find the start position of the row to clone.'); } return $rowStart; } /** * Find the end position of the nearest table row after $offset. * * @param integer $offset * * @return integer */ protected function findRowEnd($offset) { return strpos($this->tempDocumentMainPart, '</w:tr>', $offset) + 7; } /** * Get a slice of a string. * * @param integer $startPosition * @param integer $endPosition * * @return string */ protected function getSlice($startPosition, $endPosition = 0) { if (!$endPosition) { $endPosition = strlen($this->tempDocumentMainPart); } return substr($this->tempDocumentMainPart, $startPosition, ($endPosition - $startPosition)); } public function setImg( $strKey, $img){ $strKey = '${'.$strKey.'}'; $relationTmpl = '<Relationship Id="RID" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/image" Target="media/IMG"/>'; $imgTmpl = '<w:pict><v:shape type="#_x0000_t75" style="width:WIDpx;height:HEIpx"><v:imagedata r:id="RID" o:title=""/></v:shape></w:pict>'; $toAdd = $toAddImg = $toAddType = ''; $aSearch = array('RID', 'IMG'); $aSearchType = array('IMG', 'EXT'); $countrels=$this->_countRels++; //I'm work for jpg files, if you are working with other images types -> Write conditions here $imgExt = 'jpg'; $imgName = 'img' . $countrels . '.' . $imgExt; $this->zipClass->deleteName('word/media/' . $imgName); $this->zipClass->addFile($img['src'], 'word/media/' . $imgName); $typeTmpl = '<Override PartName="/word/media/'.$imgName.'" ContentType="image/EXT"/>'; $rid = 'rId' . $countrels; $countrels++; list($w,$h) = getimagesize($img['src']); if(isset($img['swh'])) //Image proportionally larger side { if($w<=$h) { $ht=(int)$img['swh']; $ot=$w/$h; $wh=(int)$img['swh']*$ot; $wh=round($wh); } if($w>=$h) { $wh=(int)$img['swh']; $ot=$h/$w; $ht=(int)$img['swh']*$ot; $ht=round($ht); } $w=$wh; $h=$ht; } if(isset($img['size'])) { $w = $img['size'][0]; $h = $img['size'][1]; } $toAddImg .= str_replace(array('RID', 'WID', 'HEI'), array($rid, $w, $h), $imgTmpl) ; if(isset($img['dataImg'])) { $toAddImg.='<w:br/><w:t>'.$this->limpiarString($img['dataImg']).'</w:t><w:br/>'; } $aReplace = array($imgName, $imgExt); $toAddType .= str_replace($aSearchType, $aReplace, $typeTmpl) ; $aReplace = array($rid, $imgName); $toAdd .= str_replace($aSearch, $aReplace, $relationTmpl); $this->tempDocumentMainPart=str_replace('<w:t>' . $strKey . '</w:t>', $toAddImg, $this->tempDocumentMainPart); //print $this->tempDocumentMainPart; if($this->_rels=="") { $this->_rels=$this->zipClass->getFromName('word/_rels/document.xml.rels'); $this->_types=$this->zipClass->getFromName('[Content_Types].xml'); } $this->_types = str_replace('</Types>', $toAddType, $this->_types) . '</Types>'; $this->_rels = str_replace('</Relationships>', $toAdd, $this->_rels) . '</Relationships>'; } function limpiarString($str) { return str_replace( array('&', '<', '>', "\n"), array('&', '<', '>', "\n" . '<w:br/>'), $str ); } }
使用方法:
可使用占位符替换文字和图片。
注:图片路径必须是相对路径。
phpword 模板替换文字和图片相关推荐
- phpword 模板替换并导出教程
phpword 模板替换并导出教程 word 模板文件定义 楼主在 public\uploads\application\template.docx 该路径下面创建了 word 的模板文件templa ...
- phpword模板替换并导出
PHPWord模板替换并导出 适用的场景是有word模板,需要替换掉里面的指定内容,并导出修改后的word文档. 1.准备word模板,word模板里面的变量应该以${param}的形式声明,需要替换 ...
- 【java spring boot使用easypoi实现word文档占位符替换文字和图片、Excel图片贴到对应单元格】
最近接到一个任务,写两个导出工具:1.word文档导出,将数据和图片放入到word中,将多个word合并为一个导出.2.Excel文档导出,将二维码信息和图片按照模板放入到Excel中,按9个一页排版 ...
- word模板插入文字、图片
1.建立word模板文件 person.dot 用书签 标示相关字段的填充位置 2.建立web应用程序 加入Microsoft.Office.Interop.Word引用 具体添加引用请参看 http ...
- aspose.word 20 java 替换占位符为文字或图片
以前写过用asposeword 替换文字和图片,但是后来遇到问题,有些word替换替换图片后会导致打开时弹出错误:此文件中检测到错误,单word可以通过进行一下修复来打开文件. 考虑可能是版本有bug ...
- 利用Spire实现对Word模板的指定文字替换(文字、图片、表格)
1.安装Spire.Office word文件内对要替换的地方用 [=xxx] 做标记 2.WordUtil.cs using Spire.DataExport.XLS; using Spire. ...
- java word标签替换_JAVA实现替换WORD模板中的文字和图片
1.本来有其他方法可以实现的,但是由于jar包一直有问题所以换了种,要是还有其他的更好的方法,希望可以讨论 2.废话不说直接上代码: 3.我自己加了个生成图片的方法,也可以不需要直接用已经存在的图片替 ...
- java操作word文档(文字,图片,表格添加以及替换操作)
注:本文由于个人工作需要,有对多个他人博文进行借鉴,但是多数博文都只是讲到了小部分,例如图片/表格的操作,都只有根据书签进行替换,比较片面,本人有总结到根据文字进行图片/表格的替换,希望可以帮到更多有 ...
- java pdf工具类_Java PDF工具类(一)| 使用 itextpdf 根据PDF模板生成PDF(文字和图片)...
Java PDF工具类(一)| 使用 itextpdf 根据设置好的PDF模板填充PDF(文字和图片) 相关文章: Java PDF工具类(二)| 使用 wkhtmltox 实现 HTML转PDF(文 ...
- PhpOffice——PHPWord导入导出水印模板替换
当然:PHPWord也支持导出pdf,不过依赖于MPDF或者tcpdf或者dompdf PHPWord 需要以下内容: PHP 5.3.3+ XML 解析器扩展 Laminas Escaper 组件 ...
最新文章
- 从源码安装GDB-8.1
- apt-mirror 校验错误文件处理
- TOJ5398: 签到大富翁(简单模拟) and TOJ 5395: 大于中值的边界元素(数组的应用)...
- java的整型_java 整型
- C#的二维码生成和解析
- python编程教学软件-编程教学平台的python编辑器的开发
- Web开发笔记(一)
- c语言上机实践题库,C语言上机题库
- 《现代操作系统》知识点整理
- java quartz 教程_Quartz 教程
- xp系统如可用计算机截图,WinXP系统电脑怎么截图 常见截图方法介绍
- 深入理解Nginx负载均衡和反向代理_学习笔记
- Regester 正则表达式测试工具
- Android模拟器不支持蓝牙
- 小实验:PC9与PC10连通的命令操作
- Minimum supported Gradle version is 5.1.1. Current version is 4.8
- java版超级玛丽游戏
- 蹩脚的程序员们,我们来谈谈你的未来!
- 无人驾驶一 协方差矩阵的几何意义
- 普元 AppServer 部署应用时报错:Exception while loading the app : CDI deployment failure