准备工作
首先,请确保在你的Windows系统中已经安装并配置好了一个典型的WAMP环境。由于Interop纯粹是一个Windows的特性,我们将在Windows平台下搭建Apache和PHP。在这个实例中,我使用了EasyPHP 14.1,这款软件安装和配置都十分容易。
接下来,我们要安装Microsoft Office。版本不是严格要求的。我正在使用的是Office2013专业版,但是任何2007之后的Office版本都应该可以使用。
我们然后需要去确保开发Interop应用(又被称作PIA,优先交互组件)的库是安装好的。为了确保这个,我们可以打开资源管理器,然后找到f3366f29246ffb2889202f6f7d4ed99f\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:
调用类编译后的文件后缀名为通常为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을 직접 사용하여 인쇄합니다.
또한 인쇄 작업이 백그라운드를 완전히 종료하는 데 시간이 걸리기 때문에 워드 응용 프로그램을 종료하기 전에 잠시 기다려야 합니다. 지연 없이(3) $w->Quit이 즉시 실행되고 인쇄 작업이 즉시 종료됩니다.
마지막으로 $w->Quit(false)를 호출하여 PHP 스크립트 호출을 통해 단어 응용 프로그램을 닫도록 선택합니다. 여기에 제공된 유일한 매개변수는 종료하기 전에 변경 사항을 저장할지 여부를 나타내는 것입니다. 문서를 변경했지만 다른 사용자의 입력을 위한 깔끔한 템플릿을 원하기 때문에 변경 사항을 저장하고 싶지 않습니다.
코딩이 끝나면 양식 페이지를 로드하고 일부 내용을 입력한 후 양식을 제출할 수 있습니다. 아래 스크린샷은 Word 문서를 업데이트하는 동안 PHP 스크립트의 출력을 보여줍니다.
코딩 속도를 높이고 PIA에 대한 이해를 높입니다
PHP는 약한 유형의 언어입니다. COM 개체는 개체 유형입니다. PHP 코딩 프로세스에서는 개체에서 코드 자동 제안 및 완성 기능을 사용할 수 없습니다. Word 응용 프로그램, 문서 또는 필드에서도 마찬가지입니다. 우리는 그것이 어떤 기능을 가지고 있는지, 어떤 방법을 지원하는지 모릅니다.
이로 인해 개발 속도가 크게 저하됩니다. 개발 속도를 높이려면 우선 C#에서 개발하는 기능을 PHP 코딩으로 마이그레이션하는 것이 좋습니다. 여기에서 다운로드할 수 있는 "#develop"이라는 무료 C# IDE를 추천합니다. #develop이 더 작고, 간단하며, 반응성이 더 좋기 때문에 VS보다 이 소프트웨어를 선호합니다.
C# 코드를 PHP로 마이그레이션하는 것은 전혀 두렵지 않습니다. 먼저 몇 가지 C# 코드를 보여드리겠습니다.
C# 코드가 이전에 보여드린 PHP 코드 베이스와 정확히 동일하다는 것을 알 수 있습니다. C#은 강력한 형식의 언어이므로 일부 형식 변환 문을 볼 수 있으며 변수에 형식을 명시적으로 할당해야 합니다.
코드 유형을 사용하면 코드의 자동 프롬프트 및 자동 코드 완성 기능을 즐길 수 있으므로 개발 속도가 크게 향상됩니다.
더 빠른 PHP 개발을 제공할 수 있는 또 다른 방법은 Word 매크로 명령을 사용하는 것입니다. 먼저 반복해야 하는 작업을 수행한 다음 매크로를 사용하여 기록합니다. 매크로는 실제로 Visual Basic이며 PHP로 매우 쉽게 변환될 수도 있습니다.
가장 중요한 것은 Office PIA Microsoft 공식 문서, 특히 문서에 포함된 각 Office 애플리케이션의 네임스페이스가 항상 우리에게 필요한 가장 중요한 참고 자료가 된다는 것입니다. 가장 일반적으로 사용되는 세 가지 애플리케이션은 다음과 같습니다.
결론
이 기사에서는 PHP COM 라이브러리와 Microsoft Office Interop 기능을 사용하여 Word 문서를 섀도우하는 방법을 보여줍니다.
Windows와 Office는 일상생활에서 널리 사용된다고 할 수 있습니다. Windows 플랫폼에서 PHP를 개발하는 프로그래머에게는 Office나 Windows 및 PHP의 강력한 기능을 알고 이해할 수 있는 능력이 매우 필요합니다.
PHP의 COM 확장을 사용하면 이 조합을 마스터할 수 있는 문이 열립니다.
프로그래밍의 이 부분에 관심이 있으신 경우 의견을 남겨주시면 이 주제에 대한 추가 기사 작성을 고려해 보겠습니다. 저는 이 접근 방식을 사용하여 더욱 실제적인 애플리케이션 개발을 기대하고 있습니다.