Create Nice-Looking PDFs with PHP and FPDF

Learn how to use the free FPDF library to produce great-looking PDF documents from within your PHP scripts. Full example included.

The PDF format can be a handy way to distribute documents to your visitors. A PDF document is self-contained, looks the same on any PDF reader, and is easy to print. PDFs are often used for reports, brochures, manuals, invoices, product data sheets, and lots more.

Often it's useful to be able to create PDF documents dynamically from within a PHP script. For example, you can produce a custom PDF report based on a user's preferences and include up-to-the-minute data.

In this tutorial I'll walk you through the process of creating a nice-looking, 2-page PDF document using PHP. You'll use the freely-available FPDF library to handle the nitty-gritty of PDF creation.

Here's what your PDF will look like (click to view the finished PDF):

Report page 1 Report page 2

If you want to try out the finished PHP script, you can grab the entire code at the end of the article.

Installing FPDF

To use FPDF, you first need to install the FPDF files on your website. To do this, download the FPDF archive file and extract it to a folder within your website. Call the folder fpdf.

Starting the PHP script

Now that you've installed FPDF, you can start writing your PHP script to produce the PDF report. Create a file called report.php in the same place that you saved your fpdf folder, and open the file in a text editor.

The first thing to do is include the FPDF library so that you can use it. The library is called fpdf.php, and it's inside the fpdf folder that you extracted earlier:


<?php

require_once( "fpdf/fpdf.php" );

Now add some variables to configure the report:


// Begin configuration

$textColour = array( 0, 0, 0 );
$headerColour = array( 100, 100, 100 );
$tableHeaderTopTextColour = array( 255, 255, 255 );
$tableHeaderTopFillColour = array( 125, 152, 179 );
$tableHeaderTopProductTextColour = array( 0, 0, 0 );
$tableHeaderTopProductFillColour = array( 143, 173, 204 );
$tableHeaderLeftTextColour = array( 99, 42, 57 );
$tableHeaderLeftFillColour = array( 184, 207, 229 );
$tableBorderColour = array( 50, 50, 50 );
$tableRowFillColour = array( 213, 170, 170 );
$reportName = "2009 Widget Sales Report";
$reportNameYPos = 160;
$logoFile = "widget-company-logo.png";
$logoXPos = 50;
$logoYPos = 108;
$logoWidth = 110;
$columnLabels = array( "Q1", "Q2", "Q3", "Q4" );
$rowLabels = array( "SupaWidget", "WonderWidget", "MegaWidget", "HyperWidget" );
$chartXPos = 20;
$chartYPos = 250;
$chartWidth = 160;
$chartHeight = 80;
$chartXLabel = "Product";
$chartYLabel = "2009 Sales";
$chartYStep = 20000;

$chartColours = array(
                  array( 255, 100, 100 ),
                  array( 100, 255, 100 ),
                  array( 100, 100, 255 ),
                  array( 255, 255, 100 ),
                );

$data = array(
          array( 9940, 10100, 9490, 11730 ),
          array( 19310, 21140, 20560, 22590 ),
          array( 25110, 26260, 25210, 28370 ),
          array( 27650, 24550, 30040, 31980 ),
        );

// End configuration

These variables make it easy to tweak your report by keeping all the key configuration data at the top of the file. The variables include:

  • Various colours used in the report. Each colour is specified as a 3-element array containing red, green and blue values (in the range 0-255).
  • The report title ("2009 Widget Sales Report") and position.
  • The URL and dimensions of the company logo image. You'll include this image in the title page of the report.
  • The row and column labels for the report data. You'll use these when displaying the table and chart in the report.
  • Configuration settings for the chart. These include the chart position, dimensions, axis labels, and the step value to use for the Y-axis scale.
  • The colours to use for the chart bars. As with the other report colours, these are specified as 3-element arrays. There are 4 colours: 1 for each bar in the chart.
  • The report data. This is a 2-dimensional array containing 4 rows of quarterly sales figures, 1 row per product.

Creating the title page

Now that you've set up the report configuration, you're ready to start building the PDF. First, you'll create the title page for the report. This consists of the company logo and the report name, centred in the page.

Creating the FPDF object

The first thing you need to do is create a new FPDF object to hold the PDF data. The FPDF constructor accepts 3 optional arguments, as follows:

  • The page orientation. Use 'P' for portrait, or 'L' for landscape. The default is 'P'.
  • The units to use for the page measurements. Use 'pt', 'mm', 'cm', or 'in'. The default is 'mm'.
  • The page format. Possible values include 'A3', 'A4', 'A5', 'Letter', and 'Legal'. Or you can specify a custom width and height with a 2-element array. The default value is 'A4'.

For this example, use a portrait orientation, millimetres for units, and A4 format:


/**
  Create the title page
**/

$pdf = new FPDF( 'P', 'mm', 'A4' );

Setting the text colour

