2013年03月28日

複数のサイトのRSSを読み込んで新着順に表示する

GoogleのRSSリーダーが廃止になる・・・ということでというわけでもないのですが、サイトのリニューアル時に関連する技術関係のRSSがまとめて表示されたらいいなぁと思って、そのような機能をPHPで実装してみました。
PHPでRSSリーダーというと、simplexml_load_fileがうんたらかんたらという記事が多いのですが、やりたいことは、
・複数のサイトのRSSを取得して
・最新順に並び替えて表示
だったのですが、なかなか同じようなことをやっている人が少なく、自分で組んでみました。

ポイントは
・RSSはサイト(もしくはサービス)によって出力が異なる
・simplexml_load_fileは非常に簡単にRSSを取得して吐き出せる反面、複数のサイトに対応させようとすると面倒
・オレPHP得意じゃなかった・・・!
というところです。

で、まぁ最後はなんでわざわざそんなこと書くかというと、もっといい書き方があるんだろうけどわからないのでこう書いたわけですが、以下のサイトを参考にしています。

・ウェブ学のすすめ - PHPのsimplexmlで複数のブログのRSSを読み込み新着順に表示する方法
・FOOTMARK - PHPでRSSを読み込む方法

どちらのサイトも基本的に同じ事をやっています。
「ウェブ学のすすめ」さんからは、複数サイトからのデータ抽出の仕方、「FOOTMARK」さんからは、allow_url_fopenがOFFの場合の処理の仕方&RSSによって書き方が変わるんだということを学ばせて頂きました。

んで結局どうなったのよ、というのが以下のコードですが、ちょっとお恥ずかしい・・・
知識のなさが浮き彫りですが

<?php
//1・・・はてブ、2・・・Wordpress
$rss_url = array(
'http://d.hatena.ne.jp/*****/rss<>1',
'http://********.com/feed<>2',
'http://www.******.com/feed/<>2'
);

function curl_get_contents( $url, $timeout = 60 ){
$ch = curl_init();
curl_setopt( $ch, CURLOPT_URL, $url );
curl_setopt( $ch, CURLOPT_HEADER, false );
curl_setopt( $ch, CURLOPT_RETURNTRANSFER, true );
curl_setopt( $ch, CURLOPT_TIMEOUT, $timeout );
$result = curl_exec( $ch );
curl_close( $ch );
return $result;
}

foreach ($rss_url as $url) {
$count = 0;
$buff=explode("<>",$url);

if(trim($buff[1])==1){
$result=curl_get_contents(trim($buff[0]), 120);
$rss = simplexml_load_string($result);
$site_title = $rss->channel->title;

foreach ($rss->item as $item) {
if ($count == 2) { //そのサイトから取得したい記事数
break;
}
$count++;

$link = $item ->link;
$title = $item ->title;
date_default_timezone_set('Asia/Tokyo');
$dc = $item ->children('http://purl.org/dc/elements/1.1/');
$day = date('Y/m/d',strtotime($dc -> date));
$key = date('YmdHi', strtotime($dc -> date));
$entryArr[$key] = "<li>$site_title - <a href=\"$link\" target=\"_blank\">$title</a>$day</p></li>\n";
}
} else if(trim($buff[1])==2){
$result=curl_get_contents(trim($buff[0]), 120);
$rss = simplexml_load_string($result);
$site_title = $rss->channel->title;
foreach ($rss->channel->item as $item) {
if ($count == 2) { //そのサイトから取得したい記事数
break;
}
$count++;

$link = $item ->link;
$title = $item ->title;
$day = date('Y/m/d',strtotime($item -> pubDate));
$key = date('YmdHi', strtotime($item -> pubDate));
$entryArr[$key] = "<li>$site_title - <a href=\"$link\" target=\"_blank\">$title</a>$day</p></li>\n";
}
}
}
krsort($entryArr);

foreach ($entryArr as $key=> $val) {
echo $val;
}
?>


いくつかポイントになる点があります。

先頭の「$rss_url = array()」の中にはRSSを取得したいページのURLを入れておきます。
以降で振り分けるため、ここでははてブを1、Wordpressで出力しているページを2として、
FeedURL+<>+番号
の形式で$rss_urlに突っ込んでいます。
違う形式のものがあれば、それも新たに登録が必要です。
あとで<>をexplodeして前後を振り分けているのですが、そんなことするんなら連想配列使えば?という人はそうしてください。(強気)

で、foreach ($rss_url as $url) {}内で、はてブの場合はこの項目をこう、Wordpressの場合はこの項目をこう・・・という処理をしています。
ここも・・・もうちょっといい方法があるんじゃないかなーと思ってますが、いい方法が思い当たらなかったので///

最終的には日付を$keyにして$entryArrに突っ込んでいます。
で、元の「ウェブ学のすすめ」さんでは、arsort()でソートしていますが、日付でソートしなければいけないので、krsortの間違いだと思われます。

これの欠点といえば、いちいちそのRSSがどのような構造になっているかを判断して登録しないといけないというところです。
もうちょっと楽に登録出来ればいいんですが。。。
posted by BigMoonEz at 16:22 | Comment(0) | TrackBack(0) | PHP | このブログの読者になる | 更新情報をチェックする