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

news2024/11/20 11:30:20

在这里插入图片描述

公司里边有生成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.coloradmin.cn/o/1389400.html

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

相关文章

CHS_06.2.1.6_2+线程的实现方式和多线程模型

CHS_06.2.1.6_2线程的实现方式和多线程模型 知识总览线程的实现方式用户级线程&#xff08;User-Level Thread, ULT&#xff09;内核级线程 多线程模型一对一模型多对一多对多模型 知识回顾 在上个小节中 我们学习了线程相关的一些基本概念 基础的知识 那这个小节中 我们回来看…

人脸识别打卡系统的设计与应用!人脸识别打卡系统有什么用?

教育行业的快速日新月异&#xff0c;对信息化建设的要求也越来越高。学校物业管理成为保障学校正常运行的重要环节。然而&#xff0c;在实践中&#xff0c;由于服务人员数量不足、管理不规范等问题&#xff0c;服务质量往往难以保证物业对学校师生的服务质量。为了解决这一问题…

如果你正在学自动化测试,那么请你仔细看完这篇文章

接触了不少同行&#xff0c;由于他们之前一直做手工测试&#xff0c;现在很迫切希望做自动化测试&#xff0c;其中不乏工作5年以上的人。 本人从事软件自动化测试已经近5年&#xff0c;从server端到web端&#xff0c;从API到mobile&#xff0c;切身体会到自动化带来的好处与痛楚…

高级 Python 面试问题与解答

文章目录 专栏导读1.什么是PIP&#xff1f;2.什么是 zip 函数&#xff1f;3.Python 中的 __init __ () 是什么&#xff1f;4.Python 中的访问说明符是什么&#xff1f;5.Python 中的单元测试是什么&#xff1f;6.Python全局解释器锁&#xff08;GIL&#xff09;&#xff1f;7.P…

linux yum仓库

yum是基于rpm包构建的软件更新机制&#xff0c;能够自动解决软件包之间的依赖关系。 常用命令 查询 yum list [软件名] 显示可用的安装包&#xff0c;如果不加软件名则显示所有的可用包 yum info [软件名] 显示安装包的详细信息 如果不加软件名是显示所有包…

CF1178F2 Long Colorful Strip 题解 搜索

Long Colorful Strip 传送门 题面翻译 题目描述 这是 F 题的第二个子任务。F1 和 F2 的区别仅在对于 m m m 和时间的限制上 有 n 1 n1 n1 种颜色标号从 0 0 0 到 n n n&#xff0c;我们有一条全部染成颜色 0 0 0 的长为 m m m 的纸带。 Alice 拿着刷子通过以下的过…

MybatisPlus框架入门级理解

MybatisPlus 快速入门入门案例常见注解常用配置 核心功能条件构造器自定义SQLService接口 快速入门 入门案例 使用MybatisPlus的基本步骤&#xff1a; 1.引入MybatisPlus的起步依赖 MybatisPlus官方提供了starter&#xff0c;其中集成了Mybatis和MybatisPlus的所有功能&#…

Spring Cloud 微服务中 gateway 网关如何设置健康检测端点

主要是为了让 k8s 识别到网关项目已经就绪&#xff0c;但是又不想在里面通过 Controller 实现。因为在 Controller 中这样做并不是最佳实践&#xff0c;因为 Gateway 的设计初衷是专注于路由和过滤&#xff0c;而不是业务逻辑的处理。 在 Gateway 中配置健康检查端点可以通过以…

QT报错记录

Ubuntu22.04安装Qt之后启动Qt Creator报错&#xff1a; Fron 6.5.0, xcb-cursor0 or libxcb-cursor0 is needed to load the Qt xcb platforn plugin. Could not load. This application failed to start because no Qt platforn plugin could be initialized. Reinstalling t…

Qt vs开发将Graphics view提升 QChartview

1提升部件 2 添加Charts模块 3 在包含ui类的头文件添加QT_CHARTS_USE_NAMESPACE 或者添加 using namespace QtCharts #include <QtWidgets/QMainWindow> #include <QtCharts> #include "ui_mainwin.h" #include <qchartview.h> QT_CHARTS_USE_N…

