- 追加された行はこの色です。
- 削除された行はこの色です。
* Googleカレンダー連携 [#zaec426f]
#setlinebreak(on);
OAuth認証後に Google Calendar APIを使用してカレンダー情報を取得する簡単なWebアプリケーションを作成する。
ここではPHPで実装するが、他の言語でも基本的な流れは同じ。
エンドポイントに対して直接リクエストを発行する場合のインターフェースは以下のURLを参照。
https://developers.google.com/google-apps/calendar/v3/reference/
&br;
#contents
// サービスアカウント版は別途記載予定。
** 概要 [#a76b6172]
#html(<div style="padding-left:10px">)
以下の通り、カレンダーAPIからのデータ取得を行う簡単なアプリケーションを作成する。
#TODO(フォルダ構成、サンプル概要)
|URI|クライアントAPIの言語|h
|http://localhost/test/google-calendar/|PHP|
※Google認証後のリダイレクトページも同じURIを使用する
#html(</div>)
** プロジェクトの作成と認証情報の設定/取得 [#h9ad68bf]
#html(<div style="padding-left:10px">)
*** プロジェクトの登録 [#sfdc52cf]
#html(<div style="padding-left:10px">)
Google API Console から プロジェクトを作成する
//https://console.developers.google.com/?hl=ja
// https://console.developers.google.com/flows/enableapi?apiid=calendar&hl=ja
https://console.developers.google.com/project
#html(</div>)
*** APIの有効化 [#u005b2fe]
#html(<div style="padding-left:10px">)
(1) 対象のプロジェクトを選択して「APIとサービスの有効化」をクリック。
(2) 検索ボックスに ”Calendar” を入力。
(3) "Google Calendar API"を選択し、「有効にする」をクリック。
#html(</div>)
*** 認証情報の作成 [#kd46634e]
#html(<div style="padding-left:10px">)
(1)「認証情報の作成」から「OAuthクライアントID」をクリックして以下の通り入力して「作成」。
アプリケーションの種類: ウェブ アプリケーション
名前: カレンダー連携テストクライアント
承認済みのリダイレクト URI: http://localhost/test/google-calendar/
(2) ”認証情報” の OAuth同意画面を以下の通り入力し、「保存」
ユーザーに表示するサービス名: カレンダー連携テストサービス
※利用規約やプライバシーポリシーの URLを入力する場合はここで入力。
(3) "認証情報" から作成したOAuthクライアントを選択し、「JSONをダウンロード」
※client_secret.json にリネーム。
#html(</div>)
#html(</div>)
** Google クライアントライブラリをインストールする [#tf7d968f]
#html(<div style="padding-left:10px">)
ここでは composer でインストールする
#code(myterm2 nolinenums){{
cd /path/to/www/
mkdir google-calendar && cd google-calendar
composer require google/apiclient:^2.0
}}
※GitHubからダウンロードする場合はダウンロード後、上記ディレクトリ(/path/to/www/google-calendar配下)に解凍
https://github.com/google/google-api-php-client/releases
*** 参考 [#l6288920]
#html(<div style="padding-left:10px">)
https://developers.google.com/api-client-library/php
https://developers.google.com/google-apps/calendar/quickstart/php?hl=ja
https://developers.google.com/api-client-library/php/start/installation?hl=ja
https://github.com/google/google-api-php-client#download-the-release
#html(</div>)
#html(</div>)
** 連携処理の作成 [#r31062d3]
#html(<div style="padding-left:10px">)
#TODO(登録/更新/削除)
/path/to/www/test/google-calendar/index.php
#code(mycode2){{
<?php
date_default_timezone_set('Asia/Tokyo');
//error_reporting(E_ALL);
require_once 'vendor/autoload.php';
// OAuthクライアント認証用のJSONファイル
$oauth_credentials = "/path/to/client_secret.json"; // 上記でダウンロードしたJSONファイルのPATH
// Google認証後のリダイレクト先(「http://localhost/test/google-calendar/?code=アクセストークン」 という形でリダイレクトされる)
$redirect_uri = "http://localhost/test/google-calendar/";
// トークンの退避用 TODO: テスト用(本番時はDB等に退避する)
$token_file = "/tmp/google-calendar-api-token-cache.txt";
session_start();
// セッションを破棄する(テスト用)
// ※退避しておいたトークンを使用して認証が通る事の確認用
if (isset($_REQUEST['logout'])) {
session_destroy();
session_start();
header("Location: " . $redirect_uri);
exit;
}
// トークンを破棄する(テスト用)
// ※アカウントの再選択を行いたい場合
if (isset($_REQUEST['remove-token'])) {
session_destroy();
session_start();
file_put_contents($token_file, "");
header("Location: " . $redirect_uri);
exit;
}
$msg = "";
// 取得済みのトークンがある場合はセッションにセット TODO: 本番時はDBから取得
if (empty($_SESSION['google-calendar-api-token'])) {
if (file_exists($token_file)) {
$tokenText = file_get_contents($token_file);
if (trim($tokenText) !== "") {
$msg = "トークンをファイルから取得しました。";
$_SESSION['google-calendar-api-token'] = unserialize(file_get_contents($token_file));
}
}
}
// Google API Client
$client = new Google_Client();
$client->setAuthConfig($oauth_credentials);
$client->setRedirectUri($redirect_uri);
$client->addScope(Google_Service_Calendar::CALENDAR);
$client->setAccessType("offline"); // トークンの自動リフレッシュ
$client->setApprovalPrompt("force"); // これがないと初回以外はリフレッシュトークンが得られない
$authUrl = $client->createAuthUrl();
// 認証後のリダイレクトの場合
if (isset($_GET['code'])) {
$token = $client->fetchAccessTokenWithAuthCode($_GET['code']);
$_SESSION['google-calendar-api-token'] = $token;
header("Location: ${redirect_uri}");
exit;
}
// トークンの有効期限が切れている場合はリフレッシュトークンを使用して最新のトークンを得る
if (!empty($_SESSION['google-calendar-api-token'])) {
$client->setAccessToken($_SESSION['google-calendar-api-token']);
If ($client->isAccessTokenExpired()) {
if (isset($_SESSION['google-calendar-api-token']["refresh_token"])) {
$client->refreshToken($_SESSION['google-calendar-api-token']["refresh_token"]);
} else {
unset($_SESSION['google-calendar-api-token']);
}
}
}
// トークンが無効な場合は認証ページにリダイレクト
$accessToken = $client->getAccessToken();
if (!$accessToken) {
header("Location: ${authUrl}");
exit;
}
$_SESSION['google-calendar-api-token'] = $accessToken;
// トークンを退避 TODO: 本番時はDBなどに退避する
$tokenText = serialize($_SESSION['google-calendar-api-token']);
file_put_contents($token_file, $tokenText);
// カレンダーAPI用のインスタンス生成
$cal_service = new Google_Service_Calendar($client);
// カレンダ一覧を取得
$calendar_list = array();
$calendarList = $cal_service->calendarList->listCalendarList();
while(true) {
foreach ($calendarList->getItems() as $i => $calendarListEntry) {
$rec = $calendarListEntry;
$calendar_list[] = $rec;
}
$pageToken = $calendarList->getNextPageToken();
if ($pageToken) {
$optParams = array('pageToken' => $pageToken);
$calendarList = $service->calendarList->listCalendarList($optParams);
} else {
break;
}
}
// イベント情報
$calender_idx = 0;
$calender_id = "primary";
if (isset($_REQUEST["calender_idx"])){
if (isset($calendar_list[$_REQUEST["calender_idx"]])){
$calender_idx = $_REQUEST["calender_idx"];
$calender_id = $calendar_list[$calender_idx]["id"];
}
}
$event_list = array();
$optParams = array();
/* 日付指定する場合 */
$optParams["timeMin"] = "2017-01-01T00:00:00+0900"; // "2017-01-01T00:00:00Z";
$optParams["timeMax"] = "2017-12-31T23:59:59+0900";
$optParams["timeZone"] = "Asia/Tokyo";
$optParams["singleEvents"] = true;
$optParams["orderBy"] = "startTime"; // orderBy指定する場合は singleEvents=true でないと怒られる
$events = $cal_service->events->listEvents($calender_id, $optParams);
while(true) {
foreach ($events->getItems() as $event) {
$rec = array();
$rec["id"] = $event->getId();
$rec["start"] = $event->getStart()->date ? $event->getStart()->date : $event->getStart()->dateTime;
$rec["end"] = $event->getEnd()->date ? $event->getEnd()->date : $event->getEnd()->dateTime;
$rec["summary"] = $event->getSummary();
$event_list[] = $rec;
}
$pageToken = $events->getNextPageToken();
if ($pageToken) {
$optParams['pageToken'] = $pageToken;
$events = $cal_service->events->listEvents($calender_id, $optParams);
} else {
break;
}
}
// 描画
require_once("view/calendar.php");
?>
}}
#html(</div>)
** Viewの作成 [#r31062d3]
#html(<div style="padding-left:10px">)
/path/to/www/test/google-calendar/view/calendar.php
#code(myhtml2){{
<!doctype html>
<html lang="ja">
<head>
<meta charset="utf-8" />
<style>
* {
font-size: 16px;
}
h1,h2,h3,h4,h5 {
margin: 0;
}
.tbl {
border-collapse: collapse;
border-spacing: 0;
}
.tbl th {
background: #ccc;
}
.tbl th,
.tbl td{
padding: 1px 10px;
border: 1px solid #333;
}
html,body {
height: 100%;
}
#loading_layer {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0,0,0,0.7);
}
#loading_inner {
position: fixed;
top: 50%;
left: 50%;
width: 200px;
height: 50px;
margin-left: -100px;
margin-top: -25px;
background: #fff;
border-radius: 4px;
overflow-y: hidden;
}
#loading_msg {
padding-top: 10px;
padding-bottom: 10px;
text-align: center;
vertical-align: middle;
}
</style>
</head>
<body>
<div><?= $msg ?></div>
<div style="position:relative;">
<div style="position:absolute;top:0;right:10px;">
<a href="./?logout=true">セッション破棄</a>
<a href="./?remove-token=true" style="margin-left:10px;">トークン破棄</a>
</div>
<div style="display:inline-block">
カレンダー :
<select id="calendar_id">
<?php foreach ($calendar_list as $idx => $rec) {?>
<option value="<?= $idx ?>" <?= $calender_idx == $idx ? "selected" : "" ?>><?= $rec["summary"] ?></option>
<?php } ?>
</select>
</div>
</div>
<table class="tbl" style="margin-top:4px">
<thead>
<tr>
<th>Id</th>
<th>Start</th>
<th>End</th>
<th>Summary</th>
</tr>
</thead>
<tbody>
<?php foreach ($event_list as $rec) { ?>
<tr>
<td><?= $rec["id"] ?></td>
<td><?= $rec["start"] ?></td>
<td><?= $rec["end"] ?></td>
<td><?= $rec["summary"] ?></td>
<tr>
<?php } ?>
</tbody>
</table>
<div id="loading_layer" style="display:none">
<div id="loading_inner"><div id="loading_msg">Now Loading...</div></div>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>
<script>
jQuery(function($){
$("#calendar_id").on("change", function(){
$("#loading_layer").show();
location.href = "./?calender_idx=" + $(this).val();
});
});
</script>
</body>
</html>
}}
#html(</div>)
*** APIリファレンス [#me3105f5]
#html(<div style="padding-left:10px;">)
以下はAPIのエンドポイントを直叩きする場合用の記載になっているが、クライアントAPIを利用する場合でもオプション引数などはそのまま使える。
https://developers.google.com/google-apps/calendar/v3/reference/
#html(</div>)
*** サンプルソース [#t8c0d4d0]
#html(<div style="padding-left:10px;">)
https://github.com/google/google-api-php-client
https://github.com/google/google-api-php-client/tree/master/examples
#html(</div>)