Now set the colour to use for text in the page. You do this by calling the FPDF SetTextColor() method, passing in the red, green and blue values of the colour to use (each value should be in the range 0-255). Use the colour values in the $textColour array that you created in the configuration section earlier:


$pdf->SetTextColor( $textColour[0], $textColour[1], $textColour[2] );

Creating a page

Now you're ready to create a new blank page in the PDF by calling FPDF's AddPage() method:


$pdf->AddPage();

Adding the logo image

FPDF makes it really easy to insert images in the page. Just call the Image() method, passing in the following arguments:

  • The path of the image file. This can be an absolute path, or relative to the PHP script. You can also use a URL.
  • The X and Y position of the top left corner of the image in the PDF. If you omit these then the current position is used.
  • The width and height of the image in the PDF. If you omit both values then the original image dimensions are used (at 72 DPI). If you omit 1 value then the other value is calculated automatically.
  • The image type. Allowed values include 'JPG', 'JPEG', 'PNG' and 'GIF' (upper- or lower-case). If you omit this value then FPDF guesses the image format from the filename extension.
  • A URL to link the image to. This is optional — if you supply a URL then the image becomes a clickable link.

All measurements, such as X and Y positions, widths and heights, use the units you specified when you created the PDF (mm in this case).

You can create your own logo image (make sure it's 300 DPI) or download my example image. Save your logo image in the same folder as your PHP script, then insert the image in the PDF as follows:


// Logo
$pdf->Image( $logoFile, $logoXPos, $logoYPos, $logoWidth );

Setting the font

FPDF lets you choose the font face, style and size to use for text in the PDF. To do this, you call the SetFont() method, which takes the following arguments:

  • The font family. You can use any of the following standard family names: 'Courier', 'Helvetica', 'Arial', 'Times', 'Symbol', or 'ZapfDingbats'.
  • The font style. Options include: '' (regular), 'B' (bold), 'I' (italic), and 'U' (underline). You can combine these — for example, 'BU' for bold, underlined text.
  • The font size. You specify this in points (it defaults to 12 points).

For the report name on the title page, use an Arial Bold 24-point font:


// Report Name
$pdf->SetFont( 'Arial', 'B', 24 );

As well as using the standard fonts, you can import any TrueType or Type 1 font using the AddFont() method. See the manual on the FPDF website for details.

Adding some text

You're now ready to add the report name. FPDF objects have a concept of "the current position", which is where the next piece of text or other element will be inserted. Since you want the report name to appear just after halfway down the page, you first need to move the current position down to this point, which is 160mm from the top of the page (this is stored in the $reportNameYPos configuration variable). To do this, use FPDF's Ln() method, which adds a line break with an optional height value:


$pdf->Ln( $reportNameYPos );

If you don't specify a height for the line break then the height of the last printed cell is used.

Now add the report name. There are a few different ways that you can add text using FPDF. In this case, you'll use the Cell() method, which, amongst other things, lets you easily centre text.

Cell() takes the following arguments (all of them optional):

  • The cell width and height. If you omit the width then the cell stretches to the right margin. If you omit the height then it defaults to zero.
  • The string of text to print. Defaults to ''.
  • Whether to draw a border around the cell. This can be either a number (0=no border, 1=border), or a string containing 1 or more of the following: 'L' (left), 'T' (top), 'R' (right), and 'B' (bottom). Default: 0.
  • Where to place the current position after drawing the cell. Values can be 0 (to the right), 1 (to the start of the next line), or 2 (below). Default: 0.
  • The text alignment. Possible values are 'L' (left align), 'C' (centre), or 'R' (right align). Default: 'L'.
  • Whether the cell background should be filled with colour. true = filled, false = transparent. Default: false.
  • A URL to link to. If specified, turns the text cell into a link.

Now, use Cell() to insert the report name and centre it, as follows:


$pdf->Cell( 0, 15, $reportName, 0, 0, 'C' );

Creating a page header and intro text

That's the title page done. Now you'll create the page containing some header text, a heading, and some intro text, followed by a table and chart of sales data.

First the page header. Add a new page, then output the page header, which consists of the report name centred at the top of the page using an Arial Regular 17-point font. Use the $headerColour configuration variable to set the text colour:


$pdf->AddPage();
$pdf->SetTextColor( $headerColour[0], $headerColour[1], $headerColour[2] );
$pdf->SetFont( 'Arial', '', 17 );
$pdf->Cell( 0, 15, $reportName, 0, 0, 'C' );

Now for the intro text. First print a heading using the regular text colour and an Arial 20-point font. Since you don't need this text to be centred, you can use the simpler Write() method, which takes the line height, the text to write, and an optional link URL:


$pdf->SetTextColor( $textColour[0], $textColour[1], $textColour[2] );
$pdf->SetFont( 'Arial', '', 20 );
$pdf->Write( 19, "2009 Was A Good Year" );

Now you can output the intro text itself in 12-point Arial. This consists of a 16mm line break, followed by the first paragraph, a 12mm line break, and the final paragraph. Give each line a line height of 6mm:


$pdf->Ln( 16 );
$pdf->SetFont( 'Arial', '', 12 );
$pdf->Write( 6, "Despite the economic downturn, WidgetCo had a strong year. Sales of the HyperWidget in particular exceeded expectations. The fourth quarter was generally the best performing; this was most likely due to our increased ad spend in Q3." );
$pdf->Ln( 12 );
$pdf->Write( 6, "2010 is expected to see increased sales growth as we expand into other countries." );

The Write() method automatically wraps text when it reaches the right side of the page.

Adding a table of data

Next you'll add a table of sales data below the intro text. First, set the border colour for the table. The SetDrawColor() method sets the colour to use for borders and other lines, so you can use this to set the table cell borders. Then move down 15mm to create a space between the intro text and the table:


$pdf->SetDrawColor( $tableBorderColour[0], $tableBorderColour[1], $tableBorderColour[2] );
$pdf->Ln( 15 );

Creating the table header row

The table header row consists of the "PRODUCT", "Q1, "Q2", "Q3", and "Q4" cells. The "PRODUCT" cell uses different text and background colours to the other header cells.

You already know to call the SetTextColor() method to set the text colour to use. To set the background colour to use, you call SetFillColor(), which takes the same RGB arguments as SetTextColor().

To create table cells you use — you guessed it — the Cell() method, specifying the cell width, height, contents, and alignment. You'll also pass 1 as the 4th argument to set a border, and true as the 7th argument to fill the cell with a background colour.

Here, then, is the code to create the table header row. First you set a bold font, then create the left-aligned "PRODUCT" cell with appropriate text and fill colours. Finally, you set colours for the remaining 4 header cells, then loop through the $columnLabels array to display the cells using centred text:


// Create the table header row
$pdf->SetFont( 'Arial', 'B', 15 );

// "PRODUCT" cell
$pdf->SetTextColor( $tableHeaderTopProductTextColour[0], $tableHeaderTopProductTextColour[1], $tableHeaderTopProductText
Colour[2] );
$pdf->SetFillColor( $tableHeaderTopProductFillColour[0], $tableHeaderTopProductFillColour[1], $tableHeaderTopProductFill
Colour[2] );
$pdf->Cell( 46, 12, " PRODUCT", 1, 0, 'L', true );

// Remaining header cells
$pdf->SetTextColor( $tableHeaderTopTextColour[0], $tableHeaderTopTextColour[1], $tableHeaderTopTextColour[2] );
$pdf->SetFillColor( $tableHeaderTopFillColour[0], $tableHeaderTopFillColour[1], $tableHeaderTopFillColour[2] );

for ( $i=0; $i<count($columnLabels); $i++ ) {
  $pdf->Cell( 36, 12, $columnLabels[$i], 1, 0, 'C', true );
}

$pdf->Ln( 12 );

The space character before the word "PRODUCT" in the code helps to pad the word within the table cell so that it isn't hard up against the left edge of the cell. The same trick is used later on with the product names in the left hand column. (Unfortunately there's currently no way to control cell padding with FPDF without extending the class.)

