PHP アプリケーションと Instagram の統合: 第 2 回

Instagram API を利用して、PHP アプリケーションに Instagram の写真を統合する

Instagram は、ユーザーがスマートフォンで写真を撮って、その写真を Web を介して他のユーザーと共有できる、人気の高い写真共有サービスです。アプリケーション開発者は Instagram REST API を使用して、これらの写真を検索し、写真とそれに関連付けられているコメントや「いいね!」の情報を取得することができます。この全 2 回からなる記事では Instagram API を紹介するとともに、Instagram のユーザーが生成した豊富なコンテンツのリポジトリーを利用して革新的な Web アプリケーションを作成するために、この API を PHP で使用する方法を説明します。

はじめに

この記事の第 1 回では、Instagram API を紹介し、この API の動作を説明するとともに、Instagram API レスポンスの基本要素についても詳しく調べました。また、Instagram API を PHP で使用して、タグおよび場所で写真を検索して取得する方法、そしてコメントと「いいね!」の情報を含む完全な画像メタデータを取得する方法も説明しました。

さらに記事の第 1 回の例では、主に OAuth ベースのユーザー認可が不要な API エンドポイントにフォーカスしました。OAuth を構成に追加すると、この API を使用して、さらに多くの情報にアクセスできるようになります。最終回となるこの第 2 回では、OAuth 認証を PHP アプリケーションに追加する方法を説明した後、OAuth トークンを使用して、保護された API エンドポイントに対してリクエスト (認証済みユーザーの写真フィードやユーザー間の関係フィードなどに対するリクエスト) を送信します。さらに、Instagram API エクスペリエンスを簡易化できる、サード・パーティー製の PHP ライブラリーについても取り上げます。


ユーザーの検索

早速、Instagram API で使用可能なユーザー・エンドポイントをいくつか見て行きましょう。まず、Instagram で検索語と一致するユーザーを検索するには、/users/search メソッドを使用します。この検索を実行する方法を示した、リスト 1 について検討してみましょう。

リスト 1. ユーザーの検索
<html>
  <head></head>
  <body>
    <h1>Instagram User Search</h1>
    <?php
    if (!isset($_POST['submit'])) {
    ?>
    <form method="post" action="<?php echo htmlentities($_SERVER['PHP_SELF']); ?>">
      Search for:
      <input type="text" name="q" /> 
      <input type="submit" name="submit" value="Search" />      
    </form>
    <?php
    } else {
    ?>
    <h2>Search results for '<?php echo $_POST['q']; ?>'</h2>
    <?php
      require_once 'Zend/Loader.php';
      Zend_Loader::loadClass('Zend_Http_Client');

      // define consumer key and secret
      // available from Instagram API console
      $CLIENT_ID = 'YOUR-CLIENT-ID';
      $CLIENT_SECRET = 'YOUR-CLIENT-SECRET';

      try {
        // initialize client
        $client = new Zend_Http_Client('https://api.instagram.com/v1/users/search');
        $client->setParameterGet('client_id', $CLIENT_ID);
        $client->setParameterGet('q', $_POST['q']);

        // get and display users
        $response = $client->request();
        $result = json_decode($response->getBody());
        $data = $result->data;  
        if (count($data) > 0) {
          echo '<ul>';
          foreach ($data as $item) {
            echo '<li style="display: inline-block; padding: 25px">
              <img src="' . $item->profile_picture . '" /> <br/>' . 
              $item->username . ' (' . $item->full_name . ') </li>';
          }
          echo '</ul>';
        }
      } catch (Exception $e) {
        echo 'ERROR: ' . $e->getMessage() . print_r($client);
        exit;
      }
    }  
    ?>
  </body>
</html>

リスト 1 では、ユーザーが検索語を入力するための Web フォームを作成します。それに続いて Instagram API に接続し、検索語をパラメーターとして設定して /users/search メソッドにリクエストを送信し、検索語と一致するユーザーのリストを取得します。このスクリプトはユーザーごとに、ユーザー・プロフィールの写真、ユーザー名、フルネームを表示します。図 1 に出力例を示します。

図 1. ユーザーの検索結果
ユーザーの検索結果を示す画面のスクリーン・キャプチャー

ユーザー・プロフィールの取得

ユーザーのリストを取得できるのと同じく、Instagram API では特定のユーザーの詳細を取得することもできます。それには、/users/[user-id] メソッドを使用します。このメソッドからは、指定されたユーザーの詳細が含まれる JSON 文書が返されます。一例として、特定のユーザーを検索し、見つかったプロフィールの詳細を表示するようにリスト 1 を拡張した、リスト 2 について検討してみましょう。

リスト 2. ユーザー・プロフィールの取得
<html>
  <head>
    <style>
    #info {
      float: left; 
      width: 300px;
      padding-right: 20px;
    }
    #image {
      float: left; 
      width: 320px;
      padding-right: 20px;
    }    
    </style>  
  </head>
  <body>
    <h1>Instagram User Profile</h1>
    <?php
    if (!isset($_POST['submit'])) {
    ?>
    <form method="post" 
      action="<?php echo htmlentities($_SERVER['PHP_SELF']); ?>">
      Search for user:
      <input type="text" name="u" /> 
      <input type="submit" name="submit" value="Search" />      
    </form>
    <?php
    } else {
    ?>
    <?php
      require_once 'Zend/Loader.php';
      Zend_Loader::loadClass('Zend_Http_Client');

      // define consumer key and secret
      // available from Instagram API console
      $CLIENT_ID = 'YOUR-CLIENT-ID';
      $CLIENT_SECRET = 'YOUR-CLIENT-SECRET';

      try {
        // initialize client
        $client = new Zend_Http_Client('https://api.instagram.com/v1/users/search');
        $client->setParameterGet('client_id', $CLIENT_ID);
        $client->setParameterGet('q', $_POST['u']);
        $client->setParameterGet('count', '1');
        
        // search for matching users
        $response = $client->request();
        $result = json_decode($response->getBody());

        // get user id from search results
        if (count($result->data) != 1) {
          echo 'No matches found';
          exit;
        } else {
          $id = $result->data[0]->id;
        }

        // get user's profile information
        $client->setUri('https://api.instagram.com/v1/users/' . $id);
        $client->setParameterGet('client_id', $CLIENT_ID);
        $response = $client->request();
        $result = json_decode($response->getBody());
        $data = $result->data;  
    ?>    
        <div id="image">
          <h2>Image</h2>  
          <img src="<?php echo $result->data->profile_picture; ?>"
            /></a>
        </div>
        <div id="info">
          <h2>Meta</h2>  
          <strong>Username: </strong> 
          <?php echo $result->data->username; ?>
          <br/>
          <strong>Instagram id: </strong> 
          <?php echo $id; ?>
          <br/>
          <strong>Full name: </strong>
          <?php echo !empty($result->data->full_name) ? 
            $result->data->full_name : 'Not specified'; ?>
          <br/>
          <strong>Bio: </strong>
          <?php echo !empty($result->data->bio) ? 
            $result->data->bio : 'Not specified'; ?>
          <br/>
          <strong>Website: </strong>
          <?php echo !empty($result->data->website) ? 
            $result->data->website : 'Not specified'; ?>
          <br/>
          <strong>Instagram photos: </strong>
          <?php echo $result->data->counts->media; ?>
          <br/>
          <strong>Followers: </strong>
          <?php echo $result->data->counts->followed_by; ?>
          <br/>
          <strong>Following: </strong>
          <?php echo $result->data->counts->follows; ?>
          <br/>
        </div>
    <?php    
      } catch (Exception $e) {
        echo 'ERROR: ' . $e->getMessage() . print_r($client);
        exit;
      }
    }  
  ?>
  </body>
</html>

リスト 2 を詳しく見てみると、実際には Instagram API に対して 2 つのリクエストを実行していることがわかります。最初のリクエストは、検索語に一致するユーザーのリストを取得するためのものです。完全に一致するユーザーが見つかると、2 番目のリクエストでそのユーザーに固有のユーザー ID を使用して、指定されたユーザーの詳細を取得します。ユーザー ID を使用する理由は、/users/[user-id] エンドポイントが受け入れるのはユーザー ID だけであり、ユーザー名は受け入れないからです。したがって、まず始めに一致するユーザーを検索してから、該当するユーザー ID を抽出して /users/[user-id] エンドポイントに対するリクエストのパラメーターとして設定する必要があります。

/users/[user-id] API へのリクエストに対するレスポンスは、指定されたユーザーに関する詳細情報を収容した JSON 文書です。詳細情報には、ユーザーの Instagram 名、フルネーム、プロフィールの写真、略歴、Web サイトの URL が含まれます。また、そのユーザーが Instagram に投稿した写真の数、ユーザーのフォロワーの数、そのユーザーがフォローしているユーザーの数などのカウントも含まれます。図 2 に、リスト 2 の出力を示します。

図 2. 取得されたユーザー・プロフィール
取得されたユーザー・プロフィールのスクリーン・キャプチャー

セルフ・フィードの処理

前の 2 つのリストで説明したユーザー・エンドポイントには、クライアント ID のみを使用してアクセスすることができます。その一方で、Instagram API には、署名付き OAuth リクエストをこの API に送信しなければアクセスできないユーザー・エンドポイントもあります。

OAuth 2.0 は、OAuth 1.0 の改訂版として現在まだ策定作業が進められています。OAuth 1.0 とは異なり、OAuth 2.0 は (現時点では) Zend Framework ではサポートされていません。そのため、OAuth 2.0 ワークフローを処理するには独自のコードを最初から作成しなければなりませんが、このプロセスを大幅に簡易化するのが、Pierrick Charron 氏と Anis Berejeb 氏によって作成された PHP-OAuth2 ライブラリーです。このライブラリーは、GNU LGPL の下で使用することができます (「参考文献」のリンクを参照)。PHP-OAuth2 ライブラリーを使用すれば、比較的簡単に OAuth 2.0 サポートを PHP アプリケーションに追加することができます。

この仕組みを理解するために、リスト 3 について検討してみましょう。このリストは PHP-OAuth2 ライブラリーを使用して Instagram APIに接続し、アクセスを要求した後、認証済みユーザーとその認証済みユーザーがフォローするユーザーによってアップロードされた写真のリストを表示します (いわゆる、「セルフ・フィード」です)。この例で利用しているのは、/users/self/feed API メソッドです。

リスト 3. セルフ・フィードの取得
<?php
require('Client.php');
require('GrantType/IGrantType.php');
require('GrantType/AuthorizationCode.php');

const CLIENT_ID     = 'YOUR-CLIENT-ID';
const CLIENT_SECRET = 'YOUR-CLIENT-SECRET';

const REDIRECT_URI           = 'http://localhost/dev/app.php';
const AUTHORIZATION_ENDPOINT = 'https://api.instagram.com/oauth/authorize';
const TOKEN_ENDPOINT         = 'https://api.instagram.com/oauth/access_token';

$client = new OAuth2\Client(CLIENT_ID, CLIENT_SECRET);
session_start();
if (!isset($_SESSION['ACCESS_TOKEN'])) {
  if (!isset($_GET['code'])) {
    $auth_url = $client->getAuthenticationUrl(AUTHORIZATION_ENDPOINT, 
      REDIRECT_URI, array('scope' => 'relationships'));
    header('Location: ' . $auth_url);
    die('Redirect');
  } else {
    $params = array('code' => $_GET['code'], 'redirect_uri' => REDIRECT_URI);
    $response = $client->getAccessToken(TOKEN_ENDPOINT, 'authorization_code', 
      $params);  
    $_SESSION['ACCESS_TOKEN'] = $response['result']['access_token'];
  }
} else {
  $client->setAccessToken($_SESSION['ACCESS_TOKEN']);
}
?>
<html>
  <head></head>
  <body>  
    <h1>Instagram User Feed</h1>  
    <?php
    try {
      // get authenticated user's feed
      $response = $client->fetch('https://api.instagram.com/v1/users/self/feed');
      $result = json_decode(json_encode($response['result']));

      // display images
      $data = $result->data;  
      if (count($data) > 0) {
        echo '<ul>';
        foreach ($data as $item) {
          echo '<li style="display: inline-block; padding: 25px">
            <a href="' . $item->link . '">
          <img src="' . $item->images->thumbnail->url . 
            '" /></a> <br/>';
          echo 'By: <em>' . $item->user->username . 
            '</em> <br/>';
          echo 'Date: ' . date ('d M Y h:i:s', $item->created_time) . 
            '<br/>';
          echo $item->comments->count . ' comment(s). ' . 
            $item->likes->count . ' likes. </li>';
        }
        echo '</ul>';
      }

    } catch (Exception $e) {
      echo 'ERROR: ' . $e->getMessage() . print_r($client);
      exit;
    }
    ?>
  </body>
</html>

リスト 3 の最初の部分は、標準の OAuth 2.0 ワークフローです。標準ワークフローではセキュアな方法で、ユーザーをアクセス認可画面に転送し、ユーザーがアプリケーションのアクセス・リクエストを認可すると、アプリケーションに制御を戻します。このスクリプトによって生成される OAuth 2.0 アクセス・トークンは、ブラウザー・セッションに保管されます。したがって、保護された API エンドポイントへの以降のアクセスには、認可は必要ありません。

この認証プロセスで使用されている scope パラメーターに注意してください。これは、認可のスコープを定義するパラメーターです。この記事には、ユーザー間の関係を変更する方法を説明する例もあるため、上記ケースではデフォルトのスコープの他に relationships スコープも要求しています。

このプロセスで生成される OAuth 2.0 アクセス・トークンが OAuth2 クライアント・オブジェクトに接続され、このオブジェクトがユーザーのセルフ・フィードに対するリクエストを送信するために使用されます。このリクエストに対する JSON レスポンスは、第 1 回の記事で説明したように構文解析されます。それによって、認証済みユーザーとそのユーザーがフォローするユーザーの写真を表示する Web ページが動的に生成されます。動的に生成されるページは、図 3 のように表示されます。

図 3. セルフ・フィードの写真を表示するページ
セルフ・フィードの写真を表示するページのスクリーン・キャプチャー

特定のユーザーを指定した写真の検索

リスト 3 では、ユーザーのセルフ・フィード、つまりユーザーとそのユーザーがフォローするユーザーによってアップロードされた写真のフィードを取得するデモを行いましたが、実際には特定のユーザーの写真だけに興味があるとしたらどうなるでしょう?そのような検索も可能です。/users/[user-id]/media/recent API エンドポイントを使用すれば、特定のユーザーがアップロードした最近の写真のフィードが返されます。

問題は、/users/[user-id]/media/recent エンドポイントが受け入れるのはユーザー ID のみに限られることです。そのため、リスト 2 ではまず始めに、一致するユーザーを /users/search エンドポイントで検索しなければなりませんでした。一致するユーザーが見つかった後は、そのユーザーに対応するユーザー ID を使用して /users/[user-id]/media/recent エンドポイントへリクエストを送信することができます。リスト 4 に、このプロセスを示します。

リスト 4. 特定のユーザーを指定した写真の検索
<?php
require_once('oauth-instagram-bootstrap.php');
?>
<html>
  <head></head>
  <body>
    <h1>Instagram Photo Search by User</h1>
    <?php
    if (!isset($_POST['submit'])) {
    ?>
    <form method="post" 
      action="<?php echo htmlentities($_SERVER['PHP_SELF']); ?>">
      Search for user:
      <input type="text" name="u" /> 
      <input type="submit" name="submit" value="Search" />      
    </form>
    <?php
    } else {
    ?>
    <?php
      try {
        // search for matching user
        $response = $client->fetch('https://api.instagram.com/v1/users/search', 
          array('count' => 1, 'q' => $_POST['u']));
        $result = json_decode(json_encode($response['result']));
        
        if (count($result->data) != 1) {
          echo 'No matches found';
          exit;
        } else {
          $id = $result->data[0]->id;
        }
      
        // get user's recent image uploads
        $response = $client->fetch('https://api.instagram.com/v1/users/' . 
          $id . '/media/recent');
        $result = json_decode(json_encode($response['result']));

        // display images
        $data = $result->data;  
        if (count($data) > 0) {
          echo '<ul>';
          foreach ($data as $item) { 
            echo '<li style="display: inline-block; padding: 25px">
              <a href="' . $item->link . '">
            <img src="' . $item->images->thumbnail->url . 
              '" /></a> <br/>';
            echo 'By: <em>' . $item->user->username . 
              '</em> <br/>';
            echo 'Date: ' . date ('d M Y h:i:s', $item->created_time) . 
              '<br/>';
            echo $item->comments->count . ' comment(s). ' . 
              $item->likes->count . ' likes. </li>';
          }
          echo '</ul>';
        }

      } catch (Exception $e) {
        echo 'ERROR: ' . $e->getMessage() . print_r($client);
        exit;
      }
    }
  ?>
  </body>
</html>

図 4 に、検索結果を示します。

図 4. 特定のユーザーを指定した写真の検索結果
特定のユーザーを指定した写真の検索結果のスクリーン・キャプチャー

リスト 4 の /users/[user-id]/media/recent エンドポイントからのレスポンスには、指定されたユーザーがアップロードした写真のコレクションが含まれます。このコレクションを繰り返し処理して、写真ごとにサムネール画像、基本メタデータ、コメントと「いいね!」の数を表示するのはごく簡単なことです。

注意する点として、リスト 4 以降の例では、OAuth 2.0 認可ワークフローの共通コードを保管する別個のブートストラップ・ファイルが、各スクリプトの先頭で読み込まれます。このようにした目的は、この記事に記載するコード・リストを短くして読みやすくするためです。


ユーザー間の関係の調査

他のソーシャル・ネットワークと同じように、Instagram でもユーザーが他のユーザーをフォローしたり、他のユーザーからフォローされたりすることができます。そのようなユーザー間の関係に関する情報を取得するためのエンドポイントとして、Instagram API には /users/[user-id]/follows と /users/[user-id]/followed-by の 2 つが用意されています。特定のユーザー ID を指定すると、これらのエンドポイントからは、その指定されたユーザーがフォローしている他のユーザーのリスト、またはその指定されたユーザーをフォローしている他のユーザーのリストが返されます。リスト 5 に、これら 2 つの実際のエンドポイントを示します。

リスト 5. ユーザー間の関係の取得
<html>
  <head>
    <style>
    #follows {
      float: left; 
      width: 400px;
      padding-right: 20px;
    }
    #followers {
      float: left; 
      width: 400px;
      padding-right: 20px;
    }    
    </style>  
  </head>
  <body>
    <h1>Instagram User Relationships</h1>
    <?php
    if (!isset($_POST['submit'])) {
    ?>
    <form method="post" 
      action="<?php echo htmlentities($_SERVER['PHP_SELF']); ?>">
      Search for user:
      <input type="text" name="u" /> 
      <input type="submit" name="submit" value="Search" />      
    </form>
    <?php
    } else {
    ?>
      <h2>Relationships for '<?php echo $_POST['u']; ?>'</h2>
    <?php
      // userid 262796303
      require_once 'Zend/Loader.php';
      Zend_Loader::loadClass('Zend_Http_Client');

      // define consumer key and secret
      // available from Instagram API console
      $CLIENT_ID = 'YOUR-CLIENT-ID';
      $CLIENT_SECRET = 'YOUR-CLIENT-SECRET';

      try {
        // initialize client
        $client = new Zend_Http_Client('https://api.instagram.com/v1/users/search');
        $client->setParameterGet('client_id', $CLIENT_ID);
        $client->setParameterGet('q', $_POST['u']);
        
        // search for matching users
        $response = $client->request();
        $result = json_decode($response->getBody());

        // get user id from search results
        if (count($result->data) != 1) {
          echo 'No matches found';
          exit;
        } else {
          $id = $result->data[0]->id;
        }

        // get who the user follows
        $client->setUri('https://api.instagram.com/v1/users/' . 
          $id . '/follows');
        $client->setParameterGet('client_id', $CLIENT_ID);
        $response = $client->request();
        $result = json_decode($response->getBody());
        $follows = $result->data;
        unset($result);
        
        // get the user's followers
        $client->setUri('https://api.instagram.com/v1/users/' . 
          $id . '/followed-by');
        $client->setParameterGet('client_id', $CLIENT_ID);
        $response = $client->request();
        $result = json_decode($response->getBody());
        $followers = $result->data;  
        
    ?>    
        <div id="follows">
          <h2>Follows</h2>
          <?php
          if (count($follows) > 0) {
            echo '<ul>';
            foreach ($follows as $item) {
              echo '<li style="display: inline-block; padding: 25px">
                <img src="' . $item->profile_picture . '" /> <br/>' . 
                $item->username . ' (' . $item->full_name . ') </li>';
            }
            echo '</ul>';
          } else {
            echo 'Not following anyone';
          }
          ?>
        </div>

        <div id="followers">
          <h2>Followers</h2>
          <?php
          if (count($followers) > 0) {
            echo '<ul>';
            foreach ($followers as $item) {
              echo '<li style="display: inline-block; padding: 25px">
                <img src="' . $item->profile_picture . '" /> <br/>' . 
                $item->username . ' (' . $item->full_name . ') </li>';
            }
            echo '</ul>';
          } else {
            echo 'No followers';
          }
          ?>
        </div>
        
    <?php    
      } catch (Exception $e) {
        echo 'ERROR: ' . $e->getMessage() . print_r($client);
        exit;
      }
    }  
  ?>
  </body>
</html>

リスト 5 によって生成される Web フォームでは、Instagram ユーザー名を入力することができます。フォームが送信されると、リスト 5 は最初に /users/search API エンドポイントにアクセスして、対応するユーザー ID を検索します。そして検出したユーザー ID を、/users/[user-id]/follows および /users/[user-id]/followed-by エンドポイントに対するリクエストのパラメーターとして設定します。これらのエンドポイントによって生成される JSON 文書を使用して、そのユーザーがフォローしているユーザーのリストと、そのユーザーをフォローしているフォロワーのリストが表示されます。いずれのリストにも、ユーザーのプロフィールの写真、ユーザー名、フルネームが記載されます。図 5 に、出力例を示します。

図 5. ユーザー間の関係を表示するページ
ユーザー間の関係を表示するページのスクリーン・キャプチャー

ユーザー間の関係の変更

Instagram API では、ユーザー間の関係に関する情報を提供するだけでなく、これらの関係を変更することもできます。保護された /users/[user-id]/relationship エンドポイントは、「フォロー」、「フォロー解除」、「ブロック」、「ブロック解除」、「承認」、または「拒否」などのアクションの POST リクエストを受け入れ、指定されたユーザーと現行の認証済みユーザーとの間でこれらのアクションを実行します。したがって、例えばユーザー間のフォロワー関係を、API から直接設定することも可能です。

一例として、リスト 6 について検討してみましょう。このリストでは、認証済みユーザーがフォームにユーザー名を入力することによって、他の任意のユーザーをフォローできるようにします。

リスト 6. ユーザー間の関係の変更
<?php
require_once('oauth-instagram-bootstrap.php');
?>
<html>
  <head>
    <style>
    #follows {
      float: left; 
      width: 400px;
      padding-right: 20px;
    }
    #followers {
      float: left; 
      width: 400px;
      padding-right: 20px;
    }    
    </style>  
  </head>
  <body>
    <h1>Follow on Instagram</h1>
    <?php
    if (!isset($_POST['submit'])) {
    ?>
    <form method="post" 
      action="<?php echo htmlentities($_SERVER['PHP_SELF']); ?>">
      Enter name of user to follow:
      <input type="text" name="u" /> 
      <input type="submit" name="submit" value="Search" />      
    </form>
    <?php
    } else {
      // search for matching user
      $response = $client->fetch('https://api.instagram.com/v1/users/search', 
        array('q' => $_POST['u']));
      $result = json_decode(json_encode($response['result']));
      
      if (count($result->data) != 1) {
        echo 'No matches found';
        exit;
      } else {
        $id = $result->data[0]->id;
      }
    
      // get user's recent image uploads
      $response = $client->fetch('https://api.instagram.com/v1/users/' . 
        $id . '/relationship', 
        array('action' => 'follow'), 'POST');
      $result = json_decode(json_encode($response['result']));
      print_r($result); die;
    }  
  ?>
  </body>
</html>

リスト 6 は、最初にユーザー名を検索し、それに対応する Instagram ユーザー ID を見つけます。次に、認証済みユーザーとターゲット・ユーザーの間にフォロワー関係を確立するために、action パラメーターを follow に設定して、/users/[user-id]/relationship エンドポイントに対する POST リクエストを生成します。


サード・パーティー製ライブラリーの使用 (1)

これまでに記載したすべての例では、HTTP クライアントを使用して API エンドポイントにアクセスし、レスポンスを処理するというプロセスが必要でした。一方、独自のコードを作成するのが好きではない方にとって、朗報があります。それは、Instagram API を扱うための機能をそのまま使える形で提供している、さまざまなサード・パーティー製 PHP ライブラリーも存在するということです。

そのようなライブラリーのうちの 1 つが、Galen Grover 氏が作成した、Instagram API のPHP 5.3+ ラッパーを提供する PHP Instagram API です (「参考文献」のリンクを参照)。写真、ユーザー、タグ、コメントなどの Instagram エンティティーを扱いやすくするために、このライブラリーには共通機能をカプセル化した一連のクラスが用意されています。一例としてリスト 7 に、このライブラリーを使用して Instagram で最も人気の高い写真を取得する方法を示します。

