Google Feed API の代替をJSとphpでなんとかする
/ 2017.01.22 /
WEB /
様々なサイトで利用していたGoogle Feed APIが2017年1月に入って、ついに死んだ。
外部ブログ(例えばアメブロ)のRSSをGoogle Feed APIで取得し、
サイトに表示していた人は結構いるのではないだろうか。
諸事情により、下記の条件でRSSを取得して表示する必要が出てきたのでメモ。
実装要件
- 複数のブログ(クロスドメイン)からRSSを取得
- 各ブログからは最新記事1件を取得し投稿日順に並べる
- 読み込み時の処理軽減必須
- RSSからは
記事タイトル
サムネイル画像
投稿日
URL
ブログタイトル
の計5項目を取得
やったこと
結論からいうと、JS単品ではクロスドメイン(外部ブログ)の取得が困難だったので、
PHPにて対応を行った。
読み込み高速化のために、cURL multi
を用いて並列読み込みをしつつ、
キャッシュ(Package Information:Cache_Lite)を利用する。
サーバーにインストールされていない場合は、上記URLからダウンロードし、
RSS取得phpと同階層に設置する。
また、キャッシュファイルを保存するディレクトリをrsscache
という名前で同階層に作成する。
ソースコード
rss.php
<?php
//表示合計記事数
$hyojiNum = 10;
//フィード登録
$data['feedurl'][] = 'https://feedURL1.com/rss.xml';
$data['feedurl'][] = 'https://feedURL2.com/rss.xml';
$data['feedurl'][] = 'https://feedURL3.com/rss.xml';
$data['feedurl'][] = 'https://feedURL3.com/rss.xml';
// 適宜追加
$rssList = $data['feedurl'];
//キャッシュ準備
require_once('Cache/Lite.php');
$cacheDir = 'rsscache/';
$lifeTime = 60*60;
$automaticCleaningFactor = 100;
$options = array('cacheDir' => $cacheDir ,'caching' => true, 'lifeTime' => $lifeTime, 'automaticSerialization' => 'true','automaticCleaningFactor' => $automaticCleaningFactor);
$cacheData = new Cache_Lite($options);
$outdata = $cacheData->get('rsscache');
if(!$outdata) {
//同時呼び出し
$rssdataRaw = multiRequest($rssList);
for($n=0;$n<count($rssdataRaw);$n++){
$rssdata = simplexml_load_string($rssdataRaw[$n]);
if($rssdata->channel->item) $rssdata = $rssdata->channel;
if($rssdata->item){
$site = $rssdata->title;
$i = 0;
$kiji = 1; //記事取得数
foreach($rssdata->item as $myEntry){
if( $i >= $kiji){
break;
} else {
$rssDate = $myEntry->pubDate;
if(!$rssDate) $rssDate = $myEntry->children("http://purl.org/dc/elements/1.1/")->date;
date_default_timezone_set('Asia/Tokyo');
$myDateGNU = strtotime($rssDate);
$myDate = date('Y/m/d',$myDateGNU);
$coverImage = $myEntry->enclosure->attributes()->url;
$myBlogTitle = $site;
$myTitle = $myEntry->title; //タイトル取得
$myLink = $myEntry->link; //リンクURL取得
//出力内容(CSSOK)
if(preg_match('/PR:/',$myTitle)) continue;
$outdata[$myDateGNU] = '<a href="' . $myLink . '" target="_blank">' . '<div class="feed_img" style="background-image: url('.$coverImage.');"></div>';
$outdata[$myDateGNU].= '<div class="feed_text"><p><span>' . $myDate . '</span>';
$outdata[$myDateGNU].= $myTitle . '</p><p class="feed_title">By ' . $myBlogTitle .'</p></div></a>';
$i++;
}
}
}
}
//ソート
krsort($outdata);
$cacheData->save($outdata,'rsscache');
}
$nn = 0;
$html = '';
foreach($outdata as $outdata) {
$nn++;
$html.= $outdata;
if($nn == $hyojiNum) break;
}
$html = $html;
echo $html;
//同時呼び出し関数
function multiRequest($data, $options = array()) {
// array of curl handles
$curly = array();
// data to be returned
$result = array();
// multi handle
$mh = curl_multi_init();
// loop through $data and create curl handles
// then add them to the multi-handle
foreach ($data as $id => $d) {
$curly[$id] = curl_init();
$url = (is_array($d) && !empty($d['url'])) ? $d['url'] : $d;
curl_setopt($curly[$id], CURLOPT_URL, $url);
curl_setopt($curly[$id], CURLOPT_HEADER, 0);
curl_setopt($curly[$id], CURLOPT_RETURNTRANSFER, 1);
// post?
if (is_array($d)) {
if (!empty($d['post'])) {
curl_setopt($curly[$id], CURLOPT_POST, 1);
curl_setopt($curly[$id], CURLOPT_POSTFIELDS, $d['post']);
}
}
// extra options?
if (!empty($options)) {
curl_setopt_array($curly[$id], $options);
}
curl_multi_add_handle($mh, $curly[$id]);
}
// execute the handles
$running = null;
do {
curl_multi_exec($mh, $running);
} while($running > 0);
// get content and remove handles
foreach($curly as $id => $c) {
$result[$id] = curl_multi_getcontent($c);
curl_multi_remove_handle($mh, $c);
}
// all done
curl_multi_close($mh);
return $result;
}
?>
htmlにRSSを表示したい場合
phpではなくhtmlに埋め込みたい場合は、
先のRSS取得phpに加えて以下のような感じで対応する。
※Jquery使います。
rss.html
<div id="feed"></div>
<script src="jquery.js"></script>
<script src="rss.js"></script>
rss.js
$(document).ready(function(){
// vars
var rssURL = 'rss.php'; //rss.phpのディレクトリを指定
var setDOM = $('#feed'); //表示させる箇所のDOM要素を指定
// RSS取得開始
$.ajax({
url: rssURL,
type:'GET',
timeout: 5000,
dataType: 'html',
success: function(html){
setDOM.append(html).hide().fadeIn(1000);
}
});
});
おわりに
本当であれば、php側でjsonに変換してしまい、js側で取得し出力するほうが個人的にやりやすいんだけど、今回は色々なサイト様に頼って上記のカタチに落ち着きました。