5
7

QiitaのRSSフィード活用されていますか?
個人サイトや、推しメンの記事を確認するのに結構便利です。

↓↓ Feedの存在知らない方はこちら ↓↓


今回は個人用に提供されているRSSフィードをPHPで解析してみました。

公式からRSSが提供されているのに、わざわざ解析してJSON化する意味がわからない...。って思う方もいると思います。
用途は人それぞれですが、「毎朝Slack通知したい」「記録として残したい」「独自のAPIを用意して、複数のアプリで使いまわしたい」とか、まぁ役立ちそうですよね。

「HTTP通信」をして「XMLの解析」をして「JSON化」する。
わりと、初学者の学習にぴったりな題材な気がします。

使用ライブラリ

Guzzle Http Client

HTTP通信のためにGuzzleライブラリを利用します。

実装例

さっそくですが実装例を紹介。
(※ 記事用に細かい例外処理など省いています。甘い部分あるかと思いますが、ご了承ください。)

/**
 * データのFetch.
 *
 * @param string $id
 *   Qiitaのアカウント名.
 * @param bool $format_json
 *   Jsonで返すか. 配列で返すか.
 *
 * @return string|array|false
 *   例外はFALSE.
 */
public function fetch(string $id, $format_json = TRUE): string|array|false {
  $url = 'https://qiita.com/' . $id . '/feed';
  try {
    $http_request = $this->httpClient->get($url);
    $feed = $http_request->getBody()->getContents();
    if (!$feed) {
      throw new \Exception();
    }
    $data = $this->loadRawFeedData($feed);
    if (!$data) {
      throw new \Exception();
    }
    $data = $this->parseXml($data, $url);
  }
  catch (\Exception $e) {
    return FALSE;
  }
  return $format_json ? json_encode($data) : $data;
}

/**
 * Fetchした生データを \SimpleXMLElement に変換.
 *
 * @param string $feed
 *   生データ.
 *
 * @return \SimpleXMLElement|false
 *   オブジェクトを返す. 失敗したら FALSE を返す.
 */
private function loadRawFeedData(string $feed): \SimpleXMLElement|false {
  $data = simplexml_load_string($feed);
  if (assert($data instanceof \SimpleXMLElement)) {
    return $data;
  }
  return FALSE;
}

/**
 * XMLデータの解析.
 *
 * @param \SimpleXMLElement $xml
 *   XMLデータ.
 * @param string $url
 *   RSS取得URL.
 *
 * @return array
 *   解析データを配列で返す.
 */
private function parseXml(\SimpleXMLElement $xml, string $url): array {
  $articles = [];
  foreach ($xml->entry as $o) {
    $title = (string) $o->title;
    $link = (string) $o->url;
    $published = (string) $o->published;
    if (!isset($title) || !isset($link) || !isset($published)) {
      continue;
    }
    $published = new \Datetime($published);

    $articles[] = [
      'title' => $title,
      'link' => $link,
      'published' => $published->format('c'),
    ];
  }
  return [
    'title' => (string) $xml->title,
    'link' => $url,
    'data' => $articles,
  ];
}

実行

fetch('umekikazuya');

結果

{
  "title": "umekikazuyaの記事 - Qiita",
  "link": "https://qiita.com/umekikazuya/feed",
  "data": [
    {
      "title": "PRに対して意識が変わりました 〜エンジニア2年目の夏〜",
      "link": "https://qiita.com/umekikazuya/items/a3260117bbc64e6673c3",
      "published": "2024-06-25T20:42:15+09:00"
    },
    {
      "title": "【PHP】DateTime::createFromFormat における ISO 8601 形式の罠",
      "link": "https://qiita.com/umekikazuya/items/fb1b407ddd0fc4d6021c",
      "published": "2024-06-24T21:39:14+09:00"
    },
    {
      "title": "アジャイルでキャリア形成しよ 〜スプリントを管理するDB設計法〜",
      "link": "https://qiita.com/umekikazuya/items/032c1e5d144830548d79",
      "published": "2024-06-24T09:29:09+09:00"
    },
    {
      "title": "【Drupal】過去の hook_update_N をスキップしたい",
      "link": "https://qiita.com/umekikazuya/items/421cf61a64b363cf9080",
      "published": "2024-06-24T01:36:38+09:00"
    }
  ]
}

いい感じ!

解説

ちょっとだけ解説。

fetch(string $id, $format_json = TRUE) について

Fetchして、データを返す関数です。

  1. アカウント名を引数にしてどのユーザーのFeedでも取得できるようにしています
  2. 第2引数で、JSON形式でデータを返す or 配列でデータを返す を指定できます
  3. データの取得にコケた場合や、解析時に不正なデータが合った場合はFALSEを返します

コードの責務が曖昧なので HTTP通信の実装部分は関数化してもいいかもですね。

loadRawFeedData(string $feed) について

HTTP通信で取得した、生データを \SimpleXMLElement に変換します。

parseXml(\SimpleXMLElement $xml, string $url) について

XMLデータを解析して、データのフォーマットをします。
キャストがちょっと雑かもですが、大目に見てください...

まとめ

いかがでしょうか?

記事内では、関数として実装を行いましたが...。
私はAPIを提供する Controller を実装してみました!!

もちろん、アカウントごとにResponseをCacheする機構も組み込んでいます。

次回もお楽しみに。


シリーズ紹介

5
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
7