Você está na página 1de 13

Build PDF files dynamically with PHP

Easily control the format and content of PDF files with PHP
Jack D. Herrington

June 28, 2011

Walk through the entire process of building PDF files dynamically using PHP. Experiment with
open source tools, such as the Free PDF library (FPDF) or PDFLib-Lite, and PHP code for
control of the PDF format of your content.

Sometimes you need control over exactly how pages are rendered for printing. At times like those,
HTML is not the best choice. PDF files give you complete control over how pages are rendered
and how text, graphics, and images are rendered on the page. Sadly, APIs for building PDF files
are not standard parts of the PHP toolkit. Now is the time to bring in a little help.

Frequently used acronyms

API: Application programming interface


DOM: Document Object Mode
HTML: HyperText Markup Language
PDF: Portable Document Format
W3C: World Wide Web Consortium
XML: Extensible Markup Language

When you search the web for PDF support for PHP, the first thing you are likely to find is the
commercial PDFLib library and its open source version, PDFLib-Lite. These are good libraries,
but the commercial version is fairly expensive. The light version of the library is distributed only as
source, and that restriction might be an issue if you try to install it in a hosted environment.
Another choice is the Free PDF library (FPDF), which is native PHP. It doesn't require any
compilation, and it is completely free so you don't see watermarks as you do with an unlicensed
version of PDFLib. This Free PDF library is what I use in this article.
To demonstrate building PDF files dynamically, you'll use scores from women's roller derby
tournaments. These scores were mined from the web and converted into XML. Listing 1 shows an
example of the XML data file.

Copyright IBM Corporation 2011


Build PDF files dynamically with PHP

Trademarks
Page 1 of 13

developerWorks

ibm.com/developerWorks/

Listing 1. The XML data


<events>
<event name='Beast of the East 2011'>
<game score1='88' team1='Toronto Gore-Gore Rollergirls'
team2='Montreal La Racaille' score2='11'/>
<game score1='58' team1='Toronto Death Track Dolls'
team2='Montreal Les Contrabanditas' score2='49'/>
...
</event>
<event name='Dustbowl Invitational 2011'>
...
</event>
<event name='The Great Yorkshire Showdown 2011'>
...
</event>
</events>

The root element for the XML is an events tag. The data is grouped into events, where each event
holds a number of games. Within the events tag is a series of event tags, within which are multiple
game tags. These game tags include the names of each of the two teams playing and their scores
during the game.
Listing 2 shows the PHP code that you use to read the XML.

Listing 2. getresults.php
<?php
function getResults() {
$xml = new DOMDocument();
$xml->load('events.xml');
$events = array();
foreach($xml->getElementsByTagName('event') as $event) {
$games = array();
foreach($event->getElementsByTagName('game') as $game) {
$games []= array( 'team1' => $game->getAttribute('team1'),
'score1' => $game->getAttribute('score1'),
'team2' => $game->getAttribute('team2'),
'score2' => $game->getAttribute('score2') );
}
$events []= array( 'name' => $event->getAttribute('name'),
'games' => $games );
}
return $events;
}
?>

This script implements a getResults function that reads the XML file into a DOMDocument. DOM
calls are then used to traverse all of the event and game tags to build an array of events. Within
each element of the array is a hash table that includes the name of the event and an array of the
games played. The structure is basically an in-memory version of the structure of the XML.
To test that this script works, you will build an HTML export page that uses the getResults function
to read the file, then outputs the data as a series of HTML tables. Listing 3 shows the PHP code
for this test.

Listing 3. The results HTML page


<html><head><title>Event Results</title></head>

Build PDF files dynamically with PHP

Page 2 of 13

ibm.com/developerWorks/

developerWorks

