PHPでRSSを作る

(1/1)
PHPで作るRSSビューア」ではRSSを読むプログラムを作成したが、今回はRSSを生成する方のプログラムを作ってみることにする。RSS1.0, RSS1.1, RSS2.0, Atom のフィードを作成することができる。また、XMLの名前空間について学ぶ。<

(2023年9月23日)pahooRSSクラスに変更した。RSS 2.0, Atomも作れるようにした。

目次

サンプル・プログラムの実行例

PHPでRSSを作る

サンプル・プログラム

圧縮ファイルの内容
makeRSS.phpサンプル・プログラム本体。
pahooRSS.phpRSS処理に関わるクラス pahooRSS。
RSS処理に関わるクラスの使い方は「PHPで作るRSSビューア」「[https://www.pahoo.org/e-soul/webtech/php02/php02-38-01.shtm:title=PHPでRSSを作る]」「[https://www.pahoo.org/e-soul/webtech/php02/php02-52-01.shtm:title=PHPでRSSを作る(その2)]」を参照。include_path が通ったディレクトリに配置すること。
makeRSS.php 更新履歴
バージョン 更新日 内容
2.0.0 2023/09/24 pahooRSSクラスに変更
1.2 2021/05/03 PHP8対応,リファラチェック追加
1.1 2017/03/14 PHP7対応
1.0 2014/06/28 初版
pahooRSS.php 関数/メソッド一覧
関数/メソッド 機能 詳細
class::pahooRSS
__construct コンストラクタ
__destruct デストラクタ
isJapanese 使用言語が日本語かどうかを判定する
setLanguage 使用言語を設定する.
isError エラーが発生しているかどうかを取得する.
getError エラー番号を取得する.
getErrorMessage エラー・メッセージを取得する.
resetError エラー状態をリセットする.
isphp8over PHP8以上かどうか検査する
parse 指定したURLにあるフィード情報を解釈してプロパティ$itemsに代入する.
addParser ユーザーが用意したパーサを追加する. 情報を格納するプロパティ $items の構造は本ファイル冒頭を参照のこと.
parseRSS10 RSS 1.0 パーサ チャンネル情報は添字0に、アイテム情報は添字1以降に格納する.
parseRSS11 RSS 1.1 パーサ チャンネル情報は添字0に、アイテム情報は添字1以降に格納する.
parseRSS20 RSS 2.0 パーサ チャンネル情報は添字0に、アイテム情報は添字1以降に格納する.
atom Atom パーサ チャンネル情報は添字0に、アイテム情報は添字1以降に格納する.
maker チャネル情報とフィード情報を与えてフィードを生成する. 作成するフィードとして RSS1.0, RSS1.1, RSS2.0, Atomを選択できる.
makeRSS10 与えたチャネル情報とフィード情報から RSS 1.0を生成する.
makeRSS11 与えたチャネル情報とフィード情報から RSS 1.1を生成する.
makeRSS20 与えたチャネル情報とフィード情報から RSS 2.0を生成する.
makeAtom 与えたチャネル情報とフィード情報から Atomを生成する.

解説:コンテンツの準備

RSSを作りたいコンテンツを、あらかじめ配列 $Contents に用意しておく。配列の構造は下表の通り。
実際にRSSを作成するときには、コンテンツ・データベースから取得するなどすればいいだろう。
配列 $Items の構造
$items[0] チャネルの情報
 ["title"]タイトル
 ["link"]URL
 ["rss"]RSSのURL
 ["creator"]製作者
 ["copyright"]著作権者
 ["desctiption"]説明
$items[1以上] フィードの情報
 ["title"]タイトル
 ["link"]URL
 ["desctiption"]説明
 ["date"]更新日時(ISO 8601形式)

  55: $Items = array(
  56: //チャネル情報
  57: 0 => array(
  58:     'link'  => 'http://www.pahoo.org/',
  59:     'rss'   => 'http://www.pahoo.org/rss/pahoo.rdf',
  60:     'title' => 'ぱふぅ家のホームページ',
  61:     'description' => '武蔵野・三鷹の地域情報、鉄道や旅先の写真、PHPやMySQLなどを使ったWebアプリケーションの作り方まで、知的な情報満載のホームページです。',
  62:     'creater' => 'studio pahoo',
  63:     'copyright' => 'Copyright (c) studio pahoo, All rights reserved.'
  64:     ),
  65: //フィード情報
  66: 1 => array(
  67:     'link' => 'http://www.pahoo.org/e-soul/webtech/php06/php06-21-01.shtm',
  68:     'title'       => 'PHPで2つの文章の類似度を計算する(WebAPI版)',
  69:     'description' => 'PHPでYahoo! JAPAN WebAPIやKAKASIを利用し、異なる2つの文章の類似度を計算するプログラムを紹介する。2つの文章がまったく違うテーマを扱っているのかどうかを判定する際に役立つ。',
  70:     'date'        => '2014-06-22T01:04:02+09:00'
  71:     ),
  72: 2 => array(
  73:     'link' => 'http://www.pahoo.org/athome/vehicle/jreast/img20130323-043352.html',
  74:     'title'       => 'JR東日本 183系は直流区間専用車',
  75:     'description' => '183系電車は1972年デビューの特急用車両で、485系に似ているが、こちらは直流区間線用である。1974年に登場した1000番台は非貫通型となり、強力な耐寒・耐雪構造となっており、上越線や中央本線へ導入された。',
  76:     'date'        => '2014-06-21T23:42:02+09:00'
  77:     ),
  78: 3 => array(

解説:フィードの生成

 446: /**
 447:  * チャネル情報とフィード情報を与えてフィードを生成する.
 448:  * 作成するフィードとして RSS1.0, RSS1.1, RSS2.0, Atomを選択できる.
 449:  * @param   array  $items チャネル情報とフィード情報
 450:  * @param   string $method       作成するフィード(RSS1.0,RSS1.1,RSS2.0,Atom)
 451:  * @return  string フィード(XMLテキスト)
 452: */
 453: function maker($items, $method='RSS1.0') {
 454:     $functions = array(
 455: 'RSS1.0' => 'makeRSS10',
 456: 'RSS1.1' => 'makeRSS11',
 457: 'RSS2.0' => 'makeRSS20',
 458: 'Atom'   => 'makeAtom'
 459: );
 460: 
 461:     foreach ($functions as $key=>$func) {
 462:         if ($key === $method) {
 463:             return $this->$func($items);
 464:         }
 465:     }
 466:     $this->error = 141;
 467:     throw new Exception($this->getErrorMessage());
 468:     return FALSE;
 469: }

pahooRSSのメソッド maker は、チャネル情報とフィード情報を与えてフィードを生成する。作成するフィードを引数 $method に指定する。ここでは、RSS1.0, RSS1.1, RSS2.0, Atomを選択できる。
実際にフィードを作成するのは、後述するメソッドになる。

解説:RSS 1.0 フィードの生成

 471: /**
 472:  * 与えたチャネル情報とフィード情報から RSS 1.0を生成する.
 473:  * @param   array  $items チャネル情報とフィード情報
 474:  * @return  string XML文字列
 475: */
 476: function makeRSS10($items) {
 477:     //テンプレート読み込み
 478:     $xml = simplexml_load_string($this->templateRSS10);
 479:     if ($xml === FALSE) {
 480:         $this->error = 123;
 481:         throw new Exception($this->getErrorMessage());
 482:         return FALSE;
 483:     }
 484: 
 485:     //channel部作成
 486:     $channel = $xml->addChild('channel', NULL, $this->nameSpaces['RSS1.0']['xmlns']);
 487:     $channel->addAttribute('rdf:about', $items[0]['rss'], $this->nameSpaces['RSS1.0']['rdf']);
 488:     $channel->addChild('title', $items[0]['title']);
 489:     $channel->addChild('link',  $items[0]['link']);
 490:     $channel->addChild('description', $items[0]['description']);
 491:     $channel->addChild('language', 'ja', $this->nameSpaces['RSS1.0']['dc']);
 492:     $channel->addChild('creater', $items[0]['creater'], $this->nameSpaces['RSS1.0']['dc']);
 493:     $channel->addChild('rights', $items[0]['copyright'], $this->nameSpaces['RSS1.0']['dc']);
 494:     $channel->addChild('date', date('c', time()), $this->nameSpaces['RSS1.0']['dc']);
 495: 
 496:     $node = $channel->addChild('items');
 497:     $node = $node->addChild('Sec', NULL, $this->nameSpaces['RSS1.0']['rdf']);
 498: 
 499:     for ($i = 1$i < count($items); $i++) {
 500:         $e = $node->addChild('li', NULL, $this->nameSpaces['RSS1.0']['rdf']);
 501:         $e = $e->addAttribute('rdf:resource', $items[$i]['link'], $this->nameSpaces['RSS1.0']['rdf']);
 502:     }
 503: 
 504:     //item部作成
 505:     for ($i = 1$i < count($items); $i++) {
 506:         $node = $xml->addChild('item', NULL, $this->nameSpaces['RSS1.0']['xmlns']);
 507:         $node->addAttribute('rdf:about', $items[$i]['link'], $this->nameSpaces['RSS1.0']['rdf']);
 508:         $node->addChild('title', $items[$i]['title']);
 509:         $node->addChild('link',  $items[$i]['link']);
 510:         $node->addChild('description', $items[$i]['description']);
 511:         $node->addChild('date', $items[$i]['date'], $this->nameSpaces['RSS1.0']['dc']);
 512:     }
 513: 
 514:     return $xml->asXML();
 515: }

pahooRSSのメソッド RSS10 は、チャネル情報とフィード情報を与えて RSS 1.0 フィードを生成する。

  76:     //RSS1.0のテンプレート
  77:     $this->templateRSS10 =<<< EOT
  78: <?xml version="1.0" encoding="utf-8" ?>
  79: <rdf:RDF
  80:     xmlns="http://purl.org/rss/1.0/"
  81:     xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
  82:     xmlns:dc="http://purl.org/dc/elements/1.1/"
  83:     xml:lang="ja">
  84: </rdf:RDF>
  85: 
  86: EOT;

まず、あらかじめ用意してあるテンプレート $templateRSS1 を  #simplexml_load_string  に投入し、SimpleXML で処理できるようにする。

ここで注意するのが、XMLの名前空間(name space)だ。
PHPでコロンを含むXML要素名を扱う方法」で紹介したが、コロンを含むXML要素は、コロンの前方が名前空間となっている。メソッド addChildaddAttribute を使って子ノードや属性を追加するときには、名前空間のURLを指定してやる必要がある。

 113:     //名前空間(name space)
 114:     $this->nameSpaces = array(
 115:         'RSS1.0' => array(
 116:             'xmlns' => 'http://purl.org/rss/1.0/',
 117:             'rdf'   => 'http://www.w3.org/1999/02/22-rdf-syntax-ns#',
 118:             'dc'    => 'http://purl.org/dc/elements/1.1/',
 119:             'lang'  => 'ja'
 120:         ),
 121:         'RSS1.1' => array(
 122:             'xmlns' => 'http://purl.org/net/rss1.1#',
 123:             'rdf'   => 'http://www.w3.org/1999/02/22-rdf-syntax-ns#',
 124:             'about' => 'http://www.xml.com/xml/news.rss'
 125:         ),
 126:         'ATOM' => array(
 127:             'xmlns' => 'http://www.w3.org/2005/Atom'
 128:         )
 129:     );

名前空間は、あらかじめプロパティ $nameSpaces として用意してある。

生成した RSS 1.0 は、asXML メソッドを使って文字列として返す。

解説:RSS 1.1 フィードの生成

 517: /**
 518:  * 与えたチャネル情報とフィード情報から RSS 1.1を生成する.
 519:  * @param   array  $items チャネル情報とフィード情報
 520:  * @return  string XML文字列
 521: */
 522: function makeRSS11($items) {
 523:     //テンプレート読み込み
 524:     $xml = simplexml_load_string($this->templateRSS11);
 525: 
 526:     //channel部作成
 527:     $xml->addChild('title', $items[0]['title']);
 528:     $xml->addChild('link',  $items[0]['link']);
 529:     $xml->addChild('description', $items[0]['description']);
 530: 
 531:     $node = $xml->addChild('items');
 532:     $node->addAttribute('rdf:parseType', 'Collection', $this->nameSpaces['RSS1.1']['rdf']);
 533: 
 534:     //item部作成
 535:     for ($i = 1$i < count($items); $i++) {
 536:         $e = $node->addChild('item');
 537:         $e->addAttribute('rdf:about', $items[$i]['link'], $this->nameSpaces['RSS1.1']['rdf']);
 538:         $e->addChild('title', $items[$i]['title']);
 539:         $e->addChild('link',  $items[$i]['link']);
 540:         $e->addChild('description', $items[$i]['description']);
 541:     }
 542: 
 543:     //xml宣言を除く
 544:     return preg_replace("/\<\?xml version=\"1.0\"\?\>\n/u", '', $xml->asXML());
 545: }

同様の仕組みで RSS 1.1 を生成するメソッド makeRSS11 である。

解説:RSS 2.0 フィードの生成

 547: /**
 548:  * 与えたチャネル情報とフィード情報から RSS 2.0を生成する.
 549:  * @param   array  $items チャネル情報とフィード情報
 550:  * @return  string XML文字列
 551: */
 552: function makeRSS20($items) {
 553:     //テンプレート読み込み
 554:     $xml = simplexml_load_string($this->templateRSS20);
 555:     if ($xml === FALSE) {
 556:         $this->error = 123;
 557:         throw new Exception($this->getErrorMessage());
 558:         return FALSE;
 559:     }
 560: 
 561:     //channel部作成
 562:     $channel = $xml->addChild('channel', NULL);
 563:     $channel->addChild('title',         $items[0]['title']);
 564:     $channel->addChild('link',          $items[0]['link']);
 565:     $channel->addChild('description',   $items[0]['description']);
 566:     $channel->addChild('language',      'ja');
 567:     $channel->addChild('pubDate',       date('c', time()));
 568:     $channel->addChild('lastBuildDate', date('c', time()));
 569: 
 570:     //item部作成
 571:     for ($i = 1$i < count($items); $i++) {
 572:         $node = $channel->addChild('item', NULL);
 573:         $node->addChild('title',        $items[$i]['title']);
 574:         $node->addChild('link',         $items[$i]['link']);
 575:         $node->addChild('description',  $items[$i]['description']);
 576:         $node->addChild('pubDate',      $items[$i]['date']);
 577:     }
 578: 
 579:     return $xml->asXML();
 580: }

同様の仕組みで RSS 2.0 を生成するメソッド makeRSS20 である。

解説:Atom フィードの生成

 582: /**
 583:  * 与えたチャネル情報とフィード情報から Atomを生成する.
 584:  * @param   array  $items チャネル情報とフィード情報
 585:  * @return  string XML文字列
 586: */
 587: function makeAtom($items) {
 588:     //テンプレート読み込み
 589:     $xml = simplexml_load_string($this->templateAtom);
 590:     if ($xml === FALSE) {
 591:         $this->error = 123;
 592:         throw new Exception($this->getErrorMessage());
 593:         return FALSE;
 594:     }
 595: 
 596:     //チャネル情報作成
 597:     $xml->addChild('title', $items[0]['title']);
 598:     $link = $xml->addChild('link', NULL);
 599:     $link->addAttribute('href', $items[0]['link']);
 600:     $xml->addChild('updated', date('c', time()));
 601:     $author = $xml->addChild('author', NULL);
 602:     $author->addChild('name', $items[0]['creater']);
 603: 
 604:     //フィード情報作成
 605:     for ($i = 1$i < count($items); $i++) {
 606:         $entry = $xml->addChild('entry', NULL);
 607:         $entry->addChild('title',   $items[$i]['title']);
 608:         $link = $entry->addChild('link', NULL);
 609:         $link->addAttribute('href', $items[$i]['link']);
 610:         $entry->addChild('updated', $items[$i]['date']);
 611:         $entry->addChild('summary', $items[$i]['description']);
 612:     }
 613: 
 614:     return $xml->asXML();
 615: }

同様の仕組みで Atom を生成するメソッド makeAtom である。

参考サイト

(この項おわり)
header