在Windows系统下使用PHP生成Word文档的教程

准备工作

首先,请确保在你的Windows系统中已经安装并配置好了一个典型的WAMP环境。由于Interop纯粹是一个Windows的特性,我们将在Windows平台下搭建Apache和PHP。在这个实例中,我使用了EasyPHP 14.1,这款软件安装和配置都十分容易。

接下来,我们要安装Microsoft Office。版本不是严格要求的。我正在使用的是Office2013专业版,但是任何2007之后的Office版本都应该可以使用。

我们然后需要去确保开发Interop应用(又被称作PIA,优先交互组件)的库是安装好的。为了确保这个,我们可以打开资源管理器,然后找到<Windows目录>\assembly,我们将会看到下面安装好的PIAs分支:

我们可以看到一个 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表单做前台的展示,看起来应该是这样的:

我们有一个文本框用于输入“Name”,一个“Gender”的单选按钮组,一个“Age”的域值控制还有一个文本域来写“Message”,最后,还需要一个“Submit”按钮。

将该文件命名为“index.html”,保存在虚拟主机的根目录下,这样我们可以直接通过URL访问该文件,例如:http://test/test/interop

后台

后台的PHP文件是我们所要讨论的核心部分。我先将代码贴到下面,接下来在一步一步的进行解释

<?php

$inputs = $_POST;
$inputs['printdate']='';
// A dummy value to avoid a PHP notice as we don't have "printdate" in the POST variables. 

$assembly = 'Microsoft.Office.Interop.Word, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c';
$class = 'Microsoft.Office.Interop.Word.ApplicationClass';

$w = new DOTNET($assembly, $class);
$w->visible = true;

$fn = __DIR__ . '\\template.docx';

$d = $w->Documents->Open($fn);

echo "Document opened.<br><hr>";

$flds = $d->Fields;
$count = $flds->Count;
echo "There are $count fields in this document.<br>";
echo "<ul>";
$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 "<li>Mappig field $index: $key with value $value</li>";
}
echo "</ul>";

echo "Mapping done!<br><hr>";
echo "Printing. Please wait...<br>";

$d->PrintOut();
sleep(3);
echo "Done!";

$w->Quit(false);
$w=null;

function setupfields()
{
  $mapping = array();
  $mapping[0] = 'gender';
  $mapping[1] = 'name';
  $mapping[2] = 'age';
  $mapping[3] = 'msg';
  $mapping[4] = 'printdate';

  return $mapping;
}

在设置完用来获取表单中传过来的值的变量$inputs之后,我们要创建一个虚拟值用来存放printdate——我们稍后会讨论为何需要这个变量——现在,我们看到这4行比较关键的代码:

$assembly = 'Microsoft.Office.Interop.Word, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c';
$class = 'Microsoft.Office.Interop.Word.ApplicationClass';

$w = new DOTNET($assembly, $class);
$w->visible = true;

在PHP中的COM操纵需要在一个assembly里请求一个class的实例。在我们的案例中,我见将要操作Word。如果考虑到我们上一个截图中展示的代码,我们将能够构造出一个完整签名的Word PIA:

  • “Name”,“Version”,“Public Key Token”是在当我们浏览“c:\Windows\assembly”时所展示的信息
  • “Cultrue”总是neutrual的。

调用类编译后的文件后缀名为通常为ApplicationClass.

通过设置下面两个步骤,我们可以初始化一个word对象:

首先,word对象可以保存在后台或者通过将visible属性设置为true,使它在前台展示出来。

然后,我们打开将要处理的文档,把它实例化为一个$d变量。

在文档对象中,基于html表单的文本来添加文档的内容,这里可以设置一些参数。
最不好的方式是对php页面上所有内容进行硬编码,然后将它们添加到word对象中。我强烈建议不采用此种方式,原因有:

1 代码没有灵活性,php内容的任何变化都需要重新修改脚本;
2 违反了控制层、展示层的分离;
3  如果需要设置word内容的格式(对齐,字体,样式,等),这种方式大大增加了代码行数,并且以编程的方式来修改样式是非常麻烦的。

