1. はじめに
週間スケジュールを○×で表示するシステムを作成しました。当初はGoogleカレンダーと自動連携する仕様を目指しましたが、OAuth認証の設定で予期せぬ問題に直面し、最終的には手動更新方式に方針転換しました。この記事では、その開発過程と最終的な実装方法を記録します。
2. 実現したい機能
4つの固定時間帯について、月曜から金曜までの空き状況を○×で表示するシステムです。時間帯は10:15-10:55、11:30-12:10、13:15-13:55、14:30-15:10の4つ。今週から3週後までの4週間分を切り替えて表示できる仕様です。
他の人に空き状況を共有するため、カレンダーの予定には個人名などの詳細情報が含まれていても、公開ページには○×のみを表示します。
3. 当初の構想:Googleカレンダー連携
最初は、自分のGoogleカレンダーから予定を自動で読み取り、指定した時間帯に予定が入っているかを判定して○×を表示する仕組みを考えました。これには、カレンダーの情報にアクセスするための認証(OAuth 2.0)が必要です。
3.1. OAuth 2.0とは
OAuth 2.0は、他のサービスのデータに安全にアクセスするための仕組みです。銀行のATMに例えると分かりやすいでしょう。プロジェクトは銀行口座、Calendar APIは預金を見る権限、クライアントIDはキャッシュカード、クライアントシークレットは暗証番号に相当します。
3.2. Google Cloud Consoleでの設定
Googleカレンダーにアクセスするには、Google Cloud Consoleで以下の設定が必要でした。
まず、プロジェクトを作成します。これは「週間スケジュールというアプリを作ります」とGoogleに登録する手続きです。次に、Google Calendar APIを有効化します。これで「このアプリはGoogleカレンダーの情報を読み取ります」という許可を取得できます。
最後に、OAuthクライアントIDとクライアントシークレットを作成します。これらはアプリの身分証明書と秘密の合言葉のようなもので、正しいアプリからのアクセスであることをGoogleに証明します。
3.3. PHPでの実装
PHPでカレンダーデータを取得するため、cURLを使ってGoogleのAPIに直接リクエストを送る方法を試しました。認証コードを取得し、それをアクセストークンに交換してからカレンダー情報を読み取る流れです。
// 認証URLにリダイレクト
$authUrl = 'https://accounts.google.com/o/oauth2/v2/auth?' . http_build_query($params);
header('Location: ' . $authUrl);
// コールバックでトークン取得
$response = curl_exec($ch);
$token = json_decode($response, true);
Code language: PHP (php)
3.4. 遭遇した問題
OAuth認証の設定を進める中で、「invalid_client」というエラーが発生しました。クライアントIDとシークレットは正しく設定されており、リダイレクトURIも一致していました。テストユーザーの登録やスコープの設定も確認しましたが、エラーは解消されませんでした。
HTTPステータスコード401が返され、「Unauthorized」というメッセージが表示されます。デバッグ情報を出力して送信パラメータを確認しても、すべて正しく設定されているように見えました。
HTTPステータス: 401
送信したパラメータ:
Array
(
[code] => 4/0AVGzR1BtDrDJBX9v5Xs...
[client_id] => ****
[client_secret] => ***
[redirect_uri] => https://chiilabo.jp/schedule/callback.php
[grant_type] => authorization_code
)
レスポンス:
{
"error": "invalid_client",
"error_description": "Unauthorized"
}
Code language: PHP (php)
3.5. 原因の探索
いくつかの可能性を検証しました。クライアントシークレットの再生成、Content-Typeヘッダーの明示的な指定、JavaScript生成元の削除などを試しましたが、状況は変わりませんでした。
参考サイトを調べると、多くの実装例でGoogle公式のPHPライブラリ(google/apiclient)を使っていることが分かりました。cURLで直接HTTPリクエストを送る方法は複雑でエラーが起きやすく、公式ライブラリを使う方が確実です。
4. 方針転換:手動更新版への切り替え
OAuth認証の問題解決に時間がかかることが明らかになったため、手動で○×を入力する方式に切り替えることにしました。Googleカレンダーは自分で確認し、管理画面から空き状況を入力します。他の人には完成したスケジュール表だけを見せる仕組みです。
この方式には明確な利点があります。認証の複雑な設定が不要で、確実に動作します。情報を自分でコントロールでき、個人情報の扱いも安全です。
5. システムの構成
最終的なシステムは3つのPHPファイルで構成されます。
config.phpは設定ファイルです。時間帯の定義、データファイルのパス、管理画面のパスワード、週の日付を取得する関数、データの読み書き関数を含みます。
admin.phpは管理画面です。パスワード認証でログインし、週ごとにチェックボックスで○×を設定します。データはJSON形式で保存されます。
index.phpは公開ページです。保存されたデータを読み込んで○×を表示します。週の切り替えボタンで今週から3週後まで表示できます。
6. 実装の詳細
6.1. データ構造
空き状況のデータはJSON形式で保存します。週の開始日をキーとし、時間帯と曜日のインデックスで○×を管理します。
{
"2025-09-22": {
"0": {
"0": "×",
"1": "×",
"2": "○",
"3": "○",
"4": "○"
},
"1": {
"0": "○",
"1": "×",
...
}
}
}
Code language: JavaScript (javascript)
週の開始日(月曜日)をキーにすることで、どの週のデータかを一意に識別できます。時間帯は0から3、曜日は0から4のインデックスで表現します。
6.2. 週の日付計算
現在の日付から指定した週の月曜日を計算する関数を実装しました。
function getWeekDates($weekOffset = 0) {
$monday = new DateTime();
$monday->modify('monday this week');
$monday->modify('+' . ($weekOffset * 7) . ' days');
$dates = [];
for ($i = 0; $i < 5; $i++) {
$date = clone $monday;
$date->modify('+' . $i . ' days');
$dates[] = $date;
}
return $dates;
}
Code language: PHP (php)
DateTimeクラスのmodifyメソッドを使うと、「今週の月曜日」や「7日後」といった相対的な日付計算が簡単にできます。$weekOffsetに0を渡すと今週、1なら来週、2なら再来週、3なら3週後の日付を取得できます。
6.3. 管理画面の認証
管理画面にはパスワード認証を実装しました。セッションを使ってログイン状態を保持します。
session_start();
if (isset($_POST['login'])) {
if ($_POST['password'] === ADMIN_PASSWORD) {
$_SESSION['admin_logged_in'] = true;
}
}
if (!isset($_SESSION['admin_logged_in'])) {
// ログインフォームを表示
exit;
}
Code language: PHP (php)
セッションは、PHPでユーザーの状態を保持する仕組みです。ログインすると$_SESSION['admin_logged_in']にtrueが設定され、ページを移動してもログイン状態が維持されます。
6.4. データの保存と読み込み
チェックボックスの状態をPOSTで受け取り、JSON形式で保存します。
if (isset($_POST['save'])) {
$data = loadData();
$weekKey = $_POST['week_key'];
foreach ($timeSlots as $slotIndex => $slot) {
for ($dayIndex = 0; $dayIndex < 5; $dayIndex++) {
$key = "status_{$slotIndex}_{$dayIndex}";
$data[$weekKey][$slotIndex][$dayIndex] = isset($_POST[$key]) ? '○' : '×';
}
}
saveData($data);
}
Code language: PHP (php)
チェックボックスはチェックされた項目のみがPOSTされるため、isset()で存在を確認します。チェックされていれば○、されていなければ×を設定します。
6.5. 公開ページの表示
保存されたデータを読み込んで表示します。データが存在しない場合は×をデフォルト値として表示します。
$data = loadData();
$currentData = $data[$weekKey] ?? [];
$status = $currentData[$slotIndex][$dayIndex] ?? '×';
$class = $status === '○' ? 'available' : 'unavailable';
Code language: PHP (php)
null合体演算子(??)を使うと、データが存在しない場合のデフォルト値を簡潔に設定できます。CSSクラスを切り替えて、○は緑、×は赤で表示します。
7. デザインの工夫
シンプルで見やすいデザインを心がけました。白を基調とした背景に、影を付けたカードデザインで表を囲みます。
週の切り替えボタンは、選択中のボタンを青色で強調表示します。ホバー時の背景色変化でクリック可能であることを示します。
○×の表示は大きなフォントサイズ(36px)で視認性を高めました。○は緑(#34a853)、×は赤(#ea4335)で色分けし、直感的に空き状況が分かります。
8. 使用方法
config.phpのADMIN_PASSWORDを適切なパスワードに変更します。3つのファイルをサーバーにアップロードしたら、admin.phpにアクセスしてログインします。
チェックボックスで○×を設定して保存ボタンをクリックすると、データが保存されます。週の切り替えボタンで4週間分のスケジュールを管理できます。
公開ページのURL(index.php)を他の人に共有すれば、空き状況を確認してもらえます。
9. 得られた知見
OAuth認証は想像以上に複雑でした。設定項目が多く、エラーメッセージも必ずしも明確ではありません。公式ドキュメントを読んでも、実際の実装では予期しない問題に遭遇することがあります。
一方、手動更新方式は実装がシンプルで、トラブルシューティングも容易です。機能は限定されますが、確実に動作するシステムを短時間で構築できました。
完璧な自動化を目指すよりも、まず動くものを作ることが重要だと実感しました。自動化は後から追加できますが、基本的な機能が動作しなければ意味がありません。
10. まとめ
Googleカレンダー連携を目指した週間スケジュール表示システムの開発において、OAuth認証の設定で問題が発生し、手動更新方式に切り替えました。最終的にPHP、JSON、セッション認証を組み合わせた実用的なシステムを構築できました。管理画面で空き状況を入力し、公開ページで○×表示する仕組みは、シンプルながら効果的に機能しています。