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 developerWorks profile is displayed to the public, but you may edit the information at any time. Your first name, last name (unless you choose to hide them), and display name will accompany the content that you post.

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]

Understanding the Zend Framework, Part 4: When there is no feed, the Zend_HTTP_Client

Building the perfect reader

Tyler Anderson (tyleranderson5@yahoo.com), Engineer, Stexar Corp.
Tyler Anderson graduated with a degree in computer science from Brigham Young University in 2004 and is currently in his last semester as a master's student in computer engineering. In the past, he worked as a database programmer for DPMG.com, and he is currently an engineer for Stexar Corp., based in Beaverton, Ore.

Summary:  This "Understanding the Zend Framework" series chronicles the building of an online feed reader, Chomp, while explaining the major aspects of using the recently introduced open source PHP Zend Framework. Part 3 explains how to use the Zend Framework to construct your online feed reader, Chomp, by creating an interface to subscribe to and read feeds, and to save feed entries into the database. Now you will learn how to use the Zend Framework to incorporate websites that do not support RSS feeds into the online feed-reader interface.

View more content in this series

Date:  18 Jan 2011 (Published 25 Jul 2006)
Level:  Intermediate PDF:  A4 and Letter (339KB | 16 pages)Get Adobe® Reader®

Activity:  16909 views
Comments:  

About this series

Part 1 talks about the overall concepts of the Zend Framework, including a list of relevant classes and a general discussion of the MVC pattern. Part 2 expands on that to show how MVC can be implemented in a Zend Framework application. You also created the user registration and login process, adding user information to the database and pulling it back out again.

Parts 3 and 4 deal with the actual RSS and Atom feeds. In Part 3, you enabled users to subscribe to individual feeds and to display the items listed in those feeds. You also discussed some of the Zend Framework's form-handling capabilities, validating data, and sanitizing feed items. Part 4 explains how to create a proxy to pull data from a site that has no feed.

The rest of the series involves adding value to the Chomp application. Part 5 explains how to use the Zend_PDF module to enable the user to create a customized PDF of saved articles, images, and search results. In Part 6, you use the Zend_Mail module to alert users to new posts. In Part 7, you look at searching saved content and returning ranked results. In Part 8, you create your own mashup, adding information from Amazon, Flickr, Twitter and Yahoo! And in Part 9, you add Ajax interactions to the site using JavaScript object notation.


Introduction

Not all sites have feeds, but it's still useful to track everything in one place. This article shows how to use the Zend_HTTP_Client module to create a proxy to pull data into the feed-reader interface. In this article, you will learn:

  • How to use the Zend_HTTP_Client module to load website data.
  • How to save the full text of feed entries and that of web pages not supporting feeds.
  • How to read the full text of saved feed entries within the feed-reader interface.

At the end of this article, you will have completed the framework of the feed-reader application. First, modify the database schema, then update the code to support the new schema. Next, add the functionality to save feed entry and web pages to the database. Finally, use Zend_HTTP_Client to allow users to optionally save the entries to the database and view them in your updated online feed reader.


Updating the database schema

To save feed entries into the feed-reader interface, you need to update the database schema first. Enter the SQL statements in Listing 1 in the MySQL console.


Listing 1. Modifying the database schema
                
drop table feeds;

