2012年9月24日 星期一

PHPWord 中文字顯示與下載問題

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

這次碰上的問題主要是有個網頁委託內容包含需動態產生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則會出現亂碼。
// 原始寫法
$givenText = utf8_encode($text);

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

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

// 修改後
//$givenText = utf8_encode($text);
$givenText = $text;

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



至於該如何直接產生word供使用者一點擊就下載,方法我也都找到了,只是Template在PHPWord中的寫法與其他比較不一樣,因此方法也有被侷限住,一般的如Basic Table可以用以下方法來達到不存檔而下載,只要在最後Save File部分動一點手腳即可:
// 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無法使用上述方法,須使用下面範例才行:
// 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)的檔案,也是一個令人頭痛的問題。

沒有留言:

張貼留言