实战 php 使用 wkhtmltopdf 生成pdf的全过程

在这里插入图片描述

公司里边有生成pdf报告的业务需求,之前有过尝试用tcpdf,直接生成的pdf的过程,但是pdf报告的内容数据,根据不同内容的变化,都是各种各样的bug,一直处理修修补补的状态,让后台开发人员很是头疼.

经过思索和甄选,总结出我们的业务中是由于样式不可控导致的,当时从逻辑上就思考到用html转pdf的思维,后边在搜索中发现wkhtmltopdf(一下简称wk)和其他几款软件及插件的比较,决定选用wk,是由于样式灵活可控,并且我们都没有js动态加载的数据,只是常规的数据渲染到html页面中,然后导出pdf,上手使用后,发现带来了很好的效果,

  • 1.解决了以往pdf报告容量大的弊病
  • 2.解决了出报告效率的问题.
  • 3.提升开发效率
  • 4.适用于windows和linux平台

我们的操作流程是:

web页面中发起请求---->生成一个经过数据渲染的静态页面--->调用wk生成pdf--->返回生成pdf报告地址--->为使用者提供下载入口

wk可以直接把任何一个可以在浏览器中浏览的网页直接转换成一个pdf,首先说明一下它不是一个php 类,而是一个把html页面转换成pdf的一个软件(需要安装在服务器上),但是它并不是一个简单的桌面软件,而且它直接cmd批处理的,使用php中的 shell_exec()函数就可以调用它。下面就介绍如何用php+js+html来让它生成pdf文件的方法(不过有个缺陷就是他需要在服务器端生成一个缓存文件,如果你使用thinkphp框架的话就可以将其缓存文件放在runtime 文件夹中暂存就行)。

  • 下载地址:http://wkhtmltopdf.org/downloads.html

栗子:使用1

<?php
//转成pdf
$html=$_POST['html'];
//Turn on output buffering
ob_start();
$html='<link rel="stylesheet" href="css/common.css" rel="external nofollow" rel="external nofollow" >;
<link rel="stylesheet" href="css/myCenter.css" rel="external nofollow" rel="external nofollow" >;
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" >;'.$html;
//这儿可以引入生成的Html的样式表 路径可以是绝对路径也可以是相对路径,也可以把样式表文件复制到临时html文件的目录下 即这儿的demo文件目录下(默认) 也可以直接把样式写在html页面中直接传递过来
//$html = ob_get_contents();
//$html=$html1.$html;
$filename = "hld";
//save the html page in tmp folder 保存的html临时文件位置 可以是相对路径也是可以是绝对路径 下面用相对路径
file_put_contents("{$filename}.html", $html);
//Clean the output buffer and turn off output buffering
ob_end_clean();
//convert HTML to PDF
shell_exec("wkhtmltopdf -q {$filename}.html {$filename}.pdf");
if(file_exists("{$filename}.pdf")){header("Content-type:application/pdf");header("Content-Disposition:attachment;filename={$filename}.pdf");echo file_get_contents("{$filename}.pdf");//echo "{$filename}.pdf";
}else{exit;
}
>;<div>使用2:</div>
<div>
<pre>phpwkhtmltopdf类库的使用,</pre>
<pre><code>composer require mikehaertl/phpwkhtmltopdf</code></pre>
</div>

———————————分割线———————————

以下是其他朋友在客户端中运用的思路:

一年前产品提了一个让我们试着实现看看的需求,前端要支持用户将系统中java动态页面一键导出为pdf文件。当时项目组决定使用wkhtmltopdf这个第三方软件来实现。当时是由一位后端开发的同学来实现的,逻辑是前端点击按钮,后端生成动态文件,调用wkhtmltopdf生成pdf文件,存储在服务器中,并将文件地址返回给前端进行调用下载,并且要加上页眉页脚(页眉中包含客户商标)。逻辑图如下:

发送请求–>生成动态文件–>调用wkhtmltopdf生成pdf–>返回pdf地址–>下载pdf文件

总算是试着实现了,后来理所当然的三番五次接到各种生成pdf的需求了,wkhtmltopdf在系统中也开始渐渐“活跃”了起来,同时也bug不断。再后来, 由于人员变动,我承接了使用wkhtmltopdf的全部bug。

wkhtmltopdf相信用过的人大多数用过的人对其实又爱又恨。优缺点不多说了,用过的自然会明白。简单总结就是:功能强大,漏洞百出。

———————————分割线———————————

最近接到一个新需求,在动态页面中的过程变量(就是各种交互组件,涉及到产品保密不做多描述)需要支持用户设置宽高,其中图片有一种配置是上传后,如果配置了默认,则显根据图片原始大小显示。最近在对前端项目进行改造升级,毫不犹豫的使用了React作为输出渲染,功能实现的很愉快。

最终,从测试那里接到噩耗,生成pdf内容不全,甚至说没有内容。鉴于wkhtmltopdf的使用者较少,或者用来生成文件的目标页面几乎都比较简单,网上也没有太多的相关问题解答,于是本老中医根据病情列出了如下可能进行排查:

javascript脚本执行太慢导致部分dom元素无法加载
wkhtmltopdf版本太低
图片以及其他元素动态缩放引起的reflow导致页面加载迟缓
wkhtmltopdf不支持动态页面或者react
第一个猜想很快被排除了,除了调整–javascript-delay参数以外,各种参数调整都无效
第二个猜想也很快排除,wkhtmltopdf已经停止维护好久了(年中的时候本打算替换为phantomjs来实现生成pdf的,结果刚要决定就接到其核心成员退出项目停止维护的噩耗)
第三个测试比较费力气,单个搭建动态页面进行测试,排除每一种动态缩放的可能,但是最终还是一样
第四个测试简单粗暴,先删除了react以及相关组件的引用,居然成功了。注意这里只测试了react。于是当前晚上大张旗鼓,对前三天的功能进行重构,使用传统的javascript对图片过程变量进行了重构,好在轻车熟路,一晚上加上第二天一上午搞定了,编译+测试。。。。。。失败最后冥思苦想,突然想到把动态页面里面的资源拷贝出来,存储成html文件在本地调用生成pdf,成功了!。在请教了部门老大(公司大牛)后,决定使用静态化过程进行处理,方案如下:
发起请求

生成动态页面—>返回动态页面—>获取动态资源—>中间层服务存储为html—>将静态化url传递给后端—>生成pdf并下载

完美解决问题。不过为了赶项目,方案解决的优点仓促。有个弊端就是上行数据量太大,要修改中间层服务器的上传限制。完美的方案是应该把页面静态化和打印访问全部做在中间层中。当然这部分后来慢慢优化吧。

总结:

wkhtmltopdf对动态页面的支持效果一般,动态页面输出pdf的需求中最好不要有太复杂的javascript逻辑,尤其是一些比较大的视图框架(至少react是的)。加载的js文件最好不要太大。如果可以最好先静态化再输出。对于输出页面的样式,尤其是圆角等css3特性,能少则少,否则缺失个线条啥的都是家常便饭

参考

  • https://blog.csdn.net/qq_20867249/article/details/84643252

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/626382.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

医院如何选择高效的内外网数据交换方案 替代U盘进行跨网传输?

医院信息网络是所有网络中安全性要求较高的网络之一&#xff0c;因此很多医院基于信息安全相关要求&#xff0c;会使用防火墙将网络隔离成内网和外网。内网用于日常医疗信息交换&#xff0c;外网可以及时获取Internet信息资源。但是网络隔离后&#xff0c;医院仍存在将报告资料…

【NI国产替代】PXI-6254,32 AI(16位,1 MS/s),48 DIO,PXI多功能I/O模块

32 AI&#xff08;16位&#xff0c;1 MS/s&#xff09;&#xff0c;48 DIO&#xff0c;PXI多功能I/O模块 PXI-6254提供模拟输入、关联数字I/O、两个32位计数器/定时器以及模拟和数字触发。该设备为从实验室自动化、研究、设计验证/测试到制造测试等各种应用提供了低成本的可靠D…

Mybatis基础---------增删查改

增删改 1、新建工具类用来获取会话对象 import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder; import org.apache.ibatis.io.Resources;import java.io.IOExcept…

典型场景解析|PolarDB分布式版如何支撑SaaS多租户?

SaaS多租户背景 很多平台类应用或系统&#xff08;如电商CRM平台、仓库订单平台等等&#xff09;&#xff0c;它们的服务模型是围绕用户维度&#xff08;这里的用户维度可以是一个卖家或品牌&#xff0c;可以是一个仓库等&#xff09;展开的。因此&#xff0c;这类型的平台业务…

【原创】docker +宝塔+安装zabbix

Zabbix: Zabbix可以监控各种网络服务、服务器和网络设备&#xff0c;而无需在目标设备上安装客户端。它的强大之处在于自带的Web界面&#xff0c;能够提供实时监控和各种报警功能。方法1&#xff1a; 步骤 创建Docker Compose文件: 首先&#xff0c;你需要创建一个docker-comp…

C技能树-学习笔记(1-2)C语言概述和数据类型

参考&#xff1a;https://edu.csdn.net/skill/c 1、输出 “Hello, World!” 字符串&#xff0c;请选出错误答案。 2、错误的print函数。 for … in …&#xff1a;是python的语法&#xff0c;C语言的写法是for (;&#x1f609; 3、C标准 没有C19标准。 4、了解C编译管道 …

AI嵌入式K210项目(4)-FPIOA

文章目录 前言一、FPIOA是什么&#xff1f;二、FPIOA代码分析总结 前言 磨刀不误砍柴工&#xff0c;在正式开始学习之前&#xff0c;我们先来了解下K210自带的FPIOA&#xff0c;这个概念可能与我们之前学习STM32有很多不同&#xff0c;STM32每个引脚都有特定的功能&#xff0c…

关于前端面试中forEach方法的灵魂7问?

目录 前言 一、forEach方法支持处理异步函数吗&#xff1f; 二、forEach方法在循环过程中能中断吗&#xff1f; 三、forEach 在删除自己的元素后能重置索引吗&#xff1f; 四、forEach 的性能相比for循环哪个好&#xff1f; 五、使用 forEach 会不会改变原来的数组&#…

