badcaffeine

Thursday, December 10, 2009

Using mpdf with codeigniter to generate pdfs from html and css

I’ve been using the outstanding invoice app called Bamboo Invoice for a while now at work, but unfortunately our needs have outgrown it.

So i set to work creating a custom order to invoice system myself using my beloved codeigniter (which is the same php framework that bamboo invoice is created upon).

Once again i found that i was able to create the bulk of the app within a ridiculously short amount of time due to the power of codeigniter (and the fact that i kept sneaking a peek at the source code of bamboo invoice for “inspiration”) and i was left with the one thing i’d been dreading. Coding up the pdf generation part.

Bamboo uses dompdf to generate the pdf’s from html files and to be fair does quite a good job of it. For me however there is one major sticking point with dompdf, and that is it’s frankly awful html and css support. You’re pretty much limited to tables if you want any vaguely acceptable control over your layout and even then making them do what you want them to do is a dark and painful art that i thankfully bullied someone else into doing for me when it came to replicating our invoice form layout.

mPDF

I spent a lot of time searching for another pdf generation library that would accept html files as it’s source, and other than dompdf i was drawing a blank. Then one fine glorious day i stumbled across the magic that is mPDF, i don’t recall what path led me to it (it wasn’t google though grrr) but i leaped upon it and pored over the documentation like a crazed, rabid, desperate animal.

At first glance it seemed to have everything i needed, html support, really really decent css support, and a fine piece of documentation (i’ve been spoiled by how good the codeigniter docs are so anything less really grinds my gears). Right then, time to get it in, and get it going.

Implement

As with any third party library, it needs to be structured properly to allow codeigniter to load it using the loader class see here for details but thankfully mPDF was already setup in that way and i could simply:

  • Drop the mPDF folder into my applications/libraries folder (see below)
  • move the mpdf.php file from the mpdf folder up a level to my application/libraries folder
  • Change line 32 of mpdf.php to reflect the path of the mPDF folder
    ('_MPDF_PATH','/Applications/MAMP/htdocs/invoices/system/application/libraries/mpdf/');
  • And away we go….

The image below is how your folder layout should look.


I can now load the library like any other and start making my pdf’s.

The core methods to make the pdf are very nice and simple and you can actually make a quick pdf with about 3 lines of code:

$this->load->library('mpdf');
$this->mpdf->WriteHTML('<p>Hallo World</p>');
$this->mpdf->Output();

That will output a pdf with all the defaults saying “Hallo world” (example taken from a mPDF example). Nice and simple.

So the next thing to do is to get it to accept a html file as the input source and again we can do that very simply by just passing a view file to the WriteHTML method:

$html = $this->load->view('/pdf_views/order_view',$data, TRUE);
$this->mpdf->WriteHTML($html);
$this->mpdf->Output();

In the above, i’m also passing data to the view file which contains my dynamic information that will be added into the view file when it is parsed, you don’t need to do this yet though, you can just pass in the view file and omit the $data if you want. The TRUE switch added to the end of the loading statement is there to get codeigniter to pass the view file data back as a string instead of outputting it to the browser, Read more about that here.

Configure

That really is all there is to it, what we can do next is add some options to mpdf if we want and concentrate on getting the layout of our pdf how we want it.

mPDF seems to have a really convoluted way of adding new fonts into the mix and i can’t really be bothered with it. Adobe pdf has something called “Core Fonts” that will be supported on any system and i opted to use this option. Basically it means that i can choose from Arial, Helvetica and Times New Roman as my fonts. Well, sounds good to me so i’ll add that option and in my stylesheet or inline css i’ll choose Helvetica as the font. So just add the useOnlyCoreFonts method before the final mPDF output method and that should be enabled. I also add the document title at this stage using the SetTitle call. The image below shows the whole lot. I should say now that the “I” switch i’ve used in the Output method is to output the pdf inline to the browser, you could also use “D” which forces the browser to prompt to download the pdf instead.

Okay, now that you’re able to generate the pdf in different ways and also add some config options, you can move onto the creation of the view file itself. mPDF supports inline css, external stylesheets using <link> or @import and actually adding the styles to each element individually using style=”” syntax.

The first thing you need to add to your css file AND THIS IS IMPORTANT YOU PAY ATTENTION HERE is the page layout setup (height, width etc etc) which you can read up on here Page setup doc link.

I have tried to make my page be A4 so have used the following

@page {
  size: 11.7in 16.6in;
  margin: 15px;
  margin-header: 1mm; 
  margin-footer: 1mm;
}

I suggest you start out making the page as you would a normal web page, in theory mPDF will render it as the browser would but there may be a few things that don’t work, it shouldn’t be hard to work out what they are though with a quick look at the css support element of the docs, i’ve found that floats work very well (which i tend to use a lot) so i was happy, also changing html elements from inline to block using css works well too.

I’m not going to go through anything else as i can’t be bothered and the mPDF docs are more than adequate, you should look at those here mPDF User Guide.

Extra fluff

You may want to move the whole mPDF directory above your webroot for security sake, mines running on a closed doors network so i haven’t, at the very least you should add the following to the top of the mPDF php files:

<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');

There are lots of special tags in mPDF that you can use for page breaks etc, they are worth looking at.

mPDF seems to be setup with support for other languages very well and also a lot of thought seems to have gone into the fonts to make sure they support large character sets, i don’t need any of that but someone else probably does. So great.

I have one problem at the moment, it seems that Firefox (on mac at least) won’t see the .pdf extension and downloads the file without it. Other browsers are fine, i’m going to do some foruming and see what is going on, i imagine it is something simple so when i know i’ll update this post to that effect.

[Edit to above] It seems firefox has some issues with the filename having spaces, if it has a space it won’t append the .pdf extension! Odd. So i replace all spaces with an underscore. Problem solved!

Good luck, if you need any help go on the forums, the main developer seems to be really active there and also really helpful.

Posted by Me on 10/12/2009 at 11:11 AM

{ Categories: CodeIgniterPermalink
Page 1 of 1 pages