另一种方式是使用“搜索-替换”。PHP内置的这种功能非常强大。我们可以创建一个word文档,在那些需要被替换的占位内容周围放置一些分隔符。比如,我们创建一个文档包含如下内容:

{{name}}

在PHP中,我们只需使用从表单提交中获取的“Name”值来替换。这种方式避免了第一选项中的那些缺点。我们只需要找到正确的分隔符,在这个例子中,除了使用的模板是word文档,我们更像是做一个模板渲染。

第三个选项是我的建议,并是Word中的高级主题。我们将用域来表示占位符,在我们的PHP代码中,我们会直接更新了相应的表单值的字段。

这种方法灵活,快速,符合Word的最佳实践。这也避免了文件的全文搜索,这有助于提高性能。请注意,此选项有它的缺点了。

总之,自从首次亮相,Word从来没有支持命名索引的字段。尽管我们对于我们在Word文档中创建的字段提供了一个名字,我们还是要用数字下标来访问每个字段。这也解释了为什么我们要使用专用的功能(setupfields)做表单字段的字段索引和名之间的映射手册

学习如何在word文档中插入字段(点击这里查看一个定制好的版本),请参阅相关 Word 帮助主题和手册。对于这个demo,我们有一个具备5个MERGEFIELD字段的文档。此外,我们将文档和PHP脚本放在一个目录下,以方便获取。

请注意,printdate字段并没有一个相应的窗体字段。这就是为什么我们要在$inputs数组中添加一个假的printdate作为key。没有这个key,脚本依然可以执行,但是会有提示说明$inputs数组中不存在索引printdate。

在使用表单数据更新完字段的值之后,我们将会使用下面的命令打印文档:

$d->PrintOut();

PrintOut方法有几个可选参数,这里,我们使用最简单的格式。这将会给链接到我们Windows机器的默认打印机打印一份副本。

我们可以通过使用PrintPreview进行打印预览。在纯自动化的情景下,当然,我们直接使用PrintOut进行打印。

在退出word应用程序之前,我们还需要稍作等待,因为打印工作需要时间来完全退出后台。如果没有delay(3),$w->Quit将会立刻得到执行,并且打印工作立刻被终止。

最终,我们调用 $w->Quit(false) 来选择通过我们的PHP脚本调用关闭word应用程序。这里提供的唯一参数是用来指明我们是否希望在退出前保存更改。我们确实对文档进行了更改,但是我们不希望保存它们,因为我们希望能为其他用户的输入提供一份干净的模板。

当我们完成编码之后,我们可以加载表单页面,输入一些内容并提交表单。下面的截图展示了PHP脚本的输出,同时更新了Word文档:

提高编码速度并更好的理解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扩展,掌握这一组合的大门就被打开了。

如果你对于这部分的编程比较感兴趣,请留下你的评论,我们将会考虑在这个话题上写更多的文章。我十分期待更多现实生活的应用开发能使用这种方式。

(0)

