Escolar Documentos
Profissional Documentos
Cultura Documentos
Easily control the format and content of PDF files with PHP
Jack D. Herrington
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.
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.
Trademarks
Page 1 of 13
developerWorks
ibm.com/developerWorks/
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.
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.
Page 3 of 13
developerWorks
ibm.com/developerWorks/
This result even uses bold font for the winning teams to make it easy to see which team won which
event.
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
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.
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.
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.
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.
Page 7 of 13
developerWorks
ibm.com/developerWorks/
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.
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.
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.
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.
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.
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.
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/)
Page 13 of 13