2006年2月8日 星期三

關於 MagpieRSS

什麼是 MagpieRSS ?

MagpieRSS 是一個用 PHP 寫成的 RSS 分析器,他可以分析的 RSS 規格包括 RSS 0.9 、 RSS 1.0 、 RSS 2.0 、 Atom(有少許限制) 。而 LifeType 的 RSS 分析器便是進一步將 MagpieRSS 封裝成 RSSParser 類別來加以使用。

LifeType 在什麼地方用到 MagpieRSS ?

講到這就有點尷尬了,為什麼?因為一般的使用者是完全用不到的,至少我就是。若不是阿欣來問新聞閱讀器( FeedReader plugin)的亂碼問題,我還沒研究到他。等等, LifeType 不是有提供網站的各種格式的 RSSFeed 嗎?是沒錯啦!不過 LifeType 的 RSSFeed 是直接用與前台頁面相同的模版技術產生的,跟 MagpieRSS 一點關係也沒有,因為, MagpieRSS 的用途,是用來分析由 RSSFeed 取得的資料用的,也就是說,訂閱別人的 RSSFeed 用的。

目前,就我所知, LifeType 有用到 MagpieRSS 的地方有兩個:

  1. blog 裡的 $rss 物件。
  2. 新聞閱讀器( FeedReader plugin)

蝦米!玩了好久的模板,怎麼不知道有 $rss 物件可以使用?沒錯,我也是今天早上 trace 好久才發現的。整個 LifeType 的 class 目錄裡面只有 blogview.class.php 裡面用到了 RSSParser 物件,而他做的唯一一件事,就是傳送一個 $rss 物件給模版用。

根據 rssparser.class.php 裡面的註解說明,可以將下面的樣版代碼寫在樣版檔裡(以 main.template 為例):

{include file="$blogtemplate/header.template"}
<div id="content">
{foreach from=$posts item=post}
{include file="$blogtemplate/post.template"}
{/foreach}
<div>
{if $rss->parse("http://163.17.156.130/plog/rss/rss10/1")}
{foreach from=$rss->getItems() item=rssItem}
<a xhref="{$rssItem->getLink()}">{$rssItem->getTitle()}</a>
{/foreach}
{/if}
</div>

</div>
{include file="$blogtemplate/panel.template"}
{include file="$blogtemplate/footer.template"}

上面的例子,是訂閱阿欣部落RSS1.0 。然後,就可以在部落格的首頁下面看到阿欣部落的新文章標題及連結的………亂碼 !像下面這樣:

rssfeed亂碼問題

新聞閱讀器外掛也是相同的問題,像下面這樣:

feedreader plugin 的亂碼現像

內行人一看就知道,編碼出問題。

尋找問題

既然是編碼的問題,只要 讓 MagpieRSS 的輸出使用 UTF-8 編碼 就成了。可是找了官方網站,我沒有找到相關的文件說明,只好自己 trace 程式碼了。

MagpieRSS 已經被 LifeType 封裝成 RSSParser 類別了,所以從 class/xml/rssparser/rssparser.class.php 裡面開始找起。裡面的 parse 成員函式,便是負責執行 MagpieRSS 做分析的用途。

/**
* Parses an RSS feed
*
* @param rssFeed The URL of the RSS feed.
* @return Returns true if the parsing was successful.
*/
function parse( $rssFeed )
{
$rss = fetch_rss( $rssFeed );

if( !$rss )
return false;

$this->_channel = new RSSChannel( $rss->channel );

$this->_items = Array();
foreach ($rss->items as $item ) {
$itemObject = new RSSItem( $item );
array_push( $this->_items, $itemObject );
}

return true;
}

實際上, parse 函式是呼叫 Magpie 的 fetch_rss 函式來執行分析,並將分析的結果放在物件的 $_items 屬性裡。 fetch_rss 函式則是在 MagpieRSS 的 class/xml/rssparser/magpierss/rss_fetch.inc 裡面。

找到資料了!在 rss_fetch.inc 裡面有一段註解,我大概翻譯一下:

/*
* CONSTANTS - 在你的程式中重新定義這些常數來改變 rss_fetch()
* 的動作,目前大部份選項影響快取。
*
* MAGPIE_CACHE_ON - 是否讓 Magpie 快取分析過的 RSS 物件?
* For me a built in cache was essential to creating a "PHP-like"
* feel to Magpie, 基本原理請參考 rss_cache.inc 。
*
*
* MAGPIE_CACHE_DIR - Magpie 存放 RSS 物件的快取路徑。
* 這個路徑必需為 http 伺服程式具有寫入權限。如果這個路徑不存在,
* Mapie 會試著聰明地建立他。這個動作通常失敗的於權限不足。
*
*
* MAGPIE_CACHE_AGE - 設定 RSS 物件快取的時間,單位為秒。
*
*
* MAGPIE_CACHE_FRESH_ONLY - 如果遠端連結失敗,要丟出錯誤
* 還是要傳回過期的物件?
*
* MAGPIE_DEBUG - 顯示除錯用訊息。
*
*/

很不幸的,沒有關於輸出編碼的設定常數。終於,在同一個檔案的 init 函式裡找到了(在 rss_fetch 下面不遠處)應該是所有影響 MagpieRSS 的常數。整理如下:

常數名稱 預設值 說明
MAGPIE_CACHE_ON
true 是否開啟 RSS 物件快取?
MAGPIE_CACHE_DIR
./cache RSS 物件的快取目錄, http 伺服器程式必需具有寫入該目錄權限。
MAGPIE_CACHE_AGE
60*60 RSS 物件的快取時間,單位為秒。
MAGPIE_CACHE_FRESH_ONLY
false 若遠端連線失敗,丟出錯誤或傳回過期的 RSS 物件?
MAGPIE_DEBUG
0 是否顯示錯誤訊息。
MAGPIE_OUTPUT_ENCODING ISO-8859-1 輸出 RSS 物件時的字元編碼。
MAGPIE_INPUT_ENCODING null 讀取 RSSFeed 資料時的字元編碼。
MAGPIE_DETECT_ENCODING true 是否自動偵測讀取 RSSFeed 資料時的字元編碼?
MAGPIE_USER_AGENT * 做遠端連線時,送出的 USER AGENT 資訊。
MAGPIE_FETCH_TIME_OUT
5
遠端連線的 time out 時間,單位為秒。
MAGPIE_USE_GZIP
true
是否使用 gzip 壓縮?

所以,找到解決問題的方法啦!只要在產生 RSSParser 物件之前,先定義如下常數:

define('MAGPIE_OUTPUT_ENCODING', 'UTF-8');

就可以解決問題了。在新聞閱讀器外掛裡面,可以在 plugins/feedreader/class/action/readfeedaction.class.php 的第 60 行下面加上:

define('MAGPIE_OUTPUT_ENCODING', $this->_locale->getCharset());

如此,可以對使用不同編碼的網站具有比較好的相容性。不過,依據 class/xml/rssparser/magpierss/rss_parse.inc 裡面第 54 行的宣告:

var $_KNOWN_ENCODINGS = array('UTF-8', 'US-ASCII', 'ISO-8859-1');

目前 MapgieRSS 似乎只認得以上三種編碼而已。

後記

在尋找問題的過程中,線上 API 文件是個很有幫助的工具,相關類別/函式/檔案都有連結,很方便的就可以深入原始碼找尋只有註解/程式才有的說明,建議要好好熟悉利用。

補充:已經回報到臭蟲追蹤系統 ID:830

沒有留言:

張貼留言