作成の目的

さまざまな情報サイトではすでに RSS 配信は当然のようになっていますが、ブログツールが普及したために個人サイトでも RSS を発信しているところが多くなり、ウェブサイトの更新状況を把握するための媒体として RSS フィードが標準的なものとして定着してきました。このような状況にあっては、一般論としてブログツールを使っていないサイトでも RSS は提供したほうがよい、と言えると思います。

RSS フィードには RSS 1.0 とか RSS 2.0 とか種類がありますが、どのように記述するかは細かく決まっています。これを手作業で作成するのはちょっとたいへんです。ここのところを補助するため、必要なデータを入力して RSS フィードを作成するツールもあります(窓の杜 RSS 作成支援)。

ただ、個人的にこういったツールがちょっとなじまなかったのは、RSS フィードのための元データはテキストファイルで編集したいし、過去の更新情報も消去するのではなく残しておきたい、という希望があったからです。

そこで慣れないながらも PHP で、データファイルから RSS 1.0 と RSS 2.0 のフィードを生成するスクリプトを書きました。そのうち多少は汎用性があると思われる部分を公開します。

このスクリプトはローカルサーバでブラウザから呼び出して使う想定で書いてありますが、データファイルとスクリプトを(ローカルではない)サーバに置いて実行することも問題ないはずです。

データ形式

UTF-8 のテキストファイルでそれぞれのアイテムを次のように記述。空行がアイテム区切り。マーク行(「-----」)で読み込み終了。マーク行の前には空行を入れない。RSS 生成の対象とならなくなった記事アイテムは、マーク行の後ろに移動する。

link:[tab]記事の URL
title:[tab]記事タイトル
summary:[tab]記事概要
category:[tab]記事カテゴリ
date:[tab]記事公開日時
[空行]

日時は「2009-05-06T22:00:00+09:00」の形式で。最後の「+09:00」はその前の時刻表記が日本時間である、という意味。

スクリプト本体

スクリプト内容は次のとおり。色分けは、PHP の highlight_file 関数によるものです。


<?php
// feed generator script by Kaburaya http://painterfun.com/ 2009/07/01
// このスクリプトは自由にお使いください。ただし作者は動作結果について責任を負いません。
// 参考にしてもらう程度のものとして公開しているので、サポートはありません。
// 入力ファイルを別途作成する必要があります。書式などは付属の feed_generator_readme.txt を参照してください。

// データファイル設定(パス含む)
$update_file 'updates.dat';
$marker '-----'// マーク行
// 出力ファイル名(スクリプトからの相対パス。要書き込み可能属性)
$rss1 'index.rdf';
$rss2 'index.xml';

// サイト情報(例を参考に変更する)
$site_title 'Painter Fun!';
$author 'Kaburaya';
$site_link 'http://painterfun.com/';
$image 'http://painterfun.com/open/painterfun_banner.jpg';
$site_description 'Corel Painter をめぐる雑多な情報提供サイト by Kaburaya';
$about_rss1 'http://painterfun.com/index.rdf';

// データファイル読込
$data fopen($update_file'r');
$item_num 1;
while (!
feof($data)) {
    
$line fgets($data);
    
trim($line);
    if (!
strncmp($marker,$line,5)) {break;} // マーク行があれば終了
    
if (strlen($line) < 3) { // 空行でアイテム区切り
        
$item_num++;
        continue;
    }
    
$items explode ("\t",$line);
    
$key $items[0];
    
$value $items[1];
    
$entries[$item_num]["$key"] = $value;
}

$update trim($entries[1]['date:']);
$t explode('-', (str_replace(array(':','T','+'), '-'$update)));
$timestamp mktime($t[3],$t[4],$t[5],$t[1],$t[2],$t[0],0);
$update_long date('D, d M Y H:i:s'$timestamp) . ' +0900';

// 確認用スクリーン出力
print "number of items: $item_num<br />\n";
print 
"timestamp: $update<br />\n";
var_dump($entries);
print 
"<br /><br />\n";


//======================================================================
//section 1 : RSS1 RDF
//======================================================================

$file1 fopen($rss1'w');

$string = <<<_RDF_
<?xml version="1.0" encoding="utf-8"?>
<rdf:RDF
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns="http://purl.org/rss/1.0/">

<channel rdf:about="
$about_rss1">
<title>
$site_title</title>
<link>
$site_link</link>
<description>
$site_description</description>
<dc:language>ja</dc:language>
<dc:date>
$update</dc:date>
<image rdf:resource="
$image" />


_RDF_;

fwrite($file1$string);

$string "<items>\n<rdf:Seq>\n";
for (
$count 1$count <= $item_num$count++) {
    
$link trim($entries[$count]['date:']);
    
$string .= "<rdf:li rdf:resource=\"$link\" />\n";
}
$string .= "</rdf:Seq>\n</items>\n</channel>\n\n";

fwrite($file1$string);

$string '';
for (
$count 1$count <= $item_num$count++) {
    
$link trim($entries[$count]['link:']);
    
$string .= "<item rdf:about=\"$link\">\n";
    
$title trim($entries[$count]['title:']);
    
$string .= "<title>$title</title>\n";
    
$string .= "<link>$link</link>\n";
    
$summary trim($entries[$count]['summary:']);
    
$string .= "<description>$summary</description>\n";
    
$category trim($entries[$count]['category:']);
    
$string .= "<dc:subject>$category</dc:subject>\n";
    
$string .= "<dc:creator>$author</dc:creator>\n"// new
    
$date trim($entries[$count]['date:']);
    
$string .= "<dc:date>$date</dc:date>\n";
    
$string .= "</item>\n\n";
}

$string .= "</rdf:RDF>\n";
fwrite($file1$string);
fclose($file1);

//======================================================================
//section 2 : RSS2 XML
//======================================================================

$file2 fopen($rss2'w');

$string = <<<_RSS_
<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">

<channel>
<title>
$site_title</title>
<link>
$site_link</link>
<description>
$site_description</description>
<pubDate>
$update_long</pubDate>
<language>ja</language>
<image>
  <url>
$image</url>
  <title>
$site_title</title>
  <link>
$site_link</link>
</image>


_RSS_;

fwrite($file2$string);

$string '';
for (
$count 1$count <= $item_num$count++) {
    
$string .= "<item>\n";
    
$title trim($entries[$count]['title:']);
    
$string .= "<title>$title</title>\n";
    
$link trim($entries[$count]['link:']);
    
$string .= "<link>$link</link>\n";
    
$string .= "<guid>$link</guid>\n";
    
$date trim($entries[$count]['date:']);
    
$date str_replace(array(':','T','+'), '-'$date);
    
$t explode('-'$date);
    
$timestamp mktime($t[3],$t[4],$t[5],$t[1],$t[2],$t[0],0);
    
$time date('D, d M Y H:i:s'$timestamp) . ' +0900';
    
$string .= "<pubDate>$time</pubDate>\n";
    
$category trim($entries[$count]['category:']);
    
$string .= "<category>$category</category>\n";
    
$summary trim($entries[$count]['summary:']);
    
$string .= "<description>$summary</description>\n";
    
$string .= "<author>$author</author>\n"// new
    
$string .= "</item>\n\n";
}

$string .= "</channel>\n</rss>\n";
fwrite($file2$string);
fclose($file2);

print 
"\n<br />\ndone!\n";
?>

このスクリプトとサンプルデータは feed_generator.zip としてまとめましたので、必要でしたらどうぞ。

(2009/07/01)