日記
おまけ: RSSをサイドバーに表示Edit

RSSを取得するサンプルについては、XML_RSSを利用したコードを4章3節RSSのところで書いたが、実用的なサンプルではなかったので、ここでもうちょっと実用的なサンプルを補足しておく。

機能としては、blogツールのサイドバーなどにRSSを表示する機能を実装するイメージ。ただしここではサイドバーではなく、index.phpで新着記事一覧を表示した後ろに指定したRSSの内容を表示している。ベースとなるコードは、4章6節で作成したバージョンのHandMadeBlogだ。サンプルアーカイブはソフトバンクパブリッシングのサポートページからダウンロードできる。

他のサイトから取得したRSSを表示する際に、毎回RSSデータをHTTP GETするのは迷惑なので、一度取得したRSSデータは一定期間キャッシュするようにしてある。RSSの表示はテンプレート化されているので、適当に改造して表示するといいだろう。

/config.php

<?php

//キャッシュディレクトリの定義を追加する
define('CACHE_DIR', BLOG_DATA_DIR.'/cache');

?>

上記の設定は、BLOG_DATA_DIRの定義行以降ならばどこに書いてもいい。UNIX系プラットフォームで実行する場合は、上記キャッシュディレクトリにWebサーバーからの書き込み権限を付与しておく必要がある。

/index.php

<?php
/
$Id: index.php 152 2005-03-12 06:00:28Z ishinao $
/

require_once 'config.php';

main();

function
main() {
    
$entry_list = get_recent_entry_list();

    
show_template('htmlheader.tmpl', array(
        
'title' => '新着記事'
    
));
    
show_template('entry_list.tmpl', array(
        
'entry_list' => $entry_list
    
));

    
// $rss_urlで指定したRSSの内容を表示する
    
$rss_url = 'http://1470.net/bm/urlranking.html?mode=rss';
    
show_rss($rss_url, 10);

    
show_template('htmlfooter.tmpl');
}
?>

$rss_urlはコードに直接埋め込んでいるが、設定ファイルなどから取得するようにしておく方が無難だろう。また、複数のRSSを取得し、それらをdc:dateをキーにソートして、最新n件を表示するコードなどを書いてみるのもいいだろう。サイドバーに表示するように改造したい場合は、各要素をテーブルタグで適当に段組して表示するなり、CSSでレイアウトするなりすればいい。

/lib/rsslib.php

<?php

require_once 'XML/RSS.php';

function
show_rss($rss_url)
{
  
$data = parse_rss(get_rss_with_cache($rss_url));
  
show_template('rss_sidebar.tmpl', $data);
}

function
parse_rss($rss_data, $limit = 10)
{
  
$rss =& new XML_RSS();
  
$rss->setInputString($rss_data);
  
$rss->parse();

  if (
preg_match('/charset="(.+?)"/i', $rss_data, $matches)) {
    
$charset = $matches[1];
  } else {
    
$charset = 'auto';
  }

  
$channel = to_euc($rss->getChannelInfo(), $charset);
  
$items = to_euc($rss->getItems(), $charset);
  if (
count($items) > $limit) {$limit = array_slice($items, 0, $limit);}

  return array(
    
'channel' => $channel,
    
'items' => $items,
  );
}

function
get_rss_with_cache($rss_url, $cache_time = 600)
{
  
$cache_file = CACHE_DIR.'/rss_'.urlencode($rss_url);
  if (!
file_exists($cache_file) || filemtime($cache_file) < time() - $cache_time) {
    
touch($cache_file);
    
$rss = file_get_contents($rss_url);
    
$fp = fopen($cache_file, 'w');
    
fwrite($fp, $rss);
    
fclose($fp);
  } else {
    
$rss = file_get_contents($cache_file);
  }
  return
$rss;
}

?>

RSSのパースにはPEARのXML_RSSを使っているので、使える環境を用意する必要がある。また、setInputStringメソッドが使えるXML_Parserにpear upgradeしておく必要がある。具体的なやり方は本書で書いたので省略。

取得したRSSデータの文字コードを内部文字コードであるEUCに変換している。XMLのヘッダ部にcharsetがある場合はそれを見て、なければ(あるいは指定して正規表現にマッチしなければ)autoで文字コード変換をしている。場合によっては、うまく変換できない可能性もある。to_eucはcommon.phpに収録した配列に対応した文字コード変換関数。

URLにはファイル名として使えない文字が含まれる可能性があるため、RSSのURLをURLエンコードしたものをキャッシュファイル名として使用している。この方法だと長いURLだとファイルシステムの文字数制限に引っかかる場合もあるので、md5($rss_url)したファイル名などを使ってもいいだろう。

キャッシュを更新する前にtouchしているのは、RSSをGETするのに長い時間がかかるような場合に、複数のプロセスが同時にRSSをGETしに行くのを防ぐため。ひとまずtouch(キャッシュファイルのmtimeを更新)しておくことで、次のプロセスはひとまず古いキャッシュファイルを読んで動作することになる。

/tmpl/rss_sidebar.tmpl

<h4><a href="<?=h($channel['link']) ?>"><?=h($channel['title']) ?></a></h4>
<dl>
<?php foreach ($items as $item) : ?>
<dt>
<?php if (isset($item['dc:date'])) : ?>
    <?=h($item['dc:date']) ?>
<?php
endif ?>
    <a href="<?=h($item['link']) ?>"><?=h($item['title']) ?></a>
</dt>
<?php if (isset($item['description'])) : ?>
<dd><?=h($item['description']) ?></dd>
<?php endif ?>
<?php
endforeach ?>
</dl>

RSSでは(バージョンにもよるが)URL以外の要素は存在するとは限らないので、もしもあったら表示する、といった形でテンプレートを書いておく。dc:dateはW3CDateフォーマットのまま表示してしまっているが、本当ならばいったんUNIXタイムスタンプなどに変換しておいてから表示した方が融通が利く。特に、dc:dateでソートする場合などにはそのような変換が必須となる。

『自分で作るblogツール(PHP編)』サポートエントリーに戻る

Published At2005-03-31 16:17Updated At2005-03-31 16:17