理解Zend 框架(4): 用Zend_HTTP_Client 獲取無提要的內容

日期:2006-11-21  作者:喜騰小二  來源:PHPChina


    並非所有的站點都包含提要,但是跟進某個地方的所有改動仍然是很有用的。本文將介紹如何使用 Zend_HTTP_Client 模塊創建代理,從而將數據提取到提要閱讀器界麵中。在本文中,您將學到:

如何使用 Zend_HTTP_Client 模塊加載網站數據。
如何保存提要條目的全文以及那些不支持提要的網頁的全文。
如何在提要閱讀器界麵中閱讀已保存提要條目的全文。
在本文的末尾,將完成提要閱讀器應用程序的框架。首先,修改數據庫綱要,其次,更新代碼以支持新的綱要,然後添加將提要條目和網頁保存到數據庫中的功能。最後,使用 Zend_HTTP_Client 模塊支持用戶有選擇地將條目保存到數據庫中,並在已更新的在線提要閱讀器中查看它們。

更新數據庫綱要

為了將提要條目保存到提要閱讀器界麵中,首先我們需要更新數據庫綱要。在 MySQL 控制臺中鍵入清單 1 中的SQL 語句。


清單 1. 更改數據庫綱要

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
(username varchar(20), feedname varchar(256), channelname varchar(256),
 link varchar(512), entrysaved varchar(5), entrydata varchar(307200));
 


您能看到 feeds 表添加了一個新的字段:rss。這個字段用於辨別該提要是 RSS 提要還是不支持提要的網頁。訂閱列表中添加了另外三個不同 PHP 論壇的提要。請注意,對於第 3 部分中的提要,這個新字段值為 true,而三條新提要的值則為 false,這說明它們是網頁,而非 RSS 提要。savedentries 表有兩個新的字段:entrysaved 和 entrydata。entrysaved 字段說明 entrydata 字段中的數據是有效數據。entrydata 字段保存了該文章的全文。新的可訂閱網頁如圖 1 所示。

現在需要回到第 3 部分的代碼中做一些更改。

更新 IndexController 類

稍後我們將對 viewFeeds 視圖進行更新,這需要當前用戶所訂閱的非 RSS 提要的列表,該列表列出了已訂閱的提要和網頁。在 IndexController 類中更改 indexAction 方法,如下所示。


清單 2. IndexController 類中的 indexAction 方法

    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');
        }
    }
 


這裡包含了兩個結果列表:一個包含用戶訂閱的 RSS 提要,而另一個包含當前用戶訂閱的網頁。這些提要隨後被傳送到 viewFeeds 視圖,並被顯示出來。

更新 saveEntryAction 方法

我們需要更新那些可以用來將條目保存到數據庫中的鏈接,這樣我們就可以更新這兩個新字段了。更改 FeedController 類中的 saveEntryAction 方法,如下所示。


