Skip to main content

By clicking Submit, you agree to the developerWorks terms of use.

The first time you sign into developerWorks, a profile is created for you. Select information in your profile (name, country/region, and company) is displayed to the public and will accompany any content you post. You may update your IBM account at any time.

All information submitted is secure.

  • Close [x]

The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerworks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

By clicking Submit, you agree to the developerWorks terms of use.

All information submitted is secure.

  • Close [x]

developerWorks Community:

  • Close [x]

Understanding the Zend Framework, Part 5: Creating PDF files

Building the perfect reader

Nicholas Chase (nicholas@nicholaschase.com), Developer/Writer, Studio B
Nicholas Chase, a Studio B author, has been involved in Web site development for companies such as Lucent Technologies, Sun Microsystems, Oracle, and the Tampa Bay Buccaneers. Nick has been a high school physics teacher, a low-level radioactive waste facility manager, an online science fiction magazine editor, a multimedia engineer, and an Oracle instructor. More recently, he was the Chief Technology Officer of an interactive communications firm in Clearwater, Florida, USA, and is the author of several books on Web development, including XML Primer Plus (Sams). He's currently trying to buy a farm so he and his wife can raise alpacas and chickens. He loves to hear from readers and can be reached at: nicholas@nicholaschase.com.

Summary:  In previous parts of this "Understanding the Zend Framework" series, you created the basic application, the Chomp online feed reader, using the open source PHP Zend Framework. In this tutorial, you use the Zend Framework's PDF capabilities to generate a PDF document based on entries the user has saved.

View more content in this series

Date:  18 Jan 2011 (Published 01 Aug 2006)
Level:  Intermediate PDF:  A4 and Letter (999 KB | 35 pages)Get Adobe® Reader®

Comments:  

Integrating with the application

Now that you have the general idea, let's look at what's involved in integrating this functionality with the actual application.

Adding descriptions to the view

Because you want the PDF to show both the title and description of your saved entries, you will need to save those descriptions in the database. At the moment, information only gets saved to the database if the user checks the full text option, and in that case, you are looking at an HTML page you don't necessarily want to include in a PDF document.

Start by adding the actual descriptions to viewChannel.php (see Listing 7).


Listing 7. Adding descriptions to viewChannel.php
<html>
<head>
    <title><?php echo $this->escape($this->title);
 ?></title>
</head>
<body>
  [<a href='/'>Back to Main Menu</a>]<br>
  <h1><?php echo $this->escape($this->title); ?></h1>
  
  <table>
    <tr>
      <td>Channel Title (click to read)       
 &nbsp;&nbsp;&nbsp;\
 &nbsp;&nbsp;&nbsp;</td>
      <td>Save entry to database
        amp;nbsp;amp;nbsp;amp;nbsp;\
        amp;nbsp;amp;nbsp;amp;nbsp;</td>
      <td>Save Full Text</td>
    </tr>
  <?php
     $feedTitle = $this->title;
     foreach ($this->rssFeed as $item) {
         $entryTitle = $item->title();
         $link = $item->link();
         $description = $item->description();
         echo "<form method='POST' action='/feed/saveEntry'>";
         echo "<input type='hidden' name='feedTitle'" .
              " value='$feedTitle'/>";
         echo "<input type='hidden' name='title' " .    
              " value='$entryTitle'/>";
         echo "<input type='hidden' name='link' \
         value='$link'/>";
         echo "<input type='hidden' name='type' \
         value='rssFeed'/>";
         echo "<input type='hidden' name='description' ".
              " value='".addslashes\
              (strip_tags($description))."'/>";
         echo "<tr><td><a
 href='$link'>$entryTitle</a><br>";
         echo "$description</td>";
         echo "<td><input type='submit'
 value='save'/></td>";
         echo "<td><input name='saveFullText' " . 
              " type='checkbox'/></td></tr></form>";
     }
?>
  </table>
</body>
</html>

The first change is to actually retrieve the description from the item itself. Once you have that, you want to add it to two places.

The first is a hidden form element (so that it is available when the user submits the form to save the item). To do that, you need to make sure you remove any possibility that the description will make this tag malformed. In other words, you need to remove any HTML tags and make sure any quotes in the text are preceded by backslashes and, thus, rendered harmless. To do all that, you apply the php strip_tags() function, then the addslashes() function.

Finally, you can display the description itself on the page for the convenience of users. In this case, you don't care about removing the HTML tags because you are displaying it in HTML, anyway.


Saving the description

Now that you have the description in the form, you need to modify the saveEntryAction() function to act on it. Open the FeedController.php file and make the changes shown in Listing 8.


Listing 8. Saving descriptions to the database
...
    public function saveEntryAction()
    {
        $filterSession = Zend_Registry::get('fSession');
        $username = $filterSession->getRaw('username');

        $filterPost = Zend_Registry::get('fPost');
        $feedTitle = $filterPost->getRaw('feedTitle');
        $channelTitle = $filterPost->getRaw('title');
        $channelLink = $filterPost->getRaw('link');
        $type = $filterPost->getRaw('type');
        $saveFullText = $filterPost->getRaw('saveFullText');
        $description = $filterPost->getRaw('description');

        if($saveFullText){
            $http = new Zend_Http_Client($channelLink);
            $response = $http->get();
            if ($response->isSuccessful())
                $fullText = $response->getBody();
            else{
                echo 'Error occurred, full text not saved, please reload.';
                return;
            }
        }

        $db = Zend_Registry::get('db');
        $row = array(
                     'Username' => $username,
                     'feedname' => $feedTitle,
                     'channelname' => $channelTitle,
                     'link' => $channelLink,
                     'entrysaved' => $saveFullText ? 'true' : 'false',
                     'entrydata' => 
                          $saveFullText ? $fullText : $description
                     );
        
        $table = 'savedentries';
        $rowsAffected = $db->insert($table, $row);

        if($type == 'webPage')
            $this->_redirect("/");
        else
            $this->_redirect("/feed/viewChannel?title=$feedTitle");
    }
...

The process is straightforward: You retrieve the description value from the form, and use it to populate the entrydata item in the update row array. In this case, you want to use this value only if the user did not select the fullText option.

Now you're ready to start dealing with the PDF itself.


Creating the new action

From the MVC standpoint, it's a toss-up as to whether creating the PDF should be part of the user, the index, or the feed. Here, you make the arbitrary decision to make it part of the feed. To that end, add the following function to the FeedController.php file, as shown in Listing 9.


Listing 9. Adding the createPdfAction() to FeedController.php
...
    public function createPdfAction()
    {
        $filterSession = Zend::registry('fSession');
        $username = $filterSession->getRaw('username');

    }
...

It is just a simple function, accessible from the browser. Start by retrieving the session from the registry and using it to get the current username.


Adding saved entries

Let's look at retrieving the information that will ultimately wind up in the PDF (see Listing 10).


Listing 10. Adding saved entries
...
public function createPdfAction()
    {
        $filterSession = Zend_Registry::get('fSession');
        $username = $filterSession->getRaw('username');

        $db = Zend_Registry::get('db');
        $select = $db->select();
        $select->from('savedentries', '*');
        $select->where("username=?", $username);
        $sql = $select->__toString();
        $entries = $db->fetchAll($sql);
        foreach($entries as $row){
            $title = $row['feedname'];
            $entrydata = $row['entrydata'];
            if($row['channelname'] != '')
            {
                $title = "$title > " . $row['channelname'];
            }
            echo '<p>'.$title.'<br />';
            echo $entrydata.'</p>';

        }
    }
...

First, retrieve the database connection for the registry, then create a select statement that retrieves all the rows in the savedentries table for the current username. Execute the query, retrieving the title and data for each entry, and adding a channel name to the title if available.

If you view the results of this function by pointing the browser to http://localhost/feed/createPdf, you should see results similar to those shown in Figure 1


Figure 1. Adding saved entries
Adding saved entries

Creating the new document

Creating the PDF involves the same steps in the sample document (see Listing 11).


Listing 11. Creating the new document
...
    public function createPdfAction()
    {

        require_once 'Zend/Pdf.php';

        $pdf = new Zend_Pdf();
        $page = new Zend_Pdf_Page(Zend_Pdf_Page::SIZE_LETTER);

        $filterSession = Zend_Registry::get('fSession');
        $username = $filterSession->getRaw('username');

        $db = Zend_Registry::get('db');
        $select = $db->select();
            if($row['channelname'] != '')
            {
                $title = "$title > " . $row['channelname'];
            }
            echo '<p>'.$title.'<br />';
            echo $entrydata.'</p>';

        }
        $pdf->pages[0] = ($page);
    }
...

You're creating the new PDF document and a single page, then adding the page to the document after all processing has been completed.


Adding interface items

Adding the image, text, and borders should also look familiar (see Listing 12).


Listing 12. Adding a logo
...
    public function createPdfAction()
    {

        require_once 'Zend/Pdf.php';

        $pdf = new Zend_Pdf();
        $page = new Zend_Pdf_Page(Zend_Pdf_Page::SIZE_LETTER);
        $chompImage = new 
                Zend_Pdf_Image::imageWithPath('E:\sw\public_html\chomp.jpg');

        $pageHeight = $page->getHeight();
        $pageWidth = $page->getWidth();
        $imageHeight = 72;
        $imageWidth = 72;

        $topPos = $pageHeight - 36;
        $leftPos = 36;
        $bottomPos = $topPos - $imageHeight;
        $rightPos = $leftPos + $imageWidth;

        $page->drawImage($chompImage, $leftPos, $bottomPos,
                                         $rightPos, $topPos);
    
        $style = new Zend_Pdf_Style();
        $style->setLineColor(new Zend_Pdf_Color_RGB(0.9, 0, 0));
        $style->setFillColor(new Zend_Pdf_Color_GrayScale(0.2));
        $style->setLineWidth(3);
        $style->setFont(Zend_Pdf_Font::fontWithName(
                            Zend_Pdf_Font:FONT_HELVETICA_BOLD), 32);

        $page->setStyle($style);
              ->drawText('Chomp! To go', $rightPos + 32, $topPos - 48);
              ->drawRectangle(18, $pageHeight - 18, $pageWidth - 18,
                                18, Zend_Pdf_Page::SHAPEDRAW_STROKE);

        $filterSession = Zend_Registry::get('fSession');
        $username = $filterSession->getRaw('username');

        $db = Zend_Registry::get('db');
        $select = $db->select();
        $select->from('savedentries', '*');
...

Note that in this case, you set a specific location for the image so the application can find it.


Outputting the PDF

Outputting the PDF is a little different from in the sample file because part of the setup for the Zend Framework involves making sure that all requests go to the index.php file. That means you can't simply save the file to the server and have the user download. (Yes, there are server configuration tweaks you can make, but you're trying to keep this simple.)

The alternative is to simply output the PDF to the user's browser after it's been generated (see Listing 13).


Listing 13. Outputting the PDF
...
        foreach($entries as $row){
            $title = $row['feedname'];
            $entrydata = $row['entrydata'];
            if($row['channelname'] != '')
            {
                $title = "$title > " . $row['channelname'];
            }
//            echo '<p>'.$title.'<br />';
//            echo $entrydata.'</p>';

        }

        $pdf->pages[0] = ($page);

        header('Content-type: application/pdf');
        echo $pdf->render();

    }
...

Starting at the bottom, the render() function outputs the actual text that is the PDF document, but for the browser to interpret it correctly, it needs to know the text consists of a PDF file. Normally, when the browser downloads a PDF, the server sends the content type based on the file extension. Since there is no file, there is no file extension, so you have to set it manually using the headers.

Before you can use the headers, you must make sure that nothing gets output before them, so you remove the statements that were previously sent to the page.

If you refresh the browser (see Figure 2), you should see the actual PDF document (assuming you have Adobe Acrobat Reader installed).


Figure 2. Outputting the PDF
Outputting the PDF

3 of 9 | Previous | Next

Comments



static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Open source
ArticleID=148418
TutorialTitle=Understanding the Zend Framework, Part 5: Creating PDF files
publish-date=01182011
author1-email=nicholas@nicholaschase.com
author1-email-cc=dwxed@us.ibm.com