リスト 7. PHP Instagram API を使用することによる、人気の高い画像の取得
<html>
  <head></head>
  <body>  
    <h1>Popular on Instagram</h1>  
    <?php
    // set up autoloader
    function app_autoloader($class) {
      include './' . $class . '.php';
    }
    spl_autoload_register('app_autoloader');

    // define consumer key and secret
    // available from Instagram API console
    $CLIENT_ID = 'YOUR-CLIENT-ID';
    $CLIENT_SECRET = 'YOUR-CLIENT-SECRET';

    // initialize client
    try {
      $instagram = new Instagram\Instagram;
      $instagram->setClientID($CLIENT_ID);

      // get and display popular images
      $media = $instagram->getPopularMedia();
      $data = $media->getData();
      if ($media->count() > 0) {
        echo '<ul>';
        foreach ($data as $item) {
          echo '<li style="display: inline-block; padding: 25px">
            <a href="' . $item->link . '"><img src="' . 
            $item->images->thumbnail->url . 
            '" /></a> <br/>';
          echo 'By: <em>' . $item->user->username . 
            '</em> <br/>';
          echo 'Date: ' . date ('d M Y h:i:s', $item->created_time) . '<br/>';
          echo $item->comments->count . ' comment(s). ' . 
            $item->likes->count . ' likes. </li>';
        }
        echo '</ul>';
      }
    } catch (Exception $e) {
      echo 'ERROR: ' . $e->getMessage() . print_r($client);
      exit;
    }
    ?>
  </body>
</html>

リスト 7 ではまず、オート・ローダーを設定します。このローダーが、必要に応じてライブラリー・クラスを自動的にロードします。次に、Instagram クラスのインスタンスを初期化してクライアント ID を設定し、Instagram から人気の高い写真のリストを取得するために、このオブジェクトの getPopularMedia() メソッドを呼び出します。getPopularMedia() メソッドによって返される MediaCollection オブジェクトの内部には、メディア・オブジェクトのコレクションが格納されています。これで、このコレクションを繰り返し処理すれば、Web ページに表示する各写真の詳細を簡単に取得できるというわけです。図 6 に結果を示します。

図 6. 人気の高い画像を表示するページ
人気の高い画像を表示するページのスクリーン・キャプチャー

PHP Instagram API も OAuth リクエストをサポートしていることから、保護された API エンドポイント用の組み込みラッパー・メソッドが付属しています。一例として、PHP Instagram API を使用してリスト 4 を作成し直したリスト 8 について検討してみましょう。

リスト 8. PHP Instagram API を使用することによる、特定のユーザーを指定した写真の検索
<?php
// set up autoloader
function app_autoloader($class) {
  include './' . $class . '.php';
}
spl_autoload_register('app_autoloader');

// start session
session_start();

// set authentication details
$config = array(
  'client_id'         => 'YOUR-CLIENT-ID',
  'client_secret'     => 'YOUR-CLIENT-SECRET',
  'redirect_uri'      => 'http://localhost/dev/app.php',
);

// perform authentication
if (!isset( $_SESSION['instagram_access_token'] ) ) {
  $auth = new Instagram\Auth($config);
  if (isset($_GET['code'])) {
      $_SESSION['instagram_access_token'] = $auth->getAccessToken( $_GET['code'] );
      header( 'Location: ' . REDIRECT_AFTER_AUTH );
      exit;
  } else {
    $auth->authorize();
  }
  exit;
}
?>
<html>
  <head></head>
  <body>
    <h1>Instagram Photo Search by User</h1>
    <?php
    if (!isset($_POST['submit'])) {
    ?>
    <form method="post" action="<?php echo htmlentities($_SERVER['PHP_SELF']); ?>">
      Search for user:
      <input type="text" name="u" /> 
      <input type="submit" name="submit" value="Search" />      
    </form>
    <?php
    } else {
    ?>
    <?php
      try {      
        // set up client
        $instagram = new Instagram\Instagram;
        $instagram->setAccessToken($_SESSION['instagram_access_token']);
        
        // search for matching user
        $user = $instagram->getUserByUsername($_POST['u']);
        $media = $user->getMedia();  
        if ($media->count() > 0) {
          echo '<ul>';
          foreach ($media->getData() as $item) {
            echo '<li style="display: inline-block; padding: 25px">
              <a href="' . $item->link . '">
            <img src="' . $item->images->thumbnail->url . 
              '" /></a> <br/>';
            echo 'By: <em>' . $item->user->username . 
              '</em> <br/>';
            echo 'Date: ' . date ('d M Y h:i:s', $item->created_time) . 
              '<br/>';
            echo $item->comments->count . ' comment(s). ' . 
              $item->likes->count . ' likes. </li>';
          }
          echo '</ul>';
        }
      } catch (Exception $e) {
        echo 'ERROR: ' . $e->getMessage() . print_r($client);
        exit;
      }
    }
  ?>
  </body>
</html>

ご覧のように、リスト 8リスト 4 に比べてかなり短く、読みやすくなっています。このリストは必要な OAuth ワークフローを実装した後、ユーザー名の入力を求めるプロンプトを出し、続いて getUserByUsername() メソッドを使用して、指定されたユーザーの詳細を User オブジェクトとして取得します。User オブジェクトが公開する getMedia() オブジェクトによって、該当するユーザーがアップロードした最近の写真を表すメディア・オブジェクトのコレクションが返されます。このコレクションを処理すれば、リスト 4 と同じく、アップロードされた写真ごとのサムネールを表示することができます。


サード・パーティー製ライブラリーの使用 (2)

他にも使用できるサード・パーティー製ライブラリーとしては、同じく Instagram API を扱うための使いやすい PHP クラスを提供する、Christian Metz 氏が開発したライブラリーがあります (「参考文献」のリンクを参照)。リスト 9 は、このライブラリーを使用して Instagram から人気の高いメディアを取得する例です。

