理解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 互動。


 

<<<返回技術中心

技術文章

站內新聞