k8s---pod控制器

pod控制器发的概念&#xff1a; 工作负载&#xff0c;workload用于管理pod的中间层&#xff0c;确保pod资源符合预期的状态。 预期状态&#xff1a; 1、副本数 2、容器重启策略 3、镜像拉取策略 pod出故障的出去等等 pod控制器的类型&#xff1a; 1、replicaset&#xf…

Star 72.4k!神仙级开源项目,真的一行代码都没有!

前言 在 GitHub 开源社区&#xff0c;我们经常能发现一些优秀的开源高分项目&#xff01;有时候为了找到最优秀的开源项目&#xff0c;却往往要在 GitHub 上搜罗很久&#xff0c;很消耗时间。 今天小编就给大家推荐一个近乎于完美的 GitHub 中文排行榜&#xff0c;在这里&…

java基础之线程练习题

1.关于线程设计&#xff0c;下列描述正确的是&#xff08;&#xff09; A.线程对象必须实现Runnable 接口 B.启动一个线程直接调用线程对象的 run()方法 C.Java 对多线程同步提供语言级的支持 synchronized D.一个线程可以包括多个进程 2.在java 中的线程模型包含&#xff0…

【刷题】leetcode 1 . 两数之和

两数之和 两数之和1 思路一 &#xff08;简单突破&#xff09;2 思路二 &#xff08;进行优化&#xff09;3 思路三 &#xff08;哈希表 我还不会&#xff09; 谢谢阅读Thanks♪(&#xff65;ω&#xff65;)&#xff89;下一篇文章见&#xff01;&#xff01;&#xff01; 两数…

发票系统对接诺诺平台

诺诺平台判断设备不在线&#xff0c;导致开票失败 代码方面优化&#xff1a;调用接口的时候&#xff1a;是否先调用在线状态检测接口&#xff0c;确认开票设备是在线的状态 &#xff0c;在调用诺诺平台&#xff0c;不在线直接拦截&#xff1b;例如&#xff1a;这个原理就类似于…

三使用Docker Hub管理镜像

使用Docker Hub管理镜像 Docker Hub是Docker官方维护的Docker Registry&#xff0c;上面存放着很多优秀的镜像。不仅如此&#xff0c;Docker Hub还提供认证、工作组结构、工作流工具、构建触发器等工具来简化我们的工作。 前文已经讲过&#xff0c;我们可使用docker search 命…

虚拟机连接(与主机断开连接)U盘的按钮为灰色之解决方法

在WIN11中&#xff0c;虚拟机“连接(与主机断开连接)U盘”选项为灰色&#xff0c;解决方法如下&#xff1a; 1、关闭虚拟机电源&#xff0c;得到下面的界面&#xff1a; 2、根据上述提示&#xff0c;找到虚拟机所在磁盘 3、配置文件属性见下图&#xff1a; 4、使用记事本打开…

C++力扣题目98--验证二叉搜索树

给你一个二叉树的根节点 root &#xff0c;判断其是否是一个有效的二叉搜索树。 有效 二叉搜索树定义如下&#xff1a; 节点的左子树只包含 小于 当前节点的数。节点的右子树只包含 大于 当前节点的数。所有左子树和右子树自身必须也是二叉搜索树。 示例 1&#xff1a; 输入…

在Overleaf中解决IEEE LaTeX模板不能显示中文问题

解决IEEE的Latex模板不能显示中文的问题 写在最前面编译器选择XeLatex导入CTeX包IEEE单栏转换为双栏如何在Overleaf中解决IEEE LaTeX模板显示中文问题&#xff1a;一些其他的补充引言问题描述准备工作为什么中文字符在IEEE LaTeX模板中显示有问题——了解LaTeX编码的基础概念 关…

【JavaEE】CAS

作者主页&#xff1a;paper jie_博客 本文作者&#xff1a;大家好&#xff0c;我是paper jie&#xff0c;感谢你阅读本文&#xff0c;欢迎一建三连哦。 本文于《JavaEE》专栏&#xff0c;本专栏是针对于大学生&#xff0c;编程小白精心打造的。笔者用重金(时间和精力)打造&…