首頁 >後端開發 >php教程 >在Windows系統下使用PHP產生Word文件的教學課程

在Windows系統下使用PHP產生Word文件的教學課程

WBOY
WBOY原創
2016-07-25 08:45:00974瀏覽

準備工作

首先,請確保在你的Windows系統中已經安裝並設定好了典型的WAMP環境。由於Interop純粹是Windows的特性,我們將在Windows平台下建置Apache和PHP。在這個實例中,我使用了EasyPHP 14.1,而這款軟體安裝和設定都十分容易。

接下來,我們要安裝Microsoft Office。版本不是嚴格要求的。我正在使用的是Office2013專業版,但是任何2007之後的Office版本都應該可以使用。

我們接著需要去確保開發Interop應用(又被稱為PIA,優先互動元件)的函式庫是安裝好的。為了確保這個,我們可以打開資源管理器,然後找到assembly,我們將會看到下面安裝好的PIAs分支:

201573144223171.png (1050×656)

我們可以看到一個 Microsoft.Office.Interop.Word 條目(在這個截圖中有底線)。 這就是我們在這個範例中將要使用的 PIA。請特別注意它的“名稱”,“版本”和“公鑰標記”。我們將要在PHP腳本中用到它們。

在這個目錄中,我們還可以看到其它用於程式設計(不僅是PHP,還有VB.net, C#等)的PIAs(包括整個Office家族)。

如果這個清單沒有包含 Microsoft.Office.Interop 的整個包,我們可以重新安裝Office並且在安裝中包含PIA;我們也可以手動下載安裝這個包。安裝的詳細步驟可以參考這個MSDN頁面。

注意:只有Microsoft Office 2010 PIA Redistributable 可以被單獨下載安裝。這個包中的 PIA 版本是14.0.0。版本15只能透過安裝Office取得。

最後,我們需要在檔案 php.ini 中啟用 PHP 擴充功能 php_com_dotnet.dll,並且重新啟動伺服器。

現在我們可以開始程式設計了。

HTML表單

由於該demo主要關注與後台的處理,所以我們這裡就用一個簡單的HTML表單做前台的展示,看起來應該是這樣的:

201573144251848.png (889×757)

我們有一個文字方塊用於輸入“Name”,一個“Gender”的單選按鈕組,一個“Age”的域值控制還有一個文字域來寫“Message”,最後,還需要一個“ Submit”按鈕。

將該文件命名為“index.html”,保存在虛擬主機的根目錄下,這樣我們可以直接透過URL存取該文件,例如:http://test/test/interop

後台

後台的PHP檔案是我們所要討論的核心部分。我先將程式碼貼到下面,接下來在一步一步的進行解釋

  1. $inputs = $_POST;
  2. $inputs['printdate']='';
  3. /// A dummy value to avoid a PHP notice as we don't have "printdate" in the POST variables.
  4. $assembly = 'Microsoft.Office.Interop.Word, Version=15.0.0.0, Culture=kenral, Culture =71e9bce111e9429c';
  5. $class = 'Microsoft.Office.Interop.Word.ApplicationClass';
  6. $w = new DOTNET($assembly, $class);
  7. $w->ible =$ true;
  8. $fn = __DIR__ . '\template.docx';
  9. $d = $w->Documents->Open($fn);
  10. echo " Document opened.

    ";
  11. $flds = $d->Fields;
  12. $count = $flds->Count;
  13. echo "There are $count fields in this document.
    ";
  14. echo "
      ";
    • $mapping = setupfields();
    • foreach ($flds as $index => $f)
    • {
    • $f->Select();
    • $key = $mapping[$index];
    • $value = $inputs[$key];
    • if ($key == 'gender')
    • {
    • if ($value == 'm')
    • $value = 'Mr.';
    • else
    • $value = 'Ms.';
    • }
    • if($key=='printdate')
    • $value= date ('Y-m-d H:i:s');
    • $w->Selection->TypeText($value);
    • echo "
    • Mappig field $index: $key with value $value
    • ";
    • }
    • echo "
    ";
  15. echo "Mapping done!

    ";
  16. echo "Printing. Please wait...
    ";
  17. $d->PrintOut();
  18. sleep(3);
  19. echo "Done!";
  20. $w->Quit(false);
  21. $w=null;
  22. function setupfields()
  23. {
  24. $mapping = array();
  25. $mapping[0] = 'gender';
  26. $mapping[1] = 'name';
  27. $mapping[2] = 'age';
  28. $mapping[3] = 'msg';
  29. $mapping[4] = 'printdate';
  30. return $mapping;
  31. }
複製程式碼

在設定完用來取得表單中傳過來的值的變數$inputs之後,我們要建立一個虛擬值用來存放printdate-我們稍後會討論為何需要這個變數-現在,我們看到這4行比較關鍵的程式碼:

  1. $assembly = 'Microsoft.Office.Interop.Word, Version=15.0.0.0, Culture=neutral, PublicToken=71e9bce111e9429'Keyneutral, PublicToken=71e9bce111e9429' .Office.Interop.Word.ApplicationClass';
  2. $w = new DOTNET($assembly, $class);
  3. $w->visible = true;
複製程式碼
在PHP中的COM操縱需要在一個assembly裡請求一個class的實例。在我們的案例中,我見將要操作Word。如果考慮到我們上一個截圖中展示的程式碼,我們將能夠建構出一個完整簽名的Word PIA:

    “Name”,“Version”,“Public Key Token”是在當我們瀏覽“c:Windowsassembly”時所展示的資訊
  • 「Cultrue」總是neutrual的。

呼叫類別編譯後的檔案後綴名為通常為ApplicationClass.

透過設定下面兩個步驟,我們可以初始化一個word物件:

首先,word物件可以保存在背景或透過將visible屬性設為true,使它在前台展示出來。

然後,我們打開將要處理的文檔,把它實例化為一個$d變數。

在文件物件中,基於html表單的文字來新增文件的內容,這裡可以設定一些參數。

最不好的方式是對php頁面上所有內容進行硬編碼,然後將它們新增到word物件中。我強烈建議不採用此種方式,原因有:

1 程式碼沒有彈性,php內容的任何變更都需要重新修改腳本;

2 違反了控制層、展示層的分離;
3 如果需要設定word內容的格式(對齊,字體,樣式,等),這種方式大大增加了程式碼行數,並且以程式設計的方式來修改樣式是非常麻煩的。

另一種方式是使用“搜尋-替換”。 PHP內建的這種功能非常強大。我們可以建立一個word文檔,在那些需要被替換的佔位內容周圍放置一些分隔符號。例如,我們建立一個文件包含以下內容:

  1. {{name}}
複製程式碼
在PHP中,我們只需使用從表單提交中取得的「Name」值來替換。這種方式避免了第一選項中的那些缺點。我們只需要找到正確的分隔符,在這個例子中,除了使用的模板是word文檔,我們更像是做一個模板渲染。

第三個選項是我的建議,並且是Word中的高級主題。我們將用網域來表示佔位符,在我們的php程式碼中,我們會直接更新了對應的表單值的欄位。

這種方法靈活,快速,符合Word的最佳實務。這也避免了文件的全文搜索,這有助於提高效能。請注意,此選項有它的缺點了。

總之,自從首次亮相,Word從來沒有支援命名索引的欄位。儘管我們對於我們在Word文件中建立的欄位提供了一個名字,我們還是要用數字下標來存取每個欄位。這也解釋了為什麼我們要使用專用的功能(setupfields)來做表單欄位的欄位索引和名稱之間的對應手冊

學習如何在word文件中插入欄位(點擊這裡查看一個客製化好的版本),請參閱相關 Word 說明主題和手冊。對於這個demo,我們有一個具備5個MERGEFIELD欄位的文件。此外,我們將文件和PHP腳本放在一個目錄下,以便於取得。

請注意,printdate欄位並沒有一個對應的窗體欄位。這就是為什麼我們要在$inputs數組中添加一個假的printdate作為key。沒有這個key,腳本仍然可以執行,但是會有提示說明$inputs數組中不存在索引printdate。

在使用表單資料更新完欄位的值之後,我們將會使用下面的指令列印文件:



  1. $d->PrintOut();
複製程式碼

PrintOut方法有幾個可選參數,這裡,我們使用最簡單的格式。這將會為連結到我們Windows機器的預設印表機列印一份副本。


我們可以透過使用PrintPreview進行列印預覽。在純自動化的情景下,當然,我們直接使用PrintOut進行列印。

在退出word應用程式之前,我們還需要稍作等待,因為列印工作需要時間來完全退出背景。如果沒有delay(3),$w->Quit將會立刻得到執行,並且列印工作立刻被終止。

最終,我們呼叫 $w->Quit(false) 來選擇透過我們的PHP腳本呼叫關閉word應用程式。這裡提供的唯一參數是用來指明我們是否希望在退出前保存更改。我們確實對文件進行了更改,但是我們不希望保存它們,因為我們希望能為其他用戶的輸入提供一份乾淨的模板。

當我們完成編碼之後,我們可以載入表單頁面,輸入一些內容並提交表單。下面的截圖展示了PHP腳本的輸出,同時更新了Word文件:

201573144442664.png (889×757)

201573144502426.png (1663×843)

提高編碼速度並更好的理解PIA

PHP是一種弱型態的語言。一個COM物件是一種Object型別。在我們的PHP編碼過程中,在一個物件中我們無法使用程式碼自動提示和完成功能,在一個Word應用,一個文件甚至一個欄位中也是如此。我們不知道它有哪些特性,或它支援哪些方法。


這將大幅度的降低我們所開發的速度。為了讓開發更快,首先,我建議我們在c#中開發功能應當遷移至我們的PHP編碼。我推薦一款免費的C# IDE 叫做"#develop",你可以在這裡下載。比起VS,我更喜歡這款軟體,因為#develop體積更小,更簡潔,反應更快。

C#程式碼遷移至PHP一點也不嚇人。先讓我展示一些C#的程式碼:
複製程式碼 程式碼如下: Word.Application w=new Word.Application();
w.Visible=true;

String path=Application.StartupPath "\template.docx";

Word.Document d=w.Documents.Open(path) as Word.Document;

Word.Fields flds=d.Fields;
int len=flds.Count;

foreach (Word.Field f in flds)
{
f.Select();
int i=f.Index;
w.Selection.TypeText("...");
}

我們可以看到,C#的程式碼和我們之前展示的PHP的程式碼基礎一模一樣。由於C#是一種強型別語言,所以我們可以看到有些型別轉換的語句,我們必須顯性的給我們的變數賦一種型別。

有了程式碼的類型,我們可以盡情的享受程式碼的自動提示和程式碼自動完成功能,這樣我們開發的速度將有大幅提升。


另一種可以給我們更快速度進行php開發的方式是使用Word的巨集指令。我們先操作一遍我們需要重複的動作,然後用一個巨集將其錄製下來。一個宏其實是Visual Basic,同樣也可以非常容易的翻譯成PHP。

最重要的是,Office PIA微軟官方文檔,特別是文檔中對於每個Office應用的命名空間,總是會是我們所需要的最想進的參考。比較常用的3個應用如下:

  • Excel 2013:http://msdn.microsoft.com/en-us/library/microsoft.office.interop.excel(v=office.15).aspx
  • Word 2013:http://msdn.microsoft.com/en-us/library/microsoft.office.interop.word(v=office.15).aspx
  • PowerPoint2013:http://msdn.microsoft.com/en-us/library/microsoft.office.interop.powerpoint(v=office.15).aspx

結語

在這篇文章中,我們示範如何使用PHP COM函式庫和Microsoft Office Interop功能來倩影一個Word文件。

Windows和Office在我們的日常生活中可以說是被廣泛的使用。能夠知道並了解Office或Windows的強大之處還有PHP,對於任何一個在Windows平台上進行PHP開發的程式設計師都是十分必要的。

使用PHP的COM擴展,掌握這一組合的大門就被打開了。

如果你對於這部分的程式設計比較有興趣,請留下你的評論,我們將會考慮在這個主題上寫更多的文章。我十分期待更多現實生活的應用程式開發能使用這種方式。

Windows, PHP, Word


陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn