てけノート

on the foot of giants

[PHP] Instagram API のリアルタイム通知+cakePHPなサンプルwebサービス

      2016/11/25


最近絡ませてもらっていたプロジェクトでやっていたことまとめ。
コピペの固まりなので、先に参考サイト様方を紹介いたします。

Instagram APIでwebサービスを作りたい全ての人に向けて書きました
以下に上げてるコードはほとんどがこのサイト様ベースです。若干動かないところがあったので今回修正しました。

Instagram APIでデータ取得をPHPで行う場合の注意点
修正はこのサイト様より頂きました。自分でやったこと…cakeで使えるように整形、くらいです。

Instagram本家

Instagram Real-time API

サーバーに対して、インスタグラム側から更新通知をくれるAPI。
通知の種類は4種類:ユーザー、タグ、場所、位置範囲。

こんな関数を準備する

これをcontrollerに突っ込んでしまうのが素人の悲しさ。肥大化します。json処理とかは関数化にしてcomponentから呼び出すべきか。

public function callback_instagram(){

        // 設定
        $client_id = '' ;       // クライアントID。instagram developperで登録したもの
        $client_secret = '' ;       // クライアントシークレット。同上
        // test code
        $callback_url = 'http://techete.xyz/insta/posts/callback_instagram' ;   //この関数のurl
        $verify_token = 'onedrivedoukishinai' ;     // 認証確認用の文字列

     // このアプリケーションの登録時に呼ばれる
        if (isset ($_GET['hub_challenge'])){
        // 確認用のキーを返却
            echo $_GET[ 'hub_challenge' ] ;
            exit ;
        }
     // 登録後はこちらが呼ばれる
        else if($this->request->is('post')){
            $myString = @file_get_contents('php://input');
            $obj = json_decode($myString);
            $object = $obj[0]->object;// "user"が入ってる
            $user_id = $obj[0]->object_id; // instaのuserid

            $user = $this->User->find('first',array(
                'conditions' => array('User.insta_id' => $user_id))
            );
            $acc_token = ''; // 今回は自分のをベタ打ち
            $tag_to_get = 'cat'; // 欲しいハッシュタグを指定

       // インスタグラムにアクセスするurl
            $photos_api_url = 'https://api.instagram.com/v1/tags/'.$tag_to_get.'/media/recent/?access_token=' . $acc_token. '&count=3';
            // アイテムデータをJSON形式で取得する (CURLを使用)
            $curl = curl_init() ;
            // オプションのセット
            curl_setopt( $curl , CURLOPT_URL , $photos_api_url ) ;
            curl_setopt( $curl , CURLOPT_HEADER, 1 ) ; 
            curl_setopt( $curl , CURLOPT_SSL_VERIFYPEER , false ) ; // 証明書検証を行わない
            curl_setopt( $curl , CURLOPT_RETURNTRANSFER , true ) ;      // curl_execの結果
            curl_setopt( $curl , CURLOPT_TIMEOUT , 5 ) ;   // タイムアウト秒数
            // 実行
            $res1 = curl_exec( $curl ) ;
            $res2 = curl_getinfo( $curl ) ;
            // 終了
            curl_close( $curl ) ;
            // 取得データ
            $json = substr( $res1, $res2['header_size'] ) ;  

            // JSONデータをオブジェクト形式に変換するが、整形が必要
            $jsondata = json_decode(preg_replace('/[\x00-\x1F\x80-\xFF]/', '', $json),true) ;
            $tmpdata = json_encode($jsondata["data"]);
            $items = json_decode($tmpdata);

            foreach ($items as $item) {
          // 配列で#のない文字列が入る
                $tags = ( isset($item->tags) && !empty($item->tags) ) ? $tags = $item->tags : '' ;
         // 時間
                $time = date( 'Y-m-d h:i:s' , time() ) ;
                // 文章
                $text = ( isset($item->caption->text) ) ? $item->caption->text : '' ;      
                // 場所ID
                $location_id = ( isset($item->location->id) ) ? $item->location->id : '' ;
                // 場所名。自由度が高い(Apple Store 渋谷店、など)
                $location_name = ( isset($item->location->name) ) ? $item->location->name : '' ;                           
                // 緯度
                $location_lat = ( isset($item->location->latitude) ) ? $item->location->latitude : '' ;                                 
                // 経度
                $location_long = ( isset($item->location->longitude) ) ? $item->location->longitude : '' ;
                // 写真
                $photo = $item->images->standard_resolution->url;

         // DBに保存する処理
         
            }
        }
    
        // 以下、登録時に行う処理。

        // パラメータを連想配列形式で指定(tagの場合)
        $params = array(
            'client_id' => $client_id ,
            'client_secret' => $client_secret ,
            'object' => 'tag' ,
            'aspect' => 'media' ,
            'object_id' => $tag_to_get ,
            'verify_token' => $verify_token ,
            'callback_url' => $callback_url ,
            ) ;

        // POSTリクエストを送信し、返ってきたJSONデータをオブジェクト形式に変換
        $json = @file_get_contents(
            'https://api.instagram.com/v1/subscriptions/' ,
            false,stream_context_create( array( 'http' => array(
                'method' => 'POST' ,
                'content' => http_build_query( $params ) ,
                )))
            ) ;
        $obj = json_decode( $json ) ;

        // 各データの整理
        $id = $obj->data->id ;      // 通知ID
        $url = 'https://api.instagram.com/v1/subscriptions?client_id=' . $params['client_id'] . '&client_secret=' . $params['client_secret'] ;      // 登録状況確認用URL

        // HTML用
        $html = '' ;

        // 取得したデータ
        $html .= '<h2>取得したデータ</h2>' ;
        $html .= '<p>リアルタイム通知を登録しました。通知IDは<mark>' . $id . '</mark>です。</p>' ;
        $html .=    '<h3>JSON</h3>' ;
        $html .=    '<p><textarea rows="8">' . $json . '</textarea></p>' ;
        $html .=    '<h3>登録状況の確認</h3>' ;
        $html .=    '<p><a href="' . $url . '" target="_blank">' . $url . '</a></p>' ;
        echo $html;
    }

使い方は簡単。これをどこかのControllerに配置して、一度直でURLを叩いてやるだけ。
初回は登録状況の確認が出るはず。IDが空だったら、userとか同じ属性で同一アプリケーションを重複登録をしている恐れがあります。

 - API, プログラミング