一开始看到这样的需求我内心是拒绝的,服务端不该去做桌面端的事。但...甲方爸爸的脑洞要求简单推辞掉岂不是显得我很没水平?!
所以..我还是决定挑战一下。

具体的要求是有一张既定格式的Word表格,用户在网上填表单,提交保存后把内容填入Word文件导出给管理员(目的:减去人手复制黏贴录入的工作步骤,便于批量打印做线下用途)

之前有用过 phpexcel,举一反三想会不会有 phpword呢?还真有!(不知道是不是同一个团队的作品,这方面我不求甚解了)

挑战的流水账:

直接去官方Github 弄下来就干!
https://github.com/PHPOffice/PHPWord

检索官方的samples.. 有点晕,没有演示怎样在已有的表格上填写内容(定位输入指针,添加内容),只有如何创建表格按顺序添加元素。如果要重新新建自己创建表格涉及的表格排版、样式、布局极其复杂,看的脑壳疼。 (其实脑子转个弯,已有的表格填表是有现成解决方案的……这是后来的发现) 看看源码它的类有什么方法。 不看不得了, 一看吓到了!

当前最新的 0.16.0 版经过几十个版本的演进已非常完善,换句话说...非常的庞大臃肿!同时考虑到了老版本 .doc 和 新版 .docx 的相容还有其他的pdfhtmlrtf 等关联格式;内容上考虑到了文档的数字签名、版权信息、文档安全、多语言支持、图文、分页、页头页脚,基本上把 软件 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 也生成了
QQ截图20190503071606.png

完美!

P.S. 顺带一提,上文说的转换思路解决方案就是..用word模板功能 在模板文件中自己标注 ${变量名} 的格式,然后用 loadTemplate() 加载文件 用 setValue()方法查找和替换内容。

最后的最后

我还是认为,服务端最好还是不要代劳桌面端的活..不合适(遛)..

标签: php, phpword, word, composer

添加新评论