这是一个老的PHP项目,上家公司不维护了,我们公司接手过来,而我领到了一个导出word文档的需求,而项目中已经有PHPWord(ps:是个老版本,还不知道有没有改过),所以直接使用项目中的PHPWord来实现。
写了一个公共的方法,使用一个模板来生成docx文档(ps:文档统一使用docx的格式,看网上的说法,使用doc格式有问题,没有求证),这里由于PHPWord的版本较老,没有网上常提到的TemplateProcessor类,但有Template类可以使用。
/**
* 自定义docx文档生成
* @param $docxTemplatePath docx文档模板路径 (含文件名及文件后缀)
* @param $docxDownloadPath 生成docx文档目录 (用于docx文档下载)
* @param $fileName 生成docx文档名称 (含文件后缀)
* @param $data 用于替换模板标记的数据
* @return void
* @throws Exception
*/
function DocxGeneration($docxTemplatePath, $docxDownloadPath, $fileName, $data) {
require_once('./ThinkPHP/Library/Vendor/PHPWord/PhpWord.php');
require_once('./ThinkPHP/Library/Vendor/PHPWord/PHPWord/Autoloader.php');
require_once('./ThinkPHP/Library/Vendor/PHPWord/PHPWord/Template.php');
$tmp = new Template($docxTemplatePath);
// data = array(key1=>value1, key2=>value2);
foreach ($data as $key => $val) {
$tmp->setValue($key, $val);
}
$tmp->save($docxDownloadPath . "/" .$fileName);
}
但在最后使用save方法进行文件保存的时候报了一个“Could not close zip file.”的错误,于是打断点在Template类中找到抛出错误的地方。
// Close zip file
if($this->_objZip->close() === false) {
throw new Exception('Could not close zip file.');
}
但从这里提供的信息太少,网上的答案是没有权限,但是我把存储模板和存放文档的目录权限开放,依旧没有解决这个问题,直到我看到了这个对象要使用的一个目录路径,而项目中却没有这个目录,这肯定会出现错误,于是我手动的创建了这个目录,“Could not close zip file.”的问题就解决了!
然而却没有在指定的目录下生成文档,也无法替换模板中的标记,进过反复调试,找到两处原因。
一:是获取document.xml的路径错误,导致生成文档内容为空,Template类中写的是document2.xml,修改为document.xml。
$this->_documentXML = $this->_objZip->getFromName('word/document2.xml');// 改为document.xml
二:中文文件名和中文值导致无法保存和替换模板中的标记,通过对文件名和替换数据设置编码格式解决。
// Template类中,save方法最后rename文件前,对中文文件名处理
$strFilename = iconv('utf-8' , 'gbk' ,$strFilename);
// Template类中,setValue方法在对模板文档进行标记替换前,对中文数据处理
$replace = iconv('utf-8', 'GB2312//IGNORE', $replace);
$replace = iconv('gbk', 'utf-8', $replace);