PHP8.2.0にて、スプレッドシートの読み込みと書き込み時のエラー解決方法

PHP8.2.0を使用してスプレッドシートの読み込み、書き込みを行う方法
何かの手順通りにやってみたところエラーが出て困ったので、解決方法を残しておきます

# 実行環境
windows10のxamppのlocalhost内に配置したphpファイルを、コマンドプロンプトから実行

![php6.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/187537/3a0ad958-eb3b-4ff7-1201-f553e8cd0f13.png)



# 読み込み、書き込みに使用した実際のソースコード
```php

require_once __DIR__ . '/vendor/autoload.php';

$key =  __DIR__ . '/API_KEY/independent-bay-xxxxxxxxxxx自分のファイルパスに書き換えてください。私はAPI_KEYフォルダの中に入れたので、こういうパスになっていますxxxxxxxxxxxxx.json';//取得したサービスキーのパスを指定

$client = new Google_Client();//Googleクライアントインスタンスを作成
$client->setScopes([//スコープを以下の内容でセット
    \Google_Service_Sheets::SPREADSHEETS,
    \Google_Service_Sheets::DRIVE,]);
$client->setAuthConfig($key);//サービスキーをセット

$sheet = new Google_Service_Sheets($client);//シートを操作するインスタンス
$sheet_id = 'xxxxxxxxxxx自分のスプレッドシートIDに書き換えてくださいxxxxxxxxxxxxxxxx';//対象のスプレッドシートのIDを指定

//取得範囲を指定（書き方: シート名+ビックリマーク+範囲の左上のセル+コロン+範囲の右下のセル)(data!A1:C3と書くと、dataというシートのセルA1～C3を指定したことになる）
//※自分のシート名と範囲に書き換えてください。私はシートの名前を「Sheet_spleadAPI」なので下記のようになっています。
$range = 'Sheet_spleadAPI!A1:C3';

//多分スプレッドシートにアクセスしている
$response = $sheet->spreadsheets_values->get($sheet_id, $range);

//返ってきたresponseから、セルの値（配列）を取得して、変数に格納
$values = $response->getValues();//帰ってきたresponseから値を取得

//取得したセルの値（配列）を表示してみる
print_r($values);

/*
print_r($values); の結果は下記のようにコマンドプロンプトに表示された。
※スプレッドシートには事前に"b"を書いて置いた

Array
(
    [0] => Array
        (
            [0] => b
            [1] => b
            [2] => b
        )

    [1] => Array
        (
            [0] => b
            [1] => b
            [2] => b
        )

    [2] => Array
        (
            [0] => b
            [1] => b
            [2] => b
        )

)
*/


//書き込み範囲を指定（書き方: シート名+ビックリマーク+範囲の左上のセル+コロン+範囲の右下のセル)(data!A1:C3と書くと、dataというシートのセルA1～C3を指定したことになる）
//必ず、書き込む内容の配列と同じ形にする。今回は2行3列のデータを書き込むので、A6:C7(2行3列)を指定している
$range = 'Sheet_spleadAPI!A6:C7';

//書き込む内容を配列にて指定指定
$values = [
    ["jog","dio","audi"],
    ["jog","dio","audi"]
    ];


//書き込む内容を収めた配列をbodyに格納
$body = new Google_Service_Sheets_ValueRange(['values' => $values]);

/*
　いよいよシートの該当範囲に書き込む内容を反映します。
　ValueInputOptionは値を書き込む際の形式指定で、
　「RAWS」、もしくは「USER_ENTERED」のいずれかで指定します。
　特にこだわりがない場合は「USER_ENTERED」で問題ありません。 （との事。）
*/
$sheet->spreadsheets_values->update($sheet_id, $range, $body, ["valueInputOption" => 'USER_ENTERED']);
```






# 下準備

## Google Sheets APIを利用する準備
PHPでスプレッドシートの読み書きを行う場合、Google Sheets APIを使用することが一般的です。Google Sheets APIを使用するには、vendorをインストールする必要があるらしいので、
windows コマンドプロンプトにて、"phpファイルを置いてあるディレクトリに移動した後"、下記コマンドを実行する。
すると当該ディレクトリにvendorフォルダが作成される。（その中には沢山のphpファイル(API)が入っていました。）
```
composer require google/apiclient:"^2.0"
```


## スプレッドシートにアクセスするためのAPIを有効化して、認証情報(.jsonファイル)をダウンロードしておく
下記記事にAPIの有効化方法と、認証情報(.jsonファイル)のダウンロード方法が書いてあります
https://sterfield.co.jp/programmer/google%E3%82%B9%E3%83%97%E3%83%AC%E3%83%83%E3%83%89%E3%82%B7%E3%83%BC%E3%83%88%E3%81%AE%E3%83%87%E3%83%BC%E3%82%BF%E3%82%92php%E3%81%A7%E5%8F%96%E5%BE%97/