<body>
<?php
include_once('getresults.php');
$results = getResults();
foreach( $results as $event ) {
?>
<h1><?php echo( $event['name'] ) ?></h1>
<table>
<?php
foreach( $event['games'] as $game ) {
$s1 = (int)$game['score1'];
$s2 = (int)$game['score2'];
?>
<tr>
<td style="font-weight:<?php echo( ( $s1 > $s2 ) ? 'bold' : 'normal') ?>">
<?php echo( $game['team1'] ) ?></td>
<td><?php echo( $s1 ) ?></td>
<td style="font-weight:<?php echo( ( $s2 > $s1 ) ? 'bold' : 'normal') ?>">
<?php echo( $game['team2'] ) ?></td>
<td><?php echo( $s2 ) ?></td>
</tr>
<?php
}
?>
</table>
<?php
}
?>
</body></html>

With this code, the getresults.php, and the XML data file uploaded to the web server, you can look
at the HTML result. which resembles Figure 1.

Build PDF files dynamically with PHP

Page 3 of 13

developerWorks

ibm.com/developerWorks/

Figure 1. The derby results in HTML

This result even uses bold font for the winning teams to make it easy to see which team won which
event.

Building the PDF


With the data in hand, it's time to focus on building PDF files. The first step is to download the
FPDF library and install it in the same directory as the existing set of application files. Actually, you
can install it wherever you like as long it's in the PHP library path. Keep track of where you put the
fonts directory, as you will need to set the 'FPDF_FONTPATH' as in Listing 4.

Listing 4. A PDF Hello World


<?php
define('FPDF_FONTPATH','/Library/WebServer/Documents/derby/font/');
require( 'fpdf.php' );
$pdf = new FPDF();
$pdf->SetFont('Arial','',72);
$pdf->AddPage();
$pdf->Cell(40,10,"Hello World!",15);
$pdf->Output();
?>

This script is literally a "Hello World" but as a PDF instead of HTML. The first thing the script does
is set the location of the FPDF fonts directory using the define statement. It then brings in the
FPDF library using the require statement. From there, the script creates an FPDF object, sets the
font, adds a page, puts some text on the page using the Cell method, and outputs the PDF.
Build PDF files dynamically with PHP

Page 4 of 13

ibm.com/developerWorks/

developerWorks

Figure 2 shows the result when everything works properly.

Figure 2. A Hello World in PDF

If you don't see a PDF, you will probably want to run the script on the command line to see if you
are missing the fpdf.php file or if there is another issue.
Now that the PDF rendering works, it's time to merge it with the roller derby results file and see
what you can generate dynamically. Listing 5 shows the first version of this merging.

Listing 5. The first version of the PDF displaying the results


<?php
define('FPDF_FONTPATH','/Library/WebServer/Documents/derby/font/');
require( 'fpdf.php' );
require( 'getresults.php' );
class PDF extends FPDF
{
function EventTable($event)
{
$this->Cell(40,10,$event['name'],15);
$this->Ln();
}
}
$pdf = new PDF();
$pdf->SetFont('Arial','',48);
foreach( getResults() as $event ) {
$pdf->AddPage();
$pdf->EventTable($event);
}

Build PDF files dynamically with PHP

Page 5 of 13

developerWorks

ibm.com/developerWorks/

$pdf->Output();
?>

Instead of driving the FPDF class from the outside we extend the FPDF class with our own PDF
subclass. Within that subclass, we create a new method called EventTable that builds a table of
results for a given event. In this case, we start small and just put out the name of the event. That
name is wrapped in a foreach loop at the bottom of the script that adds a page for each event, then
invokes the EventTable method.
You can see the output for this script in Figure 3.

Figure 3. The first version of the dynamic PDF

Scrolling down the page shows that each of the events is on its own page. The next step from here
is to start adding the results to the page.

Building a results table


No table structure is as easy as HTML when you are building PDF files. The way to build tables is
to build a bunch of cells that have various widths, fonts, fill color, line color, and so on.
Listing 6 shows the addition code that sets up the header bar for the table.

Listing 6. Adding the results table header


<?php
define('FPDF_FONTPATH','/Library/WebServer/Documents/derby/font/');
require( 'fpdf.php' );

Build PDF files dynamically with PHP

Page 6 of 13

ibm.com/developerWorks/

developerWorks

