Do You PHP はてブロ

Do You PHPはてなからはてブロに移動しました

PHPからService AccountsとしてGoogleカレンダーAPIにアクセスしてみる

今更感漂いますが気にしない:-)
ちょっとGoogleカレンダーにアクセスするバッチアプリを書いてたんですが、いろいろと苦労したのでまとめてみます。

前置き

PHPからGoogleAPI群にアクセスする記事はいろいろありますが、ユーザーがブラウザを介してアクセスするモノ(Web Server Applicationsと呼ばれる)がほとんどです。一方で、バッチアプリなどブラウザを介さずにGoogleAPIにアクセス(Service Accountsと呼ばれる)するモノはあまり見つかりません。

上のリンクにある図を見比べてもらえれば分かりますが、これら2つの大きな違いは"User Login & Consent"の部分、つまり、ログインとアプリのアクセス許可があるかどうか?なんですが、バッチアプリの場合はこれをGoogle側の設定であったり、PHPコードで書く必要があります。

今回の環境

  • CentOS5+PHP5.3.3(rpm)
  • CentOS6+PHP5.5.3(src)

Google APIs Consoleでの作業

1. Google APIs Consoleにアクセスする
まずはGoogleアカウントでログインした後、Google APIs Consoleにアクセスします。

2. プロジェクトを作成する
デカデカと表示されている"Create project..."ボタンをクリックして、プロジェクトを作成します。

3. 利用するGoogleのサービスを設定する
プロジェクト作成後、Googleのサービス一覧が表示されますので、このプロジェクトで利用するサービスを"ON"にします。今回は"Calendar API"のトグルスイッチをクリックします。

4. OAuth 2.0用のクライアントIDを作成する
Google APIs Consoleの左メニューにある"API Access"をクリックし、表示される青い大きなボタンをクリックします。

ダイアログが表示されるので、Product nameに入力して"Next"ボタンをクリック。その他の項目は適宜入力してください。

"Client ID Setting"ダイアログが表示されますので、真ん中の"Service account"を選択して"Create client ID"ボタンをクリックします。クリックするとキーペアが生成されます。

10秒ほど時間がかかりますが、以下の様なダイアログが表示されたら、"Download private key"ボタンをクリックして秘密鍵をダウンロードします。

ダウンロードされる秘密鍵のファイル名は、

[0-9a-f]{40}-privatekey.p12

のようなパターンです。このp12ファイルはバッチアプリに必要です。また、p12ファイルはSSHなどの秘密鍵と同様、他のユーザーからの読み書きできないパスに保存し、p12ファイル自身の権限も変更しておきます。
3. Client IDとメールアドレスを確認する
クライアントIDを生成したダイアログを閉じると、Google APIs Console画面に以下のような項目が追加表示されているはずです。ここに表示されている

  • Client ID
  • Email address

がバッチアプリに必要になりますので、メモしておきます。

Googleカレンダーの設定

これ、ハマりどころだと思うんですが、バッチアプリからカレンダーを参照/更新する場合のアカウントは、先ほど作成したクライアントになります。ですので、カレンダーを参照/更新する権限を、クライアントに追加しておく必要があります
Googleカレンダーにアクセスし、バッチからアクセスするカレンダーの設定画面にある"このカレンダーを共有"タブから権限を与えておきます。今回は

  • 予定の変更権限

を指定しています。

PHPコードを書く

事前準備が終わったので、ようやくPHPコードの方です。
1. Google APIs Client Library for PHPをダウンロードする
Google APIs Client Library for PHPをダウンロードします。今回ダウンロードしたのは、ver.0.6.6です。

$ wget https://google-api-php-client.googlecode.com/files/google-api-php-client-0.6.6.tar.gz
$ tar zxf google-api-php-client-0.6.6.tar.gz
$ 

2. カレンダー一覧を取得してみる
以下の様なコードで動作を確認してみます。カレンダーの一覧が取得できればOKです。

<?php
require_once '/path/to/src/Google_Client.php';
require_once '/path/to/src/contrib/Google_CalendarService.php';

const CLIENT_ID = 'xxxxxxxxxxxx.apps.googleusercontent.com';
const SERVICE_ACCOUNT_NAME = 'xxxxxxxxxxxx@developer.gserviceaccount.com';
const KEY_FILE = '/path/to/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx-privatekey.p12';

$client = new Google_Client();
$client->setApplicationName("Google Prediction Sample");
$client->setAssertionCredentials(new Google_AssertionCredentials(
    SERVICE_ACCOUNT_NAME,
    array('https://www.googleapis.com/auth/calendar'),
    file_get_contents(KEY_FILE)
));

$client->setClientId(CLIENT_ID);
$service = new Google_CalendarService($client);
$calList = $service->calendarList->listCalendarList();
var_dump($calList);

3. すべてのカレンダーに登録されたすべての予定を取得してみる
前半は先ほどのコードと同じです。

<?php$service = new Google_CalendarService($client);
$calList = $service->calendarList->listCalendarList();
foreach ($calList['items'] as $calendar) {
    $events = $service->events->listEvents($calendar['id']);
    foreach ($events['items'] as $event) {
        printf('%s - %s %s%s',
            (isset($event['start']['dateTime']) ? $event['start']['dateTime'] : $event['start']['date']),
            (isset($event['end']['dateTime']) ? $event['end']['dateTime'] : $event['end']['date']),
            $event['summary'],
            PHP_EOL
        );
    }
}

実行してみると分かりますが、開始日時と終了日時はISO-8601形式です。
4. カレンダーに予定を登録してみる
前半はこれまでのコードと同じです。登録する場合、イベント自体を表すGoogle_Eventクラスを使用します。開始・終了日時はGoogle_EventDateTimeオブジェクトでラップします。

<?php$service = new Google_CalendarService($client);

// Google_CalendarService.calendarList#listCalendarList()を使って
// 登録対象のカレンダーのIDを取得しておく
//       :
// $calendarId = ... ;

/**
 * 予定(イベント)の作成
 */
$event = new Google_Event();
$start_time = new Google_EventDateTime();
$start_time->setDateTime('2013-10-25T10:00:00+09:00');
$event->setStart($start_time);
$end_time = new Google_EventDateTime();
$end_time->setDateTime('2013-10-25T11:00:00+09:00');
$event->setEnd($end_time);
$event->setLocation('ヨドバシAkiba');
$event->setSummary('QX100を触りに行く');
$event->setDescription('QX100が展示されてたらいろいろと弄ってみる。Wi-Fi接続とかNFCとか。');
$service->events->insert($calendarId, $event);

カレンダーサービスのリファレンスは以下を参照してください。

まとめ

Google APIをService Accountsとして利用する場合のいろいろをまとめてみました。ここまでできれば、他のカレンダーサービスと同期するとか、何らかのメールが届いたらカレンダーにイベントを登録するとか、いろいろできそうです:-)
また、基本的には「認証部分をどう書けばいいのか?」が確認できたので、他のサービスでも似たような感じで行けるんじゃないかと思います。