xshell:关于ssh用户身份验证不能选择password的解决方法

接下来我将告诉大家如何进行修改让其能够进行密码登录 我使用的软件是VM VirtualBox管理器 进行用户名密码登录后 输入 cd /etc/ 切换到etc目录下 cd /etc/ 切换到etc目录后输入ls ls 切换到ssh目录下 cd ssh 进入文件 sshd_config vi sshd_config 找到指定部分进行修改 如何…

多级缓存架构(三)OpenResty Lua缓存

文章目录 一、nginx服务二、OpenResty服务1. 服务块定义2. 配置修改3. Lua程序编写4. 总结 三、运行四、测试五、高可用集群1. openresty2. tomcat 通过本文章&#xff0c;可以完成多级缓存架构中的Lua缓存。 一、nginx服务 在docker/docker-compose.yml中添加nginx服务块。…

评估文字识别准确性的方法与流程

随着信息技术的发展&#xff0c;文字识别技术在各个领域得到了广泛的应用。然而&#xff0c;在实际应用中&#xff0c;如何评估文字识别的准确性&#xff0c;一直是相关领域的一个难题。本文将介绍几种常用的文字识别准确性评估方法&#xff0c;以期为相关领域的研究提供参考。…

使用vite框架封装vue3插件,发布到npm

目录 一、vue环境搭建 1、创建App.vue 2、修改main.ts 3、修改vite.config.ts 二、插件配置 1、创建插件 2、开发调试 3、打包配置 4、package.json文件配置 上一篇文章讲述使用vite《如何使用vite框架封装一个js库&#xff0c;并发布npm包》封装js库&#xff0c;本文将…

Jmeter后置处理器——JSON提取器

目录 1、简介 2、使用步骤 1&#xff09;添加线程组 2&#xff09;添加http请求 3&#xff09; 添加JSON提取器 1、简介 JSON是一种简单的数据交换格式&#xff0c;允许互联网应用程序快速传输数据。JSON提取器可以从JSON格式响应数据中提取数据、简化从JSON原始数据中提取特定…

Java学习——Junit单元测试

​​ Junit&#xff1a;事实上的标准单元测试框架 使用Junit&#xff1a;只需要使用 TestCase 和 Assert http://t.csdnimg.cn/hgMFJ

Linux网络编程---IP 地址格式转换函数

Linux网络编程—IP 地址格式转换函数 我们更容易阅读的IP地址是以点分十进制表示的&#xff0c;例如&#xff1a;192.168.5.10 &#xff0c;这是一种字符串的形式&#xff0c;但是计算器所需要的IP地址是以二进制进行表示&#xff0c;这便需要我们在点分十进制字符串和二进制地…

java版直播商城平台规划及常见的营销模式 电商源码/小程序/三级分销+商城 免 费 搭 建

鸿鹄云商 B2B2C产品概述 【B2B2C平台】&#xff0c;以传统电商行业为基石&#xff0c;鸿鹄云商支持“商家入驻平台自营”多运营模式&#xff0c;积极打造“全新市场&#xff0c;全新 模式”企业级B2B2C电商平台&#xff0c;致力干助力各行/互联网创业腾飞并获取更多的收益。从消…

【现代密码学】笔记6--伪随机对象的理论构造《introduction to modern cryphtography》

【现代密码学】笔记6--伪随机对象的理论构造《introduction to modern cryphtography》 写在最前面6 伪随机对象的理论构造 写在最前面 主要在 哈工大密码学课程 张宇老师课件 的基础上学习记录笔记。 内容补充&#xff1a;骆婷老师的PPT 《introduction to modern cryphtogr…

Qt/C++中英输入法/嵌入式输入法/小数字面板/简繁切换/特殊字符/支持Qt456

一、前言 在嵌入式板子上由于没有系统层面的输入法支持&#xff0c;所以都绕不开一个问题&#xff0c;那就是在需要输入的UI软件中&#xff0c;必须提供一个输入法来进行输入&#xff0c;大概从Qt5.7开始官方提供了输入法的源码&#xff0c;作为插件的形式加入到Qt中&#xff…

网络广播号角喇叭在智能工地施工现场的应用,以及网络广播在公共广播中的实际作用。

网络号角喇叭在智能工地施工现场的应用&#xff0c;以及网络广播在公共广播中的实际作用。 SV-7044村村通ip网络通信广播号角喇叭&#xff0c;网络音箱&#xff0c;网络音柱是一种公共广播技术&#xff0c;主要应用于公共场所&#xff0c;如公交、商场、大型活动场所等。可以用…

visual studio的安装及scanf报错的解决

visual studio是一款很不错的c语言编译器 下载地址&#xff1a;官网 点击后跳转到以下界面 下滑后点击下载Vasual Sutdio&#xff0c;选择社区版即可 选择位置存放下载文件后&#xff0c;即可开始安装 安装时会稍微等一小会儿。然后会弹出这个窗口&#xff0c;我们选择安装位…