要在 PHP 產出 Word 檔,因為之前用同事導入的 PHPExcel 的體驗還不錯,所以決定這次要用 PHPWord。但是事情沒有我想像的簡單,到 PHPWord 的 Github 專案下載專案檔案後,直接解壓縮 src 目錄放到、專案目錄下,光是要按照 PHPWord 的說明文件產生最基本的檔案,就出現錯誤訊息:
PHP Fatal error: Uncaught Exception: Could not find file '/autoload.php'. It is generated by Composer. Use 'install --prefer-source' or 'update --prefer-source' Composer commands to move forward
回頭從安裝仔細看 PHPWord 的說明裡的安裝步驟,發現要用 copmopser 安裝,才會產生前述的 "Autoloader.php" 檔案。
研究了一下,照 composer 官網的說法,在 Windows 上頭,composer 要這樣裝:
步驟一 取得 composer-setup.php。我在 command 視窗 (CMD),先切到 PHP 目錄下(如果有在環境變數設定過 PHP 主目錄就可以省略),然後執行以下指令:
php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');
不過這句我一直執行不成功,所以我乾脆自己手動在瀏覽器視窗把 'https://getcomposer.org/installer" 這個網址打開,直接另存成 "composer-setup.php",丟回 PHP 目錄下。弄好才發現 PHP error.log 裡面有寫錯誤訊息,基本上也是打開 php.ini 裡頭的 extension=openssl 就可以了:
PHP Warning: copy(): Unable to find the wrapper "https" - did you forget to enable it when you configured PHP? in Command line code on line 1
在 composer 的官網會建議再執行以下這行,用 hash 來驗證 composer-setup.php 是不是內容完整無損:
php -r "if (hash_file('sha384', 'composer-setup.php') === '756890a4488ce9024fc62c56153228907f1545c228516cbf63f885e036d37e9a59d27d63f46af1d4d07ee0f76181c7d3') { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;"
步驟二 執行安裝:
php composer-setup.php
這時要看底下出現的錯誤訊息,像我被要求:
- 需要在 php.ini 設定 "allow_url_fopen = On"。(我之前因為資安政策都設成 Off)
- 需要在 php.ini 打開 "extension=openssl"。(我之前沒有用到,所以這行前面有分號 (;),要拿掉)
不過光是打開 "extension=openssl" 還是會出現錯誤訊息,參考了 stackoverflow 的 "Composer Warning: openssl extension is missing. How to enable in WAMP",裡面提到 'extension_dir = "ext"' 這行也要打開。
安裝完畢後,我的 PHP 主目錄下會多一個 "composer.phar",就可以執行 composer 指令:
php composer.phar
就可以刪除步驟一的 "composer-setup.php" 了。
執行安裝的指令如下,"-d" 參數後面接目標安裝目錄:
php composer.phar install -d D:\PHPWord-master
安裝時出現 command 視窗出現錯誤訊息:
Root composer.json requires PHP extension ext-gd * but it is missing from your system. Install or enable PHP's gd extension.
所以要把 php.ini 的 "extension=gd2" 再打開。(根本大地遊戲)
安裝完畢後發現有一篇也在講怎麼在 Windows 上安裝 composer、取得 autoload.php 的文章:《PhpWord的autoload.php文件及目录的生成方式》,他是直接下載了 composer.exe 來用,我覺得兩個方法都可以試試看啦。
安裝完畢後,開始做檔案。
做檔案時,如果輸出的內容檔名一直是一樣的,把檔案打開來檢視時,又同時要再重新產製一次檔案,這時會得到 PHP error:
PHP Warning: unlink(helloworld.docx): Resource temporarily unavailable
PHP Warning: ZipArchive::close(): Renaming temporary file failed: Permission denied
PHP Fatal error: Uncaught PhpOffice\PhpWord\Exception\Exception: Could not close zip file helloworld.docx
這是因為檔案產製時無法直接覆寫檔案。把打開的 Word 檔檔案關掉就好。
先來做一個表格:
<?php
include("../inc/PhpWord/bootstrap.php"); // 初始化 PHPWord
$phpWord = new \PhpOffice\PhpWord\PhpWord(); // create Word object
$section = $phpWord->addSection(); // 新增分節 (再 addSection() 會切成下一節,可當換頁符號用)
$table = $section->addTable(array('borderColor' => '000000', 'borderSize' => 6, 'cellMargin' => 50));
$table->addRow();
$table->addCell(2000)->addText("", $style["fontStyle"]);
$objWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, 'Word2007');
$tmpdocfile = 'test.docx';
$objWriter->save($tmpdocfile); // 儲存為暫存檔
$file_size = filesize($tmpdocfile);header("Content-Type: application/vnd.openxmlformats-officedocument.wordprocessingm");
header("Content-Length: " . $file_size);
header('Content-Disposition: attachment; filename="test_download.docx";');
header('Content-Transfer-Encoding: binary');
readfile($tmpdocfile); // 讀出檔案內容開始下載
unlink($tmpdocfile); // 刪除暫存檔
?>
其中 addCell() 裡的數字,單位是微軟特有的單位 twips (緹),可以利用換算工具計算,例如 2000 twips 相當於 3.53 cm。
欄寬要逐格指定,不然預設會自動被內容撐開。
【將 HTML 內容插入到 PHPWord 中】
根據 "How to add styles to incoming HTML in PHPWord",可以利用以下語法將 HTML 插入到 PHPWord 裡:
<?php
$phpWord = new \PhpOffice\PhpWord\PhpWord();
$section = $phpWord->addSection();
\PhpOffice\PhpWord\Shared\Html::addHtml($section, $html);
?>
不過僅支援以下 HTML tag:
<p>,<h1>,<h2>,<h3>,<h4>,<h5>,<h6>,<strong>, <em>,<sup>,<sub>,<table>,<tr>,<td>,<ul>,<ol>,<li>
【設定加入網底】
文字加入網底 (shading) 或文字醒目提示 (Text Highlight Color),參考 "With PHPWord can you change the true Microsoft Word “Text Highlight Color” values and not merely the style applied by the library?" 一文,設定如下:
<?php
$section->addText(
'This is some text highlighted using fgColor (limited to 15 colors)',
array('fgColor' => \PhpOffice\PhpWord\Style\Font::FGCOLOR_YELLOW)
);
?>
【設定定位點】
使用定位點,可以利用 tab 把文件排得更整齊。
$section->addText("一般文字段落", $style, array('alignment' => \PhpOffice\PhpWord\SimpleType\Jc::CENTER));
// 同一行變換樣式,須用 textrun 將內容切開;用 tabs 做定位點
$textrun = $section->addTextRun(array('tabs' => array(
new \PhpOffice\PhpWord\Style\Tab('center', 5145),
new \PhpOffice\PhpWord\Style\Tab('right', 10285)
)));
$textrun->addText("<預設置左>", $style); // 直接寫 "<>" 會出錯,產出的 Word 檔會無法打開,需要使用 "<>"
$textrun->addText("\t置中定位點", $style);
$textrun->addText("\t置右定位點", $style);
【中英文使用不同字型】
一開始 OpenAI 提供了幾個不存在的 function,像是 setFallbackFontName()、setEastAsianFont():
<?php
$fontStyle = new \PhpOffice\PhpWord\Style\Font();
$fontStyle->setName('Arial');
$fontStyle->setFallbackFontName('Microsoft JhengHei');
?>
(此段尚未完全驗證過)後來 OpenAI 提供的解法是使用正規表示式,將字串先切開,分開套用不同 style:
<?php
$phpWord = new \PhpOffice\PhpWord\PhpWord();
$section = $phpWord->addSection();
$fontStyleEnglish = new \PhpOffice\PhpWord\Style\Font();
$fontStyleEnglish->setName('Arial');
$fontStyleEnglish->setSize(12);
$fontStyleChinese = new \PhpOffice\PhpWord\Style\Font();
$fontStyleChinese->setName('Microsoft YaHei');
$fontStyleChinese->setSize(12);
$text = 'Hello World! 你好世界!';
$paragraph = $section->addTextRun();
$parts = preg_split('/([\x{4e00}-\x{9fa5}]+)/u', $text, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
foreach ($parts as $part) {
if (preg_match('/[\x{4e00}-\x{9fa5}]/u', $part)) {
$paragraph->addText($part, $fontStyleChinese);
} else {
$paragraph->addText($part, $fontStyleEnglish);
}
}
?>
留言列表