Hatena::ブログ(Diary)

xmallocのプログラミングノート

2010年05月04日

そろそろOAuth対応しないとヤベーんじゃねーのと思ってるPHPerに贈るコピペ用コード

ツイッターAPIですが6月30日からBASIC認証がNGになるということで、なんか適当にbotとか作ったんだけどそろそろ対応しないといけないんじゃねーの?と思ってる方もいらっしゃるのではないかと思います。そんなお困りのあなたに今日はコピペ用コードをご用意しました。

以下、BASIC認証OAuth認証に変更するための大まかな順序です。

  1. OAuthライブラリダウンロードする
  2. OAuthアプリケーション登録する
  3. コードを直す

では具体的な方法について説明しますが、今回説明するのはbot等のユーザー固定のツイッターアプリの認証方法をOAuthに変える方法です。OAuth認証を使って不特定多数のユーザーからウェブサービスを利用できるようにする方法ではありませんのでご注意ください。


OAuthライブラリダウンロードする

一からコーディングしてもいいのですが全部説明するのも面倒なので、その辺に転がってるライブラリを利用させて頂くことにします。探せばPHPOAuthライブラリも色々あると思いますが、今回はツイッター本家のページからリンクされているTwitterOAuthを利用することにします。(以下の例ではこのライブラリを使用しjsonツイッターAPIを呼び出していますが、PHP-5.2.10未満のjsonモジュールにはバグがあるため、PHP-5.2.10以降が必要です。この辺については後述します。)

http://github.com/abraham/twitteroauthにアクセスしてアーカイブダウンロードしてもいいのですが(そうしたい人はどうぞ)、必要なのはOAuth.phpとtwitteroauth.phpの二つだけですので、http://github.com/abraham/twitteroauth/tree/master/twitteroauth/から個別にファイルをダウンロードした方が早いと思います。

とりあえずダウンロードしたら適当なフォルダに保存しておいてください。使い方は後で説明します。


OAuthアプリケーション登録する

ライブラリダウンロードしたらOAuthアプリケーション登録をします。順番的にはこちらを先にしても構いません。

アプリケーション登録はhttp://dev.twitter.com/apps/newから行います。ページにアクセスすると以下の登録フォームが表示されます。

f:id:xmalloc:20100504014631p:image

各項目には以下の内容を入力してください。

各項目を入力したら「アプリケーションを登録する」ボタンを押してください。エラーが無ければアプリケーションのページに遷移します。


アプリケーションのページに遷移したら後で必要になる項目を控えておいてください。まずアプリケーションのページのOAuth 1.0a Settingsから、Consumer keyとConsumer secret(以下のモザイクをかけた部分)をメモっておきます。

f:id:xmalloc:20100504014632p:image

次に、アプリケーションのページのサイドバーのMy Access Tokenをクリックし、oauth_tokenとoauth_token_secret(以下のモザイクをかけた部分)をメモっておきます。

f:id:xmalloc:20100504014633p:image

oauth_token_secretとかは人が読める形で保存するなと書いてますが、(繰り返し言いますが非公開前提ですので)華麗にスルーします。


コードを直す

準備が終わりましたので、プログラムの方をいじくります。

例として、home_timelineを読み込む処理を想定します。PHPcURLモジュールを使用してAPIを呼び出し、jsonモジュールPHPオブジェクトに変換しています。

<?php
function home_timeline($username, $password) {
    $ch = curl_init('http://api.twitter.com/1/statuses/home_timeline.json');
    curl_setopt($ch, CURLOPT_USERPWD, "{$username}:{$password}");
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    $ctx = curl_exec($ch);
    if ($ctx === false) {
        curl_close($ch);
        return false;
    }
    $info = curl_getinfo($ch);
    curl_close($ch);
    if ($info['http_code'] != 200) {
        return false;
    }
    return json_decode($ctx);
}

これをBASIC認証OAuth認証に変えます。ダウンロードしたtwitteroauth.phpOAuth.phpを同じディレクトリ(もしくは適当なPATH)に配置し、以下のようにコードを書き換え認証をOAuthに変更します。

<?php
require_once 'twitteroauth.php';
$CONSUMER_KEY = 'CONSUMER_KEY';
$CONSUMER_SECRET = 'CONSUMER_SECRET';
function oauth_home_timeline($oauth_token, $oauth_token_secret) {
    global $CONSUMER_KEY, $CONSUMER_SECRET;
    $t = new TwitterOAuth($CONSUMER_KEY, $CONSUMER_SECRET, $oauth_token, $oauth_token_secret);
    $result = $t->get('statuses/home_timeline');
    if ($t->http_code != 200) {
        return false;
    }
    if (isset($result->error)) {
        return false;
    }
    return $result;
}

