PHPで2-legged OAuthによるAPIアクセス

            <div class="section">

OAuthの実装の仕組みを理解するためにPHPでMyOAuthクラスなるものを自分で作った。

mixiの「2-legged OAuthによるAPIアクセス」を参考にしてるよ。

http://developer.mixi.co.jp/appli/spec/mob/2-legged-oauth

※「こうして生成されたパラメータをAuthorizationヘッダに追加して、APIリクエストを送信します。」ってどうやるねん!と思った。

※2-legged OAuthはTwitterで採用してるOAuthなんかと違って「ユーザが認証する」プロセスがないようです。

※追記 : クエリパラメータに ?fields=birthday,gender みたいに , 区切りがあると失敗する。なぜだ。

     ⇒ どうやらパラメータの , はエンコードしてはいけないらしい。というか最初にエンコードしとらしい。なので , だけはわざと二重エンコードするようにした。

my_oauth.class.php
<?php
/**
* OAuth認証APIにリクエストを送信するライブラリ
*
* 2010-10-28
* @author Tanny
*/
require_once 'HTTP/Request.php' ;
class MyOAuth {
const OAUTH_SIGNATURE_METHOD = 'HMAC-SHA1',
OAUTH_VERSION          = '1.0';
private $oauth_consumer_key;        //事前に発行されたconsumer_keyを設定
private $oauth_consumer_secret_key; //事前に発行されたconsumer_secret_keyを設定
private $oauth_nonce;               //ランダムな文字列。必ずリクエストごとに違う値を設定してください。
private $oauth_signature;           //APIリクエストの妥当性を検証するための署名
private $oauth_signature_method;    //署名方式。’HMAC-SHA1′固定
private $oauth_version;             //1.0
private $oauth_timestamp;           //UNIXタイムスタンプ。時刻がずれているとエラーになるので、サーバの時刻設定を確認ください。
private $xoauth_requestor_id;       //ViewerのIDを設定
/**
* コンストラクタ
*
* @param $oauth_consumer_key 事前に発行されたconsumer_key
* @param $oauth_consumer_secret_key 事前に発行されたconsumer_secret_key
* @param $xoauth_requestor_id ViewerのID
*/
public function __construct($oauth_consumer_key, $oauth_consumer_secret_key, $xoauth_requestor_id) {
$this->oauth_consumer_key        = $oauth_consumer_key;
$this->oauth_consumer_secret_key = $oauth_consumer_secret_key;
$this->xoauth_requestor_id       = $xoauth_requestor_id;
$this->oauth_signature_method    = self::OAUTH_SIGNATURE_METHOD;
$this->oauth_version             = self::OAUTH_VERSION;
}
/**
* get
* GETでOAuth認証をして、APIにリクエストを送信する
*
* @param $api_url APIのURL
* @param $query_params クエリパラメータの配列
* @return APIからのレスポンス
*/
public function get($api_url, $query_params = array()) {
return $this->request('GET', $api_url, $query_params);
}
/**
* post
* POSTでOAuth認証をして、APIにリクエストを送信する
*
* @param $api_url APIのURL
* @param $query_params クエリパラメータの配列
* @return APIからのレスポンス
*/
public function post($api_url, $query_params = array()) {
return $this->request('POST', $api_url, $query_params);
}
/**
* request
* OAuth認証をして、APIにリクエストを送信する
*
* @param $method リクエストの送信方法(GET or POST)
* @param $api_url APIのURL
* @param $query_params クエリパラメータの配列
* @return APIからのレスポンス
*/
private function request($method, $api_url, $query_params) {
$this->oauth_nonce     = uniqid();  //TODO この乱数生成は微妙かもしれない
$this->oauth_timestamp = time();
$query_params = $this->fix_query_params($query_params);
$this->oauth_signature = $this->create_oauth_signature($method, $api_url, $query_params);
$request = new HTTP_Request();
$request->setUrl($api_url . '?' . $this->join_param('&', $query_params));
$request->addHeader('Authorization', $this->create_authorization_header());
if ($method === 'POST') {
$request->setMethod(HTTP_REQUEST_METHOD_POST);
}
$response = $request->sendRequest();
if (PEAR::isError($response)) {
return false;
}
return $request->getResponseBody();
}
/**
* fix_query_params
* クエリパラメータにVIEWERのIDを付属させる
*
* @param $query_params クエリパラメータの配列
* @return VIEWERのIDを付属させたクエリパラメータの配列
*/
private function fix_query_params($query_params) {
$query_params['xoauth_requestor_id'] = $this->xoauth_requestor_id;
return $query_params;
}
/**
* create_oauth_signature
* OAuth認証のためのシグニシャを生成する
*
* @param $method リクエストの送信方法(GET or POST)
* @param $api_url APIのURL
* @param $query_params クエリパラメータの配列
* @return OAuth認証のためのシグニシャ
*/
private function create_oauth_signature($method, $api_url, $query_params) {
if (!$method || !$api_url) {
return false;
}
$oauth_signature_params = array(
'oauth_consumer_key'     => $this->oauth_consumer_key,
'oauth_nonce'            => $this->oauth_nonce,
'oauth_signature_method' => $this->oauth_signature_method,
'oauth_timestamp'        => $this->oauth_timestamp,
'oauth_version'          => $this->oauth_version,
);
if ($query_params) {
foreach ($query_params as $key => $val) {
$oauth_signature_params[$key] = $val;
}
}
ksort($oauth_signature_params);
$oauth_signature_param = $this->join_param('&', $oauth_signature_params);
$base_params = array(
rawurlencode($method),
rawurlencode($api_url),
rawurlencode($oauth_signature_param),
);
$base_str   = join('&', $base_params);
$secret_key = $this->oauth_consumer_secret_key . '&';
return base64_encode(hash_hmac('sha1', $base_str, $secret_key, true));
}
/**
* create_authorization_header
* Authorizationヘッダーにつける値を生成
*
* @return Authorizationヘッダーにつける値
*/
private function create_authorization_header() {
$headers = array(
'oauth_consumer_key'     => $this->oauth_consumer_key,
'oauth_signature_method' => $this->oauth_signature_method,
'oauth_signature'        => $this->oauth_signature,
'oauth_timestamp'        => $this->oauth_timestamp,
'oauth_nonce'            => $this->oauth_nonce,
'oauth_version'          => $this->oauth_version,
);
ksort($headers);
$authorization_header = 'OAuth realm=""';
foreach ($headers as $key => $val) {
$authorization_header .= ", {$key}=\"{$val}\"";
}
return $authorization_header;
}
/**
* 配列のキーと値を「=」で繋ぎ、それらを$glueで指定された文字で連結する
*
* @param $glue 連結文字
* @param $params 連結する連想配列
* @return @配列のキーと値を「=」で繋ぎ、それらを$glueで指定された文字で連結した配列
*/
private function join_param($glue, $params) {
$ary = array();
foreach ($params as $key => $val) {
$ary[] = "{$key}={$val}";
}
return join($glue, $ary);
}
}
?>
MyOAuthを使用する側
<?php
require_once 'my_oauth.class.php';
$oauth    = new MyOAuth(OAUTH_CONSUMER_KEY, OAUTH_CONSUMER_SECRET_KEY, VIEWER_ID);
$response = $oauth->get('APIURL', ARRAY_PARAM);
?>