Google Cloud Storage に google-api-php-client で普通にアップロード 


先ほど次のような記事を書きましたが。

- [Google Cloud Storage に AWS CLI や AWS SDK for PHP でアップロード](http://qiita.com/ngyuki/items/fd3bb47cd4aeb2f61fec "Google Cloud Storage に AWS CLI や AWS SDK for PHP でアップロード")
- [Google Cloud Storage に S3 互換の REST でアップロード](http://qiita.com/ngyuki/items/e84e895130de95a5ca7a "Google Cloud Storage に S3 互換の REST でアップロード")

よく考えたら普通に SDK とか使って Google Cloud Storage にアップロードしたことないな、と思ったのでやってみました。

## Client ID の作成

[デベロッパーコンソール](https://console.developers.google.com/) を開きます。

- [https://console.developers.google.com/](https://console.developers.google.com/)

対象のプロジェクトを選択します。

![01-projects.png][01-projects.png]

「APIと認証」の「認証情報」を選択して「新しいクライアント ID を作成」をクリックします。

![02-create-client.png][02-create-client.png]

アプリケーションの種類に「サービスアカウント」を選択し、キーのタイプに「JSONキー」を選択します。

![03-service-account.png][03-service-account.png]

「クライアント ID を作成」をクリックすると、JSON ファイルがダウンロードされます。
メッセージの通りこのファイルは大切なファイルなので、誰にも見られないように大切に保管してください。

![04-download-key.png][04-download-key.png]

元の画面に戻ると、次のようにクライアント ID が追加されています。

![05-key-generated.png][05-key-generated.png]

## PHP コードの作成

ほとんど下記の通りです。

- https://gist.github.com/AidanThreadgold/9997654

[google-api-php-client](https://packagist.org/packages/google/apiclient) をインストールします。packagist に登録されているので composer でインストールできます。

```
composer require google/apiclient:\*
```

次のように使います。詳細はコードのコメントを見てください。

```php
<?php
require __DIR__ . '/vendor/autoload.php';

// JSON キーファイルのパス
$privateJsonPath = __DIR__ . '/private.json';

// アクセストークンのパス
$accessTokenPath = __DIR__ . '/cache/accessToken.txt';

// API クライアントを作成してアプリケーション名をつける
// アプリケーション名はなんでも良いっぽい
$client = new Google_Client();
$client->setApplicationName("My Application");

// キャッシュを無効にする
$client->setCache(new Google_Cache_Null($client));

// アクセストークンが既にあるなら使う
if (is_file($accessTokenPath)) {
    $client->setAccessToken(file_get_contents($accessTokenPath));
}

// JSONキーからクレデンシャルをロードする
// スコープには Storage の read/write を指定する
$credential = $client->loadServiceAccountJson(
    $privateJsonPath,
    [Google_Service_Storage::DEVSTORAGE_READ_WRITE]
);

// クレデンシャルをクライアントに設定する
$client->setAssertionCredentials($credential);

/* @var $auth Google_Auth_OAuth2 */
$auth = $client->getAuth();

// アクセストークンの有効期限を確認する
// 有効期限切れなら再取得して保存する
if ($auth->isAccessTokenExpired()) {
    $auth->refreshTokenWithAssertion($credential);
    file_put_contents($accessTokenPath, $client->getAccessToken());
}

// ストレージサービスを作成する
$storage = new Google_Service_Storage($client);

// アップロードするファイル名とデータ
$name = "ore/sample.txt";
$data = "ore no sample";

// ストレージオブジェクトを作成する
$obj = new Google_Service_Storage_StorageObject();
$obj->setName($name);

// アップロードする
$storage->objects->insert("ngyuki-testing",$obj, [
    'name' => $name,
    'data' => $data,
    'uploadType' => 'media',
]);
```

JSON ファイル（の中に含まれている P12 証明書）を用いてアクセストークンを取得し、そのアクセストークンを使ってストレージサービスにファイルをアップロードするようです。

なので、tcpdump とかで見てみると初回は２回リクエストが飛びます。

２回目以降は保存されたアクセストークンを使うので１回しかリクエストが飛びません。

なお、変数 `$accessTokenPath` のパスにアクセストークンを保存するようにしていますが、実はそんなことしなくてもデフォで勝手にアクセストークンはキャッシュされます。

が、なんか微妙な位置に保存されるので、あえて
  `$client->setCache(new Google_Cache_Null($client))`
のようにデフォのキャッシュは無効にしています。

- [google-api-php-client src/Google/Config.php#L139](https://github.com/google/google-api-php-client/blob/517fc2bb11d2d3cfd27af3f783fce6f2f61c688c/src/Google/Config.php#L139)

あるいは次のようにデフォのキャッシュの位置を変更することもできます。

```php
<?php
require __DIR__ . '/vendor/autoload.php';

// JSON キーファイルのパス
$privateJsonPath = __DIR__ . '/private.json';

// キャッシュディレクトリのパス
$cachePath = __DIR__ . '/cache';

// API クライアントを作成してアプリケーション名をつける
// アプリケーション名はなんでも良いっぽい
$client = new Google_Client();
$client->setApplicationName("My Application");

// キャッシュディレクトリを指定する
$client->setClassConfig(Google_Cache_File::class, ['directory' => $cachePath]);

// JSONキーからクレデンシャルをロードする
// スコープには Storage の read/write を指定する
$credential = $client->loadServiceAccountJson(
    $privateJsonPath,
    [Google_Service_Storage::DEVSTORAGE_READ_WRITE]
);

// クレデンシャルをクライアントに設定する
$client->setAssertionCredentials($credential);

// ストレージサービスを作成する
$storage = new Google_Service_Storage($client);

// アップロードするファイル名とデータ
$name = "ore/sample.txt";
$data = "ore no sample";

// ストレージオブジェクトを作成する
$obj = new Google_Service_Storage_StorageObject();
$obj->setName($name);

// アップロードする
$storage->objects->insert("ngyuki-testing",$obj, [
    'name' => $name,
    'data' => $data,
    'uploadType' => 'media',
]);
```

[01-projects.png]: https://qiita-image-store.s3.amazonaws.com/0/8734/2d9a9ba3-a22e-9a58-d602-dab5ba733b45.png
[02-create-client.png]: https://qiita-image-store.s3.amazonaws.com/0/8734/8aef63f2-db67-7b3f-2911-57102bbef6a8.png
[03-service-account.png]: https://qiita-image-store.s3.amazonaws.com/0/8734/724234be-ad90-2fd8-da3e-55249a1e894a.png
[04-download-key.png]: https://qiita-image-store.s3.amazonaws.com/0/8734/86c815c4-3a0b-e519-1971-0e9c522bae34.png
[05-key-generated.png]: https://qiita-image-store.s3.amazonaws.com/0/8734/e5f8177d-b296-2787-efe3-e0e7781b8724.png