Creating the data rows

The rest of the table consists of 4 rows of sales figures — 1 row for each product — over the 4 quarters. First, set a couple of variables:


// Create the table data rows

$fill = false;
$row = 0;

These variables work as follows:

$fill
Whether a cell should be filled or not. You'll toggle this value every time you've drawn a row to create a striped row effect.
$row
The current row number. This lets you display the appropriate row label for each row as you move through the table.

Now you can loop through the $data array using a foreach loop, printing a row at a time. For each row you create the left header cell containing the product name, and the 4 data cells containing the sales data. Set appropriate text and background colours for each cell as you go.

To display the data cells, use a for loop to move through the 4-element array containing the data, calling the PHP number_format() function to print the sales figure with thousands separators.

After displaying a row, you increment the $row variable, toggle the $fill variable, and use Ln() to move down to the start of the next line, ready to output the next row.

Here's the code for the whole loop:


foreach ( $data as $dataRow ) {

  // Create the left header cell
  $pdf->SetFont( 'Arial', 'B', 15 );
  $pdf->SetTextColor( $tableHeaderLeftTextColour[0], $tableHeaderLeftTextColour[1], $tableHeaderLeftTextColour[2] );
  $pdf->SetFillColor( $tableHeaderLeftFillColour[0], $tableHeaderLeftFillColour[1], $tableHeaderLeftFillColour[2] );
  $pdf->Cell( 46, 12, " " . $rowLabels[$row], 1, 0, 'L', $fill );

  // Create the data cells
  $pdf->SetTextColor( $textColour[0], $textColour[1], $textColour[2] );
  $pdf->SetFillColor( $tableRowFillColour[0], $tableRowFillColour[1], $tableRowFillColour[2] );
  $pdf->SetFont( 'Arial', '', 15 );

  for ( $i=0; $i<count($columnLabels); $i++ ) {
    $pdf->Cell( 36, 12, ( '$' . number_format( $dataRow[$i] ) ), 1, 0, 'C', $fill );
  }

  $row++;
  $fill = !$fill;
  $pdf->Ln( 12 );
}

Creating a bar chart

The last element of the page is a bar chart showing the total sales figures for the 4 products over the whole year.

Calculating scales and bar width

The first thing to do is compute the scales for the X and Y axes. For the X scale this is simply the number of products to display divided by the desired chart width (subtracting some millimetres to allow for space to the left of the bars):


/***
  Create the chart
***/

// Compute the X scale
$xScale = count($rowLabels) / ( $chartWidth - 40 );

To compute the Y scale, you need to find the total sales figure for each product, then determine the highest sales figure across all the products. You can then divide this by the desired chart height to get the Y scale:


// Compute the Y scale

$maxTotal = 0;

foreach ( $data as $dataRow ) {
  $totalSales = 0;
  foreach ( $dataRow as $dataCell ) $totalSales += $dataCell;
  $maxTotal = ( $totalSales > $maxTotal ) ? $totalSales : $maxTotal;
}

$yScale = $maxTotal / $chartHeight;

Now that you know the X scale, you can work out the width (in mm) of each bar in the chart. This is the inverse of the X scale value, reduced by a factor of 1.5 to allow some space between each bar:


// Compute the bar width
$barWidth = ( 1 / $xScale ) / 1.5;

Adding the axis lines and labels

So far, so good. Now you can add the X and Y axis lines, data labels, and axis labels. Use Arial 10-point for the data labels.

To create lines in FDPF, you use the Line() method, which accepts 4 arguments: the X and Y co-ordinates of the start of the line, and the X and Y co-ordinates of the end of the line.

For the X axis, draw a horizontal line along the bottom of the chart, allowing 30mm for the Y-axis labels on the left. Then loop through each product name in the $rowLabels array, printing the product name as a text cell at the appropriate point:


// Add the axes:

$pdf->SetFont( 'Arial', '', 10 );

// X axis
$pdf->Line( $chartXPos + 30, $chartYPos, $chartXPos + $chartWidth, $chartYPos );

for ( $i=0; $i < count( $rowLabels ); $i++ ) {
  $pdf->SetXY( $chartXPos + 40 +  $i / $xScale, $chartYPos );
  $pdf->Cell( $barWidth, 10, $rowLabels[$i], 0, 0, 'C' );
}

The SetXY() method lets you set the current position to a specific location on the page.

For the Y axis, draw a vertical line up the left side of the chart, again allowing 30mm for the Y-axis labels. Extend the line 8mm above the desired chart height to make room for the axis label later on. Then loop from zero up to the highest bar value, $maxTotal, that you calculated earlier. Jump in steps of $chartYStep (20,000) dollars. At each step, display the current value (right-aligned) and a short tick mark:


// Y axis
$pdf->Line( $chartXPos + 30, $chartYPos, $chartXPos + 30, $chartYPos - $chartHeight - 8 );

for ( $i=0; $i <= $maxTotal; $i += $chartYStep ) {
  $pdf->SetXY( $chartXPos + 7, $chartYPos - 5 - $i / $yScale );
  $pdf->Cell( 20, 10, '$' . number_format( $i ), 0, 0, 'R' );
  $pdf->Line( $chartXPos + 28, $chartYPos - $i / $yScale, $chartXPos + 30, $chartYPos - $i / $yScale );
}

Now you can add the axis labels. Use Arial Bold 12-point. Place the X-axis label below the data labels, and the Y-axis label at the top of the Y axis:


// Add the axis labels
$pdf->SetFont( 'Arial', 'B', 12 );
$pdf->SetXY( $chartWidth / 2 + 20, $chartYPos + 8 );
$pdf->Cell( 30, 10, $chartXLabel, 0, 0, 'C' );
$pdf->SetXY( $chartXPos + 7, $chartYPos - $chartHeight - 12 );
$pdf->Cell( 20, 10, $chartYLabel, 0, 0, 'R' );

Drawing the data bars

The last stage of creating the chart is to draw the bars themselves. To draw a bar you can use FPDF's Rect() method, which draws a rectangle using the following arguments:

  • The X and Y co-ordinates of the upper left corner of the rectangle.
  • The width and height of the rectangle.
  • The rectangle style. This can be 'D' or '' (draw a border), 'F' (fill with the current fill colour), or 'DF' / 'FD' (draw and fill).

Now draw the bars. First, Set a variable, $xPos, to track the current bar X position; set it 40mm to the right of the chart's start position to allow for the Y-axis labels and a gap at the start of the bars. Then create a variable, $bar, to hold the current bar number; you'll use this to work out which fill colour to use for each bar:


// Create the bars
$xPos = $chartXPos + 40;
$bar = 0;

Now loop through the $data array, totalling up the value in each row and drawing a bar from the X axis up to that value, scaled using $yScale. Colour each bar differently by using the $bar counter and the colour values in the $chartColours array. After you've drawn each bar, move the X position along to the start of the next bar, increment the $bar counter, and continue the loop:


foreach ( $data as $dataRow ) {

  // Total up the sales figures for this product
  $totalSales = 0;
  foreach ( $dataRow as $dataCell ) $totalSales += $dataCell;

  // Create the bar
  $colourIndex = $bar % count( $chartColours );
  $pdf->SetFillColor( $chartColours[$colourIndex][0], $chartColours[$colourIndex][1], $chartColours[$colourIndex][2] );
  $pdf->Rect( $xPos, $chartYPos - ( $totalSales / $yScale ), $barWidth, $totalSales / $yScale, 'DF' );
  $xPos += ( 1 / $xScale );
  $bar++;
}

The above code uses the PHP modulus (%) operator to repeat the bar colours if the number of bars happens to be greater than the number of elements in the $chartColours array.

Sending the PDF to the browser

Your PDF is finished! The only thing left to do is send the PDF to the browser so that the user can view or download it.

To do this, you call FPDF's Output() method to send the PDF data. This accepts 2 arguments: the suggested filename for the PDF, and a destination flag. This flag can have any of the following values:

I
Displays the PDF inline if supported by the browser, otherwise it's downloaded.
D
Forces the PDF to be downloaded.
F
Saves the file to a folder on the server.
S
Returns the PDF data as a string.

For this example, use the I option to display the PDF inline if possible:


/***
  Serve the PDF
***/

$pdf->Output( "report.pdf", "I" );

?>

Output() automatically sends an HTTP "Content-type: application/pdf" header, which tells the browser to expect a PDF document.

You're now ready to test your script. Open your browser and visit the script's URL — for example, www.example.com/report.php. You should see the PDF appear in your browser window. Alternatively you might see a dialog appear that lets you save the PDF to your hard drive. You can then open up the PDF in your PDF viewer, such as Acrobat Reader or Preview.

That's it! You've now created a PDF document on the fly using nothing but PHP and FPDF. Good work!

The complete script

Here's the complete PHP script for you to copy, paste, and play with:


<?php

/*
  An Example PDF Report Using FPDF
  by Matt Doyle

  From "Create Nice-Looking PDFs with PHP and FPDF"
  http://www.elated.com/articles/create-nice-looking-pdfs-php-fpdf/
*/

require_once( "fpdf/fpdf.php" );

// Begin configuration

$textColour = array( 0, 0, 0 );
$headerColour = array( 100, 100, 100 );
$tableHeaderTopTextColour = array( 255, 255, 255 );
$tableHeaderTopFillColour = array( 125, 152, 179 );
$tableHeaderTopProductTextColour = array( 0, 0, 0 );
$tableHeaderTopProductFillColour = array( 143, 173, 204 );
$tableHeaderLeftTextColour = array( 99, 42, 57 );
$tableHeaderLeftFillColour = array( 184, 207, 229 );
$tableBorderColour = array( 50, 50, 50 );
$tableRowFillColour = array( 213, 170, 170 );
$reportName = "2009 Widget Sales Report";
$reportNameYPos = 160;
$logoFile = "widget-company-logo.png";
$logoXPos = 50;
$logoYPos = 108;
$logoWidth = 110;
$columnLabels = array( "Q1", "Q2", "Q3", "Q4" );
$rowLabels = array( "SupaWidget", "WonderWidget", "MegaWidget", "HyperWidget" );
$chartXPos = 20;
$chartYPos = 250;
$chartWidth = 160;
$chartHeight = 80;
$chartXLabel = "Product";
$chartYLabel = "2009 Sales";
$chartYStep = 20000;

$chartColours = array(
                  array( 255, 100, 100 ),
                  array( 100, 255, 100 ),
                  array( 100, 100, 255 ),
                  array( 255, 255, 100 ),
                );

$data = array(
          array( 9940, 10100, 9490, 11730 ),
          array( 19310, 21140, 20560, 22590 ),
          array( 25110, 26260, 25210, 28370 ),
          array( 27650, 24550, 30040, 31980 ),
        );

// End configuration


/**
  Create the title page
**/

$pdf = new FPDF( 'P', 'mm', 'A4' );
$pdf->SetTextColor( $textColour[0], $textColour[1], $textColour[2] );
$pdf->AddPage();

// Logo
$pdf->Image( $logoFile, $logoXPos, $logoYPos, $logoWidth );

// Report Name
$pdf->SetFont( 'Arial', 'B', 24 );
$pdf->Ln( $reportNameYPos );
$pdf->Cell( 0, 15, $reportName, 0, 0, 'C' );