require( 'getresults.php' );
class PDF extends FPDF
{
function EventTable($event)
{
$this->SetFont('','B','24');
$this->Cell(40,10,$event['name'],15);
$this->Ln();
$this->SetXY( 10, 45 );
$this->SetFont('','B','10');
$this->SetFillColor(128,128,128);
$this->SetTextColor(255);
$this->SetDrawColor(92,92,92);
$this->SetLineWidth(.3);
$this->Cell(70,7,"Team 1",1,0,'C',true);
$this->Cell(20,7,"Score 1",1,0,'C',true);
$this->Cell(70,7,"Team 2",1,0,'C',true);
$this->Cell(20,7,"Score 2",1,0,'C',true);
$this->Ln();
}
}
$pdf = new PDF();
$pdf->SetFont('Arial','',10);
foreach( getResults() as $event ) {
$pdf->AddPage();
$pdf->EventTable($event);
}
$pdf->Output();
?>

The additional code here sets up the font, colors, and line width. Then it renders a few cells with
the four header columns. It then calls the Ln method, which is the equivalent of a carriage return to
start a new line.
When you look at this script in the browser, you see something like Figure 4.

Build PDF files dynamically with PHP

Page 7 of 13

developerWorks

ibm.com/developerWorks/

Figure 4. The pages with a header row for the table

In Figure 4, the headers are rendered in white text on a gray background. This format helps
differentiate them from the data that is rendered below the headers. To render the game results,
add the code in Listing 7.

Listing 7. Adding the full results table


<?php
define('FPDF_FONTPATH','/Library/WebServer/Documents/derby/font/');
require( 'fpdf.php' );
require( 'getresults.php' );
class PDF extends FPDF
{
function EventTable($event)
{
$this->SetFont('','B','24');
$this->Cell(40,10,$event['name'],15);
$this->Ln();
$this->SetFont('','B','10');
$this->SetFillColor(128,128,128);
$this->SetTextColor(255);
$this->SetDrawColor(92,92,92);
$this->SetLineWidth(.3);
$this->Cell(70,7,"Team 1",1,0,'C',true);
$this->Cell(20,7,"Score 1",1,0,'C',true);
$this->Cell(70,7,"Team 2",1,0,'C',true);
$this->Cell(20,7,"Score 2",1,0,'C',true);
$this->Ln();
$this->SetFillColor(224,235,255);

Build PDF files dynamically with PHP

Page 8 of 13

ibm.com/developerWorks/

developerWorks

$this->SetTextColor(0);
$this->SetFont('');
$fill = false;
foreach($event['games'] as $game)
{
$this->SetFont('Times',((int)$game['score1']>(int)$game['score2'])?'BI':'');
$this->Cell(70,6,$game['team1'],'LR',0,'L',$fill);
$this->Cell(20,6,$game['score1'],'LR',0,'R',$fill);
$this->SetFont('Times',((int)$game['score1']<(int)$game['score2'])?'BI':'');
$this->Cell(70,6,$game['team2'],'LR',0,'L',$fill);
$this->Cell(20,6,$game['score2'],'LR',0,'R',$fill);
$this->Ln();
$fill =! $fill;
}
$this->Cell(180,0,'','T');
}
}
$pdf = new PDF();
$pdf->SetFont('Arial','',10);
foreach( getResults() as $event ) {
$pdf->AddPage();
$pdf->EventTable($event);
}
$pdf->Output();
?>

In addition to the header line, you have a foreach loop in the EventTable method that iterates
through each of the games. Figure 5 shows the code for this.

Figure 5. The PDF with a table for the results

Build PDF files dynamically with PHP

Page 9 of 13

developerWorks

ibm.com/developerWorks/

The $fill variable toggles to alternate the color of each row in the table. The names and scores of
the winning teams are in a bold, italic font, which makes them really stand out. Also note that the
font changes from Arial for the headers to Times for the game content.
To finish the example code, you'll want to add some graphics.

Dressing it up with graphics


