* @package Home\Service class TemplateProcessor extends \PhpOffice\PhpWord\TemplateProcessor * 查找字符、字符串第n次出现的位置 * todo 自行添加 * @param string $str 原始字符串 * @param string $find 需要查找的字符、字符串 * @param int $start 开始搜索的位置 * @param int $num 第几次出现的字符、字符串 * @return bool|int 返回第n次出现的位置 public function strPosNum( $str = '', $find = '', $start = 0, $num = 1 ) $pos = false ; if ( $num > 0 ) { $pos = strpos ( $str , $find , $start ); for ( $i = 1; $i < $num ; $i ++ ) { $pos = strpos ( $str , $find , $pos + 1 ); return $pos ; * 找到下面几行的最后行尾的结束位置 * todo 自行添加 * @param $offset 开始搜索的位置 * @param int $rowNum 复制几行 * @return bool|int public function findRowEndWithRowNum( $offset , $rowNum = 0 ) // </w:tr> 行尾标签 return $this ->strPosNum( $this ->tempDocumentMainPart, '</w:tr>', $offset , $rowNum ) + 7 ; * 克隆多行 * todo 自行添加 * 如果clone的第一行是合并单元格的 就clone变量选择第一个合并单元格的 如下 * --------------------- * | | B | * | A |--------| * | | C | D | * --------------------- * @param $search 搜索 这个要选择克隆多行的第一行的变量 * @param $numberOfClones 克隆的个数 * @param int $rowNum 克隆这行下面几行(包括当前行) public function cloneMultiRow( $search , $numberOfClones = 0, $rowNum = 1 ) // 搜索的字符串替换成word中使用的变量 $search = static ::ensureMacroCompleted( $search ); // 查找 当前变量 字符串首次出现的位置 $tagPos = strpos ( $this ->tempDocumentMainPart, $search ); if (! $tagPos ) { throw new \PhpOffice\PhpWord\ Exception \ Exception ('Can not clone row, template variable not found or variable contains markup.' ); // 找到行的开始位置 $rowStart = $this ->findRowStart( $tagPos ); // 需要行尾的结束位置 $rowEnd = $this ->findRowEndWithRowNum( $tagPos , $rowNum ); // 找到 行开始和行结束中间的 xml字符串 $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 ->findRowEndWithRowNum( $extraRowEnd + 1, $rowNum ); // 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"\s*/>#', $tmpXmlRow )) { break ; // This row was a spanned row, update $rowEnd and search for the next row. $rowEnd = $extraRowEnd ; $xmlRow = $this ->getSlice( $rowStart , $rowEnd ); // 获取 tempDocumentMainPart 中 开头到 查找行开始位置的字符串 $result = $this ->getSlice(0, $rowStart ); // 获取 clone变量 之后的xml 并拼接 $result .= implode ( $this ->indexClonedVariables( $numberOfClones , $xmlRow )); // 获取 行结尾到 xml的结束的字符串 并拼接 $result .= $this ->getSlice( $rowEnd ); $this ->tempDocumentMainPart = $result ;
$templateFile = 'info.docx';
$templateProcessor = new TemplateProcessor($templateFile);

//
日志
$logList = $data['log_list']; $logListLen = count($logList);
// 重点:5,是循环的多行的行数
$templateProcessor->cloneMultiRow('id', $logListLen, 5);
$templateProcessor->saveAs("b.docx");