PHP
Article
By Ahmed Shreef

Generating Invoices with Zend_Pdf

By Ahmed Shreef
Help us help you! You'll get a... FREE 6-Month Subscription to SitePoint Premium Plus you'll go in the draw to WIN a new Macbook SitePoint 2017 Survey Yes, let's Do this It only takes 5 min

The PDF format is currently the most used format to exchange documents. If you provide your website users with printable versions of invoices, event tickets and other similar documents, you’ll most likely want to generate them as PDFs on the fly. In this article you will see how you can use Zend_Pdf to auto-generate PDF invoices.

Getting Started

Zend_Pdf allows you to create new PDF documents or load existing ones and modify them. While creating a new document isn’t that difficult, it makes more sense to create a template of the invoice with the information that doesn’t change (company name, address, logo, etc.). It’s better to design your invoice in a program like Microsoft Word or LibreOffice Writer and export it as a PDF. Then you can update the PDF with Zend_Pdf with customer and transaction-specific information. You’ll save coding time because you don’t have to position every element, and it will take less time for the PDF to be generated.

This is what the invoice template I will be using in this article looks like. Your invoice can look different depending on your needs, but the concepts in this article will remain the same.

invoice template

If this is the first time you’re using Zend Framework, download the latest version from www.zendframework.com, upload and unpack the compressed file on your server, and use the following lines at the top of your script to configure the class autoloader. The autoloader will let you create new objects without having to explicitly include all the required files in your code.

<?php
define("ZF_PATH", realpath("/path/to/zf/library/"));
set_include_path(get_include_path() . PATH_SEPARATOR . ZF_PATH);
require_once "Zend/Loader/Autoloader.php";
$loader = Zend_Loader_Autoloader::getInstance();

Remember to change the value of the ZF_PATH constant to the path where you uploaded the copy of the Zend Framework library.

Editor Note Oct 14 2012: The accompanying code on GitHub has been updated to use Composer for installing Zend Framework. As ZF2 is not backwards compatible with ZF1, the version has been locked at 1.11.11. Please refer to the code for suitable ZF_PATH.

Loading the PDF Template

Zend_Pdf allows you to load an existing PDF document with the static load() method.

<?php
// load the invoice
$invoice = Zend_Pdf::load("/path/to/invoice-template.pdf");

The load() method reads the file at the given path and returns an instance of a Zend_Pdf object which manages everything related to the PDF.

Zend_Pdf represents each page of the PDF as instances of the Zend_Pdf_Page object. Its public field pages is an array of the objects in the same order the pages are found in the document. You can benefit from this behavior if you have a PDF document with many pages and you want to reorder its pages; whichever order the Zend_Pdf_Page objects are in the pages array, that is the order the pages will be rendered in the final document.

<?php
// access the first page
$page = $invoice->pages[0];

Specifying Fonts and Colors

When you write text to the PDF page, you are actually drawing shapes that looks like text, and these shapes are defined by the chosen font. So before writing/drawing text, you must specify which font you want to use. The Zend_Pdf_Font class is used to create a font resource which you then use to specify the font used when placing text.

There are two ways to load a font. The first is to use the static method fontWithName() and provide one of the following constants that represent the 14 standard fonts that all PDF viewers support:

  • Zend_Pdf_Font::FONT_COURIER (_BOLD, _ITALIC, _BOLD_ITALIC)
  • Zend_Pdf_Font::FONT_HELVETICA (_BOLD, _ITALIC, _BOLD_ITALIC)
  • Zend_Pdf_Font::FONT_TIMES (_BOLD, _ITALIC, _BOLD_ITALIC)
  • Zend_Pdf_Font::FONT_SYMBOL
  • Zend_Pdf_Font::FONT_ZAPFDINGBATS

The second way is to provide the path to the font file that resides on your file system to the static method fontWithPath(). Make sure that the font is a TrueType font or else fontWithPath() will throw a Zend_Pdf_Exception.

<?php
//loading a font by its name
$font = Zend_Pdf_Font::fontWithName(Zend_Pdf_Font::FONT_TIMES_BOLD);

//load font from file system
$font = Zend_Pdf_Font::fontWithPath("/path/to/myfont.ttf");

The font resource is then passed to the Zend_Pdf_Page‘s setFont() instance method as the first parameter, and the font size measured in points as the second parameter (1 point = 1/72 inches). The represented font will then be used whenever text is drawn to that page.

<?php
$page->setFont($font, 12);