Adding images to a PDF is remarkably easy. To make it happen, first grab an image off the web. I
grabbed the logo of one of the roller derby teams and stored it as a PNG. From there, I used the
new code in Listing 8.

Listing 8. Adding a logo image


<?php
define('FPDF_FONTPATH','/Library/WebServer/Documents/derby/font/');
require( 'fpdf.php' );
require( 'getresults.php' );
class PDF extends FPDF
{
function EventTable($event)
{
$this->Image('logo.png',5,5,33);
$this->SetXY( 40, 15 );
$this->SetFont('','B','24');
$this->Cell(40,10,$event['name'],15);
$this->Ln();
$this->SetXY( 10, 45 );
$this->SetFont('','B','10');
$this->SetFillColor(128,128,128);
$this->SetTextColor(255);
$this->SetDrawColor(92,92,92);
$this->SetLineWidth(.3);
$this->Cell(70,7,"Team 1",1,0,'C',true);
$this->Cell(20,7,"Score 1",1,0,'C',true);
$this->Cell(70,7,"Team 2",1,0,'C',true);
$this->Cell(20,7,"Score 2",1,0,'C',true);
$this->Ln();
$this->SetFillColor(224,235,255);
$this->SetTextColor(0);
$this->SetFont('');
$fill = false;
foreach($event['games'] as $game)
{
$this->SetFont('Times',((int)$game['score1']>(int)$game['score2'])?'BI':'');
$this->Cell(70,6,$game['team1'],'LR',0,'L',$fill);
$this->Cell(20,6,$game['score1'],'LR',0,'R',$fill);
$this->SetFont('Times',((int)$game['score1']<(int)$game['score2'])?'BI':'');
$this->Cell(70,6,$game['team2'],'LR',0,'L',$fill);
$this->Cell(20,6,$game['score2'],'LR',0,'R',$fill);
$this->Ln();
$fill =! $fill;
}

Build PDF files dynamically with PHP

Page 10 of 13

ibm.com/developerWorks/

developerWorks

$this->Cell(180,0,'','T');
}
}
$pdf = new PDF();
$pdf->SetFont('Arial','',10);
foreach( getResults() as $event ) {
$pdf->AddPage();
$pdf->EventTable($event);
}
$pdf->Output();
?>

The key method in Listing 8 is the Image method, which takes a file name for the image, a location,
and a width. All of the additional parameters are optional so you specify only as much information
as you want.
Some new calls to SetXY move the text and table around to appropriate positions to keep them
from overwriting the image.
Figure 6 shows the output from this script.

Figure 6. The completed PDF with the logo images

With all the other methods provided by the library to render graphics, add flowing text, add
hyperlinks, and manage page mechanics such as margins and orientation, you have complete
control over your PDF files.

Build PDF files dynamically with PHP

Page 11 of 13

developerWorks

ibm.com/developerWorks/

Conclusion
With the right tools, building PDF files in PHP is remarkably easy. This approach is ideal for
printing invoices or tickets, or filling in forms, anything that requires exacting control over the layout
of the content.

Build PDF files dynamically with PHP

Page 12 of 13

ibm.com/developerWorks/

developerWorks

Related topics
The W3C: Visit a great site for standards, in particular the XML standard is relevant to this
article.
The PHP site: Explore the best reference for PHP that's available.
PDFLib: Try a commercial library for building PDF files.
PDFLib-Lite:Download an open source version of the PDFLib 7 and explore its functionality
subset.
PECL package: Download an extension that wraps the PDFLib programming library for
processing PDF on the fly.
FPDF: Get the library used to generate PDF files in this article.
More articles by this author (Jack Herrington, developerWorks, March 2005-current): Read
articles about Ajax, JSON, PHP, XML, and other technologies.
XML area on developerWorks: Find the resources you need to advance your skills in the XML
arena.
IBM product evaluation versions.
Copyright IBM Corporation 2011
(www.ibm.com/legal/copytrade.shtml)
Trademarks
(www.ibm.com/developerworks/ibm/trademarks/)

Build PDF files dynamically with PHP

Page 13 of 13

Você também pode gostar