清單 3. FeedController 類中的 saveEntryAction 方法

    public function saveEntryAction()
    {
        $filterSession = Zend::registry('fSession');
        $username = $filterSession->getRaw('username');

        $filterPost = Zend::registry('fPost');
        $feedTitle = $filterPost->getRaw('feedTitle');
        $channelTitle = $filterPost->getRaw('title');
        $channelLink = $filterPost->getRaw('link');
        $type = $filterPost->getRaw('type');
        $saveFullText = $filterPost->getRaw('saveFullText');
...
        $db = Zend::registry('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");
    }
 


清單 3 中第一段黑體代碼將數據從 POST 數組(而不是 GET 數組)中提取出來,因為這就是請求保存提要的方式(不想在 URL 中發送文章的全文)。請注意 savedentries 表中的兩個新字段 type 和 saveFullText 是如何被檢索的。已經檢索的數據被保存為 savedentries 表中的一個新行,並且,如果保存了一個網頁,那麼用戶將被轉回到主頁;否則用戶將被轉回到他正在查看的頻道。

更新 deleteEntryAction 方法

我們更新了從數據庫中刪除條目的代碼。更改 FeedController 類中的 deleteEntryAction 方法,如下所示。


清單 4. FeedController 類中的 deleteEntryAction 方法

    public function deleteEntryAction()
    {
        $filterSession = Zend::registry('fSession');
        $username = $filterSession->getRaw('username');

        $filterPost = Zend::registry('fPost');
        $feedTitle = $filterPost->getRaw('feedTitle');
        $channelTitle = $filterPost->getRaw('channelTitle');
        $type = $filterPost->getRaw('type');

        $db = Zend::registry('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/');
    }
 


第一段黑體代碼從 POST 數組中獲取數據。同樣,也獲得了條目中的 type 字段。我們可以看到新的 where 子句根據 RSS 提要搜尋匹配的 channelname,因為網頁不包含 channelname。

將數據庫變更和新功能添加到視圖中

既然控制器與將傳送給視圖的新數據是一起更新的,那麼我們需要更新該視圖來捕獲此數據,並適當地將其展示給用戶。

viewFeeds 視圖

這個視圖嚮已登錄用戶展示了已訂閱的提要和 Web 站點。我們需要更改此視圖,以展示用戶當前訂閱的非 RSS Web 站點。所以,讓我們來更改 viewFeeds.php 文件,如下所示。


清單 5. viewFeeds 視圖

...
         echo "".
              "$feedTitle

";
     }
     ?>
 


 


   
     
     
     
   
 
     foreach($this->webFeeds as $row){
         $feedTitle = $row['feedname'];
         $link = $row['link'];
         echo "";
         echo "
              "value='$feedTitle'/>";
         echo "";
         echo "";
         echo "";
         echo "";
         echo "";
     }
     ?>
 
Subscribed Web Pages:     
       
Save Entry to Database
       
Save Full Text

 href='$link'>$feedTitle


 value='save'/>

              "type='checkbox'/>


...
 


清單 5 中的表顯示了已訂閱的網頁。當我們在每個循環遍歷每個條目時,會嵌入了一些包含页面標題、鏈接和類型(webPage,與 rssFeed 相對)的隱藏輸入項,並且顯示了一個到實際網頁的鏈接。在這個網頁中,包含了一個帶復選框的用來保存條目的表單,可通過該復選框支持用戶保存页面的全文。參見圖 2。

試着保存 “MySQL Forums :: PHP” 页面條目及其全文,我們稍後就會看到它的樣子。

viewChannel 視圖

更新 viewChannel 視圖,以包含如清單 5 中所示的用於保存條目的表單。修改 viewChannel 視圖,如下所示。


清單 6. 修改後的 viewChannel 視圖

...
     Save entry to database
              
      Save Full Text
   
 
     $feedTitle = $this->title;
     foreach ($this->rssFeed as $item) {
         $entryTitle = $item->title();
         $link = $item->link();
         echo "

";
         echo "
              "value='$feedTitle'/>";
         echo "
              "value='$entryTitle'/>";
         echo "";
         echo "";
         echo "$entryTitle
";
         echo "";
         echo "
              "type='checkbox'/>
";
     }
?>
 
...
 


可以看到上麵清單與清單 5 有相似之處,但要注意的是,該隱藏值類型被設置為 rssFeed,而不是 webPage。查看已更新示例的浏覽器輸出,如圖 3 所示。

viewSavedEntries 視圖

有了與(或不同)全文一起保存的條目,還需要相應地修改 viewSavedEntries 視圖。為此,請參照下列清單。


清單 7. viewSavedEntries 視圖

...
      Delete Channel Entry
      
       

      View Saved Full Text
   
 
     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 "

";
         echo "
              "value='$feedTitle'/>";
         echo "
              "value='$channelTitle'/>";
         echo "";
         echo "";
         echo "
 href='$link'>$title
