phpoffice

安装

composer require phpoffice/phpword

注意事项

1:setValue方法中如果valueb不显示html标签或者<>符号
2:类似遍历list的场景,使用 $wordTmp->cloneBlock('EXAM_BLOCK', count($questionList), 1, 1);,
然后item解析语句:
$block_index= $key + 1;
$wordTmp->setValue('right_answer#' . $block_index, $rightAnswer);
3:如果content包含图片,则第一次替换文本的时候,预留图片的占位符,然后在load一次本次生成doc,这里要注意点,第一次不能写<w:br />这种doc换行符

代码示例

$tmp_path = (resource_path('assets/doc/examTemplate.docx'));//模版文件位置
        ini_set('pcre.backtrack_limit', -1);  //防止有时正则匹配不上
        $wordTmp = new TemplateProcessor($tmp_path);//打开模板
        /*赋值 replace过程*/
        $wordTmp->setValue('test_name', Helper::hideHtmlTag($examMainInfo->name));
        $wordTmp->setValue('user_name', $userName);
        $wordTmp->setValue('user_time', $participateData->commit_time);
        $wordTmp->setValue('total_score', $examMainInfo->total_score);
        $wordTmp->setValue('question_count', count($questionList));
        $wordTmp->setValue('get_score', $participateData->score);
        $wordTmp->cloneBlock('EXAM_BLOCK', count($questionList), 1, 1);

        $json = json_encode($questionList);
        $hasImage = 0;
        if(strpos($json,'<img') && strpos($json,'src=')) $hasImage = 1;

        foreach ($questionList as $key => $item) {
            $block_index= $key + 1;
            $content = strval($block_index) . ($item->content).self::DOC_EOL_TMP;//不允许出现标签,而且<>这种符号也不行
            if (!empty($item->audio_urls)) {
                foreach ($item->audio_urls as $au) {
                    $content .= '【' . $au['audio_title'] . '】'; //docx不支持加载音频
                }
            }
            if (!empty($item->option_list)) {
                //选项
                $content.=self::DOC_EOL_TMP;
                foreach ($item->option_list as $opKey => $op) {
                    $content .= (Arr::get(ExamStore::OPTIONS_MAP, $opKey) .($op->describ)) . self::DOC_EOL_TMP;
                }
            }
            $content = $this->getStoreHtmlImg($content,$imgMap,$hasImage);
            $wordTmp->setValue('question_content#' .$block_index, $content);
            $wordTmp->setValue('full_score#' .$block_index, $item->score);
            $stuAnswer = $examStore->arrAnswerToString($item->answer_content);
            $stuAnswer = $this->getStoreHtmlImg($stuAnswer,$imgMap,$hasImage);
            $wordTmp->setValue('stu_answer#' .$block_index, $stuAnswer);

            $rightAnswer = $examStore->arrAnswerToString($item->correct_answer_content);
            $rightAnswer = $this->getStoreHtmlImg($rightAnswer,$imgMap,$hasImage);
            $wordTmp->setValue('right_answer#' . $block_index, $rightAnswer);

            $item->analysis = empty(trim($item->analysis)) ? '略' : $item->analysis;
            $item->analysis = $this->getStoreHtmlImg($item->analysis,$imgMap,$hasImage);
            $wordTmp->setValue('analysis#' . $block_index,($item->analysis)); //不允许出现标签,而且<>这种符号也不行
            $wordTmp->setValue('score#' . $block_index, $item->user_score);

        }
        $s3 = (int)(microtime(true) * 1000);

        $doc_root = storage_path() . '/doc/';
        FileUtils::checkAndCreateDirectory($doc_root);

        /**
         * $task 为空则是单个导出,否则是批量导出
         */
        if ($task == '') {
            //考生用户名+考试名称+导出日期
            $fileName = "{$userName}[{$examMainInfo->name}]{$date}.docx";
            $work_dir = $doc_root;

        } else {
            // 考生用户名+分数+导出日期+序号
            $doc_root = $doc_root . 'task/';
            FileUtils::checkAndCreateDirectory($doc_root);
            $work_dir = $doc_root . $task . '/';//本次存放考试所有学生doc ,准备打包的目录
            FileUtils::checkAndCreateDirectory($work_dir);
            $fileName = "{$userName}[{$participateData->score}分]{$date}[{$index}].docx";
        }

        $fileNameFinal = $fileName ;// $fileNameFinal 最后保存的文件名
        if(!empty($imgMap)){
            //图片为空可以不用在加载一次doc
            $tmp_rand_name = date('YmdHi').rand(100000,999999).'.docx';
            $fileName = $tmp_rand_name;
        }
        $file = $work_dir . $fileName;
//        try{
        $wordTmp->saveAs($file);//

        $s4 = (int)(microtime(true) * 1000);

        if(!empty($imgMap)){
            $wordFinal = new TemplateProcessor($file);//打开模板
            foreach ($imgMap as $index=>$src){
                $wordFinal->setImageValue('image_block' . ($index), $src);//替换图片
            }
            $wordFinal->setValue('DOC_EOL_TMP','<w:br/>');//换行符
            @unlink($file);//删除中间文件
            $file = $work_dir.$fileNameFinal;
            $wordFinal->saveAs($file);

        }

        private function getStoreHtmlImg($content,&$imgMap,$hasImage = false){

        $imgMatch = Helper::getImgSrc($content,-1);
        $imgIndex = count($imgMap);

        $imgArr = Arr::get($imgMatch,0);
        $imgSrc = Arr::get($imgMatch,1);

        foreach ($imgArr  as $k=>$v){
            $content = str_replace($v,'${image_block'.$imgIndex.'}',$content);
            $imgMap[$imgIndex] = Arr::get($imgSrc,$k);
            $imgIndex++;
        }
        $content = strip_tags($content);

        if(empty($hasImage)){
            $content = str_replace(self::DOC_EOL_TMP,'<w:br />',$content);//将临时换行符替换成doc的换行符号,
        }
        return $content;
    }

可以转载,但必须说明出处

发表评论