Shaw's Home Page(本館)

はてなダイアリーから引っ越しました。

facebookアプリのファンゲート機能をPHP4で実装する

facebookアプリで、「いいね!」が押されているかどうかで表示する内容を切り替える機能のことを、ファンゲートって呼ぶそうですね。以前、ファンゲートをPHPで実装する方法についてこの日記に書いてみたところ、意外とアクセスがあって、それなりに需要のある話だったんだなーと思ってます*1

facebookアプリをiframeで作成する時に、「いいね!」ユーザだけ表示内容を変える方法

一度実装方法がわかれば使い回しができるので、同じことをやるのに苦労することはもうあるまい、と思っていたんだけども、この期に及んでPHP4しか使えないサーバでファンゲートを実装する必要が出てきてしまってちょっと困った。前回のやり方だと、PHP5.2以上(または、5.0以上にjsonモジュールを追加した環境)でなければ動かないので、PHP4環境で同じことをやるにはコードを書き直す必要があるわけで。今更PHP4しか使えないレガシー環境なんて使うなよ…という突っ込みは当然のものだと思わるけども、まだそういうホスティング環境を使わざるを得ないってケースはわずかながらあるのではないでしょうか。

で、コードを見直してみました。ファンゲートを実装するにあたりPHP4がとっても不便なのは、facebook側から受け取るsigned_requestパラメータに対して、sha256によるハッシュ復号処理が簡単にできない点。これができるfunctionがPHP4では標準で用意されていないんだよね。なので、外部ライブラリでどうにかならないかを探してみることに。そして見つけてきた情報がこのページ。

PHP4 で HMAC-SHA256 などの hash_hmac() 関数を使えるようにする

ドンぴしゃですね、素敵すぎる。PEARのCompatライブラリが必要なので、そこをごにょごにょする必要がありますが*2、そこさえクリアしてしまえば、あとはfacebookデベロッパーサイトにあったサンプルコードをそのまま使うだけ。できあがったソースはこんな感じになりました。

<?php
// PEARライブラリにpathを通す(必要がある場合)
ini_set('include_path', '.:./pear');

// 外部ファイル読み込み
if (!function_exists('hash_hmac')) {
    require 'PHP/Compat/Function/hash_hmac.php';
}

// アプリの秘訣
$secret_key = 'xxxxxxxxxx';

$signed = parse_signed_request($_POST['signed_request'], $secret_key);
//var_dump($signed);
if ($signed['page']['liked']) {
	echo 'このFacebookページは「いいね!」が押されてぃるょ!';
} else {
	echo 'このFacebookページは「いいね!」が押されてぃなぃょ...';
}
exit();

// signed_requestの値を復号する
// 以下、サンプルコードをそのまま利用する
function parse_signed_request($signed_request, $secret) {
	list($encoded_sig, $payload) = explode('.', $signed_request, 2); 

	// decode the data
	$sig = base64_url_decode($encoded_sig);
	$data = json_decode(base64_url_decode($payload), true);

	if (strtoupper($data['algorithm']) !== 'HMAC-SHA256') {
		error_log('Unknown algorithm. Expected HMAC-SHA256');
		return null;
	}

	// check sig
	$expected_sig = hash_hmac('sha256', $payload, $secret, $raw = true);
	if ($sig !== $expected_sig) {
		error_log('Bad Signed JSON signature!');
		return null;
	}

	return $data;
}

function base64_url_decode($input) {
	return base64_decode(strtr($input, '-_', '+/'));
}

さすがに、facebook提供のライブラリを利用した場合と比べるとコード量が増えますが、そこまで大変じゃないですね。PEARライブラリの拡張をしてくれた方のおかげなんだけどw 感謝感激であります。

*1:はてブに5userも付いたのが初めてて、ちょっと嬉しかったりする

*2:私は、サーバにインストールしたPEARライブラリを使うのではなく、必要なPEARライブラリだけ抜き出したファイル群を作成し、サーバの適当な場所にそのファイル群をアップロードした後でinclude_pathを通して使ってます。個人的に、「勝手PEAR」を利用するって呼んでますw