michimani.net

cakePHPでTwitterAPIのOAuth認証を実装してみる

2016-06-07

cakePHP のプロジェクト内で Twitter API を使用できるようにしたときのメモです。

準備

フレームワークはcakePHPを使用します。 TwitterAPIのライブラリとして、 OAuth consumers for CakePHP を使用します。 こちら からzipファイルをダウンロードして、中にある OAuthフォルダを**app/Vender/**に配置します。

構成

あくまでも例ですが。

OAuth認証も含めて、その他TwitterAPIで使用する機能(ツイート、タイムライン取得など)のメソッドをTwitterCompornent.phpに記載して、各コントローラーからそれを使うというイメージです。

実装例

TwitterCompornent.php

<?php
// OAuth consumersの読み込み
App::import('Vendor', 'OAuth/OAuthClient');

class TwitterComponent extends Component {
	public function initialize( Controller $controller )
	{
		$this->Controller = $controller;
	}
	
    /** アプリケーションのConsumer Key (API Key) */
    const TWITTER_CK = 'CK1234567890';
    /** アプリケーションのConsumer Secret (API Secret) */
    const TWITTER_CS = 'CS1234567890';
    /** アプリケーションのCallback URL */
    const TWITTER_CALLBACK_URL = 'http://www.example.com/test/callback';

	/** アクセストークン取得 **/
	const URL_OAUTH_ACCESS_TOKEN = 'https://api.twitter.com/oauth/access_token';
	/** リクエストトークン取得 **/
	const URL_OAUTH_REQUEST_TOKEN = 'https://api.twitter.com/oauth/request_token';
    
	
	/**
	 * ユーザー認証を行う
	 * return array
	 */
	public function authorizeUser()
	{
		// Twitterオブジェクト作成
		$twitterOauthObj = $this->__createClient( self::TWITTER_CK, self::TWITTER_CS );
		
		$twitterOauthToken = $twitterOauthObj->post(
			self::TWITTER_AT,
			self::TWITTER_AS,
			self::URL_OAUTH_REQUEST_TOKEN,
			array(
				'oauth_callback' => rawurldecode( self::TWITTER_CALLBACK_URL )
			)
		);

		if ( $twitterOauthToken->headers[ 'status' ] != '200 OK' )
		{
			return false;
		}
		else
		{
			$return_params = explode( '&', $twitterOauthToken->body );
			$oauth_info = array();
			foreach ( $return_params as $p )
			{
				$p_tmp = explode( '=', $p );
				if ( $p_tmp[ 0 ] == 'oauth_callback_confirmed' )
				{
					$oauth_info[ $p_tmp[ 0 ] ] = ( $p_tmp[ 1 ] == 'true' ) ? true : false;
				}
				else
				{
					$oauth_info[ $p_tmp[ 0 ] ] = $p_tmp[ 1 ];
				}
			}
		}
			
		// 認証用URL生成
		$authenticate_url = sprintf( 'https://api.twitter.com/oauth/authenticate?oauth_token=%s', $oauth_info[ 'oauth_token' ] );
		
		$reutrn_array = array(
			'authenticate_url' => $authenticate_url,
			'user_oauth_session' => $oauth_info
		);
		
		return $reutrn_array;
	}
	
	/**
	 * アクセストークンを取得する
	 * @param String $request_token
	 * @param String $request_token_secret
	 * @param String $oauth_verifier
	 * @return array
	 */
	public function criateAccessToken( $request_token, $request_token_secret, $oauth_verifier )
	{
		// Twitterオブジェクト作成
		$twitterOauthObj = $this->__createClient( self::TWITTER_CK, self::TWITTER_CS );
		
		$res = $twitterOauthObj->post(
			$request_token,
			$request_token_secret,
			self::URL_OAUTH_ACCESS_TOKEN,
			array(
				'oauth_verifier' => $oauth_verifier
			)
		);
		
		// レスポンスを配列に変換
		$return_params = explode( '&', $res->body );
		$oauth_info = array();
		foreach ( $return_params as $p )
		{
			$p_tmp = explode( '=', $p );
			$oauth_info[ $p_tmp[ 0 ] ] = $p_tmp[ 1 ];
		}
		
		return $oauth_info;
	}
				
	/**
	 * インスタンス作成
	 * @param String $ck
	 * @param String $cs
	 * @return OAuthClient
	 */
	protected function _createClient( $ck, $cs )
	{
		return new OAuthClient(
			$ck, //Consumer key
			$cs  //Consumer secret
		);
	}
}

