close

要在 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

這時要看底下出現的錯誤訊息,像我被要求:

  1. 需要在 php.ini 設定 "allow_url_fopen = On"。(我之前因為資安政策都設成 Off)
  2. 需要在 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("&lt;預設置左&gt;", $style); // 直接寫 "<>" 會出錯,產出的 Word 檔會無法打開,需要使用 "&lt;&gt;"
  $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);
        }
    }
?>

 

 

 

arrow
arrow
    文章標籤
    PHPword php
    全站熱搜
    創作者介紹
    創作者 小攻城師 的頭像
    小攻城師

    小攻城師的戰場筆記

    小攻城師 發表在 痞客邦 留言(3) 人氣()