PHPWord:用php来填写word表格——兜兜转
一开始看到这样的需求我内心是拒绝的,服务端不该去做桌面端的事。但...甲方爸爸的脑洞要求简单推辞掉岂不是显得我很没水平?!
所以..我还是决定挑战一下。
具体的要求是有一张既定格式的Word表格,用户在网上填表单,提交保存后把内容填入Word文件导出给管理员(目的:减去人手复制黏贴录入的工作步骤,便于批量打印做线下用途)
之前有用过 phpexcel,举一反三想会不会有 phpword呢?还真有!(不知道是不是同一个团队的作品,这方面我不求甚解了)
挑战的流水账:
直接去官方Github 弄下来就干!
https://github.com/PHPOffice/PHPWord
检索官方的samples.. 有点晕,没有演示怎样在已有的表格上填写内容(定位输入指针,添加内容),只有如何创建表格按顺序添加元素。如果要重新新建自己创建表格涉及的表格排版、样式、布局极其复杂,看的脑壳疼。 (其实脑子转个弯,已有的表格填表是有现成解决方案的……这是后来的发现) 看看源码它的类有什么方法。 不看不得了, 一看吓到了!
当前最新的 0.16.0 版经过几十个版本的演进已非常完善,换句话说...非常的庞大臃肿!同时考虑到了老版本 .doc
和 新版 .docx
的相容还有其他的pdf
、html
、rtf
等关联格式;内容上考虑到了文档的数字签名、版权信息、文档安全、多语言支持、图文、分页、页头页脚,基本上把 软件 word 支持的功能全部在类的功能里复刻了一份(可怕!)。 项目如此的庞大 我看到它引入了 命名空间(namespace
) 来避免复杂性下的冲突,让结构更可读。由此一个坑有我逐步刨开越挖越深.
按照样例先写最简单的进行了引用。
$tpldoc = "tab2.docx";
require ("../../phpword/PhpWord.php");
$PHPWord = new \PhpOffice\PhpWord\PhpWord();
$tpl = new \PhpOffice\PhpWord\TemplateProcessor($tpldoc);
...
试运行,报了一堆错,大概是 CLASS not found 之类,反复比对了范例和自己的demo,发现phpword里并没有sample中提及的 autoloader.php 因此如果我不手动声明引用全部相关的CLASS则可能一直报错,上文说了phpword项目的功能模块十分庞大,如果要手动梳理的话,各个模块相互的依赖关系错综复杂人会疯。而且由于涉及命名空间,搞错了其中一个小路径可能会卡住整个调用过程... 于是一路往下查,到底autoload哪里来,怎么写。
我又发现,这个phpword项目目前的版本是基于 composer
的,按官方的核心开发者的说明,在github代码仓中移除了autoload文件,如有需要自行通过 composer
生成!甚至,建议用户以下命令直接从 composer 上拉取安装phpword 。
composer require phpoffice/phpword
看到这里我有点懵了... phpword项目组是假定用户都会用 composer 的前提下的啊... 那我现在除了要梳理项目命名空间外,还要去掌握composer框架的正确部署。
于是变继续向下研究呗,怎样部署 composer ,去composer 的官方站
https://getcomposer.org/download/
哇,好神奇,竟然是用php来安装部署的,php果然是世界上最好的语言(误)
php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
php -r "if (hash_file('sha384', 'composer-setup.php') === '48e3236262b34d30969dca3c37281b3b4bbe3221bda826ac6a9a62d6444cdb0dcd0615698a5cbe587c3f0fe57a54d8f5') { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;"
php composer-setup.php
php -r "unlink('composer-setup.php');"
嗯,再仔细读安装说明的话,发现就这样安装,会得到的执行文件名是 composer.phar
而且只在安装目录下,这样不太方便,所以上面的第三行要改写一下
php composer-setup.php --install-dir=/usr/local/bin --filename=composer
这样在任何路径都能直接用 composer 命令执行,才方便些。
安装完后用上文说的方法重新拉取安装phpword
发现拉取会卡在那里很久没有反应,额...我在国外的VPS上试试,秒连,看来被墙了..查找国内有镜像分流,可以解决这个问题... 好吧..又研究了怎样更改composer的源,找到个(并不是唯一的一个)
https://pkg.phpcomposer.com/
然后进入phpword项目的有 composer.json
文件的路径,执行
composer dump-autoload
再再再然后,我修改了最初的demo 试运行
我还是得到了一些错误.. =____=|||
感觉玩脱了... 事情进展成这样,需求变得越来越复杂。我发现距离自己原初的需求越走越远!不行!!
首先,我并没有说composer不好,当项目复杂的时候,使用成熟规范框架无疑可以大大缩减后期维护。
但我并不想因为一个小小的需求而去动牛刀,把PHP这么简单快乐的东西变成另一个JAVA.
就如我只想要装台电动滑板车,并不应动用到太空穿梭机的技术一样。
我只要实现一个该死的简单要求,把几个中文字写到一个word文件里去,仅此而已!
于是,我发了个大招!
我去找github的历史版本.. 查到从 0.9.0 开始使用 namespace
。 我果断下载了再早一个版本的 0.8.0
(复联4的梗?)
然后把这个 0.8 的版本套用到代码上,删干净了之前定义的 autoload 和 命名空间的引用。
<?php
echo "start init.<br/>";
require_once("../../phpword08/PHPWord.php");
$pw = new PhpWord();
$tpl = $pw->loadTemplate($tpldoc);
echo "replacing.<br/>";
$tpl->setValue('name', '张三');
$tpl->setValue('sex', '男');
$tpl->setValue('edu', '大专');
$tpl->saveAs('filled.docx');
echo "done.";
?>
试运行!提示执行完毕,文件 filled.docx
也生成了
完美!
P.S. 顺带一提,上文说的转换思路解决方案就是..用word模板功能 在模板文件中自己标注 ${变量名} 的格式,然后用 loadTemplate() 加载文件 用 setValue()方法查找和替换内容。
最后的最后
我还是认为,服务端最好还是不要代劳桌面端的活..不合适(遛)..
