OAuth認証でFacebookを利用するWebアプリケーション(PHPの場合)


OAuth認証でTwitterを利用するWebアプリケーションの作り方を以前紹介しました。OAuth認証はさまざまなサイトで使われていますが、使い方がちょっとずつ違っていたりして、プログラミングが苦手な人には敷居が高い気がします。せっかくおもしろいことを思いついても、最初の段階で躓いて挫折するのはがっかりなので、簡単なサンプルがたくさんあるといいと思います。

というわけで、PHPでFacebookのOAuth認証を利用する例を紹介しましょう。

Facebookの開発者サイトでアプリケーションを登録し、アプリケーションIDシークレットキーを取得します。

アプリケーション登録

2つのファイルでOAuth(説明用)

OAuth認証の開始ページを/facebook/oauth-start.php、終了ページを/facebook/oauth-end.phpとします。

oauth-start.phpは次のようになります。おおざっぱなTwitterと比べて、Facebookでは、OAuth認証時に認可する機能をかなり細かく設定できます。ここでは、掲示板への登録を許可するように、「scope=publish_stream」をつけておきます。他の権限については、Extended Permissionsを参照してください。

<?php
session_start();
$_SESSION['application_id'] = アプリケーションID;
$_SESSION['application_secret'] = シークレットキー;
$_SESSION['redirect_uri'] = 'http://localhost/facebook/oauth-end.php';
$_SESSION['state'] = md5(uniqid(rand(), TRUE)); //CSRF対策

$url = 'https://www.facebook.com/dialog/oauth'
        . '?client_id=' . $_SESSION['application_id']
        . '&redirect_uri=' . urlencode($_SESSION['redirect_uri'])
        . '&state=' . $_SESSION['state']
        . '&scope=publish_stream'; //投稿する場合
?>
<!doctype html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>OAuth Start</title>
  </head>
  <body>
    <p><a href="<?php echo $url; ?>">OAuth</a></p>
  </body>
</html>

oauth-start.phpが生成するURLにアクセスすると、認証画面になります。

認証画面