";
         echo "
 value='delete'/>";
         echo "
 href='/feed/fullText?feedTitle=$feedTitle&".
              "channelTitle=$channelTitle'>".
              "$entrysaved";
     }
?>
 
...
將 delete 鏈接修改成一個帶有 Delete 按鈕的表單。在 foreach 循環中,查看條目是否保存了全文,如果是,則將 entrysaved 變量設置為 "Full Text "。否則,該變量仍為空。然後設置條目標題及其類型。在表單中,我們嵌入了四個隱藏的輸入項:條目的 feedname、channelname(此值在 webPage 類型時為空)、完整的 link 和 type。隨後我們顯示了到實際網頁的鏈接、刪除條目按鈕以及到已保存網頁的全文的鏈接(如果保存了全文)。請注意,該行為指嚮 /feed/fullText,所以在下一部分中,將在 FeedController 中定義一個新的 fullTextAction 方法。可以在圖 4 中看到修改後的 viewSavedEntries 視圖。

保存提要條目

有了這個代碼,用戶就能夠選擇是否要保存提要條目和網頁的全文,現在惟一餘下的事情是用於抓取網頁的代碼(使用 Zend_HTTP_Client )。在這一小節中,我們定義了該代碼和 fullText 行為,該行為用於嚮用戶展示已保存條目的全文。

使用 Zend_HTTP_Client:saveEntryAction

是時候在 FeedController 類中完成 saveEntryAction 方法了,此方法所對應的行為是通過選中復選框保存條目的全文來完成的。修改 saveEntryAction 方法,如下所示。

清單 8. FeedController 類中的 saveEntryAction 方法

    public function saveEntryAction()
    {
        $filterSession = Zend::registry('fSession');
        $username = $filterSession->getRaw('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');
...
    }
 

如果復選框指出要保存條目,則使用 Zend_Http_Client 類抓取它,如上所示。將條目的全文保存到 fullText 變量中,隨後,該變量在此方法中把全文保存到數據庫條目中(參見 清單 3)。如果檢索失敗,則將一個錯誤消息顯示給用戶,用戶可通過重新加載页面來再次嘗試。

查看已保存條目的全文

定義 fullTextAction 方法,用戶就能查看已保存條目的全文了。定義 FeedController 類中的 fullTextAction 方法,如下所示。

清單 9. FeedController 類中的 fullTextAction 方法

    public function fullTextAction()
    {
        $filterSession = Zend::registry('fSession');
        $username = $filterSession->getRaw('username');
       
        $filterGet = Zend::registry('fGet');
        $feedTitle = $filterGet->getRaw('feedTitle');
        $channelTitle = $filterGet->getRaw('channelTitle');

        $db = Zend::registry('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'];
    }
 

從 Session 及 Get 數組中獲取 username、feedname 和 channelname。隨後搜索 savedentries 表來獲得匹配條目,然後獲取匹配條目的全文並顯示給用戶。已保存的 “MySQL Forums :: PHP” 页面條目的全文如圖 5 所示。

結束語

這樣就完成了提要閱讀器的創建!使用 Zend_HTTP_Client 從互聯網抓取網頁,並將它們保存到您的提要閱讀器中。您的在線提要閱讀器同樣支持 RSS 提要和網頁。

本繫列餘下的部分包含對如何為 Chomp 應用程序增值的介紹。第 5 部分將介紹用戶如何使用 Zend_PDF 模塊為已保存的文章、圖形和搜索結果創建一個定制的 PDF。第 6 部分中,將介紹如何使用 Zend_Mail 模塊提醒用戶有新的文章發佈。第 7 部分將探討如何搜索已保存內容並返回排列好的結果。第 8 部分中,我們將創建自己的混合模塊,以添加 Amazon、Flickr 和 Yahoo! 中的信息。而在第 9 部分中,我們將使用 JavaScript 對象符號為網站添加 Ajax 交互。


 

<<<返回技術中心

技術文章

站內新聞