/**
  Create the page header, main heading, and intro text
**/

$pdf->AddPage();
$pdf->SetTextColor( $headerColour[0], $headerColour[1], $headerColour[2] );
$pdf->SetFont( 'Arial', '', 17 );
$pdf->Cell( 0, 15, $reportName, 0, 0, 'C' );
$pdf->SetTextColor( $textColour[0], $textColour[1], $textColour[2] );
$pdf->SetFont( 'Arial', '', 20 );
$pdf->Write( 19, "2009 Was A Good Year" );
$pdf->Ln( 16 );
$pdf->SetFont( 'Arial', '', 12 );
$pdf->Write( 6, "Despite the economic downturn, WidgetCo had a strong year. Sales of the HyperWidget in particular exceeded expectations. The fourth quarter was generally the best performing; this was most likely due to our increased ad spend in Q3." );
$pdf->Ln( 12 );
$pdf->Write( 6, "2010 is expected to see increased sales growth as we expand into other countries." );


/**
  Create the table
**/

$pdf->SetDrawColor( $tableBorderColour[0], $tableBorderColour[1], $tableBorderColour[2] );
$pdf->Ln( 15 );

// Create the table header row
$pdf->SetFont( 'Arial', 'B', 15 );

// "PRODUCT" cell
$pdf->SetTextColor( $tableHeaderTopProductTextColour[0], $tableHeaderTopProductTextColour[1], $tableHeaderTopProductTextColour[2] );
$pdf->SetFillColor( $tableHeaderTopProductFillColour[0], $tableHeaderTopProductFillColour[1], $tableHeaderTopProductFillColour[2] );
$pdf->Cell( 46, 12, " PRODUCT", 1, 0, 'L', true );

// Remaining header cells
$pdf->SetTextColor( $tableHeaderTopTextColour[0], $tableHeaderTopTextColour[1], $tableHeaderTopTextColour[2] );
$pdf->SetFillColor( $tableHeaderTopFillColour[0], $tableHeaderTopFillColour[1], $tableHeaderTopFillColour[2] );

for ( $i=0; $i<count($columnLabels); $i++ ) {
  $pdf->Cell( 36, 12, $columnLabels[$i], 1, 0, 'C', true );
}

$pdf->Ln( 12 );

// Create the table data rows

$fill = false;
$row = 0;

foreach ( $data as $dataRow ) {

  // Create the left header cell
  $pdf->SetFont( 'Arial', 'B', 15 );
  $pdf->SetTextColor( $tableHeaderLeftTextColour[0], $tableHeaderLeftTextColour[1], $tableHeaderLeftTextColour[2] );
  $pdf->SetFillColor( $tableHeaderLeftFillColour[0], $tableHeaderLeftFillColour[1], $tableHeaderLeftFillColour[2] );
  $pdf->Cell( 46, 12, " " . $rowLabels[$row], 1, 0, 'L', $fill );

  // Create the data cells
  $pdf->SetTextColor( $textColour[0], $textColour[1], $textColour[2] );
  $pdf->SetFillColor( $tableRowFillColour[0], $tableRowFillColour[1], $tableRowFillColour[2] );
  $pdf->SetFont( 'Arial', '', 15 );

  for ( $i=0; $i<count($columnLabels); $i++ ) {
    $pdf->Cell( 36, 12, ( '$' . number_format( $dataRow[$i] ) ), 1, 0, 'C', $fill );
  }

  $row++;
  $fill = !$fill;
  $pdf->Ln( 12 );
}


/***
  Create the chart
***/

// Compute the X scale
$xScale = count($rowLabels) / ( $chartWidth - 40 );

// Compute the Y scale

$maxTotal = 0;

foreach ( $data as $dataRow ) {
  $totalSales = 0;
  foreach ( $dataRow as $dataCell ) $totalSales += $dataCell;
  $maxTotal = ( $totalSales > $maxTotal ) ? $totalSales : $maxTotal;
}

$yScale = $maxTotal / $chartHeight;

// Compute the bar width
$barWidth = ( 1 / $xScale ) / 1.5;

// Add the axes:

$pdf->SetFont( 'Arial', '', 10 );

// X axis
$pdf->Line( $chartXPos + 30, $chartYPos, $chartXPos + $chartWidth, $chartYPos );

for ( $i=0; $i < count( $rowLabels ); $i++ ) {
  $pdf->SetXY( $chartXPos + 40 +  $i / $xScale, $chartYPos );
  $pdf->Cell( $barWidth, 10, $rowLabels[$i], 0, 0, 'C' );
}

// Y axis
$pdf->Line( $chartXPos + 30, $chartYPos, $chartXPos + 30, $chartYPos - $chartHeight - 8 );

for ( $i=0; $i <= $maxTotal; $i += $chartYStep ) {
  $pdf->SetXY( $chartXPos + 7, $chartYPos - 5 - $i / $yScale );
  $pdf->Cell( 20, 10, '$' . number_format( $i ), 0, 0, 'R' );
  $pdf->Line( $chartXPos + 28, $chartYPos - $i / $yScale, $chartXPos + 30, $chartYPos - $i / $yScale );
}

// Add the axis labels
$pdf->SetFont( 'Arial', 'B', 12 );
$pdf->SetXY( $chartWidth / 2 + 20, $chartYPos + 8 );
$pdf->Cell( 30, 10, $chartXLabel, 0, 0, 'C' );
$pdf->SetXY( $chartXPos + 7, $chartYPos - $chartHeight - 12 );
$pdf->Cell( 20, 10, $chartYLabel, 0, 0, 'R' );

// Create the bars
$xPos = $chartXPos + 40;
$bar = 0;

foreach ( $data as $dataRow ) {

  // Total up the sales figures for this product
  $totalSales = 0;
  foreach ( $dataRow as $dataCell ) $totalSales += $dataCell;

  // Create the bar
  $colourIndex = $bar % count( $chartColours );
  $pdf->SetFillColor( $chartColours[$colourIndex][0], $chartColours[$colourIndex][1], $chartColours[$colourIndex][2] );
  $pdf->Rect( $xPos, $chartYPos - ( $totalSales / $yScale ), $barWidth, $totalSales / $yScale, 'DF' );
  $xPos += ( 1 / $xScale );
  $bar++;
}


/***
  Serve the PDF
***/

$pdf->Output( "report.pdf", "I" );

?>

Summary

In this tutorial you've learned how to use PHP with the FPDF library to produce a good-looking PDF report. Along the way you've looked at some useful methods of the FPDF library, and seen some techniques for creating tables and charts using FPDF.

There's a lot more to FPDF, such as the ability to create headers and footers, use automatic page breaks, and more. Find out more by reading the online manual at the FPDF website.

Have fun!

Learn PHP With Ease!

Written by Matt Doyle — ELATED's resident Web programming expert — Beginning PHP 5.3 is a complete introduction to PHP, covering everything in these tutorials and lots more besides. Find out how to:

  • Set up PHP on your computer
  • Use strings, arrays, functions and objects
  • Create interactive Web forms
  • Handle cookies and sessions
  • Work with files on the server
  • Build database-driven sites with MySQL
  • Send emails from your scripts
  • Create images on the fly with PHP
  • Work with regular expressions
  • Write robust, secure PHP applications

...and lots more!

“What a pleasure it's been spending hours and hours studying PHP with this magical book.” — Lulio, Florida
“The book is not only great for learning, but I find myself using it constantly as a reference as well!” — David A. Stoltz

Buy Beginning PHP 5.3 now from Amazon.comBeginning PHP 5.3 or Amazon.co.ukBeginning PHP 5.3.

Follow Elated

Related articles

Responses to this article

20 most recent responses (oldest first):

20-Jul-10 06:53
very nice... but i am having a problem ... i want to show grid on bars .. how can i do this?can you guide me?
21-Jul-10 18:49
@rubina: You could modify the code that draws the y-axis ticks to instead draw lines across the whole chart, eg:


for ( $i=0; $i <= $maxTotal; $i += $chartYStep ) {
$pdf->SetXY( $chartXPos + 7, $chartYPos - 5 - $i / $yScale );
$pdf->Cell( 20, 10, '$' . number_format( $i ), 0, 0, 'R' );
$pdf->Line( $chartXPos + 28, $chartYPos - $i / $yScale, $chartXPos + $chartWidth, $chartYPos - $i / $yScale );
}


Does that help?
29-Sep-10 08:31
TCPDF by Nicola Asuni at http://www.tcpdf.org is much more powerful and constantly developed than FPDF
06-Jan-11 07:13
hi,

I've created a pdf page using php and its is working fine in my local. But it is not working in the online server. The data content in the server's database is too large when compared to my local database. Here's my code:

$columns = 3; //number of Columns
$pdf->tbInitialize($columns, true, true);
$pdf->tbSetTableType($table_default_table_type);
$aSimpleHeader1 = array();
for($i=0; $i<$columns; $i++)
{
$aSimpleHeader1[$i] = $table_default_header_type;
}

$aSimpleHeader1[0]['TEXT'] = "Preparedness";
$aSimpleHeader1[0]['WIDTH'] = 112;
$aSimpleHeader1[0]['COLSPAN'] = 2;
$aSimpleHeader1[0]['T_COLOR'] = array(0,0,0);
$aSimpleHeader1[1]['WIDTH'] = 40;
$aSimpleHeader1[2]['WIDTH'] = 40;

$pdf->tbSetHeaderType($aSimpleHeader1);
$pdf->tbDrawHeader();

