SOFTELメモ Developer's blog

会社概要 ブログ 調査依頼 社員募集 ...

素のphpでOAuthする

oauth

概要

なるべく素のphpでOAuthしてみる。

これで他のライブラリ等に依存しなくても、twitterのAPIや、tumblerのAPIが使える。

アクセストークンを取得するまでの流れはまた別な機会に。アクセストークンが取得済みの状況で、APIを使うところをやってみる。

phpの5.4ならば、やりやすい条件はそろっている。

20行目までは必要な関数の準備。メインの処理がその後に。

サンプル スクリプト

<?php
//ライブラリは要らないけど、これだけは使いたい
//OAuth式 パラメータのソート用比較関数
function oauthcmp($a, $b)
{
    return strcmp($a[0], $b[0])
            ? strcmp(rawurlencode($a[0]), rawurlencode($b[0]))
            : strcmp(rawurlencode($a[1]), rawurlencode($b[1]));
}
//OAuth式 パラメータのソート関数
function oauthsort($a)
{
    $b = array_map(null, array_keys($a), $a);
    usort($b, 'oauthcmp');
    $c = array();
    foreach ($b as $v) {
        $c[$v[0]] = $v[1];
    }
    return $c;
}

//OAuthのいつもの
$consumer_key = '**********************';
$consumer_secret = '****************************************';
$oauth_token = '********-*****************************************';
$oauth_token_secret = '*****************************************';

//どの twitter API
$url = 'https://api.twitter.com/1/statuses/update.json';
//POST or GET
$method = 'POST';
//パラメータ
$parameters = array('status' => 'テストのツイート');
$oauth_parameters = array(
    'oauth_version' => '1.0',
    'oauth_nonce' => microtime(),
    'oauth_timestamp' => time(),
    'oauth_consumer_key' => $consumer_key,
    'oauth_token' => $oauth_token,
    'oauth_signature_method' => 'HMAC-SHA1',
);

//署名を作る
//パラメータを仕様のとおりに並び替える(これが少々手間)
$base_string = implode('&', array(
    rawurlencode($method),
    rawurlencode($url),
    rawurlencode(http_build_query(oauthsort(array_merge($oauth_parameters, $parameters)), '', '&', PHP_QUERY_RFC3986))
));
$key = implode('&', array(rawurlencode($consumer_secret), rawurlencode($oauth_token_secret)));
$oauth_parameters['oauth_signature'] = base64_encode(hash_hmac('sha1', $base_string, $key, true));

//POSTリクエストはfile_get_contents()で十分可能
$options = array(
    'http'=>array(
        'method' => $method,
        'header' => array(
            'Authorization: OAuth ' . http_build_query($oauth_parameters, '', ',', PHP_QUERY_RFC3986),
        ),
        'content' => http_build_query($parameters)
    )
);
$result = file_get_contents($url, false, stream_context_create($options));

//結果を確認してみる
var_dump($result);

注意など

oauthcmpでなにやら複雑な比較をしているのは、パラメータをキーの順で並び替える部分で、キーが同じだったら値の順で並び替えることになっているため。

そのように作ってみたものの、パラメータをphpの連想配列で表現していたら、キーを重複させたくても重複できない。

また、一般にパラメータに配列を受け取るようなAPIが(たぶん)ないと思うので、あまり問題にならないと思う。

問題が発生したらまたそのときに。。。

追記: GETリクエストも考慮した

上の例ではGET渡しするパラメータを考えていなかった。GET渡しするパラメータも取り扱うようにすると、こんな感じ。

<?php

//OAuthのいつもの
$consumer_key = '**********************';
$consumer_secret = '****************************************';
$oauth_token = '**************************************************';
$oauth_token_secret = '*****************************************';

//どのAPI?(URL)
$url = 'https://api.twitter.com/1.1/search/tweets.json';

//POST or GET
$method = 'GET';

//パラメータ
$post_parameters = array(
);
$get_parameters = array(
    'q' => 'あああ',
    'lang' => 'ja',
);
$oauth_parameters = array(
    'oauth_consumer_key' => $consumer_key,
    'oauth_nonce' => microtime(),
    'oauth_signature_method' => 'HMAC-SHA1',
    'oauth_timestamp' => time(),
    'oauth_token' => $oauth_token,
    'oauth_version' => '1.0',
);
 
//署名を作る
//署名の計算にはoauth_*とAPIのパラメータを含めて全部使う
//GETリクエストのときでもURLにはクエリ文字列を含めない
//キーと値でソートする仕様なのだが、キーが重複したり英数字以外が混じったりしないのでksort関数で十分
$a = array_merge($oauth_parameters, $post_parameters, $get_parameters);
ksort($a);
$base_string = implode('&', array(
    rawurlencode($method),
    rawurlencode($url),
    rawurlencode(http_build_query($a, '', '&', PHP_QUERY_RFC3986))
));
$key = implode('&', array(rawurlencode($consumer_secret), rawurlencode($oauth_token_secret)));
$oauth_parameters['oauth_signature'] = base64_encode(hash_hmac('sha1', $base_string, $key, true));
 
//APIにリクエスト送信
$options = array(
    'http'=>array(
        'method' => $method,
        'header' => array(
            'Authorization: OAuth ' . http_build_query($oauth_parameters, '', ',', PHP_QUERY_RFC3986),
        ),
        'content' => http_build_query($post_parameters)
    )
);
$result = file_get_contents($url . ($get_parameters ? '?' . http_build_query($get_parameters) : ''), false, stream_context_create($options));
 
//結果を確認してみる
var_dump($result);

関連するメモ

コメント