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

Mee*_*rts 13 html css php pdf

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

这是我使用 DomPDFPHP将其转换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);
Run Code Online (Sandbox Code Playgroud)

我认为我的问题在于HTML代码。

css的问题

我已经尝试了几件事,但这些都不适合我!这是我尝试过的:

尝试 1

我试过css用这样的link标签添加:

$html .= '<link type="text/css" href="/absolute/path/to/pdf.css" rel="stylesheet" />'; 我也试过添加link像一个正常的(在文件的头部),但是这两次我都没有让它工作。

尝试 2

我也试图把cssstyle标签中head是这样的:

<style>
    /* my css here */
</style>
Run Code Online (Sandbox Code Playgroud)

这没有奏效。我的css.

图片的问题

html代码包含img这样的:

<img src="/path/to/file" alt="" />
Run Code Online (Sandbox Code Playgroud)

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

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

编辑

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

Chi*_*iel 7

这不是一个完整的答案,但我至少可以帮助您解决有关图像的一些问题,并解释为什么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);

Run Code Online (Sandbox Code Playgroud)

使用此代码,我们得到以下结果:

(使用 ajsFiddle防止图像占用太多空间。现在它们是内联的)

<img src="https://i.stack.imgur.com/86xNQ.png" width="600px" />
<img src="https://i.stack.imgur.com/coyyn.png" width="600px" />
Run Code Online (Sandbox Code Playgroud)

这样,至少可以呈现徽标。那么还剩下什么?查看结果,只有部分 html 被正确呈现。所以css文件实际上正在工作。但这里唯一的问题是发票使用了其他属性,flex诸如此类display: flex。但是,正如在此 GitHub 问题 中所见,尚不支持此功能。这就是为什么并非所有元素都能正确呈现的原因。

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

可能的解决方案

无论如何,由于Snappy 也不支持 flex,我已经为这个特定情况创建了一个改编的例子html2canvas(它支持 flex)和jsPdf

首先,例如,invoice.php在页面顶部添加以下php函数。此函数toBase64将任何“外来”svg 转换为本地 base64 字符串,可以通过以下方式处理html2canvas

function toBase64($url) {
  $data = file_get_contents($url);
  $base64 = 'data:image/svg+xml;base64,' . base64_encode($data);
  return $base64;
}
Run Code Online (Sandbox Code Playgroud)

要仅制作实际发票的 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')?>" alt="Logo">
Run Code Online (Sandbox Code Playgroud)

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

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

Run Code Online (Sandbox Code Playgroud)

最后,在页面底部添加这个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();
      });
}

Run Code Online (Sandbox Code Playgroud)

这基本上是对发票进行截图,创建它的 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();
Run Code Online (Sandbox Code Playgroud)

它将创建以下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" />
Run Code Online (Sandbox Code Playgroud)

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

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

编辑

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


小智 0

确保您的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);

Run Code Online (Sandbox Code Playgroud)