Apache+PHP+Google Sheets API+GCPサービスアカウントでスプレッドシートを操作するまで

# はじめに
今回は下記の環境を構築して、PHPからスプレッドシートを操作できるようにしてみました。
- Windows
- Apache2.4
- PHP8.2 (フレームワークはなし)
    - Google API Client (認証はGCPサービスアカウント)

その環境構築手順の忘備録です。また、本記事は「とりあえずスプレッドシートを更新できるようにしたい」という初学者による記事ですので、本番運用で使用するには設定等の精査をしてください！


# 環境構築
### 1. GCPサービスアカウントの準備
[Google公式](https://cloud.google.com/docs/authentication/production?hl=ja) に従って、GCPサービスアカウントの作成をします。
合わせて、対象のプロジェクトでGoogle Sheets APIを有効化しておきます。
下記は2023年9月時点でのGoogle公式サイトからの引用です。

#### GCPサービスアカウント作成
> 1. Google Cloud コンソールで [サービス アカウントの作成] ページに移動します。
> 2. プロジェクトを選択します。
> 3. [サービス アカウント名] フィールドに名前を入力します。Google Cloud コンソールでは、この名前に基づいて [サービス アカウント ID] フィールドに値が設定されます。
 [サービス アカウントの説明] フィールドに説明を入力します。例: Service account for quickstart
> 4. [作成して続行] をクリックします。
> 5. サービス アカウントに Project > Owner ロールを付与します。
    ロールを付与するには、[ロールを選択] リストで [Project > Owner] を選択します。
> 6. [続行] をクリックします。
> 7. [完了] をクリックして、サービス アカウントの作成を完了します。

#### GCPサービスアカウントのキー作成
> 1. Google Cloud コンソールで、作成したサービス アカウントのメールアドレスをクリックします。
> 2. [キー] をクリックします。
> 3. [鍵を追加]、[新しい鍵を作成] の順にクリックします。
> 4. [作成] をクリックします。JSON キーファイルがパソコンにダウンロードされます。
> 5. [閉じる] をクリックします。

これらの手順で、サービスアカウントのJSONキーファイルをダウンロードできるので保管しておく。



### 2. Apacheの構築
WindowsにApache2.4環境を構築します。
今回はXAMPPではなく単品でインストールし、Google APIを試すのに必要最低限の設定を行います。

1. Apache2.4インストール
    [Apache公式](https://httpd.apache.org/)からApache2.4以上のWindows版(Files for Microsoft Windows)をダウンロードする。
    解答したフォルダをCドライブ直下に配置し、`C:\Apache24`とする。
1. 環境変数を追加
    [システム]->[システムの詳細設定]->[環境変数]ボタンクリック->[システム環境変数]の欄にあるPATHを編集し、`C:\Apache24\bin`を追加する。
1. Apacheの設定ファイル変更
    `C:\Apache24\conf`をメモ帳などで開いて編集する。
    * ServerNameの変更 : `ServerName localhost:80`
    * 他は基本的にデフォルト
1. Apacheのサービス登録
    コマンドプロンプトを管理者権限で起動する。
    `cd C:\Apache24\bin`で移動し、`httpd -k install` を実行する。
1. Apache起動
    `C:\apache24\bin\httpd.exe`をダブルクリックで起動する。
1. Apache起動確認
    ブラウザを開いてURL欄に`localhost`と入力して、Apacheのおなじみの「It Works!」の画面になれば成功。




### 3. PHPの構築
WindowsにPHP8.2を構築します。
ここでもGoogle APIを試すのに必要最低限の設定をしていきます。

1. PHP8.2インストール
    [PHP公式サイト](https://www.php.net/downloads)からPHP8.2のWindows版(Thread Safe)をダウンロードする。  
    ダウンロードしたファイルは解凍し、`C:\PHP\(解凍したPHPフォルダ)`となるパスに配置。

    ※ここで`C:\PHP\`フォルダ直下をインストールフォルダとしていないのは、複数バージョンのPHPを共存させることを考えて、フォルダ階層を一つ増やして`C:\PHP\(解凍したフォルダ)`としています。

    ::::note warn
    ※注意)
    使用する「google-api-php-client」がPHP7.4以上という動作環境なのでバージョンに注意
    つまり、Apacheは必然的に2.4以上のバージョンが必要

1. 環境変数を追加
    [システム]->[システムの詳細設定]->[環境変数]ボタンクリック->[システム環境変数]の欄にあるPATHを編集し、`C:PHP\(解凍したフォルダ)\`を追加する。
1. Apache側にPHPの設定
    `C:\Apache24\conf`をテキストエディタで開き、ファイルの末尾に下記を追加。
    PHP7系の時は`php7_module`だったのに8系は```php_module```に変わったという罠があった…。
    ```
    LoadModule php_module "c:/php/(解凍したPHPフォルダ)/php8apache2_4.dll"
    AddHandler application/x-httpd-php .php
    
    # configure the path to php.ini
    PHPIniDir "C:/php/(解凍したPHPフォルダ)"
    ```
1. PHP動作確認
    `C:\Apache24\htdocs`配下にphpinfo.phpを作成し、中に`<?php phpinfo(); ?>`を記述する。
    ブラウザから`http://localhost/phpinfo.php`にアクセスして、PHPのバージョン情報ページが表示されれば成功。

1. PHP設定
    `c:/php/(解凍したPHPフォルダ)/php.ini`をテキストエディタで編集する。
    ※注) どの環境でも本手順でうまくいくのかは正直分かりませんが、私の環境では当手順で構築しました。

    * `extension_dir = "ext"`　のコメントを外す。
    * `extension=openssl` のコメントを外す。
    * `extension=curl` のコメントを外す。
    * curl公式  [https://curl.haxx.se](https://curl.haxx.se)  からcacert.pemをダウンロード。
    `curl.cainfo=` のコメントを外し、右辺にダウロードしたpemファイルへのパスを記載。

    日本語化・日本時刻の設定もしておく。
    * `date.timezone = "Asia/Tokyo"`　を記述
    * `extension=mbstring` のコメントを外し、下記をセットで設定しておく
        ```
        mbstring.language = Japanese
        mbstring.encoding_translation = Off
        mbstring.detect_order = UTF-8,SJIS,EUC-JP,JIS,ASCII
        mbstring.substitute_character = none
        mbstring.strict_detection = Off
        ```

# コーディング
### 4. google-api-php-clientのダウンロード
ここではComposerは使わずにSourceを展開する方式で構築していきます。

1. こちらのGitHubからPHPのバージョンに合わせて「google-api-php-client--PHP8.2.zip」をダウンロードする。 
    [https://github.com/googleapis/google-api-php-client](https://github.com/googleapis/google-api-php-client)
2. 解答したフォルダを任意の場所に展開する。
    「google-api-php-client--PHP8.2」を「google-api-php-client」にフォルダ名を変更。
    ここでは`C:\apache24\httpd\TestProj\google-api-php-client\`フォルダに配置。
3. PHPのソース作成
    `C:\apache24\httpd\TestProj\test.php`を作成。
    だいたいこんな感じでサンプルを組んだ。

    ``` PHP
    require_once __DIR__.'/google-api-php-client/vendor/autoload.php';
    
    $client = new Google_Client();
    $client->setScopes(Google_Service_Sheets::SPREADSHEETS);
    $client->setAuthConfig(サービスアカウントキーのJSONファイルを配置したパス);
    $service = new Google_Service_Sheets($client);
    
    $spreadsheetId = 'スプレッドシートのID';
    $range = 'シート1!A2:e2';
    $values = [[date('Y-m-d'), date('H:i:s'), "c", "d", "e"]];
    $updateBody = new Google_Service_Sheets_ValueRange([
      'values' => $values
    ]);
    $params = [valueInputOption' => 'USER_ENTERED'];
    $result = $service->spreadsheets_values->update($spreadsheetId, $range, $updateBody, $params);
    );
    ```
4. スプレッドシートの共有化
    スプレッドシートをGCPサービスアカウントに対して共有化をしておきます。
5. PHPを実行
    スプレッドシートが更新されれば成功！
    * 実行したときのつまづきポイント
        * curlがちゃんと有効になっていないと、下記のエラーが発生した。
    参考：https://github.com/googleapis/google-api-php-client/issues/843
    「Fatal error: Uncaught GuzzleHttp\Exception\ConnectExeption: Connection refused for URI https://oauth2.googleapis.com/token in C:\~~~~\google-api-php-client\vendor\guzzlehttp\guzzle\src\Handler\StreamHandler.php:328」
        * opensslが有効化できていないと、認証ができずに下記のようなエラーが発生した。
        「Fatal error: Uncaught Error: Call to undefined openssl_sign() in ~~~(フォルダパス)~~~\google-api-client\vendor\firebase\php-jwt\src\JWT.php:242」
        * スプレッドシートをGCPサービスアカウントに対して共有化するのを忘れていてPermissionエラーになった。

ここまで環境構築できれば、あとはスプレッドシートに対して取得するなり更新するなり自由！

# 参考文献
ありがとうございました。

https://agohack.com/writing-values-using-google-sheets-api-php/