create table feeds (feedname varchar(256), link varchar(512), rss varchar(5));
insert into feeds values
('Fox Sports', 'http://feeds.feedburner.com/foxsports/rss/headlines', 'true'), 
('Google News', 'http://news.google.com/?output=rss', 'true'), 
('Yahoo News', 'http://rss.news.yahoo.com/rss/topstories', 'true'),
('phpbb', 'http://www.phpbb.com/phpBB/viewforum.php?f=14', 'false'),
('MySQL Forums :: PHP', 'http://forums.mysql.com/list.php?52', 'false'),
('SitePoint Forums :: PHP', 'http://www.sitepoint.com/forums/forumdisplay.php?
    forumid=34', 'false');

drop table savedentries;

create table savedentries (id int(11) AUTO_INCREMENT, username varchar(20), 
feedname varchar(256), channelname varchar(256), link varchar(512), entrysaved 
varchar(5), entrydata text, PRIMARY KEY (id));

You can see that one field is added to the feeds table: rss. This tells you if the feed is an RSS feed or a web page that doesn't support feeds. Three more feeds of various PHP forums are added to the subscription list. Notice that the feeds from Part 3 have true in this new field, and the three new ones have false, indicating that they are web pages and not RSS feeds. The savedentries table has two new fields: entrysaved and entrydata. The entrysaved field indicates that the data in the entrydata field is valid. The entrydata field holds the full text of the article. You can see the new subscribable web pages in Figure 1.


Figure 1. Viewing the new subscribable web pages
Viewing the new subscribable web pages

Now it's time to go back to the Part 3 code and make some changes.


Updating the IndexController class

Later, you update the viewFeeds view, which requires the list of non-RSS feeds the current user is subscribed to, listing the subscribed feeds and web pages. Modify the indexAction method in the IndexController class, as shown in Listing 2.


Listing 2. The indexAction method in the IndexController class
                
    public function indexAction()
    {
...
            $select->where('feeds.feedname=subscribedfeeds.feedname');
            $select->where('feeds.rss=?', 'true');
            $rssResults = $db->fetchAll($select);

            $select = $db->select();
            $select->from('subscribedfeeds, feeds', '*');
            $select->where('subscribedfeeds.Username = ?', $username);
            $select->where('feeds.feedname=subscribedfeeds.feedname');
            $select->where('feeds.rss=?', 'false');
            $webResults = $db->fetchAll($select);

            $view = Zend::registry('view');
            $view->username = $username;
            $view->rssFeeds = $rssResults;
            $view->webFeeds = $webResults;
            echo $view->render('viewFeeds.php');
        }
    }

Two lists of results are obtained here: One contains the RSS feeds, and the other contains the web pages to which the current user is subscribed. They are then piped to the viewFeeds view and displayed.


Updating the saveEntryAction method

You need to update links that require you to save entries to the database, so you can update the two new fields. Modify the saveEntryAction method in the FeedController class, as shown in Listing 3.


Listing 3. The saveEntryAction method in the FeedController class
                
    public function saveEntryAction()
    {
        $input = new Zend_Filter_Input(
            array('username'=>'StringTrim'),
            array('username'=>'Alpha'),
            $_SESSION);
        $username = $input->getUnescaped('username');

        $input = new Zend_Filter_Input(
            array('*'=>'StringTrim'),
            null,
            $_POST);
        $feedTitle = $input->getUnescaped('feedTitle');
        $channelTitle = $input->getUnescaped('channelTitle');
        $channelLink = $input->getUnescaped('link');
        $type = $input->getUnescaped('type');
        $saveFullText = $input->getUnescaped 'saveFullText');
...
        $db = Zend_Registry::get('db');
        $row = array(
                     'Username' => $username,
                     'feedname' => $feedTitle,
                     'channelname' => $channelTitle,
                     'link' => $channelLink,
                     'entrysaved' => $saveFullText ? 'true' : 'false',
                     'entrydata' => $fullText
                     );
        
        $table = 'savedentries';
        $rowsAffected = $db->insert($table, $row);

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

