使用PHP将带有样式(css)的html转换为pdf
Posted
技术标签:
【中文标题】使用PHP将带有样式(css)的html转换为pdf【英文标题】:Convert html with styling (css) to pdf using PHP 【发布时间】:2020-10-21 03:18:43 【问题描述】:我的代码有一些问题!我正在尝试将我的 html
发票转换为 pdf 发票。付款后,发票由以下代码生成。然后pdf文件被存储在服务器上并通过邮件发送给用户。这是我正在使用的发票:invoice。但是当我将 html
转换为 pdf 时,不会应用样式并且不会显示图像。
这是我的 php
代码,用于使用 DomPDF 将 html
转换为 pdf:
<?php
require 'vendor/autoload.php';
// reference the Dompdf namespace
$files = glob("/invoices/*.pdf");
foreach ($files as $file) include_once($file);
// instantiate and use the dompdf class
$dompdf = new Dompdf();
$dompdf->loadHtml($html);
$dompdf->setPaper('A4', 'portrait'); //landscape / portrait
$options = new Options();
$options->set('isRemoteEnabled', true);
$options->set('defaultFont', 'OpenSans');
// Render the HTML as PDF
$dompdf->render();
$output = $dompdf->output();
file_put_contents($_SERVER['DOCUMENT_ROOT'] . "/invoices/" . $order_id . ".pdf", $output);
我认为我的问题在于HTML
代码。
css 的问题
我已经尝试了几件事,但这些都不适合我!这是我尝试过的:
试试 1
我尝试添加带有link
标签的css
,如下所示:
$html .= '<link type="text/css" href="/absolute/path/to/pdf.css" rel="stylesheet" />';
我也尝试像正常一样添加link
(在文件头部),但是这两次我都没有成功。
试试 2
我还尝试将css
放在style
标记中,就像这样:
<style>
/* my css here */
</style>
这行不通。我对css
的想法已经不多了。
图片的问题
当html
代码包含img
时:
<img src="/path/to/file" />
图片不显示。即使我将src
更改为https://pathtoimg.com/path/to/file/img.png
希望您知道图像的解决方案以及我正在努力解决的css
问题!已经感谢您的努力!
编辑
我愿意接受有关其他库或其他方法的建议。我还没有找到一个稳定的解决方案,所以我可能看错了方向。如果还有其他解决方案,请告诉我!
【问题讨论】:
这正是 *** 上一个好问题的样子。关于图片,试试这个:***.com/questions/15153139/… 您是否尝试在 CSS href 中包含域?我正在使用另一个库 Knp Snappy 来生成 PDF,这就是我需要做的。 @MeesEgberts 我上面的评论中有一个链接。 dompdf:“从本质上讲,dompdf 是(大部分)符合 CSS 2.1 的 HTML 布局,处理大多数 CSS 2.1 和一些 CSS3 属性,” id 建议只使用其他更新的东西。我使用mpdf.github.io,没有任何问题。 @fubar 谢谢你的回答!我会看看并试一试! 【参考方案1】:这不是一个完整的答案,但我至少可以帮助您解决有关图像的一些问题,并解释为什么Dompdf
不能与invoice 一起使用。
问题
首先,查看您的代码,您似乎也使用了过时的函数set(..)
并且$options
也没有传递给Dompdf
。新的例子可以在the develop branch 中找到,所以我们可以通过以下方式解决第一个问题:
// Include autoloader
require 'vendor/autoload.php';
// reference the Dompdf namespace
$files = glob("/invoices/*.pdf");
foreach ($files as $file) include_once($file);
// Reference the Dompdf namespace
use Dompdf\Dompdf;
//Also reference the options namespace
use Dompdf\Options;
//First initialise the options
$options = new Options();
//This way of setting options is new see: https://github.com/dompdf/dompdf/issues/2181
$options->setIsRemoteEnabled(true);
$options->setDefaultFont('OpenSans');
// Instantiate and use the dompdf class with the options
$dompdf = new Dompdf($options);
// Load content from html file
$html = ...; //file_get_contents("invoice.html");
$dompdf->loadHtml($html);
$dompdf->setPaper('A4', 'portrait'); //landscape / portrait
// Render the HTML as PDF
$dompdf->render();
$output = $dompdf->output();
file_put_contents($_SERVER['DOCUMENT_ROOT'] . "/invoices/" . $order_id . ".pdf", $output);
使用这段代码,我们得到以下结果:
(使用jsFiddle
来防止图像占用太多空间。现在它们是内联的)
<img src="https://i.stack.imgur.com/86xNQ.png" />
<img src="https://i.stack.imgur.com/coyyn.png" />
这样,至少会呈现徽标。那么还剩下什么?
查看结果,只有部分 html 被正确呈现。所以css文件实际上正在工作。但这里唯一的问题是发票使用flex
等属性,如display: flex
等。然而,这还不被支持,正如 in this GitHub issue 所见。这就是为什么不能正确渲染所有元素的原因。
到目前为止,一种可能的解决方案是使用html2canvas
截取屏幕截图,然后使用jsPdf
将其“转换”为pdf,如in this SO answer 所示。但我不确定这是否适合您的用例。
可能的解决方案
无论如何,从Snappy has no support for flex as well 开始,我已经为这个特定情况创建了一个经过调整的示例,使用html2canvas
(确实支持flex)和jsPdf
。
首先对例如invoice.php
在页面顶部添加以下php函数。这个函数toBase64
会将任何'foreign' svg 转换为本地base64 字符串,可以由html2canvas
处理:
function toBase64($url)
$data = file_get_contents($url);
$base64 = 'data:image/svg+xml;base64,' . base64_encode($data);
return $base64;
要仅制作实际发票的 pdf,请将 id="invoice"
添加到 <div class="card-body p-5 p-md-7 p-lg-11">
,这似乎是发票的容器。
要有效使用php功能,请将带有徽标的<img>
标签更改为:
<img class="mb-2" src="<?= toBase64('https://streamlabs.nyc3.cdn.digitaloceanspaces.com/assets/svg/logos/logo-short.svg')?>" >
然后像这样更改“打印”按钮的onclick
功能:
<button type="button" class="btn btn-info transition-3d-hover" onclick="showPDF();">
<i class="fas fa-print mr-2"></i>
Print
</button>
最后,在页面底部添加这个javascript函数:
function showPDF()
//Create screenshot of body
html2canvas(document.getElementById('invoice'), scale: 3,scrollY: -window.scrollY).then(canvas =>
var imgData = canvas.toDataURL('image/jpeg');
//add the image to, and create the pdf
var pdf = new jsPDF('P', 'pt', [canvas.width, canvas.height]);
pdf.addImage(imgData, 'jpeg', 0, 0, canvas.width, canvas.height);
//set the pdfFinal to be later downloaded
//convert the pdf to a base64 string to make it uploadable
let output = btoa(pdf.output());
$.ajax(
method: "POST",
url: "upload.php",
data: data: output, fileName: 'order-123.pdf',
).done(function(data)
console.log('all done');
//view errors
console.log(data);
);
//Then, let the client print the document.
window.print();
);
这基本上是对发票进行截图,创建一个base64字符串,并将base64字符串放入pdf中并上传到服务器。
在此示例中,upload.php
是实际将 pdf 保存在服务器上的页面,如下所示:
if(isset($_POST['data']))
$data = base64_decode($_POST['data']);
if (isset($_POST['fileName']))
$file = $_POST['fileName'];
else
$file = "order-" . rand(10,1000) . ".pdf";
file_put_contents($file, $data);
echo "Succes";
else
echo "No Data Sent";
exit();
它将创建以下 pdf:
Chrome and firefox
<img src="https://i.stack.imgur.com/m4gBc.png" />
Safari
<img src="https://i.stack.imgur.com/w2x8K.png" />
如您所见,它在 chrome 和 firefox 上比在 safari 上效果更好,因为 fontawesome
和 html2canvas
在 safari 上不能很好地协同工作(不知道为什么)。
我希望我能澄清一些事情。如有任何问题,请发表评论!
编辑
因为我在服务器端找不到任何其他支持“flex”的“Dom to pdf”,所以我创建了一个适用于客户端的示例。
【讨论】:
不错的答案!这肯定会帮助人们! 你不能从图像创建一个 pdf 并将其存储在服务器上吗?这样您就可以通过邮件将发票发送给客户! @MeesEgberts 你的意思是截屏,将该图像发送到服务器,然后在服务器上从它创建一个 pdf? 是的,就是这样!这样你就可以将pdf文件存储在服务器上并发送给客户端! @MeesEgberts 我还不知道该怎么做,但也许有人可以编辑我的答案以适应它【参考方案2】:我以前用过mpdf,所以决定试一试。在我的 Windows 10 上使用 xampp、php 7.4.8
composer require mpdf/mpdf
代码
<?php
//Fadil Eldin
//8/16/2020
require_once __DIR__ . '/vendor/autoload.php';
$mpdf = new \Mpdf\Mpdf();
$html = file_get_contents('https://gostreamlabs.com/front/html/pages/invoice.html');
$mpdf->WriteHTML("");
$mpdf->WriteHTML($html);
$mpdf->Output();
?>
输出
第二页
【讨论】:
【参考方案3】:确保您的 HTML 以 <!DOCTYPE html>
开头
并且在head中还包含以下标签<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
使用以下
$dompdf = new Dompdf();
$dompdf->setPaper('A4', 'portrait');
$dompdf->set_option( 'isHtml5ParserEnabled', true);
$dompdf->set_option( 'isRemoteEnabled', true);
$dompdf->set_option( 'defaultMediaType', 'all' );
$dompdf->set_option( 'isFontSubsettingEnabled', true );
$dompdf->set_option('defaultFont', 'OpenSans');
$dompdf->loadHtml( $html, 'UTF-8' );
$dompdf->render();
// Attachment value 1 for download and 0 for preview PDF
//$dompdf->stream( 'testing.pdf', array( 'Attachment' => 1 ) );
$output = $dompdf->output();
file_put_contents($_SERVER['DOCUMENT_ROOT'] . "/invoices/" . $order_id . ".pdf", $output);
【讨论】:
【参考方案4】:请包含$dompdf->set_base_path('localhost/exampls/style.css');
<?php
require_once "dompdf/dompdf_config.inc.php";
$dompdf = new DOMPDF();
$html ="
<html>
<head>
<link type="text/css" href="localhost/exampls/style.css" rel="stylesheet" />
</head>
<body>
<table>
<tr >
<td class='abc'>testing table</td>
</tr>
<tr>
<td class='def'>Testng header</td>
</tr>
</table>
</body>
</html>";
$dompdf->load_html($html);
$dompdf->render();
$dompdf->set_base_path('localhost/exampls/style.css');
$dompdf->stream("hello.pdf");
?>
【讨论】:
【参考方案5】:您是否尝试将图像转换为 base64,然后添加为 url ?它也会使其独立于 url。
这可以帮助您转换为 base64 How to convert an image to base64 encoding?
对于我尝试过的 CSS,它适用于我。
【讨论】:
以上是关于使用PHP将带有样式(css)的html转换为pdf的主要内容,如果未能解决你的问题,请参考以下文章
使用Java将HTML文件转换为带有图片和样式的PDF [重复]
如何在 ReactJS 中将带有属性的 CSS 转换为 MaterialUI 样式
在 ASP.NET 中将 HTML 转换为 PDF 时保持 CSS 样式[关闭]