7
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

いいね!したFacebookページのフィードを定期的にMongoDBに保存する

Last updated at Posted at 2014-09-07

PHP v5.6
Facebook SDK for PHP v4.0

あんまり需要なさそうですが、自分でいいね!したFacebookページのフィードをまとめてみたいなーと思って、いろいろ探ってみました。

RSS登録すればいいんですけど最近RSSあんまり使ってないし、いいね!の方が気楽だしってことで

定期的に実行させるにはcron等を使ってphpを自動実行させ、その中でFacebook APIを実行させるのですが、Facebook APIを実行するにあたってアクセストークンが必要になるので、事前にユーザーにFacebookアプリ認証画面通してユーザー情報にアクセスができるようにしておく必要があります。

大枠の流れ

フロント側

  • Facebookアプリを通してユーザー情報にアクセスできるようにする
  • 有効期限を延長したアクセストークンを取得してDBへ保存

バッチ側

  • 登録したアクセストークンを使っていいね!しているFacebookページ一覧を取得
  • それぞれいいね!しているFacebookページのフィードを取得

Facebookアプリを通してユーザー情報にアクセスできるようにする

Facebook SDK for PHP v4.0で「いいね!」をしたFacebookページを取得
http://qiita.com/ykyk1218/items/9c315efbd14f6316318c

上のURLの中でFacebookアプリを通してアクセストークンを取得する方法を記載してあります。
しかーし、ここで問題が、、、

有効期限を延長したアクセストークンを取得してDBへ保存

通常のアクセストークンだとせいぜい1時間ぐらいしか時間がもちません。
そこでアクセストークンの有効期限を延長する必要があります。

有効期限を延長したアクセストークンの取得

Facebook APIで有効期限を延長したアクセストークンを取得するにはgrant_type=fb_exchange_tokenというパラメータを付与してあげる必要があります。

Facebook SDK for PHPを使う場合はgetLongLivedSession()を使う事で取得できます。

FacebookSession::setDefaultApplication(APP_ID, APP_SECRET);
$helper  = new FacebookRedirectLoginHelper('<facebook認証をした後の戻り先URL(今回はこのURLに戻ってくることとします)>');
$session = $helper->getSessionFromRedirect();

if($session) {
	/* ここで有効期限を延長させてます */
	$longSession = $session->getLongLivedSession()
	$accessToken = $longSession->getToken();
}

これで有効期限が延長されたアクセストークンが返却されます。
ただ、延長されたといっても60日なので、有効期限が切れたばあいはアプリ側でうまいこと
調整する必要があります。

SDKの中身をちょっと見る

ついでにSDKの中でどんなことしているのか見てみます。

こいつがまず呼ばれる関数の処理

vendor/facebook/php-sdk-v4/src/Facebook/FacebookSession.php

public function getLongLivedSession($appId = null, $appSecret = null)
{
	$longLivedAccessToken = $this->accessToken->extend($appId, $appSecret);
	return new static($longLivedAccessToken, $this->signedRequest);
}

上記の$this->accessToken->extendの部分

vendor/facebook/php-sdk-v4/src/Facebook/Entities/AccessToken.php
public function extend($appId = null, $appSecret = null)
{
	$params = array(
		'grant_type' => 'fb_exchange_token',
		'fb_exchange_token' => $this->accessToken,
	);

	return static::requestAccessToken($params, $appId, $appSecret);
}

こんな感じになっていてfb_exchange_tokenを使っているなーってすぐわかりますね!

MongoDBへアクセストークンを保存

MongoDBのインストール

PHPのMongoDB用ドライバのインストール

$ sudo pecl install mongo

もしくは下記を参考にインストールします
http://andres.jaimes.net/876/setup-mongo-php-module-centos-6/

アクセストークンをDBに保存

$con = new MongoClient();
$db  = $con->selectDB(<データベース名>);
$col = $db->createCollection("<コレクション名>");

//どのユーザーかわかるように、FacebookユーザーのIDもついでに保存しておく
$request_me  = new FacebookRequest($session, 'GET', '/me');
$response_me = $request_me->execute();
$graphObj = $response_me->getGraphObject();
$userId   = $graphObj->getProperty('id');

$data = array(
	'member_id'    => $userId,
	'access_token' => $accessToken
);
$ret = $col->insert($data);

登録したアクセストークンを使っていいね!しているFacebookページ一覧を取得

ここからはバッチ処理のはなし