$CONSUMER_KEYと$CONSUMER_SECRETにはアプリケーション登録時にメモったConsumer keyとConsumer secretをセットしてください。関数引数の$oauth_tokenと$oauth_token_secretにはMy Access Tokenのoauth_tokenとoauth_token_secretをセットします。この辺の作りについてはあくまでも例ですのでお好きなように。require_onceと、new TwitterOAuthからreturn $resultあたりをコピペして、元のコードに合わせて適当に改造してください。

TwitterOAuthを使用する場合、API呼び出し時のエントリポイントとなるURLhttp://api.twitter.com/1/statuses/home_timeline.json)は、TwitterOAuthが適当に変換してくれます。上の例ではその挙動を利用してTwitterOAuth::getの引数に'statuses/home_timeline'を渡していますが、完全なURLを指定してもちゃんと動きます。


次はpostする例です。呼び出すAPIがupdate.jsonになり、POSTメソッドでHTTPリクエストを発行していること以外は上の例と同じです。

<?php
function post($username, $password, $status) {
    $ch = curl_init('http://api.twitter.com/1/statuses/update.json');
    curl_setopt($ch, CURLOPT_USERPWD, "{$username}:{$password}");
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($ch, CURLOPT_POST, true);
    curl_setopt($ch, CURLOPT_POSTFIELDS, 'status=' . rawurlencode($status));
    $ctx = curl_exec($ch);
    if ($ctx === false) {
        curl_close($ch);
        return false;
    }
    $info = curl_getinfo($ch);
    curl_close($ch);
    if ($info['http_code'] != 200) {
        return false;
    }
    return json_decode($ctx);
}

これも認証をOAuthに変更します。API呼び出しに使用するメソッドがTwitterOAuth::getでは無くTwitterOAuth::postとなっている点以外については、基本的に上のhome_timelineの例と同じです。

<?php
require_once 'twitteroauth.php';
$CONSUMER_KEY = 'CONSUMER_KEY';
$CONSUMER_SECRET = 'CONSUMER_SECRET';
function oauth_post($oauth_token, $oauth_token_secret, $status) {
    global $CONSUMER_KEY, $CONSUMER_SECRET;
    $t = new TwitterOAuth($CONSUMER_KEY, $CONSUMER_SECRET, $oauth_token, $oauth_token_secret);
    $result = $t->post('statuses/update', array('status' => $status));
    if ($t->http_code != 200) {
        return false;
    }
    if (isset($result->error)) {
        return false;
    }
    return $result;
}

$status引数が投稿するツイートです。($statusにはUTF-8文字列を渡してください。)

実際に投稿するとhttp://twitter.com/xmalloc1/status/13345684719のようになります。通常「webから」等になっている使用クライアント名がアプリケーション登録した際のアプリケーション名となっており、リンク先も登録時のアプリケーションウェブサイトURLとなっているのが分かります。


補遺 PHP-5.2.10未満の場合

上述した通りPHP-5.2.10未満のjsonモジュールにはバグがあり、PHPのint(マシン依存、通常32bit)を越える数値を扱うことができません。

PHP-5.2.10未満を使用しており、PHPアップグレードも難しい場合は、XMLでのAPI呼び出しを検討してください。以下はhome_timelineの例をXMLでのAPI呼び出しに変更したものです。TwitterOAuth::formatプロパティを'xml'に変更し、simplexml_load_stringによりPHPオブジェクトに変換します。

<?php
require_once 'twitteroauth.php';
$CONSUMER_KEY = 'CONSUMER_KEY';
$CONSUMER_SECRET = 'CONSUMER_SECRET';
function home_timeline($oauth_token, $oauth_token_secret) {
    global $CONSUMER_KEY, $CONSUMER_SECRET;
    $t = new TwitterOAuth($CONSUMER_KEY, $CONSUMER_SECRET, $oauth_token, $oauth_token_secret);
    $t->format = 'xml';
    $xml = $t->get('statuses/home_timeline');
    if ($t->http_code != 200) {
        return false;
    }
    $result = simplexml_load_string($xml);
    if (isset($result->error)) {
        return false;
    }
    return $result;
}

PHP-5.2.10未満を使用しており、どうしてもjsonAPIを呼び出したい場合はService_JSON PEARパッケージが使用できます。Service_JSONを使用する場合は、TwitterOAuth::decode_jsonプロパティにfalseをセットしてからAPIコールを行います。TwitterOAuth::get/postが文字列でレスポンスを返しますので、Service_JSONで変換してください。例は省略します。

スパム対策のためのダミーです。もし見えても何も入力しないでください
ゲスト


画像認証