「許可する」をクリックすると、oautu-start.phpで指定したリダイレクトURL(ここではhttp://localhost/facebook/oauth-end.php)にリダイレクトされます。oauth-end.phpでは、リダイレクトが伴うcodeというパラメータを利用して、認証を完了させます。(ちなみに、http://www.facebook.com/settings/?tab=applicationsで許可を取り消せます。)

<?php
session_start();
if (!isset($_SESSION['state'], $_GET['state']) || ($_SESSION['state'] !== $_GET['state'])) {
  session_destroy();
  die();
}
        
$cxContext = NULL;
//$cxContext = stream_context_create(array(//プロキシサーバを利用する場合
//    'http' => array('proxy' => 'tcp://proxy.example.net',
//        'request_fulluri' => True)));
 
$url = 'https://graph.facebook.com/oauth/access_token'
        . '?client_id=' . $_SESSION['application_id']
        . '&client_secret=' . $_SESSION['application_secret']
        . '&redirect_uri=' . $_SESSION['redirect_uri']
        . '&code=' . $_GET['code'];
$result = file_get_contents($url, False, $cxContext);
$output = null;
parse_str($result, $output);
if (!isset($output['access_token'])) {
  session_destroy();
  die();
}
$_SESSION['access_token'] = $output['access_token'];
?>
<!doctype html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>OAuth End</title>
  </head>
  <body>
    <p>access_tokenをセッションに保存した。</p>
    <p><a href="post.php">送信テスト</a></p>
  </body>
</html>

oauth-end.phpで認証が完了したら、次のようなpost.phpで、メッセージを送信してみましょう。

<?php
session_start();
if (!isset($_SESSION['access_token'])) {
  session_destroy();
  header('Location: http://localhost/facebook/oauth-start.php');
  die();
}

//投稿
require_once 'HTTP/Request2.php';
$url = "https://graph.facebook.com/me/feed"
        . '?access_token=' . $_SESSION['access_token']
        . '&message=' . urlencode("テスト at " . time());
$request = new HTTP_Request2($url, HTTP_Request2::METHOD_POST);

if (substr(PHP_OS, 0, 3) == 'WIN') {//XAMPP(いいかげん)
  $sslCafile = 'C:/xampp/perl/vendor/lib/Mozilla/CA/cacert.pem';
} else {
  $sslCafile = '/etc/ssl/certs/ca-certificates.crt';
}
$request->setConfig(array(
    //'proxy_host' => 'proxy.example.net',//プロキシサーバを利用する場合
    //'proxy_port' => 3128,
    'ssl_cafile' => $sslCafile
));

$response = $request->send();
if ($response->getStatus() / 100 != 2) {
  echo $response->getReasonPhrase();
  die();
}
session_destroy();
?>
<!doctype html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>Message Post</title>
  </head>
  <body>
    <p>投稿成功。</p>
    <pre><?php echo $response->getBody(); ?></pre>
    <p><a href="oauth-start.php">start</a></p>
  </body>
</html>

例によって、PHPにはいろんなHTTPクライアントがあって、あまり整理されていないのですが、ここではHTTP_Request2を使っています(HTTP_Requestはプロキシ経由のSSL通信に対応していないため、ここでは使えません)。次のようなコマンドで、HTTP_Request2をインストールしておく必要があります。XAMPP for Windowsの場合、スタートメニューのコマンドプロンプトを右クリックして管理者として実行してください。プロキシが必要な環境では、事前に「set http_proxy=http://proxy.example.net:3128/」(Windows)や「export http_proxy=http://proxy.example.net:3128/」(Windows以外)が必要です。

cd \xampp\php
pear install http_request2

SSL通信のためには、PHPでOpen SSLが有効になっていなければなりません。Open SSLが有効かどうかはphpinfo()で確認できます。「OpenSSL suppor」がenabledになっていれば大丈夫です。有効になっていない場合は、php.iniに「extension=php_openssl.dll」という行を追加してください(XAMPPの場合はc:\xampp\php\php.ini)。「extension=」という記述がたくさんある場所に書いておけばいいでしょう。php.iniを変更したら、Apacheを再起動してください。

実験時には、「'ssl_cafile' => $sslCafile」の代わりに「'ssl_verify_peer' => false」としていてもいいでしょう。

1つのファイルでOAuth+投稿

oauth-start.phpとoauth-end.php、post.phpを1つのファイル1click-post.phpにまとめると次のようになります。コールバック処理の最後で一度転送しているのは、ブラウザのアドレス欄にトークンを表示させないためです(セキュリティのためではありません)。

<!doctype html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>Message Post</title>
  </head>
  <body>
    <?php
    session_start();

    $application_id = アプリケーションID;
    $application_secret = シークレットキー;
    $redirect_uri = 'http://localhost/facebook/1click-post.php';

    if (!isset($_SESSION['access_token'])) {
      if (!isset($_GET['code'])) {//OAuth
        $_SESSION['state'] = md5(uniqid(rand(), TRUE)); //CSRF対策
        $url = 'https://www.facebook.com/dialog/oauth'
                . "?client_id=$application_id"
                . '&redirect_uri=' . urlencode($redirect_uri)
                . '&state=' . $_SESSION['state']
                . '&scope=publish_stream'; //投稿する場合
        echo("<script>top.location.href='$url';</script>");
      } else if (isset($_SESSION['state'], $_GET['state']) && ($_SESSION['state'] === $_GET['state'])) {//コールバック
        $cxContext = NULL;
        //$cxContext = stream_context_create(array(//プロキシサーバを利用する場合
        //    'http' => array('proxy' => 'tcp://proxy.example.net:3128',
        //        'request_fulluri' => True,)));
        $url = 'https://graph.facebook.com/oauth/access_token'
                . "?client_id=$application_id"
                . "&client_secret=$application_secret"
                . "&redirect_uri=$redirect_uri"
                . '&code=' . $_GET['code'];
        $result = file_get_contents($url, False, $cxContext);
        $output = null;
        parse_str($result, $output);
        if (!isset($output['access_token'])) {
          session_destroy();
        } else {
          $_SESSION['access_token'] = $output['access_token'];
          header("Location: $redirect_uri"); //トークン隠すための転送(オプショナル)
        }
      }
    } else {//投稿
      require_once 'HTTP/Request2.php';
      $url = "https://graph.facebook.com/me/feed"
              . '?access_token=' . $_SESSION['access_token']
              . '&message=' . urlencode('テスト at ' . time());
      $request = new HTTP_Request2($url, HTTP_Request2::METHOD_POST);
      
      if (substr(PHP_OS, 0, 3) == 'WIN') {//XAMPP(いいかげん)
        $sslCafile = 'C:/xampp/perl/vendor/lib/Mozilla/CA/cacert.pem';
      } else {
        $sslCafile = '/etc/ssl/certs/ca-certificates.crt';
      }
      $request->setConfig(array(
          //'proxy_host' => 'proxy.example.net',//プロキシサーバを利用する場合
          //'proxy_port' => 3128,
          'ssl_cafile' => $sslCafile
      ));
      
      $response = $request->send();
      if ($response->getStatus() / 100 != 2) {
        echo $response->getReasonPhrase();
      } else {
        echo '<p>投稿成功。</p>';
        printf('<pre>%s</pre>', $response->getBody());
      }
      session_destroy();
    }
    ?>
  </body>
</html>

お約束ですが、こういう話を基本から学びたいという方には、拙著『Webアプリケーション構築入門 実践!Webページ制作からマッシュアップまで 』(森北出版, 2011)がおすすめです。

OAuth認証でFacebookを利用するWebアプリケーション(PHPの場合)” への1件のコメント

  1. ピンバック: WordPress+OAuth | はじめてのブログ

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です