The second section of Listing 3 takes the data from the POST array, instead of GET, since this is how requests to save entries are made (wouldn't want to send the full text of an article in the URL). Notice how the two new fields in the savedentries table are retrieved: type and saveFullText. The retrieved data is saved as a new row in the savedentries table, and if a web page is being saved, the user is sent back to the main page; otherwise, the user is sent back to the channel he was viewing.


Updating the deleteEntryAction method

You update the code where you deleted entries from the database. Modify the deleteEntryAction method in the FeedController class, as shown in Listing 4.


Listing 4. The deleteEntryAction method in the FeedController class
                
    public function deleteEntryAction()
    {
        $input = new Zend_Filter_Input(
            array('username'=>'StringTrim'),
            array('username'=>'Alpha'),
            $_SESSION);
        $username = $input->getUnescaped('username');

        $input = new Zend_Filter_Input(
            array('*'=>'StringTrim'),
            null,
            $_GET);
        $feedTitle = $input->getUnescaped('feedTitle');
        $channelTitle = $input->getUnescaped('channelTitle');
        $type = $input->getUnescaped('type');

        $db = Zend_Registry::get('db');
        $table = 'savedentries';
        $where = "username='$username' and feedname='$feedTitle'";
        if($type == 'rssFeed')
            $where = "$where and channelname='$channelTitle'";
        $rowsAffected = $db->delete($table, $where);
        
        $this->_redirect('/feed/viewSavedEntries/');
    }

The second section of code in Listing 4 retrieves the data from POST. Also, the type of entry is also retrieved. You see the new where clause, which also searches for a match on the channelname for RSS feeds, since web pages don't have a channelname.


Incorporating database changes and new functionality into the views

Now that the controllers are updated with new data being sent to the views, you need to update the views to capture this data and display it appropriately to the user.

The viewFeeds view

This view displays the subscribed feeds and websites to logged-in users. You need to modify this view to show the non-RSS websites currently subscribed to by customers. So, modify the viewFeeds.php file, as shown in Listing 5.


Listing 5. The viewFeeds view
                
...
         echo "<a href='feed/viewChannel?title=$feedTitle'>".
              "$feedTitle</a><br>";
     }
     ?>
  <br><br>
  <table>
    <tr>
      <td>Subscribed Web Pages:      
 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</td>
      <td>Save Entry to Database
 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</td>
      <td>Save Full Text</td>
    </tr>
  <?php
     foreach($this->webFeeds as $row){
         $feedTitle = $row['feedname'];
         $link = $row['link'];
         echo "<form method='POST' action='feed/saveEntry'>";
         echo "<input type='hidden' name='feedTitle' ".
              "value='$feedTitle'/>";
         echo "<input type='hidden' name='link' value='$link'/>";
         echo "<input type='hidden' name='type' value='webPage'/>";
         echo "<tr><td><a
 href='$link'>$feedTitle</a><br></td>";
         echo "<td><input type='submit'
 value='save'/></td>";
         echo "<td><input name='saveFullText' ".
              "type='checkbox'/></td></tr></form>";
     }
     ?>
  </table>
</body>
...

In Listing 5, a table is displayed that shows the subscribed web pages. As you loop through each entry, you embed hidden inputs that contain the page title, link, and type (webPage, as opposed to rssFeed), and you display a link to the actual web page, including a form to save the entry with a checkbox that allows users to save the full text of the page. See Figure 2.


Figure 2. The modified viewFeeds view
The modified viewFeeds

Try saving the "MySQL Forums :: PHP" page entry, along with its full text. You'll see what it looks like later.

The viewChannel view

You update the viewChannel view to include the form to save entries as in Listing 5. Modify the viewChannel view, as shown in Listing 6.


Listing 6. The modified viewChannel view
                
...
     <td>Save entry to database
        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</td>
      <td>Save Full Text</td>
    </tr>
  <?php
     $feedTitle = $this->title;
     foreach ($this->rssFeed as $item) {
         $entryTitle = $item->title();
         $link = $item->link();
         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 "<tr><td><a href='$link'>$entryTitle</a><br></td>";
         echo "<td><input type='submit' value='save'/></td>";
         echo "<td><input name='saveFullText' ".
              "type='checkbox'/></td></tr></form>";s
     }
?>
  </table>
...

Notice the similarities above with that of Listing 5, but notice that the hidden value type is set to rssFeed, instead of webPage. View the updated example browser output in Figure 3.


Figure 3. The modified viewChannel view
The modified viewChannel view

The viewSavedEntries view

With entries being saved with and without full text into the database, you have to modify the viewSavedEntries view accordingly. Do so, as shown in Listing 7.


Listing 7. The viewSavedEntries view
                
...
      <td>Delete Channel Entry
       
 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
</td>
      <td>View Saved Full Text</td>
    </tr>
  <?php
     foreach ($this->entries as $row) {
         $link = $row['link'];
         $channelTitle = $row['channelname'];
         $feedTitle = $row['feedname'];
         $entrysaved = '';
         if($row['entrysaved'] == 'true')
             $entrysaved = 'Full Text'; 
         $title = "$feedTitle";
         if($row['channelname'] != ''){
             $title = "$title > $channelTitle";
             $type = 'rssFeed';
         } else {
             $type = 'webPage';
         }
         echo "<form method='POST' action='/feed/deleteEntry'>";
         echo "<input type='hidden' name='feedTitle' ".
              "value='$feedTitle'/>";
         echo "<input type='hidden' name='channelTitle' ".
              "value='$channelTitle'/>";
         echo "<input type='hidden' name='link' value='$link'/>";
         echo "<input type='hidden' name='type' value='$type'/>";
         echo "<tr><td><a
 href='$link'>$title</a></td>";
         echo "<td><input type='submit'
 value='delete'/></td>";
         echo "<td><a
 href='/feed/fullText?feedTitle=$feedTitle&".
              "channelTitle=$channelTitle'>".
              "$entrysaved</td></tr></form>";
     }
?>
  </table>
...

Modify the delete link into a form with a Delete button. In the foreach loop, check to see if the entry had its full text saved, and, if so, set the entrysaved variable to Full Text. Otherwise, it will remain empty. Then set up the title of the entry and its type. In the form, you embed four hidden inputs: the entry's feedname, channelname (empty for webPage types), full link, and type. Then you display the link to the actual web page, a button to delete the entry, and a link to the full text of the saved web page, if the full text was saved. Note that the action pointed to is /feed/fullText, so you define a new fullTextAction method in the FeedController in the next section. The updated viewSavedEntries view can be seen in Figure 4.


Figure 4. The modified viewSavedEntries view
 The modified viewSavedEntries view

Saving feed entries

With the code in place for users to choose to save the full text of feed entries and web pages, the only thing missing is the code that grabs the web page using the Zend_HTTP_Client class. In this section, you define that code and the fullText action that displays the full text of saved entries to users.

Using Zend_HTTP_Client: saveEntryAction

It's time to complete the saveEntryAction method in the FeedController class by saving the full text of entries where the checkbox was checked. Modify the saveEntryAction method, as shown in Listing 8.


Listing 8. The saveEntryAction method in the FeedController class
                
    public function saveEntryAction()
    {
       $input = new Zend_Filter_Input(
            array('username'=>'StringTrim'),
            array('username'=>'Alpha'),
            $_SESSION);
        $username = $input->getUnescaped('username');
...
        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('db');
...
    }

If the checkbox indicates to save the entry, then grab it using the Zend_Http_Client class, as shown above. Save the full text of the entry into the fullText variable, which saves it into the database entry later in this method. If the retrieval was unsuccessful, an error message is displayed to the user who can try again by reloading the page.

Viewing full text of saved entries

Define the fullTextAction method so users can view the full text of saved entries. Define the fullTextAction method in the FeedController class, as shown in Listing 9.


Listing 9. The fullTextAction method in the FeedController class
                
    public function fullTextAction()
    {
       $input = new Zend_Filter_Input(
            array('username'=>'StringTrim'),
            array('username'=>'Alpha'),
            $_SESSION);
        $username = $input->getUnescaped('username');

        $db = Zend_Registry::get('db');
        $select = $db->select();
        $select->from('savedentries', '*');
        $select->where("username=?", $username);
        $select->where("feedname=?", $feedTitle);
        if($channelTitle)
            $select->where("channelname=?", $channelTitle);
        $sql = $select->__toString();
        $fullText = $db->fetchAll($sql);

        echo $fullText[0]['entrydata'];
    }

Grab the username, along with the feedname and channelname from the Session and Get arrays. Then search the savedentries table for a match, grab its full text and display it to the user. See the full text of the "MySQL Forums :: PHP" page entry saved in Figure 5.


Figure 5. Viewing the full text of a saved entry
Viewing the full text of a saved entry

Summary

That completes the feed reader! Use Zend_HTTP_Client to grab web pages from the Internet and save them into your feed reader. Your online feed reader also supports RSS feeds and web pages.

The rest of this series involves adding value to the Chomp application. Part 5 explains how to use the Zend_PDF module to enable the user to create a customized PDF of saved articles, images, and search results. In Part 6, you use the Zend_Mail module to alert users to new posts. In Part 7, you look at searching saved content and returning ranked results. In Part 8, you create your own mashup, adding information from Amazon, Flickr, and Yahoo. And in Part 9, you add Ajax interactions to the site using JavaScript object notation.



Download

DescriptionNameSizeDownload method
Source codeos-php-zend4.source.zip10KBHTTP

Information about download methods


Resources

Learn

Get products and technologies

Discuss

About the author

Tyler Anderson graduated with a degree in computer science from Brigham Young University in 2004 and is currently in his last semester as a master's student in computer engineering. In the past, he worked as a database programmer for DPMG.com, and he is currently an engineer for Stexar Corp., based in Beaverton, Ore.

Report abuse help

Report abuse

Thank you. This entry has been flagged for moderator attention.


Report abuse help

Report abuse

Report abuse submission failed. Please try again later.


developerWorks: Sign in


Need an IBM ID?
Forgot your IBM ID?


Forgot your password?
Change your password

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 developerWorks profile is displayed to the public, but you may edit the information at any time. Your first name, last name (unless you choose to hide them), and display name will accompany the content that you post.

Choose your display name

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.

(Must be between 3 – 31 characters.)

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

 


Rate this article

Comments

Help: Update or add to My dW interests

What's this?

This little timesaver lets you update your My developerWorks profile with just one click! The general subject of this content (AIX and UNIX, Information Management, Lotus, Rational, Tivoli, WebSphere, Java, Linux, Open source, SOA and Web services, Web development, or XML) will be added to the interests section of your profile, if it's not there already. You only need to be logged in to My developerWorks.

And what's the point of adding your interests to your profile? That's how you find other users with the same interests as yours, and see what they're reading and contributing to the community. Your interests also help us recommend relevant developerWorks content to you.

View your My developerWorks profile

Return from help

Help: Remove from My dW interests

What's this?

Removing this interest does not alter your profile, but rather removes this piece of content from a list of all content for which you've indicated interest. In a future enhancement to My developerWorks, you'll be able to see a record of that content.

View your My developerWorks profile

Return from help

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Open source
ArticleID=145591
ArticleTitle=Understanding the Zend Framework, Part 4: When there is no feed, the Zend_HTTP_Client
publish-date=01182011
author1-email=tyleranderson5@yahoo.com
author1-email-cc=troy@backstopmedia.com

Tags

Help
Use the search field to find all types of content in My developerWorks with that tag.

Use the slider bar to see more or fewer tags.

For articles in technology zones (such as Java technology, Linux, Open source, XML), Popular tags shows the top tags for all technology zones. For articles in product zones (such as Info Mgmt, Rational, WebSphere), Popular tags shows the top tags for just that product zone.

For articles in technology zones (such as Java technology, Linux, Open source, XML), My tags shows your tags for all technology zones. For articles in product zones (such as Info Mgmt, Rational, WebSphere), My tags shows your tags for just that product zone.

Use the search field to find all types of content in My developerWorks with that tag. Popular tags shows the top tags for this particular content zone (for example, Java technology, Linux, WebSphere). My tags shows your tags for this particular content zone (for example, Java technology, Linux, WebSphere).

Try IBM PureSystems. No charge.

Special offers