リスト 9. Instagram-PHP-API を使用することによる、人気の高い画像の取得
<html>
  <head></head>
  <body>  
    <h1>Popular on Instagram</h1>  
    <?php
    require 'instagram.class.php';
    
    // define consumer key and secret
    $CLIENT_ID = 'YOUR-CLIENT-ID';
    $CLIENT_SECRET = 'YOUR-CLIENT-SECRET';

    // initialize client
    try {
      $instagram = new Instagram($CLIENT_ID);

      // get and display popular images
      $media = $instagram->getPopularMedia();

      if (count($media->data) > 0) {
        echo '<ul>';
        foreach ($media->data as $item) {
          echo '<li style="display: inline-block; padding: 25px">
            <a href="' . $item->link . '"><img src="' . 
            $item->images->thumbnail->url . 
            '" /></a> <br/>';
          echo 'By: <em>' . $item->user->username . 
            '</em> <br/>';
          echo 'Date: ' . date ('d M Y h:i:s', $item->created_time) . 
            '<br/>';
          echo $item->comments->count . ' comment(s). ' . 
            $item->likes->count . ' likes. </li>';
        }
        echo '</ul>';
      }
    } catch (Exception $e) {
      echo 'ERROR: ' . $e->getMessage() . print_r($client);
      exit;
    }
    ?>
  </body>
</html>

リスト 9 では、最初にクラス・ファイルを読み込みます。次に、Instagram オブジェクトのインスタンスを作成して、人気の高い写真のリストを取得するために、このオブジェクトの getPopularMedia() メソッドを使用します。このメソッドは、内部で/media/popular エンドポイントを呼び出し、JSON レスポンスを受け取ってデコードします。それによって生成されたオブジェクトを処理して、人気の高いメディアのリストを表示することで、リスト 7 の出力と同じ結果になります。

このライブラリーを使用して、リスト 8 を作成し直すこともできます。それが、リスト 10 です。

リスト 10. Instagram-PHP-API を使用することによる、特定のユーザーを指定した写真の検索
<?php
// include class
require 'instagram.class.php';

// define credentials
$config = array(
  'apiKey'        => 'YOUR-CLIENT-ID',
  'apiSecret'     => 'YOUR-CLIENT-SECRET',
  'apiCallback'   => 'http://localhost/dev/app.php',
);

// initialize client
session_start();
$instagram = new Instagram($config);

// performa authentication
if (!isset($_SESSION['IACCESS_TOKEN'])) {
  if (!isset($_GET['code'])) {
    $auth_url = $instagram->getLoginUrl();
    header('Location: ' . $auth_url);
    die('Redirect');
  } else {
    $data = $instagram->getOAuthToken($_GET['code']);  
    $_SESSION['IACCESS_TOKEN'] = $data;
    $instagram->setAccessToken($_SESSION['IACCESS_TOKEN']);
  }
} else {
  $instagram->setAccessToken($_SESSION['IACCESS_TOKEN']);
}

?>
<html>
  <head></head>
  <body>
    <h1>Instagram Photo Search by User</h1>
    <?php
    if (!isset($_POST['submit'])) {
    ?>
    <form method="post" 
      action="<?php echo htmlentities($_SERVER['PHP_SELF']); ?>">
      Search for user:
      <input type="text" name="u" /> 
      <input type="submit" name="submit" value="Search" />      
    </form>
    <?php
    } else {
      try {      
        // search for matching user
        $user = $instagram->searchUser($_POST['u']);

        // search for user's photos
        $media = $instagram->getUserMedia($user->data[0]->id);  
        if (count($media->data) > 0) {
          echo '<ul>';
          foreach ($media->data as $item) {
            echo '<li style="display: inline-block; padding: 25px">
              <a href="' . $item->link . '">
            <img src="' . $item->images->thumbnail->url . 
              '" /></a> <br/>';
            echo 'By: <em>' . $item->user->username . 
              '</em> <br/>';
            echo 'Date: ' . date ('d M Y h:i:s', $item->created_time) . 
              '<br/>';
            echo $item->comments->count . ' comment(s). ' . 
              $item->likes->count . ' likes. </li>';
          }
          echo '</ul>';
        }
      } catch (Exception $e) {
        echo 'ERROR: ' . $e->getMessage() . print_r($client);
        exit;
      }
    }
  ?>
  </body>
</html>

リスト 8 と同じく、リスト 10 でもユーザーが Instagram で特定のユーザーを基準に写真を検索することができます。リスト 10 では、まず Instagram オブジェクトの searchUser() メソッドを呼び出し、このメソッドには Web フォームで送信されたユーザー名を渡します。その結果として検出されたユーザー・レコードのユーザー ID が getUserMedia() メソッドに渡され、このメソッドによって、該当するユーザーがアップロードした最新の写真のリストが返されます。


まとめ

この記事の例から明らかなように、Instagram API には、Instagram サービスで保管された写真を中心とした PHP ベースの Web アプリケーションを作成するための完全な機能を備えた一連のエンドポイントが用意されています。サード・パーティー製 PHP ライブラリーを使用するのか、独自のコードを作成するのかに関わらず、ユーザー・プロフィール、ユーザー間の関係、およびメディアなどにアクセスし、さまざまなエンドポイントからの情報を結合して、簡単にカスタム Web アプリケーションを作成することができます。ぜひ自分で試してみてください。

