2006年10月04日
Google Calendar APIの基礎
当初はGoogle自身がPHP用のライブラリを用意する予定だと表明していましたが、結局10月の終わりになって、Zend Google Data Client Libraryが登場しました。てなことで、PHP5をご利用の場合、以下のクラスライブラリは無用の長物と化しましたので、そこはすっ飛ばして、カレンダーAPIの解説としてご利用ください(ZendのものはPHP5用なので、PHP4をご利用の場合には、以下のクラスライブラリにも利用価値はあるかもしれません)。
なお、Googleカレンダーの携帯向けウェブアプリは元々このクラスライブラリのデモとして作ったものなので、このまま放置の予定。
PHP 4/5 class library for Google Data APIs
これは、GData APIとの通信を処理する、PHP4/5用のシンプルなクラスライブラリです(フィードの解析や作成を行う機能は提供されません)。詳細はREADMEをご覧ください。
- アーカイブの内容
-
- Google
- Account.php - アカウント認証API用クラス
- GData.php - GData APIの共通クラス
- Calendar.php - カレンダーデータAPI用クラス
- Blogger.php - BloggerデータAPI用クラス
- test.php - テストアプリその1
- gbase_demo_alt.php - テストアプリその2
- XMLParseIntoStruct.php - XMLを配列に処理する汎用のSAXパーサ(おまけ)
- README
- Google
テストアプリその1(test.php)は、以下で説明するふたつのアカウント認証API(ClientLoginとAuthSub)のそれぞれを使ってカレンダーフィードを取得する、シンプルなものです。
テストアプリその2(gbase_demo_alt.php)はGoogle Baseで料理レシピの投稿と編集を行うものです。これは、Google自身による、Google BaseデータAPIのPHP版デモを、このクラスライブラリを使って書き直したもので、これを動作させるにはAPIキーを取得して、このスクリプトの冒頭に登場する定数「GOOGLE_BASE_DEVELOPER_KEY」の値にそれを設定してください。
目次
GoogleカレンダーデータAPIへのアクセスは、公開予定の取得、及び「magicCookie」と呼ばれるURLを利用した非公開予定の取得については認証は不要ですが、予定の追加、変更、削除には認証を要します。
ここでは最初にアカウント認証について、次いでカレンダーデータAPIについてまとめています。
Google Account Authentication
Google Calendar Data API
アカウント認証の概要
認証を要するGoogleの各サービスAPIへのリクエストを行うアプリケーションは、ユーザIDとパスワードそのものではなく、アカウント認証APIによって発行される、トークン(token)と呼ばれるその代替データを送信します。トークンはその有効範囲内で繰り返し利用可能なので、アプリケーションはアクセスの都度トークンを取得する必要はありません。
アカウント認証APIにはClientLoginとAuthSubがあります。
- ClientLoginはPCのデスクトップアプリケーションなどでの利用を想定したものです。ユーザIDとパスワードはアプリケーションが直接取り扱います。トークンは、アプリケーションがユーザIDとパスワードを送信して発行されます。
- AuthSubはウェブアプリケーションでの利用を想定したものです。アプリケーションはユーザIDとパスワードは扱いません。トークンは、ユーザがGoogleアカウントのウェブサイトで、そのアプリケーションに対してアクセスを許可する操作を行い発行されます。
AuthSubでは、ウェブアプリケーションは、ユーザをGoogleアカウントのウェブサイトに誘導して、アプリケーションに対するアクセスの許可を依頼します。このときのURLには、「next」パラメータに、AuthSubからのレスポンスを処理するURLを指定しておきます。
以下の画像は、ユーザに表示されるログインフォームとアクセス要求の確認フォームの例です。アクセス要求の確認フォームでユーザが「アクセスを許可」をクリックすると、「next」パラメータで指定したURLに対してリダイレクトが行われます。
注意
- 現在のGoogleアカウントは、セッション管理をCookieで行っているため、例えばiモードなどの携帯電話用ウェブブラウザのように、Cookieが利用できない環境ではGoogleアカウントにログインできず、AuthSubも利用できません。
- Googleアカウントではない独自のアカウントを提供していたサービス、例えばBloggerなどについては、AuthSubは独自アカウントでは利用できません(独自アカウントをGoogleアカウントに移行すれば利用できます)。
なお、AuthSubのアクセスの確認フォームでは、アプリケーションがGoogleに登録されたものではない場合、以下のような警告文が表示されます。
このウェブサイトはGoogleに登録されていないため、承認リクエスト用の保護された接続を確立できません。
下記のリンク先を信頼できる場合にのみ、処理を続行してください。
登録済みのアプリケーションでは、この警告文は表示されません。また、登録済みのウェブアプリケーションはセキュアなトークンを利用可能ですが、これはここでは省略します。
ClientLogin
ClientLoginでは、https://www.google.com/accounts/ClientLoginに対して以下のようなリクエストを送信します。
POST /accounts/ClientLogin HTTP/1.1 Content-Type: application/x-www-form-urlencoded Email=Email&Passwd=Passwd&service=service&source=source
ポストデータの内容は以下の通りです。
| キー | 値 |
|---|---|
| ユーザID(ドメイン名を含むメールアドレス) | |
| Passwd | パスワード |
| service | 対象サービスのID(Googleカレンダーの場合は「cl」) |
| source | アプリケーションのID(任意の文字列で、「企業名-アプリケーション名-バージョン」形式が推奨されています) |
| logintoken | CAPTCHAチャレンジのトークン(CAPTCHAチャレンジ以外では省略) |
| logincaptcha | CAPTCHAチャレンジの回答(CAPTCHAチャレンジ以外では省略) |
リクエストが成功した場合のレスポンスはHTTP 200 OKで、そのボディは、以下のような「キー=値」形式のテキストです。このうち「Auth」キーの値がトークンです。他の値は現時点では使用されていません。
SID=DQAAAGgA...7Zg8CTN LSID=DQAAAGsA...lk8BBbG Auth=DQAAAGgA...dk3fA5N
なお、リクエストが不成功の場合、そのボディが、以下のような「キー=値」形式のテキストで、「Error」キーの値が「CaptchaRequired」である場合があります。これは、ClientLoginがロボットなどによる不正侵入の可能性を疑い、CAPTCHAチャレンジ(画像認証)を要求しているものです。
Error=CaptchaRequired CaptchaToken=DQAAAGgA...dkI1LK9 CaptchaUrl=Captcha?ctoken=DQAAAGgA...dkI1LK9
この場合、アプリケーションは、「CaptchaToken」キーに示された値と、「CaptchaUrl」キーに示されたURLで表示されるCAPTCHAチャレンジ画像の回答を、それぞれ「logintoken」と「logincaptcha」の値としてポストデータに追加し、ClientLoginへのリクエストを再度行うことになります。
クラスライブラリを使ったサンプルプログラム
以下の例は、この文章の冒頭で紹介しているPHPクラスライブラリを利用して、ClientLoginでトークンを取得し、それを表示するものです。
<?php
$email = 'example@gmail.com';
$password = 'password';
require_once 'Google/Calendar.php';
$service = new Google_Calendar;
session_start();
if (!isset($_SESSION['tokens'])) {
$_SESSION['tokens'] = array();
}
if (!isset($_SESSION['tokens']['calendar'])) {
if (!$service->requestClientLogin($email, $password)) {
exit("ClientLogin has failed.\n".$service->getResponseBody());
}
$_SESSION['tokens']['calendar'] = array(
$service->token,
$service->authType
);
}
var_dump($_SESSION['tokens']);
?>
ここでは、取得したトークンはいったんPHPのセッションデータに保存しています。トークンは繰り返し利用可能なので、アプリケーションがサービスAPIに複数回のリクエストを行う予定なら、トークンをPHPのセッションデータに保存しておくことで、リクエストの都度トークンを取得せずに、保存してあるものを利用することができます。この場合、実際にAPIにリクエストを行う際には、トークンを取得したアカウント認証APIがClientLoginかAuthSubかによって送信内容が異なるので、トークンには、それを取得したアカウント認証APIの種類(このクラスではauthTypeプロパティ)も紐付けておきます。
また、トークンは各サービスAPIごとに異なるので、アプリケーションが複数のサービスを利用する場合は、上の例でハッシュのキーにサービス名を用いているように、それがどのサービス用のものかを識別できるようにしておきます(AuthSubでは、AuthSubTokenInfoによってトークンの対象サービスを確認することが可能です)。
AuthSub
AuthSubではトークンは、Googleアカウントのウェブサイトで表示されるアクセス要求の確認フォームで、ユーザが「アクセスを許可」をクリックすることで発行されます。
ユーザはまず、https://www.google.com/accounts/AuthSubRequestに、以下のパラメータをクエリー文字列に指定したURLにアクセスします(ウェブアプリケーションはユーザにこのURLを示して、アクセスの許可を依頼します)。
| キー | 値 |
|---|---|
| next | アクセスが許可された場合に行われるリダイレクト先のURL(AuthSubのレスポンスを処理するウェブアプリケーションのURL) |
| scope | 対象サービスのURL(Googleカレンダーの場合は「http://www.google.com/calendar/feeds/」) |
| session | 使い捨てトークンをセッショントークンと交換するか否か |
アクセス要求の確認フォームで、ユーザが「アクセスを許可」をクリックすると、AuthSubは「next」パラメータで指定されたURLに、「token」パラメータを付加してリダイレクトします。
この「token」パラメータの値は使い捨てトークン(one-time|single use token)です。これは一回限り有効で、繰り返し利用することはできませんが、上表にある「session」パラメータの値が「1」の場合、この使い捨てトークンは、繰り返し利用可能なセッショントークン(multi-use session token)と交換することができます。
使い捨てトークンをセッショントークンと交換するには、https://www.google.com/accounts/AuthSubSessionTokenに対して以下のようなリクエストを送信します。Authorizationヘッダで指定するtokenは使い捨てトークンの値です。
GET /accounts/AuthSubSessionToken HTTP/1.1 Authorization: AuthSub token="token"
リクエストが成功した場合のレスポンスはHTTP 200 OKで、そのボディは、以下のような「キー=値」形式のテキストです。このうち「Token」キーの値がセッショントークンです。他の値については、現時点では使用されていません。
Token=DQAA...7DCTN Expiration=20061004T123456Z
なお、Googleに登録済みのウェブアプリケーションはセキュアなトークンを利用可能ですが、これはここでは省略します。
クラスライブラリを使ったサンプルプログラム
ユーザが、以下の例で示されるリンクをクリックして表示されるアクセス要求の確認フォームで、「アクセスの許可」をクリックすると、http://www.abcd.com/gcal/auth.php?token=tokenというURLにリダイレクトが行われます。このURLの「token」パラメータの値は、カレンダーデータAPIを対象とした、セッショントークンと交換可能な使い捨てトークンです。
<p>以下のリンクをクリックしてGoogleアカウントのウェブサイトに移動し
お客様のGoogleカレンダーにABCD.comがアクセスすることを許可してください。<br />
ABCD.comがお客様のパスワードおよび個人情報を入手することはありません。</p>
<p><a href="<?php
require_once 'Google/Calendar.php';
echo Google_Calendar::getAuthSubRequestUrl('http://www.abcd.com/gcal/auth.php')
?>">Googleアカウント アクセス要求</a></p>
そして以下の例では、使い捨てトークン(「token」パラメータの値)をセッショントークンと交換しています。なお、取得したトークンはClientLoginでの例と同様に、PHPのセッションデータに保存しています。
<?php
require_once 'Google/Calendar.php';
$service = new Google_Calendar;
session_start();
if (isset($_GET['token']) and strlen($_GET['token']) > 0) {
if (!$service->requestAuthSubSessionToken($_GET['token'])) {
exit("AuthSubSessionToken has failed.\n".$service->getResponseBody());
}
if (!isset($_SESSION['tokens'])) {
$_SESSION['tokens'] = array();
}
$_SESSION['tokens']['calendar'] = array(
$service->token,
$service->authType
);
var_dump($_SESSION['tokens']);
}
?>
トークンの確認と廃棄
AuthSubの有効なトークンの発行数は、1ユーザ/1アプリケーションあたり10ヶまでに制限されています。そのため、取得済みの有効なトークンを廃棄(revoke)する必要が生じる場合があります。
https://www.google.com/accounts/AuthSubTokenInfoに対して以下のようなリクエストを送信することで、そのトークンが有効かどうかを確認できます。
GET /accounts/AuthSubTokenInfo HTTP/1.1 Authorization: AuthSub token="token"
指定したトークンが有効な場合のレスポンスはHTTP 200 OKで、そのボディは、以下のような「キー=値」形式のテキストです。
Target=www.abcd.com Scope=http://www.google.com/calendar/feeds/ Secure=false
有効なトークンを廃棄するには、https://www.google.com/accounts/AuthSubRevokeTokenに対して以下のようなリクエストを送信します。
GET /accounts/AuthSubRevokeToken HTTP/1.1 Authorization: AuthSub token="token"
リクエストが成功した場合のレスポンスはHTTP 200 OKです。
なお、ユーザはGoogleアカウントウェブサイトの「アカウント情報」ページで、現在有効なAuthSubトークンの確認と廃棄が行えます。また、AuthSubのアクセス要求時に、既に制限数を超えるトークンが発行されている場合は、その旨のメッセージが表示されます。
以下の画像は、制限数を超えるトークンが発行済みの場合のメッセージと、トークンの確認と廃棄の画面です。確認と廃棄の画面で「アクセスを取り消す」をクリックしたトークンは廃棄され、無効になります。
クラスライブラリを使ったサンプルプログラム
以下の例では、まずトークンが有効かどうかの確認を行い、有効な場合はそのトークンを廃棄しています。
<?php
$token = 'GD32CMCL25aZ-v____8B';
require_once 'Google/Calendar.php';
$service = new Google_Account;
if (!$service->requestAuthSubTokenInfo($token)) {
echo("Token $token is not valid.");
} else {
if (!$service->requestAuthSubRevokeToken($token)) {
exit("AuthSubRevokeToken has failed.\n".$service->getResponseBody());
}
echo("Token $token has been revoked and is no longer valid.");
}
?>
カレンダーデータの取得
GoogleカレンダーデータAPIとアプリケーションは、Atom 1.0(またはRSS 2.0)に準じた、GDataと呼ばれるフィードデータをHTTP通信でやり取りします。
Googleカレンダーのフィードは、http://www.google.com/calendar/feeds/User_ID/Visibility/Projection[/Entry_ID|?Query_String]という形式のURLにアクセスすることで取得しますが、イベントの追加、変更、削除を行うアプリケーションでは一般的に、http://www.google.com/calendar/feeds/default/private/fullに対して以下のようなリクエストを送信して、読み書きのいずれにも利用可能な、非公開予定を含むフィードを取得します。
GET /calendar/feeds/default/private/full[/Entry_ID|?Query_String] HTTP/1.1 Authorization: [GoogleLogin auth=ClientLogin_token|AuthSub token="AuthSub_token"]
- Authorizationヘッダの値は、トークンを取得した認証APIがClientLoginかAuthSubかで異なります。
- VisibilityやProjectionの詳細はUsing the Google Calendar Data APIの“Calendar feed types”を参照してください。
URLに以下の検索パラメータをクエリー文字列に指定することで、条件付きでフィードを取得できます。
なお、日時は、Atom 1.0が採用しているRFC3339形式で指定します。
| キー | 値 |
|---|---|
| q | 文字列の検索式(Googleのウェブ検索などと同様、「"」、「|」、「-」などのオペレータが使用可能です) |
| max-results | 最大取得件数(省略時:25件) |
| start-index | 取得開始エントリーの索引番号(省略時:1) |
| orderby | エントリーの並び順(省略時:更新日時順|starttime:開始日時順) |
| start-min | 最も古いイベントの開始日時(省略時:1970-01-01) |
| start-max | 最も新しいイベントの終了日時(省略時:2031-01-01) |
| updated-min | 最も古いエントリーの更新日時 |
| updated-max | 最も新しいエントリーの更新日時 |
| author | エントリーのauthor/name要素またはauthor/email要素(完全一致) |
| alt | フィード種別(省略時:Atom 1.0|rss:RSS 2.0) |
これらの検索パラメータのうち、「start-min」、「start-max」、「orderby」はカレンダーデータAPI特有のもので、それ以外はGData共通のものです。なお、カレンダーデータAPIは、GData共通の検索パラメータのうち、「category」はサポートしていません。
クラスライブラリを使ったサンプルプログラム
以下の例では、ClientLoginでトークンを取得した後、現在以降に開始予定のイベントエントリーのうち「横河」または「佐川」という文字列を含むものを、イベントの開始日時順に最大10件、という条件でフィードを取得しています。
<?php
$email = 'example@gmail.com';
$password = 'password';
require_once 'Google/Calendar.php';
$service = new Google_Calendar;
if (!$service->requestClientLogin($email, $password)) {
exit("ClientLogin has failed.\n".$service->getResponseBody());
}
$queries = array(
'q' => '横河|佐川',
'max-results' => 10,
'orderby' => 'starttime',
'start-min' => date('Y-m-d\TH:i:s+09:00', time())
);
if (!$service->requestFeed($queries)) {
exit("Requesting a feed has failed.\n".$service->getResponseBody());
}
header('Content-Type:application/xml;charset=UTF-8');
echo $service->getResponseBody();
?>
イベントの追加
イベントを追加するには、http://www.google.com/calendar/feeds/default/private/fullに対して以下のようなリクエストを送信します。
POST /calendar/feeds/default/private/full HTTP/1.1 Authorization: [GoogleLogin auth="ClientLogin_token"|AuthSub token="AuthSub_token"] Content-Type: application/atom+xml GData
GDataは、例えば以下のような、Atom 1.0に準じたフィードデータです。
<entry
xmlns="http://www.w3.org/2005/Atom"
xmlns:gd="http://schemas.google.com/g/2005">
<category
scheme="http://schemas.google.com/g/2005#kind"
term="http://schemas.google.com/g/2005#event">
</category>
<title type="text">横河武蔵野FC vs. 佐川急便東京SC</title>
<content type="text">最後の東京ダービー</content>
<gd:where valueString="横河電機グラウンド">
</gd:where>
<gd:when
startTime="2006-10-07T15:00:00+09:00"
endTime="2006-10-07T17:00:00+09:00">
</gd:when>
</entry>
イベントが「終日」の場合は、gd:when要素のstartTime/endTime属性値に日付のみを指定します。「繰り返し」のイベントの場合は、gd:recurrence要素を指定します。GData要素の詳細は、Common Elements: “Kinds”を参照してください。
GDataの文字エンコーディングはUTF-8です。日時は、Atom 1.0が採用しているRFC3339形式で指定します。
リクエストが成功した場合のレスポンスはHTTP 201 Createdで、そのボディは、送信したGDataにid要素やupdated要素などが追加されたフィードデータです。
クラスライブラリを使ったサンプルプログラム
以下の例では、ClientLoginでトークンを取得した後、イベントを追加しています。
<?php
$email = 'example@gmail.com';
$password = 'password';
$entry = <<<GDATA
<entry
xmlns="http://www.w3.org/2005/Atom"
xmlns:gd="http://schemas.google.com/g/2005">
<category
scheme="http://schemas.google.com/g/2005#kind"
term="http://schemas.google.com/g/2005#event">
</category>
<title type="text">横河武蔵野FC vs. 佐川急便東京SC</title>
<content type="text">最後の東京ダービー</content>
<gd:where valueString="横河電機グラウンド">
</gd:where>
<gd:when
startTime="2006-10-07T15:00:00+09:00"
endTime="2006-10-07T17:00:00+09:00">
</gd:when>
</entry>
GDATA;
require_once 'Google/Calendar.php';
$service = new Google_Calendar;
if (!$service->requestClientLogin($email, $password)) {
exit("ClientLogin has failed.\n".$service->getResponseBody());
}
if (!$service->insert($entry)) {
exit("Inserting an entry has failed.\n".$service->getResponseBody());
}
header('Content-Type:application/xml;charset=UTF-8');
echo $service->getResponseBody();
?>
イベントの変更と削除
イベントの変更及び削除は、そのイベントエントリーのlink要素中、rel属性値が「edit」のものの、href属性値に示されているURLに対してリクエストを送信します。
変更の場合は、以下のようにPUTメソッド(または、X-Http-Method-Overrideヘッダに「PUT」を指定したPOSTメソッド)を用いて、変更したGDataを送信します。
PUT Edit_URL HTTP/1.1 Authorization: [GoogleLogin auth="ClientLogin_token"|AuthSub token="AuthSub_token"] Content-Type: application/atom+xml GData
削除の場合は、以下のようにDELETEメソッド(またはX-Http-Method-Overrideヘッダに「DELET」を指定したPOSTメソッド)を用います。
DELETE Edit_URL HTTP/1.1 Authorization: [GoogleLogin auth="ClientLogin_token"|AuthSub token="AuthSub_token"]
いずれも、リクエストが成功した場合のレスポンスはHTTP 200 OKで、変更の場合は、そのボディは、送信したGDataが加工されたフィードデータです。
クラスライブラリを使ったサンプルプログラム
以下の例では、ClientLoginでトークンを取得した後、イベントの開始/終了日時を変更しています。
<?php
$email = 'example@gmail.com';
$password = 'password';
$edit_url = 'http://www.google.com/calendar/feeds/default/private/full/abcd/1234';
$entry = <<<GDATA
<entry
xmlns="http://www.w3.org/2005/Atom"
xmlns:gd="http://schemas.google.com/g/2005">
<category
scheme="http://schemas.google.com/g/2005#kind"
term="http://schemas.google.com/g/2005#event">
</category>
<gd:when
startTime="2006-10-07T14:00:00+09:00"
endTime="2006-10-07T18:00:00+09:00">
</gd:when>
</entry>
GDATA;
require_once 'Google/Calendar.php';
$service = new Google_Calendar;
if (!$service->requestClientLogin($email, $password)) {
exit("ClientLogin has failed.\n".$service->getResponseBody());
}
if (!$service->update($entry, $edit_url)) {
exit("Updating an entry has failed.\n".$service->getResponseBody());
}
header('Content-Type:application/xml;charset=UTF-8');
echo $service->getResponseBody();
?>
Some Tips
- GDataフィードの形式が、規定のAtom 1.0の場合、日時表現形式はRFC3339ですが、PHP5では、strtotime関数はタイムゾーン指定を含むRFC3339形式の日時表現に対応しており、また、新たに追加された定数などによって、date関数などでの日時表現の生成も容易です。一方、PHP4のstrtotime関数は、タイムゾーン指定を含むRFC3339形式の日時表現には対応していないので、これをUnixタイムスタンプに置き換える必要がある場合は、独自の処理を用意することになります。
- GDataフィードを取得するURLのクエリー文字列に「alt=rss」を追加すると、フィード形式が、規定のAtom 1.0からRSS 2.0に変更されます。RSS 2.0は比較的以前からある形式のため、フィード解析に既成のパーサを利用する場合に、選択肢が広がるかもしれません。また、RSS 2.0の日時表現形式はRFC822ですが、PHP4でもこの形式については、strtotime関数はタイムゾーン指定を含む日時表現に対応しており、また、date関数での日時表現の生成も、フォーマット文字列に「r」を指定するだけで行えます。ただし、RSS 2.0はフィードの取得時のみに利用できます。イベントの追加や変更はAtom 1.0を利用します。
Category: ウェブ制作
Posted 2006年10月04日 22:53
トラックバック
このエントリーのトラックバックURL:
http://www.rcdtokyo.com/mt/mt-rcdtokyo5428-tb.cgi/786
このリストは、次のエントリーを参照しています: Google Calendar APIの基礎:
» Google Calender API利用サイトとPHPのライブラリ紹介 from using API;
Google Calender APIとAmazonをマッシュアップしたサイトと、Calender APIのPHPライブラリを紹介。
ときおりのこのみ ... [続きを読む]
Pinged at 2006/10/15 09:37