Reputation:
I'm having some problems with my code! I am trying to convert my html
invoice to a pdf invoice. After a payment is made the invoice is generated by the code below. Then the pdf file gets stored on the server and sent to the user by mail. This is the invoice I'm using: invoice. But when I convert the html
to pdf the styles are not applied and the images don't show.
This is my PHP
code to convert the html
to a pdf using DomPDF:
<?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);
I think my problem lies with the HTML
code.
I've tried a couple of things but none of these worked for me! Here's what I tried:
I've tried adding the css
with a link
tag like this:
$html .= '<link type="text/css" href="/absolute/path/to/pdf.css" rel="stylesheet" />';
I've also tried adding the link
like a normal (in the head of the file), but both these times I didn't got it working.
I've also tried putting the css
in a style
tag in the head
like this:
<style>
/* my css here */
</style>
This didn't work eighter. I'm running out of ideas for the css
.
When the html
code contains a img
like this:
<img src="/path/to/file" alt="" />
The image doesn't show up. Not even when I change the src
to https://pathtoimg.com/path/to/file/img.png
Hopefully, you know the solution to the image and the css
problems I'm struggling with! Thanks already for your effort!
I'm open to suggestions for other libraries or another approach. I still haven't found a stable solution so I may be looking in the wrong direction. If there are any other solutions out there please let me know!
Upvotes: 14
Views: 16066
Reputation: 1418
Did you try converting your images to base64 and then add as url ? It would make it independent to urls as well.
this can help you to convert to base64 How to convert an image to base64 encoding?
for CSS i tried with and it works for me.
Upvotes: 0
Reputation: 143
I used mpdf before, so decided to give it a try. Using xampp, php 7.4.8 on my windows 10
composer require mpdf/mpdf
Code
<?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();
?>
Upvotes: 1
Reputation: 1452
this won't be a full answer but I can at least help you with some of your problems regarding the images and explain why Dompdf
won't work with the invoice.
First of all, looking at your code, you also seem to use outdated functions set(..)
and $options
is also not passed to Dompdf
. New examples can be found in the develop branch So we can clear the first problems with the following:
// 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);
With this code we get the following result:
(Used a jsFiddle
to prevent the images from taking up too much space. Now they are inline)
<img src="https://i.sstatic.net/86xNQ.png" width="600px" />
<img src="https://i.sstatic.net/coyyn.png" width="600px" />
This way, at least the logo is rendered. So what is left?
Looking at the result, only part of the html is rendered properly. So the css files are in fact working. But the only problem here is that the invoice uses, among other properties, flex
like display: flex
and such. This, however, is not supported, yet, as can be seen in this GitHub issue. That is why not all of the elements will be rendered properly.
As of now, a possible solution would be to take a screenshot with html2canvas
and 'convert' it into a pdf with jsPdf
as can be seen in this SO answer. But I'm not sure if that is a possibility for your use case.
Anyhow, since Snappy has no support for flex as well, I have created an adapted example for this specific case with html2canvas
(which does support flex) and jsPdf
.
First of all on, for example, invoice.php
add the following php function on top of the page. This function toBase64
will convert any 'foreign' svg to a local base64 string, which can be handled by html2canvas
:
function toBase64($url) {
$data = file_get_contents($url);
$base64 = 'data:image/svg+xml;base64,' . base64_encode($data);
return $base64;
}
To only make a pdf of the actual invoice, add id="invoice"
to <div class="card-body p-5 p-md-7 p-lg-11">
Which seems to be the container of the invoice.
To use the php function effectively, change the <img>
tag with the logo to this:
<img class="mb-2" src="<?= toBase64('https://streamlabs.nyc3.cdn.digitaloceanspaces.com/assets/svg/logos/logo-short.svg')?>" alt="Logo">
Then change the onclick
function of the "print" button like so:
<button type="button" class="btn btn-info transition-3d-hover" onclick="showPDF();">
<i class="fas fa-print mr-2"></i>
Print
</button>
At last, add this javascript function at the bottom of the page:
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();
});
}
This basically takes a screenshot of the invoice, creates a base64 string of it, and puts the base64 string in the pdf and uploads it to the server.
In this example upload.php
is the page which actually saves the pdf on the server like so:
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();
It will create the following pdf:
Chrome and firefox
<img src="https://i.sstatic.net/m4gBc.png" width="600px" />
Safari
<img src="https://i.sstatic.net/w2x8K.png" width="600px" />
As you can see, it works better on chrome and firefox than on safari, because fontawesome
and html2canvas
don't work quite well together on safari (don't know why).
I hope I could clear up some things. If you have any questions, please comment!
Because I couldn't find any other 'Dom to pdf' on the serverside which support 'flex' I've created an example which works on the client side.
Upvotes: 10
Reputation: 854
Please include $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");
?>
Upvotes: 0
Reputation: 81
Make sure Your HTML start with
<!DOCTYPE html>
and also contain the following tag in head
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
Update Dompdf script with following
$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);
Upvotes: 0