TestController.php

<?php
class TestController extends AppController
{
    public $components = array( 'Twitter' );

    function __construct ( $request, $response )
    {
        parent::__construct( $request, $response );
    }

    /**
     * ログイン
     */
    public function login ()
    {
        $this->autoRender = false;

        // ユーザー認証
        $res = $this->Twitter->authorizeUser();

        if ( $res == false )
        {
            $this->redirect( '/' );
        }
        else
        {
            // セッション登録
            $this->Session->write( 'user_oauth', $res[ 'user_oauth_session' ] );

            // 認証ページヘリダイレクト
            $this->redirect( $res[ 'authenticate_url' ] );
        }
    }

    /**
     * コールバック
     */
    public function callback ()
    {
        $this->autoRender = false;

        try
        {
            // 認証キャンセルの場合はセッションを削除してトップページへ
            if ( isset( $this->params->query[ 'denied' ] ) )
            {
                if ( $this->Session->check( 'user_oauth' ) )
                {
                    $this->Session->delete( 'user_oauth' );
                }

                $this->redirect( '/' );
            }

            // セッション情報取得
            if ( !$this->Session->check( 'user_oauth' ) )
            {
                throw new Exception( 'セッション情報を取得できませんでした。' );
            }

            $user_oauth_session = $this->Session->read( 'user_oauth' );

            // Twitterから返却されたOAuthトークンとセッションに保存されたOAuthトークンを比較
            $retutn_oauth_token = ( isset( $this->params->query[ 'oauth_token' ] ) ) ? $this->params->query[ 'oauth_token' ] : null;
            if ( $retutn_oauth_token != $user_oauth_session[ 'oauth_token' ] )
            {
                // セッション削除
                $this->Session->delete( 'user_oauth' );
                throw new Exception( 'OAuthトークンが無効です。' );
            }

            // アクセストークンを取得する
            $access_token = $this->Twitter->criateAccessToken( $user_oauth_session[ 'oauth_token' ], $user_oauth_session[ 'oauth_token_secret' ], $this->params->query[ 'oauth_verifier' ] );
            if ( !$access_token )
            {
                // セッション削除
                $this->Session->delete( 'user_oauth' );
                throw new Exception( 'アクセストークンが取得できませんでした。' );
            }

            // セッションに保存
            $user_oauth_session[ 'access_token' ] = $access_token;
            $this->Session->write( 'user_oauth', $user_oauth_session );

            // トップページヘリダイレクト
            $this->redirect( '/' );
        }
        catch ( Exception $e )
        {
            $this->log( $e->getMessage() );
        }
    }
}

認証処理が成功すると、セッション情報として以下の形で oauth_tokenoauth_token_secretがそれぞれ取得できます。

<?php
$user_oauth_session = array(
    'access_token' => array(
        'oauth_token' => 'OT1234567890',
        'oauth_token_secret' => 'OTS1234567890'
    ) 
);

あとはこの2つの値を使ってTwitterAPIを利用することになります。

ちなみに、この方法で実装したアプリケーションがこちらです。 ただ「やっほ〜!」とつぶやくだけ 文字通り、ただやっほ〜とつぶやくだけです。一応つぶやいた数をカウントしているので、どんどんつぶやいてみてください。


comments powered by Disqus