PHPWord 中文字顯示與下載問題

UPDATE 2016-06-24:不曉得當初自己怎麼沒將這篇從 Blogger 轉過來,總之現在是轉過來了,只將內文格式改為 Markdown,不確定內文是否還能使用,請閱讀者再自行斟酌一下(畢竟也是2012時發的文了)。


好久沒有更新了,看到上次更新的日期,我覺得我的文章產出可能會是一年一篇至兩篇(崩潰)

這次碰上的問題主要是有個網頁委託內容包含需動態產生word檔以供使用者下載,因此我從先前接觸過的 PHPExcel 而找到 PHPWord 這套 library。先前使用 PHPExcel 時多半是為了利用簡單的方式來讀取 excel 檔中的內容,而並未自行產出一個獨立的 excel 檔,而這次算是剛好反過來了,要利用已有的內容來產生一個 word 檔。

起初利用 PHPWord 0.6.2-1 Beta 所提供的 examples 成功建立 word 檔後覺得還蠻放心的,後來隨即也想到若是包含中文字時會不會有編碼問題,因此測了一下,果然變成亂碼了。後來隨即在官方討論區找到此篇文章:how to properly handle UTF-8 ? (UTF8),原來不只我遇到了這個問題~而根據底下的回覆表示以簡體中文編碼為例,須將 source code 中的 $givenText = utf8_encode($text); 註解並換成 $text = iconv('gbk','utf-8','福建省泉州市惠南工业区北一路'); 即可解決問題,但這個方法只適用於範例中的 Template.php 才行,用在 Basic Table.php 則會出現亂碼。

1
2
// 原始寫法
$givenText = utf8_encode($text);
1
2
3
// 修改後
//$givenText = utf8_encode($text);
$text = iconv('gbk','utf-8','福建省泉州市惠南工业区北一路');

後來我將 source code 中所有包含 utf8_encode 的文件都以 iconv 的方式去取代,結果算是成功沒出現亂碼了,但是 word 會在開啟時跳出錯誤警告,表示此檔案已損毀是否要進行修復(修復後沒大礙就是了)。憑著吹毛求疵斤斤計較的精神,也擔心使用者若看到損毀時會有疑慮,因此我又開始找其他方式去做,而最後找到的方法就是直接將有包含 utf8_encode 的文件都註解掉,改成直接賦予對應值,如下範例:

1
2
// 原始寫法
$givenText = utf8_encode($text);
1
2
3
// 修改後
//$givenText = utf8_encode($text);
$givenText = $text;

另外範例中用來產生 word 的 PHP 也記得先改成 utf-8,之後即可輕鬆產生包含中文內容的 docx 檔~


至於該如何直接產生word供使用者一點擊就下載,方法我也都找到了,只是 Template 在 PHPWord 中的寫法與其他比較不一樣,因此方法也有被侷限住,一般的如 Basic Table 可以用以下方法來達到不存檔而下載,只要在最後 Save File 部分動一點手腳即可:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// Save File
$objWriter = PHPWord_IOFactory::createWriter($PHPWord, 'Word2007');
// 原本是儲存到當前目錄下,名為BasicTable.docx
// $objWriter->save('BasicTable.docx');

// 先寫入header,再利用$objWriter->save('php://output');
// 將結果直接show出來,即可成功進行下載動作
$filename = 'abc.docx';
header("Cache-Control: public");
header("Content-Description: File Transfer");
header("Content-Disposition: attachment; filename=$filename");
header("Content-Type: application/octet-stream; ");
header("Content-Transfer-Encoding: binary");
$objWriter->save('php://output');

而 Template 無法使用上述方法,須使用下面範例才行:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// Save File
// 原本是儲存到當前目錄下,名為Solarsystem.docx
// $document->save('Solarsystem.docx');

// 先將檔案暫存起來
$temp_file = tempnam(sys_get_temp_dir(), 'PHPWord');
$document->save($temp_file);

// 一樣是寫入header,但最後以不同指令呈現出來,最後再刪掉伺服器上的暫存檔
$objWriter = PHPWord_IOFactory::createWriter($PHPWord, 'Word2007');
$filename = 'abc.docx';
header("Cache-Control: public");
header("Content-Description: File Transfer");
header("Content-Disposition: attachment; filename=$filename");
header("Content-Type: application/octet-stream; ");
header("Content-Transfer-Encoding: binary");
readfile($temp_file); // or echo file_get_contents($temp_file);
unlink($temp_file); // remove temp file

到這裡我所需要的功能大致上齊全了,只剩下 PHPWord 沒辦法產生 word2003(*.doc) 的檔案,也是一個令人頭痛的問題。