PHPWord复制块cloneBlock及删除块deleteBlock无效的解决办法
最近在使用PHPWord进行动态文档的生成,遇到一个非常奇怪的问题,在phpword功能测试的时候,cloneBlock和deleteBlock都好用,可是在使用正式模板的时候(模板比较大),总是不好用,无法复制块,花了一下午的时间检查这个问题,终于解决,如果对你也有帮助,请打赏我喝杯咖啡压压惊哈哈~~
通过查看源码发现,在进行cloneBlock的时候,需要通过preg_match进行正则匹配,找到要复制的块内容。但是由于文档较大,导致preg_match无法匹配出要复制的块。
原来PHP有个递归次数限制pcre.recursion_limit,无限次的递归容易消耗所有进程的可用堆栈,最后导致PHP崩溃。所以默认“pcre.backtrack_limit ”的值默认只设了100000。当我们word中内容过大时候,就导致超出这个递归次数限制,导致匹配出无结果,也就没有办法实现复制块的操作。
解决办法:修改“pcre.backtrack_limit ”的值默认,在代码前面加一句,搞定!
ini_set('pcre.backtrack_limit', 999999999);
先看下cloneBlock的源码,实际比较简单,就是通过正则找出要匹配的块,然后复制几次。
public function cloneBlock($blockname, $clones = 1, $replace = true, $indexVariables = false, $variableReplacements = null) { $xmlBlock = null; //匹配要复制的块 preg_match( '/(<\?xml.*)(<w:p\b.*>\$\{' . $blockname . '\}<\/w:.*?p>)(.*)(<w:p\b.*\$\{\/' . $blockname . '\}<\/w:.*?p>)/is', $this->tempDocumentMainPart, $matches ); if (isset($matches[3])) { $xmlBlock = $matches[3]; if ($indexVariables) { $cloned = $this->indexClonedVariables($clones, $xmlBlock); } elseif ($variableReplacements !== null && is_array($variableReplacements)) { $cloned = $this->replaceClonedVariables($variableReplacements, $xmlBlock); } else { //复制几块就循环几次 $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; }
首先我是将匹配结果 $matches打印出来,发现匹配结果为空,当时是怀疑,是不是作者正则表达式写的有问题,于是将$this->tempDocumentMainPart打印出来,和表达式进行肉眼对比,发现并没有错。
public function cloneBlock($blockname, $clones = 1, $replace = true, $indexVariables = false, $variableReplacements = null) { $xmlBlock = null; preg_match( '/(<\?xml.*)(<w:p\b.*>\$\{' . $blockname . '\}<\/w:.*?p>)(.*)(<w:p\b.*\$\{\/' . $blockname . '\}<\/w:.*?p>)/is', $this->tempDocumentMainPart, $matches ); //把匹配结果打印出来 var_dump($matches)
将$this->tempDocumentMainPart打印出来的时候,记得要在浏览器调试器network中查看真是response,而不是浏览器屏幕显示的字符串,因为默认浏览器把response编码为html显示在浏览器了,看到的并不是真实内容。
既然正则表达式没有错,而匹配结果不正确,那就应该是php出了问题,考虑$this->tempDocumentMainPart内容较大,于是百度搜索 “preg_match字符串过大”,果然发现有人遇到这样的问题,于是也就定位到了问题,解决就很简单了,一行代码。
整个调试过程花了一下午,真是快崩溃了,如果解决了你的问题,不给我打赏喝杯咖啡,你好意思吗~哈哈哈哈哈
PHPOffice使用文档整理
PHPWord使用方法整理:https://www.shanhuxueyuan.com/news/detail/124.html
PHPExcel使用方法整理:https://www.shanhuxueyuan.com/news/detail/119.html
PHPPresentation(PPT)使用方法整理:https://www.shanhuxueyuan.com/news/detail/123.html
点赞(10)