因工作需要,使用了版本比較舊的
PHPWord
專案
官方已不見維護更新,上次版本更新是在Fri Jul 8, 2011 at 8:00 AM
如果PHP版本>=5.3.3,強烈推薦使用PHPOffice/PHPWord
這個開源專案
本篇針對的為舊版本的PHPWord
基本安裝
問題總結
Autoloader
自動載入部分情況下失敗
在使用
Yii 1
配置自動載入時無法正常載入類庫,需對其PHPWord/Autoloader.php
做部分調整,這兒借鑑了PHPExcel
的Autoloader
:
/**
* PHPWord_Autoloader
*/
class PHPWord_Autoloader
{
/**
* Register the Autoloader with SPL
*
*/
public static function Register() {
$functions = spl_autoload_functions();
foreach ( $functions as $function)
spl_autoload_unregister($function);
$functions = array_merge(array(array(`PHPWord_Autoloader`,`Load`)),$functions);
foreach ( $functions as $function)
$x = spl_autoload_register($function);
return $x;
} // function Register()
/**
* Autoload a class identified by name
*
* @param string $pClassName Name of the object to load
*/
public static function Load($pClassName){
if ((class_exists($pClassName,FALSE)) || (strpos($pClassName, `PHPWord`) !== 0)) {
// Either already loaded, or not a PHPWord class request
return FALSE;
}
$pClassFilePath = PHPWORD_BASE_PATH .
str_replace(`_`,DIRECTORY_SEPARATOR,$pClassName) .
`.php`;
if ((file_exists($pClassFilePath) === FALSE) || (is_readable($pClassFilePath) === FALSE)) {
// Can`t load
return FALSE;
}
require($pClassFilePath);
} // function Load()
}
模板替換時無法識別模板標籤
表現
-
使用/複製官方樣例的模板檔案替換正常
-
自己手動敲出模板標籤替換異常
原因
-
PHPWord的替換規則是將
Word
檔案解析成XML
進行替換處理,當Word
解析成XML
時字元分離了,導致匹配不上模板標籤; -
具體分析可參考一下資料:
解決辦法
改進Template
類:
可參考Github: Arisse/PHPWord_CloneRow對Template
類進行改造。
因為下面仍需要修改Template
類,這兒暫時就不貼程式碼了,下面一併貼出改造後的程式碼。
中文亂碼
編輯PHPWord/Template.php
,找到程式碼$replace = utf8_encode($replace);
,刪除或者註釋掉這行程式碼,新增$replace = iconv( `gbk`,`utf-8`, $replace);
,比如程式碼改為如下:
/**
* Set a Template value
*
* @param mixed $search
* @param mixed $replace
*/
public function setValue($search, $replace) {
if(substr($search, 0, 2) !== `${` && substr($search, -1) !== `}`) {
$search = `${`.$search.`}`;
}
if(!is_array($replace)) {
//$replace = utf8_encode($replace);
$replace =iconv(`gbk`, `utf-8`, $replace); // 註釋掉上面行後新增這行
}
$this->_documentXML = str_replace($search, $replace, $this->_documentXML);
}
空格輸出
在想要輸出換行的地方用<w:br />
代替即可.
標記符號輸出
參考百度經驗: 如何在word中選擇打鉤的方框
僅以輸出□
和☑
為例,其它符號與之類似。
注:PHP
檔案需要使用UTF-8
編碼
-
在
Word
檔案中按照參考檔案方式插入☑
; -
複製符號到
PHP
檔案; -
正常的輸出替換。
具體程式碼見如下的專案程式碼。
Template
類程式碼
// code
/**
* Set a Template value
*
* @param mixed $search
* @param mixed $replace
*/
public function setValue($search, $replace, $limit=-1) {
if(substr($search, 0, 1) !== `{` && substr($search, -1) !== `}`) {
$search = `{`.$search.`}`;
}
if(!is_array($replace)) {
// $replace = utf8_encode($replace);
// $replace = iconv( `gbk`,`utf-8`, $replace);
$replace = str_replace("
","<w:br />",$replace);
}
preg_match_all(`/{[^}]+}/`, $this->_documentXML, $matches);
foreach ($matches[0] as $k => $match) {
$no_tag = strip_tags($match);
if ($no_tag == $search) {
$match = `{`.$match.`}`;
$this->_documentXML = preg_replace($match, $replace, $this->_documentXML, $limit);
if ($limit == 1) {
break;
}
}
}
}
// code
專案程式碼
// @author Heier xheier@outlook.com
public function actionExportPersonTable() {
// 獲取資料部分程式碼
// ...
$PHPWord = new PHPWord();
// Word模板目錄
$personBasePath = Yii::app()->basePath.`/person/`;
// 刪除目錄下臨時檔案-十分鐘以前
$this->delfile( $personBasePath, 10 );
// 模板檔名
$tempName = $personBasePath . `/moban.docx`;
$word = $PHPWord->loadTemplate( $tempName );
// 專案使用的是GBK編碼,需要做轉換
$username = iconv(`gbk`, `utf-8`, getUserNameById($personData[0][`user_id`]) );
$personal_type = $personData[0][`personal_type`];
// 模板替換開始
// 可以輸出打勾的方框
$deptA=$deptBP=$deptB=$deptC=$deptD = `□`;
if( $DirectorLevel == `A` ) {
$deptA = `☑`;
} elseif( $DirectorLevel == `B+` ) {
$deptBP = `☑`;
} elseif( $DirectorLevel == `B` ) {
$deptB = `☑`;
} elseif( $DirectorLevel == `C` ) {
$deptC = `☑`;
} elseif( $DirectorLevel == `D` ) {
$deptD = `☑`;
}
$word->setValue(`deptA`, $deptA);
$word->setValue(`deptBP`, $deptBP);
$word->setValue(`deptB`, $deptB);
$word->setValue(`deptC`, $deptC);
$word->setValue(`deptD`, $deptD);
// 設定其它替換
// ...
// 生成臨時檔案以供下載
$tmpFileName = md5( time().`Heier` );
$word->save($personBasePath . `/` . $tmpFileName .`.docx`);
$file = $personBasePath . `/` . $tmpFileName .`.docx`;
// 下載Word檔案
ob_start(); //開啟緩衝區
$fp = fopen($file,"r");
$file_size = filesize($file);
$downFileName = `XXX.docx`;
header("Cache-Control: public");
header("Content-type: application/octet-stream");
header("Accept-Ranges: bytes");
header("Content-Disposition: attachment; filename={$downFileName}");
header("Pragma:no-cache");
header("Expires:0");
$buffer = 1024;
$file_count = 0;
//向瀏覽輸出回資料
while(!feof($fp) && $file_count < $file_size){
$file_con = fread($fp,$buffer);
$file_count += $buffer;
echo $file_con;
}
ob_end_flush();//輸出全部內容到瀏覽器
}
參考文件彙總
關於我
文章轉載自我的部落格:
Heier Blog: 使用PHPWord對Word檔案做模板替換