It’s not mandatory to set a color for text before drawing it; black will be used by default if none is specified. But if do you want to use a certain color, you can specify one with one of the Zend_Pdf_Color* objects. Zend_Pdf supports three different color spaces; you can use Gray Scale, RGB, or CMYK. Also, you can specify colors using HTML-style notation.

<?php
// Gray Scale colors range from 0.0 (black) to 1.0 (white)
$color = new Zend_Pdf_Color_GrayScale(0.7);

// RGB uses 3 float values from 0.0 to 1.0 for each color component
$color = new Zend_Pdf_Color_Rgb($r,$g,$b);

// CMYK uses 4 float values from 0.0 to 1.0 for each color component
$color = new Zend_Pdf_Color_Cmyk($c,$m,$y,$k);

// HTML uses any valid color name or hex notation
$color = new Zend_Pdf_Color_HTML("blue");
$color = new Zend_Pdf_Color_HTML("#FF52ED");

The color is then passed to the setFillColor() method of the Zend_Pdf_Page instance.

<?php
$page->setFillColor($color)
--ADVERTISEMENT--

Adding Content

Drawing text on a page is done using Zend_Pdf_Page‘s drawText() instance method. It takes a string of text, and the X and Y coordinates where you want the text to be placed. The coordinates are measured in points, and the origin 0,0 is placed at the bottom-left corner of the page. An increasing X value moves the position towards the right, and an increasing Y value moves the position up.

PDF X,Y coords

Typically you’ll retrieve and calculate information to put on the invoice from a database, but for the sake of example I’ve come up with the following:

<?php
$customerName = "Angelina Jolie";
$invoiceId = "DF-00025786423";

// items in the array are product description,
// quantity purchased, unit price, and total price
$items = array(array("Golden Globe Polish", 1, 25.50, 25.50),
               array("Trophy Shelf", 2, 180.00, 360.00),
               array("DIY Tattoo Kit", 1, 149.99, 149.99));

$subtotal = 535.49;
$discount = 10;
$amountDue = 481.94;

The trickiest part is finding the correct location to place the text on the page and you may require some trial and error even if you’ve meticulously measured your distances. The good news is that since the template elements are static, once you know what coordinates to use they won’t change.

<?php
// specify font
$fontBold = Zend_Pdf_Font::fontWithName(Zend_Pdf_Font::FONT_TIMES_BOLD);
$page->setFont($fontBold, 12);

// specify color
$color = new Zend_Pdf_Color_HTML("navy");
$page->setFillColor($color);

$page->drawText($customerName, 110,641);
// another font
$fontNormal = Zend_Pdf_Font::fontWithName(Zend_Pdf_Font::FONT_TIMES);
$page->setFont($fontNormal, 12);

// invoice information
$page->drawText($invoiceId, 420,642);
$page->drawText(date("M d, Y"), 420,628);
$page->drawText('$' . number_format($subtotal, 2), 510,143);
$page->drawText($discount . "%", 510,123);
$page->drawText('$' . number_format($amountDue, 2), 510,103);

// purchase items
$posY = 560;
foreach ($itmes as $item) {
    $page->drawText($item[0], 50, $posY);
    $page->drawText($item[1], 350, $posY);
    $page->drawText(number_format($item[2], 2), 430, $posY);
    $page->drawText(number_format($item[3], 2), 510, $posY);
    $posY -= 22.7;
}

Rendering the Invoice

After adding the information to the template, you can either save it to a different file (be careful not to overwrite your template!) or send it to the browser. To save it, you use Zend_Pdf‘s instance method save().

<?php
$invoice->save($pathToFile);

Using the instance method render() will return the PDF document as a string. This is probably what you want if you are generating a document on the fly and want the user to download it without saving copy of the document on your server first. You can output the correct HTTP headers so the browser will know how to handle the file, and then send the document string.

<?php
// instruct browser to download the PDF
header("Content-Type: application/x-pdf");
header("Content-Disposition: attachment; filename=invoice-". date("Y-m-d-H-i") . ".pdf");
header("Cache-Control: no-cache, must-revalidate");

// output the PDF
echo $invoice->render();

Summary

Now you know the basics of using Zend_PDF to create PDF documents, though there are still many more features available than the ones I’ve mentioned in this article. The source code for this article is available on GitHub if you’d like to clone it and experiment. And of course, feel free to leave comments with any problems you encounter.

Image via Christina DeRidder / Shutterstock

More:
Login or Create Account to Comment
Login Create Account
Recommended
Sponsors
Get the most important and interesting stories in tech. Straight to your inbox, daily.Is it good?