繁体   English   中英

使用 PHP 将带有样式(css)的 html 转换为 pdf

[英]Convert html with styling (css) to pdf using PHP

我的代码有问题! 我正在尝试将我的html发票转换为 pdf 发票。 付款后,发票由以下代码生成。 然后 pdf 文件存储在服务器上并通过邮件发送给用户。 这是我正在使用的发票: invoice 但是当我将html转换为 pdf 时,没有应用 styles 并且图像不显示。

这是我的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放在headstyle标签中,如下所示:

<style>
    /* my css here */
</style>

这行不通。 我已经没有css的想法了。

图片的问题

html代码包含这样的img时:

<img src="/path/to/file" alt="" />

图像不显示。 即使我将src更改为https://pathtoimg.com/path/to/file/img.png

希望您知道图像的解决方案以及我正在努力解决的css问题! 已经感谢您的努力!

编辑

我愿意接受其他图书馆或其他方法的建议。 我还没有找到一个稳定的解决方案,所以我可能看错了方向。 如果还有其他解决方案,请告诉我!

这不是一个完整的答案,但我至少可以帮助您解决有关图像的一些问题,并解释为什么Dompdf不能与发票一起使用。

问题

首先,查看您的代码,您似乎也使用了过时的函数set(..)并且$options也没有传递给Dompdf 可以在开发分支中找到新示例所以我们可以通过以下方式解决第一个问题:

// 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" width="600px" /> <img src="https://i.stack.imgur.com/coyyn.png" width="600px" />

这样,至少会呈现徽标。 那么还剩下什么? 查看结果,只有 html 的一部分被正确渲染。 所以 css 文件实际上是有效的。 但这里唯一的问题是发票使用了像display: flex这样的flex等属性。 然而,这还不被支持,正如在这个 GitHub issue中可以看到的那样。 这就是为什么并非所有元素都会正确渲染的原因。

截至目前,一种可能的解决方案是使用html2canvas截取屏幕截图并将其“转换”为带有 jsPdf 的jsPdf ,如在这个 SO answer中所见。 但我不确定这是否适合您的用例。

可能的解决方案

无论如何,由于Snappy 也不支持 flex ,所以我为这个特定案例创建了一个适用的示例,其中包含html2canvas (它确实支持 flex )和jsPdf

首先,例如invoice.php在页面顶部添加以下php function。 这个 function toBase64会将任何“外国” 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 function,请将带有徽标的<img>标签更改为:

<img class="mb-2" src="<?= toBase64('https://streamlabs.nyc3.cdn.digitaloceanspaces.com/assets/svg/logos/logo-short.svg')?>" alt="Logo">

然后像这样更改“打印”按钮的onclick function :

<button type="button" class="btn btn-info transition-3d-hover" onclick="showPDF();">
          <i class="fas fa-print mr-2"></i>
          Print
        </button>

最后在页面底部添加这个javascript function:

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" width="600px" /> Safari <img src="https://i.stack.imgur.com/w2x8K.png" width="600px" />

如您所见,它在 chrome 和 firefox 上比在 safari 上效果更好,因为fontawesomehtml2canvas在 Z60190CB2B5A1D64C6C22FDDA4D9E29E0 上不能很好地协同工作(知道为什么)。

我希望我能澄清一些事情。 如果您有任何问题,请发表评论!

编辑

因为我在服务器端找不到任何其他支持“flex”的“Dom to pdf”,所以我创建了一个在客户端工作的示例。

我以前用过 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();
?>

Output 在此处输入图像描述

第二页在此处输入图像描述

确保您的HTML
<!DOCTYPE html>
并且在head中还包含以下标签
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>

使用以下更新Dompdf脚本

$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);

请包括$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");
?>

您是否尝试将图像转换为 base64 然后添加为 url? 它也将使其独立于网址。

这可以帮助您转换为 base64 如何将图像转换为 base64 编码?

对于 CSS 我试过了,它对我有用。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM