基於PHP和AJAX建立RSS聚合器

日期:2006-09-28  作者:喜騰小二  來源:PHPChina


 想象使用一個簡單HTML檔案來把一個請求發送到一個伺服器端指令檔,收到一個基於該請求的自訂XML檔案,然後把它顯示給使用者而幾乎不需要重新整理浏覽器!本文作者將同妳一起探討怎樣在普通Web應用程式中聯合PHP和AJAX技術來建立即時的資料傳輸而不需要進行浏覽器重新整理。

  儘管本文所使用的是PHP語言,但是請記住任何伺服器端語言都會正常工作。為了理解本文,我假定妳基本理解JavaScript和PHP或一類似伺服器端語言。

  本文範例使用AJAX來把一請求從一個RSS饋送發送到一自訂的PHP物件。該PHP物件複製一份在本機伺服器上的該饋送並返回這一路徑。該請求物件收到這一路徑,分析它,並且把資料以HTML形式顯示給使用者。這聽起來涉及很多步驟,其實它僅由4個小檔案組成。之所以使用了4個小檔案,是為了平衡它們各自特定的力量而使整個係統的處理極富效率性。

  有些讀者可能會問,為什麼妳要建立在本機伺服器上的饋送的一個副本而不是簡單分析最原始的饋送。原因是,這樣以來可以允許繞過XML
HTTP
Request物件所強加的跨域限制。後麵,我還會解釋怎樣建立這個自訂的PHP物件;但是首先,讓我們從表單建立開始。

  建立發出請求的表單

  妳要做的第一事情是,在妳的HTML的head選項卡之間包括妳可能想使用的JavaScript和任何CSS檔案。我包括了一個式樣表來實現該聚合器的最後佈局並用一個JavaScript檔案來發出請求和進行饋送分析:

<link href="css/layout.css" rel="stylesheet" type="text/css" />
<script
src="js/request.js"></script>

  下一步,建立一個表單,它針對妳所選擇的一個RSS饋送發出請求。我建立的表單隻包括一個輸入欄位和一個提交該請求的按鈕。該請求的查詢是一個字串,它由饋送輸入值和一個將在伺服器端被校驗的口令字組成;作為一個範例,我使用了下麵形式:
"password=mypassword

  該程式碼在每次页面載入之時發出一次請求;因此,如果页面被重新整理,現有的在該輸入域中的饋送串將在页面載入時被請求。下麵是一個表單資料的範例,連同一些div選項卡用來顯示已分析的饋送的特定結點:

<body onload="javascript:makeRequest('request.php?request=' +
document.feedForm.feed.value + '"password=mypassword');">
<form
name="feedForm" method="post"
action="javascript:makeRequest('request.php?request=' +
document.feedForm.feed.value + '"password=mypassword');">
Enter a feed:
<input type="text" name="feed" id="feed" size="20">
 <input type="submit"
name="submit" value="Add Feed">
</form>
<div
id="logo"></div>
<hr/>
<div id="copy"></div>
<div
id="details"></div>
</body>

  我所建立的這三個div選項卡是logo,copy和details,其中每一個都在佈局樣式表中有一個與之相關聯的樣式。當我們分析饋送時將會用到它們,但是我們首先需要能夠存取我們所請求的饋送。這可以使用我前麵所提到的PHP物件來完成。

  建立自訂的PHP物件


  我用PHP建立了一個小型RSS類,它在本機伺服器上建立一個請求饋送的副本,這樣它可以為我們稍後要建立的XML
HTTP
Request物件所存取。典型地,妳不能跨域請求一個檔案,這意味着妳要請求的檔案需要位於本機伺服器上。這個類是一種解決跨域問題的辦法,因為它建立該饋送的一個副本,這個副本在本機伺服器上被請求並且把本機路徑返回到該饋送,然後它由該Request物件來存取。

  這個類中唯一的方法是一個請求方法,它僅有一個指嚮所請求的RSS
饋送的URL的參數。然後,它透過rss的名字來檢查是否一目錄位於本機伺服器上。如果不存在,就建立一個並把其授權權模式設定為0666,這意味着該目錄可讀寫。當被設定為可讀的時,該目錄就可以在以後被存取;而當被設定為可寫的時,就可以把該饋送的一個副本寫嚮本機伺服器上的目錄:

//如果不存在目錄就建立一個
$dir = "rss";
if(!is_dir($dir))
{
 mkdir($dir,
0666);
}

  注意

  在一臺Windows機器上,對於PHP
4.2.0及以上版本中模式設定是不被要求的。但是,如果它存在的話,它將被略過;因此,我保留了它,以備該工程被遷移到一臺UNIX或Linux伺服器上。

  在把饋送複製到該伺服器前,我們需要一個唯一的檔案名。我對這個完整的URL使用了md5加密方法以確保所有饋送的名字是唯一的。透過這個新的檔案名,它可以連線一個描述指嚮該檔案的目錄的字串;這將在建立該饋送的副本時使用:

//建立唯一的命名
$file=md5($rss_url);
$path="$dir/$file.xml";

  透過使用被定義在上麵的路徑和到原始的被請求的饋送的URL的參考,現在我們能建立該檔案的一個副本。最後,把該路徑返回到該新檔案,作為對該請求的回應:

//複製饋送到本機伺服器
copy($rss_url,"$path");
return $path;
Following is the
small, yet powerful RSS class in its entirety:
<?php
class
RSS
{
 function get($rss_url)
 {
  if($rss_url !=
"")
  {
   //如果不存在目錄就建立一個
   $dir =
"rss";
   if(!is_dir($dir))
   {
    mkdir($dir,
0666);
   }
   // 建立一個唯一的名字
   $file = md5($rss_url);
   $path =
"$dir/$file.xml";
   //複製饋送到本機伺服器
   copy($rss_url, "$path");
   return
$path;
  }
 }
}
?>

  為了存取該PHP類中的方法,需要有一個請求檔案來擔當到該類的一個介麵,這也正是我們正在請求的檔案。這個檔案首先驗證從該請求查詢的一口令變數,或者返回一條指定該請求者不是一名經授權的使用者的訊息,或者用指嚮RSS饋送(該饋送在由請求方法處理後被複製到本機伺服器)的路徑作出回應。為了回應該RSS饋送,需要包含這個RSS物件並把它實例化,並且需要透過使用被請求的饋送的URL作為一參數來活化請求方法:

<?
if($password ==
"mypassword")
{
 require_once('classes/RSS.class.php');
 $rss = new
RSS();
 echo $rss->get($request);
}
else
{
 echo "You are an
unauthorized
user";
}
?>

  GET/POST與AJAX相結合

  為了POST請求,我們首先需要建立該請求物件。如果妳沒有建立請求物件的經驗,那麼可以讀一下我的文章《How
To Use AJAX》或簡單地研究一下本文的範例源程式碼。一旦建立該請求物件,就可以調用sendFeed方法並傳遞由表單所建立的URL:

function sendFeed(url){
 post.onreadystatechange =
sendRequest;
 post.open("POST", url,
true);
 post.send(url);
}

  一旦收到來自於PHP物件的回應並被正確載入,則對與該回應相應的本機檔案發出另一個請求。在這種情況中,post.responseText提供給我們該新檔案的路徑:

function sendRequest(){
 if(checkReadyState(post)){
  request =
createRequestObject();
  request.onreadystatechange =
onResponse;
  request.open("GET", post.responseText,
true);
  request.send(null);
 }
}

  分析回應

  由於RSS饋送之間的區別,分析回應俱有一定的挑戰性。一些含有包含標題和描述結點的影像,而其它則沒有。因此,當我們分析回饋時,我們需要做一點檢查來譯解它是否包括一影像。如果它包括一影像,我們就可以,與該饋送的標題和連結一起,在image
div選項卡中顯示該影像:

var _logo = "";
var _title =
response.getElementsByTagName('title')[0].firstChild.data;
var _link =
response.getElementsByTagName('link')[0].firstChild.data;;
_logo += "<a
href='" + _link + "' target='_blank'>" + _title +
"</a><br/>";
if(checkForTag(response.getElementsByTagName('image')[0]))
{
 var
_url = response.getElementsByTagName('url')[0].firstChild.data;
 _logo +=
"<img src='" + _url + "'
border='0'><br/>"
}
document.getElementById('logo').innerHTML =
_logo;

  我們不僅必須檢查每個影像以顯示它,當遍歷饋送中所有的項時我們還需要對之進行檢查。因為如果存在一個影像,那麼所有另外的標題和連結結點索引都將無法正常工作。因此,當發現影像選項卡時,我們應該透過在每一次遍歷中增加索引值(+1)來調整標題和連結結點的索引:

if(checkForTag(response.getElementsByTagName('image')[0]) "" i>0){
 var
_title=response.getElementsByTagName('title')[i+1].firstChild.data;
 var
_link=response.getElementsByTagName('link')[i+1].firstChild.data;
}
else{
 var
_title =response.getElementsByTagName('title')[i].firstChild.data;
 var _link
=
response.getElementsByTagName('link')[i].firstChild.data;
}

  妳可以使用checkForTag方法來檢查是否存在特定的選項卡:

function checkForTag(tag){
 if(tag != undefined) {
  return
true;
 }
 else{
  return
false;
 }
}

  存在許多種進行饋送分析的可能性。例如,妳可以把項賦到類別上並使得該類別可折叠,這樣使用者就可以對其想觀看的內容進行選擇。作為一個範例,我使用日期來對項進行分類-這可以透過譯解是否針對一個特定項的pubDate不同於前一個項的pubDate並且相應地顯示一新的日期來實現:

if(i>1){
 var previousPubDate =
response.getElementsByTagName('pubDate')[i-1].firstChild.data;
}
if(pubDate
!= previousPubDate || previousPubDate == undefined){
 _copy += "<div
id='detail'>" + pubDate + "</div><hr align='left' width='90%'/>";
}
_copy
+= "<a href="javascript:showDetails('" + i + "');">" + _title +
"</a><br/><br/>";
document.getElementById('copy').innerHTML +=
_copy;

  注意,上麵的最後一部分是showDetails方法,它用於當一使用者從一個饋送中選擇一特定的項時進行細節顯示。這個方法有一個參數(項索引值),這個索引用於發現在該饋送中details結點的索引:

function
showDetails(index){
 document.getElementById('details').innerHTML =
response.getElementsByTagName('description')[index].firstChild.data;
}

  結論

  使用AJAX發送查詢字串到一個伺服器端指令檔並檢索一個基於該串的自訂回應,這對於任何web開發者都有實現的可能。這樣以來,妳的下一個web應用程式也將會充滿了新的可能性。


<<<返回技術中心

技術文章

站內新聞

我要啦免费统计