ダウンロードしたjsonファイルは、任意の場所に保存しておきましょう。
私はphpファイルと同じ階層に「API_KEY」というフォルダを作り、その中に入れました。
    このjsonファイルのパスは、phpファイルに記述してください。

## スプレッドシートの共有で(APIを利用するサービスアカウント? ※すみませんこのあたりはあまり理解していない)を招待する。
ダウンロードした認証情報(.jsonファイル)をテキストエディタで開くと、下記のようなメールアドレスがあります。
●●●●●●●●●@independent-bay-●●●●●●.iam.gserviceaccount.com
スプレッドシートを開いて、右上の「共有」を押して、[ユーザーやグループを追加]という入力フォームにメールアドレスを入れて、「編集者」を選択して、「送信」を押下。これだけでOK。
※メールを開いてクリックとかそういうのはいらない。「送信」を押すだけで、共有された事になりました


# エラー解決方法

## スプレッドシート書き込み時のエラー
```
PHP Fatal error:  Uncaught TypeError: implode(): Argument #2 ($array) must be of type ?array, string given in C:\xampp\htdocs\youtube_live\php_spleadSheetAPI_test\vendor\google\apiclient\src\Google\Service\Resource.php:295
```

原因は、PHPの純正のimplode()メソッドの仕様変更によるものらしい。
下記サイトによると、引数の順番が変更になっている。
https://www.php.net/manual/ja/function.implode.php
```php
//▼古い書き方。（エラーになる書き方)
implode(配列,文字列)
//▼新しい書き方
implode(文字列, 配列)
```

上記を直す為に、インストールしたvendor内にある下記のphpファイルを、下記のように書き換えます
### ▼書き換え前
```php:vendor\google\apiclient\src\Google\Service\Resource.php 290行目あたり
    if (count($queryVars)) {
      $requestUrl .= '?' . implode($queryVars, '&');
    }
```

### ▼書き換え後。以下のように修正すると、エラーが無くなり、スプレッドシートに書き込みが出来た。
修正内容：implode関数に渡されている引数の順番を逆にした。$queryVarsは配列だったので、第二引数に持ってきた。
```php:vendor\google\apiclient\src\Google\Service\Resource.php
    if (count($queryVars)) {
      $requestUrl .= '?' . implode('&', $queryVars);
    }
```


## スプレッドシート読み込みする時に出るエラー

```
Fatal error: Uncaught TypeError: count():
```
これを解消する方法は下記です。インストールしたvendor内にある下記のphpファイルを書き換えます

```php: vendor\guzzlehttp\guzzle\src\Handler\CurlFactory.php 64行目あたり
    public function release(EasyHandle $easy)
    {
        $resource = $easy->handle;
        unset($easy->handle);
        //以下の1行をコメントアウトしました。
        //if (count($this->handles) >= $this->maxHandles) {
        //以下の1行を追加しました
        if(count((array)$this-> handles) >= $this-> maxHandles){
            curl_close($resource);
        } else {
            // Remove all callback functions as they can hold onto references
            // and are not cleaned up by curl_reset. Using curl_setopt_array
            // does not work for some reason, so removing each one
            // individually.
            curl_setopt($resource, CURLOPT_HEADERFUNCTION, null);
            curl_setopt($resource, CURLOPT_READFUNCTION, null);
            curl_setopt($resource, CURLOPT_WRITEFUNCTION, null);
            curl_setopt($resource, CURLOPT_PROGRESSFUNCTION, null);
            curl_reset($resource);
            $this->handles[] = $resource;
        }
    }

```
(参考ページ:https://qiita.com/Takahiro_Inoway/items/fb2c847a23e7ff039840)


# まとめ
上記２つのphpファイルを修正した事により、
PHPにてスプレッドシートのとある範囲の読み込みと、
PHPにてスプレッドシートのとある範囲への書き込みが出来ました。

▼PHPプログラム実行前のスプレッドシートの状態(読み込み予定のセルに　ひらがな　を入れておきました）
![1.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/187537/ad99d0e3-4d67-fa9f-09de-ed31b6869298.png)

▼PHPプログラム実行後のコンソールの状態（スプレッドシートの値を読み込む事に成功している)
![2.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/187537/894a8282-7a66-a4ea-9d4a-abf1903ca536.png)


▼PHPプログラム実行後のスプレッドシートの状態（A6:C7の範囲への書き込みに成功している)
![3.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/187537/4fd6a025-14ca-da6a-6bd9-f236822c43af.png)