相关推荐

  • PHP创建word文档的方法(平台无关)

    本文实例讲述了PHP创建word文档的方法.分享给大家供大家参考,具体如下: 关于用PHP生成word,在网上找了很多资料,有调用COM组件生成的,有安装PHP扩展生成的.都不免麻烦,以下为比较简洁的一种方法,且可跨平台. 以下为详细代码: class.word.php <?php class Word{ function start(){ ob_start(); //打开输出控制缓冲 echo '<html xmlns:o="urn:schemas-microsoft-com:of

  • php在程序中将网页生成word文档并提供下载的代码

    在这篇文章中主要解决两个问题: 1:在php中如何把html中的内容生成到word文档中 2:php把html中的内容生成到word文档中时,不居中显示问题,即会默认按照web视图进行显示. 3:php把html中的内容生成到word文档中时,相关样式不兼容问题 正文: 复制代码 代码如下: echo '<html xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:w="urn:schemas-microso

  • php通过baihui网API实现读取word文档并展示

    项目中遇到一个小问题,想实现php 如何读取word文档,并将其内容原样显示 可以 使用API 可以看看baihui.com 的写写应用 的API 申请一个 APPKEY 就能使用,你可以看看 ... 对免费版本有限制 比如 excel 支持,可以参考我这个 appkey是我申请的,可以使用吧 ... 保存成本地的一个html文件 打开后直接使用 word 的类似 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN&q

  • PHP读取word文档的方法分析【基于COM组件】

    本文实例讲述了PHP读取word文档的方法.分享给大家供大家参考,具体如下: php开发 过程中可能会word文档的读取问题,这里可以利用com组件来完成此项操作 一.先开启php.ini的COM,操作如下 1. extension=php_com_dotnet.dll 2. com.allow_dcom = true 二.开启之后就可以试下如下操作 1.建立一个指向新COM组件的索引 $word = new COM("word.application") or die("C

  • 在PHP中读取和写入WORD文档的代码

    复制代码 代码如下: <?  // 建立一个指向新COM组件的索引  $word = new COM("word.application") or die("Can't start Word!");  // 显示目前正在使用的Word的版本号  //echo "Loading Word, v. {$word->Version}<br>";  // 把它的可见性设置为0(假),如果要使它在最前端打开,使用1(真)  // t

  • 使用PHP导出Word文档的原理和实例

    原理 一般,有2种方法可以导出doc文档,一种是使用com,并且作为php的一个扩展库安装到服务器上,然后创建一个com,调用它的方法.安装过office的服务器可以调用一个叫word.application的com,可以生成word文档,不过这种方式我不推荐,因为执行效率比较低(我测试了一下,在执行代码的时候,服务器会真的去打开一个word客户端).理想的com应该是没有界面的,在后台进行数据转换,这样效果会比较好,但是这些扩展一般需要收费.第2种方法,就是用PHP将我们的doc文档内容直接写

  • PHP实现仿百度文库,豆丁在线文档效果(word,excel,ppt转flash)

    本文实例讲述了PHP实现仿百度文库,豆丁在线文档效果.分享给大家供大家参考,具体如下: 由于项目要实现类似百度文库的功能,又是我一个人做的项目,所以就想到找免费的现成的来使用.在网上找到的都是一样的.如下: Flash Paper支持Office文档(.doc,.xls,.ppt)直接转换为PDF或SWF,速度很快,效果较好.可惜,Flash Paper V2.2后没有再更新了.安装Flash Paper后,可以直接使用命令调用FlashPrinter.exe,实现批量转换. 例如:C:\Fla

  • PHP中将网页导出为Word文档的代码

    一般,有2种方法可以导出doc文档,一种是使用com,并且作为php的一个扩展库安装到服务器上,然后创建一个com,调用它的方法.安装过office的服务器可以调用一个叫word.application的com,可以生成word文档,不过这种方式我不推荐,因为执行效率比较低(我测试了一下,在执行代码的时候,服务器会真的去打开一个word客户端).理想的com应该是没有界面的,在后台进行数据转换,这样效果会比较好,但是这些扩展一般需要收费. 第2种方法,就是用PHP将我们的doc文档内容直接写入一

  • php导出word文档与excel电子表格的简单示例代码

    生成word的代码: 复制代码 代码如下: header("Content-type: application/octet-stream"); header("Accept-Ranges: bytes"); header('Content-type: application/doc'); header('Content-Disposition: attachment; filename="测试.doc"'); 生成excel的代码 : 复制代码

  • PHP生成word文档的三种实现方式

    最近工作遇到关于生成word的问题 现在总结一下生成word的三种方法. btw:好像只要是标题带PHP的貌似点击量都不是很高(哥哥我标题还是带上PHP了),不知道为什么,估计博客园上net技术大牛比较多吧,如果把java,.net,php比作程序员的女友,那么java是Oracle门下的大家闺秀,.net微软旗下的名门望族,PHP则是草根门下的山村野姑,这让我等PHP草民闷骚男情何以堪情何以堪..牢骚发完了,正式写吧 PHP生成word原理 利用windows下面的 com组件 利用PHP将内

随机推荐