$aDataType1 = Array();
for ($i=0; $i<3; $i++)
$aDataType1[$i] = $table_default_data_type;

$pdf->tbSetDataType($aDataType1);

while($rowactivity1=mysql_fetch_array($activ_result1,MYSQL_ASSOC))
{
$activity = $rowactivity1['fld_procedure'];
$districtrole = selectsinglevalue("select fld_roleposition as retv from tbl_rolesmaster where fld_roleid='{$rowactivity1['fld_districtrole']}' and fld_delstatus=0");

$icsrole = selectsinglevalue("select fld_roleposition as retv from tbl_rolesmaster where fld_roleid='{$rowactivity1['fld_icsrole']}' and fld_delstatus=0");

$tdata1 = Array();
$tdata1[0]['TEXT'] = $activity;
$tdata1[1]['TEXT'] = $districtrole;
$tdata1[2]['TEXT'] = $icsrole;
$pdf->tbDrawData($tdata1);
}


if($pdf->GetY() > 0)
{
$pdf->SetXY($pdf->GetX(),$pdf->GetY()+10);
}
$pdf->tbOuputData();



Should i make any correction in database or in source code.
Please give a solution.
Thank in advance.
06-Jan-11 23:32
@Arunkarthik:

1. Please post this in a new topic:

http://www.elated.com/forums/authoring-and-programming/topic/new/

2. Please use the <> code button to wrap your code in code tags.

3. "The data content in the server's database is too large when compared to my local database" - if you have a problem with your data then changing the PHP code won't help!

Matt
cat
19-Jul-11 06:02
Thanks for the great tutorial. I found it to be a great help with TCPDF basics too (which is based on FPDF but takes it a bit further).
30-Sep-11 07:55
This is lovely. I used it to make people download their form after registering on my new site www.skateandwin.com but i want to save the created PDF to a file and also send it as attachment to their email. is this possible
04-Oct-11 23:07
@aristosoft: Yes. Use the 'S' option to return the PDF data as a string, then pass the string to http://pear.php.net/manual/en/package.mail.mail-mime.addattachment.php to attach the PDF to the message and send it.
07-Oct-11 19:47
I'm using the following code:


$pdf->Output("reportname.pdf","I");


But instead of my report appearing inside 'reportname.pdf', it is appearing inside the 'report.php' page which is the name of the file where I placed this line of code.

I don't want to change the code to:


$pdf->Output("reportname.pdf","D");


because this forces the file to be downloaded to a computer. The data in my report is sensitive so I don't want a copy of the report remaining in any download folder.

Any suggestions?
12-Oct-11 06:49
@Alex Kos: I don't understand the problem. What do you mean when you say the PDF appears "inside the 'report.php' page"?

It's worth pointing out that most browsers will likely cache the PDF file, even if they're displaying the PDF inline. Some browsers also ignore the 'I" option and download the PDF anyway. It's also easy for the user to save an inline PDF using File > Save As. So there is likely to be a copy of the PDF somewhere on the user's computer, even if you use the "I" option.
01-Jul-12 03:10
I found it very helpful.. thanks a lot
05-Feb-13 16:13
Good day everyone, I have tried the above code to convert a HTML form to PDF, but It shows error both in my local server and the server online. I'm using wamp Version 2.0. In the local server I am having the following error: Parse error: parse error in C:\wamp\www\FPDF\report.php on line 88; while in the server online I have the fillowing error: FPDF error: Image file has no extension and no type was specified:
Please can someone help, I will be very grateful. Thanks
jomhadonald@yahoo.ca
11-Feb-13 02:23
@jomhadonald: What's on your line 88?
26-Jun-13 02:49
Thanks for the useful post,


but how can i add content in to new pdf page when the page exeeds

thanks ,

[Edited by rohith038 on 26-Jun-13 02:50]
26-Jun-13 05:34
exceeds ...........

What exactly?
27-Jun-13 06:46
@chrishirst i mean when one page fills i need to move remaining contents to next page .Is there any extra code to be added for that .Currently i cannot view the remaining contents


thanks
27-Jun-13 16:47
It handles line breaks based on the paper size you set.
28-Jun-13 23:52
thanks man it helped..
11-Sep-14 08:45
Good read! I just want to share this site PDFFiller.com which i find very useful. It lets upload word and powerpoint document to be converted to PDF. It also let me fill out the text fields, add a variety of check marks, digitally sign the form and even add pictures. It also has the capability to print, fax, share, mail or even save it to your computer. Awesome tool. I was able to get also the form i need through

Link to fake IRS form REMOVED

[Edited by chrishirst on 11-Sep-14 15:14]
12-Sep-14 05:03
Thanks a lot..Keep Posting!

View all 24 responses »

Post a response

Want to add a comment, or ask a question about this article? Post a response.

To post responses you need to be a member. Not a member yet? Signing up is free, easy and only takes a minute. Sign up now.

Top of Page