大枠は
Facebook SDK for PHP v4.0で「いいね!」をしたFacebookページを取得
http://qiita.com/ykyk1218/items/9c315efbd14f6316318c

こちらを見ればわかると思います。
変更点としては下記の通り

$session = new FacebookSession($accessToken);
$request = new FacebookRequest($session, 'GET', '/me/likes');

上記のようにセッションを取得するときにアクセストークを使って取得するようにしましょう。

それぞれいいね!しているFacebookページのフィードを取得

RSSフィードのURLがあるので、それを使ってあげればフィードを取得できます。
ただ、UserAgentを適当なブラウザのものにしないとだめっぽかったので、そこだけ注意ですね。

下記が登録したアクセストークンをMongoDBから取得するところから、Facebookページのフィードを登録するまで処理になります。

<?php

require("vendor/autoload.php");

use Facebook\FacebookSession;
use Facebook\FacebookRequest;
use Facebook\GraphUser;
use Facebook\FacebookRequestException;
use Facebook\FacebookRedirectLoginHelper;

FacebookSession::setDefaultApplication(APP_ID, APP_SECRET);

//各ユーザーのアクセストークンを取得する
$con     = new MongoClient();
$db      = $con->selectDB(DATABASE);
$col     = $db->selectCollection(COLLECTION);
$cursor  = $col->find();

foreach($cursor as $obj) {
	//アクセストークンをもとにいいね!しているページ一覧を取得する
	//アクセストークンの期限が切れている場合はエラー
	$accessToken = $obj['access_token'];
	$memberId    = $obj['member_id'];
	$session = new FacebookSession($accessToken);
	try {
		$session->validate();
		$request = new FacebookRequest($session, 'GET', '/me/likes');
		$response = $request->execute();
		registFacebookPage($db, $response, $memberId);

	}catch(FacebookRequestException $fe) {
		//アクセストークンの有効期限切れとか不正なアクセストークンの場合
		unset($sesssion);
		echo $fe->getCode();
		echo $fe->getMessage();
		exit; 	
	}catch(\Exception $e) {
		echo $e->getMessage();
		exit;
	}
}


function registFacebookPage($db, $response, $memberId) {
	//フォーマットをjson形式で取得
	$facebookFeedUrl = 'https://www.facebook.com/feeds/page.php?format=json&id=';

	$facebookPages = array();
	$graphObjList = $response->getGraphObjectList();

	foreach($graphObjList as $r) {
		$pageId   = $r->getProperty('id');
		$pageName = $r->getProperty('name');
		$url = $facebookFeedUrl . $pageId;
		$ch = curl_init($url);

		//これやらないと直接表示出力される
		curl_setopt( $ch, CURLOPT_RETURNTRANSFER, true );

		//UA偽装しないとfacebookから怒られるので適当なブラウザのUAにしておく
		curl_setopt($ch, CURLOPT_USERAGENT, 'AppleWebKit/537.36 (KHTML, like Gecko) Chrome');

		$jsonFeed = curl_exec($ch);
		curl_close($ch);

		$feeds = json_decode($jsonFeed, true);
		$facebookPages[$pageId]['pageName'] = $pageName;
		$facebookPages[$pageId]['entries']  = $feeds['entries'];

		//mongodbに登録
		$colFeeds = $db->createCollection("feeds");

		foreach($feeds['entries'] as $entry) {
			$dataFeed = array(
				"member_id" => $memberId,
				"page_id"   => $pageId,
				"page_name" => $pageName,
				"title"     => $entry['title'],
				"feed_id"   => $entry['id'],
				"alternate" => $entry['alternate'],
				"categories"=> $entry['categories'],
				"published" => $entry['published'],
				"updated"   => $entry['updated'],
				"author"    => $entry['author'],
				"verb"      => $entry['verb'],
				"objects"   => $entry['objects'],
				"comments"  => $entry['comments'],
				"likes"     => $entry['likes'],
				"content"   => $entry['content']
			);
			//同じidの場合は登録しない
			$retCount = $colFeeds->find(array("feed_id" => $dataFeed['feed_id']))->count();
			if($retCount > 0) {
				//登録済み
				continue;
			}

			$ret = $colFeeds->insert($dataFeed);
			if($ret['OK'] != 1) {
				//登録エラー
				
			}
		}
	}
}
?>

あとはこのphpを定期的に実行してあげれば登録されていきます。
やっほー!

7
8
1

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
7
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?