参考文献

学ぶために

  • PHP アプリケーションと Instagram の統合: 第 1 回」(Vikram Vaswani 著、developerWorks、2013年5月): PHP を REST ベースの Instagram API と組み合わせることで、革新的な Web アプリケーションを作成してください。この全 2 回からなる記事の第 1 回で、Instagram API レスポンスの基礎をベースに写真を検索し、写真とそれに関連付けられているコメントや「いいね!」を取得してください。
  • Instagram API エンドポイント: Instagram を活用する方法を学んでください。
  • Instagram 開発者用コンソール: Instagram クライアントを作成してください (Instagram アカウントが必要です)。
  • Instagram 認証: Instagram 開発者ドキュメントで Instagram の使用条件やその他の情報を調べてください。
  • Instagram API Developers フォーラム: Instagram 開発者向けフォーラムでサポートを受けたり、ディスカッションに参加したりしてください。
  • Zend_Http_Client コンポーネント: HTTP (Hyper-Text Transfer Protocol) リクエストを実行するための、この簡単なインターフェースについての詳細を読んでください。
  • OAuth 2.0 仕様: Web アプリケーション、デスクトップ・アプリケーション、携帯電話、リビング・ルーム機器に固有の認可フローについての詳細を読んでください。
  • この著者による他の記事 (Vikram Vaswani 著、developerWorks、2007年8月から現在まで): XML や Google API、その他の技術に関する記事を読んでください。
  • New to XML: XML を学ぶために必要なリソースを入手してください。
  • developerWorks の XML エリア: DTD、スキーマ、XSLT など、XML 分野でのスキルを磨くために必要なリソースを見つけてください。広範な技術に関する記事、ヒント、チュートリアル、標準、そして IBM Redbooks については、XML 技術文書一覧を参照してください。
  • オープンソース技術を使用して開発し、IBM の製品と併用するときに役立つ広範なハウツー情報、ツール、およびプロジェクト・アップデートについては、developerWorks Open source ゾーンを参照してください。
  • developerWorks Web development ゾーン: さまざまな Web ベースのソリューションを話題にした記事を調べてください。広範な技術に関する記事、ヒント、チュートリアル、標準、そして IBM Redbooks については、Web development の技術文書一覧を参照してください。
  • IBM の XML 認定技術者: XML および関連技術において IBM 認定技術者になる方法を調べてください。
  • developerWorks テクニカル・イベント: これらのセッションで最新情報を入手してください。
  • Twitter での developerWorks: 今すぐ登録して developerWorks のツイートをフォローしてください。
  • developerWorks podcast: ソフトウェア開発者向けの興味深いインタビューとディスカッションを聴いてください。
  • developerWorks オンデマンド・デモ: 初心者向けの製品のインストールおよびセットアップから熟練開発者向けの高度な機能に至るまで、さまざまに揃ったデモを見てください。

製品や技術を入手するために

  • Zend Framework: ハイパフォーマンス PHP アプリケーションによく使われている、この人気のフレームワークをダウンロードしてください。
  • PHP-OAuth 2.0 ライブラリー: (OAuth 2.0 Authorization Protocol draft-ietf-oauth-v2-15 に基づいた) OAuth 2.0 プロトコルの軽量 PHP ラッパーをダウンロードしてください。
  • PHP-Instagram-API ライブラリー (1): Instagram API 用 PHP 5.3+ ラッパーをダウンロードしてください。
  • PHP-Instagram-API ライブラリー (2): Instagram の API にアクセスするために Christian Metz 氏が開発した、使いやすい PHP クラス Instagram-PHP-API をダウンロードしてください。
  • IBM 製品の評価版: DB2、Lotus、Rational、Tivoli、および WebSphere のアプリケーション開発ツールとミドルウェア製品を体験するには、評価版をダウンロードしてみてください。

議論するために

コメント

developerWorks: サイン・イン

必須フィールドは(*)で示されます。


IBM ID が必要ですか?
IBM IDをお忘れですか?


パスワードをお忘れですか?
パスワードの変更

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


お客様が developerWorks に初めてサインインすると、お客様のプロフィールが作成されます。会社名を非表示とする選択を行わない限り、プロフィール内の情報(名前、国/地域や会社名)は公開され、投稿するコンテンツと一緒に表示されますが、いつでもこれらの情報を更新できます。

送信されたすべての情報は安全です。

ディスプレイ・ネームを選択してください



developerWorks に初めてサインインするとプロフィールが作成されますので、その際にディスプレイ・ネームを選択する必要があります。ディスプレイ・ネームは、お客様が developerWorks に投稿するコンテンツと一緒に表示されます。

ディスプレイ・ネームは、3文字から31文字の範囲で指定し、かつ developerWorks コミュニティーでユニークである必要があります。また、プライバシー上の理由でお客様の電子メール・アドレスは使用しないでください。

必須フィールドは(*)で示されます。

3文字から31文字の範囲で指定し

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


送信されたすべての情報は安全です。


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=60
Zone=XML, Open source, Web development
ArticleID=957452
ArticleTitle=PHP アプリケーションと Instagram の統合: 第 2 回
publish-date=12192013