👻

【Laravel】Storageを利用せずに、SDKを利用してGCSに画像をアップロードする

2023/04/22に公開

この記事について

Laravel の FileSystem を利用して GCS に画像をアップロードする ことは割と往々にしてあると思います。

https://laravel.com/docs/5.0/filesystem

AWSのS3を利用する場合は、デフォルトでStorage::disk('s3')として利用できるのですが、GCSの場合は、デフォルトでは利用できません。

今回は、SDKを利用して、GCSに画像をアップロードする方法を紹介します。

https://cloud.google.com/php/docs/reference/cloud-storage/latest/StorageClient

対象読者

  • Storageを経由せずに、SDKを利用してGCSに画像をアップロードする方法を知りたい方

SDKを利用してGCSに画像をアップロードする

SDKをインストールする

まずは、SDKをインストールします。

$ composer require google/cloud-storage

GCSの認証情報を取得する

GCSの認証情報を取得します。

https://cloud.google.com/docs/authentication/getting-started

今回は、JSON形式で取得します。

バージョン管理はしないので、.gitignoreに追加しておきます。

$ echo "storage/app/google-cloud-storage.json" >> .gitignore

GCSを操作するクラスを作成する

毎回、認証情報を読み込んで、GCSのクライアントを作成するのは面倒なので、クラスを作成して、インスタンス化して利用します。

まずは、コードの全体像を見てみましょう。

<?php

namespace App\utilities;

use DateTime;
use Google\Cloud\Storage\Bucket;
use Google\Cloud\Storage\StorageClient;

class GcsProviderService
{
    private Bucket $gcsBucket;

    public function __construct()
    {
        $projectID = config('app.gcp_bucket_name', 'hoge');
        $keyPath = file_get_contents(storage_path('app/google-cloud-storage.json', true));

        $storage = new StorageClient([
            'projectId' => $projectID,
            'keyFile' => json_decode($keyPath, true),
        ]);

        $this->gcsBucket = $storage->bucket($projectID);
    }

    public function getGcsBucket(): Bucket
    {
        return $this->gcsBucket;
    }

    public function getSignedUrl($filePath)
    {
        $bucket = $this->getGcsBucket();
        $object = $bucket->object($filePath);
        $expiration = new DateTime('+24 hour');

        if(!$object->exists()){
            return null;
        }

        return $object->signedUrl($expiration);
    }

    public function uploadFile($file, $prefix)
    {
        if (!$file->isValid()) {
            return null;
        }

        $fileContents = file_get_contents($file);
        $bucket = $this->getGcsBucket();
        $object = $bucket->upload(
            $fileContents,
            [
                'name' => $prefix . '/' . $file->getClientOriginalName()
            ]
        );

        if ($object && $object->info()['selfLink']) {
            return $object->info()['selfLink'];
        }
        return null;
    }
}

コードの説明

GCSは、バケットという単位でファイルを管理します。

StorageClientを利用することで、GCSにアクセスすることができます。

毎回、StorageClientをインスタンス化するのは面倒なので、コンストラクタでインスタンス化して、プロパティに保持しておきます。

<?php

 $storage = new StorageClient([
            'projectId' => $projectID,
            'keyFile' => json_decode($keyPath, true),
]);

file_get_contents($file) でBufferを取得して、$bucket->upload でアップロードします。

この手順を踏むことで、GCSに画像をアップロードすることができます。

Bufferを取得せずにファイル情報をそのままアップロードしても成功はしますが、画像の実体がGCSにアップロードされないので、注意が必要です。

$fileContents = file_get_contents($file);

サインURLを取得する

GCSにアップロードした画像を、ブラウザから参照する場合は、サインURLを取得する必要があります。

サインURLを取得するには、$object->signedUrl($expiration) を利用します。

有効期限を指定する必要がありますので、DateTime を利用します。

exists で、ファイルが存在するかを確認してから、サインURLを取得しするようにすることで万が一、ファイルが存在しない場合にエラーを回避することができます。

<?php
    public function getSignedUrl($filePath)
    {
        $bucket = $this->getGcsBucket();
        $object = $bucket->object($filePath);
        $expiration = new DateTime('+24 hour');

        if(!$object->exists()){
            return null;
        }

        return $object->signedUrl($expiration);
    }

最後に

GCSに画像をアップロードする方法を紹介しました。

Storageを利用する場合と比べると、少し面倒ですが、SDKを利用することで、柔軟にGCSを利用することができます。

S3を利用する場合は Storage::disk('s3') で利用できるので、SDKを利用する必要は基本的にないと思います。

必要に応じて、SDKを利用して、GCSを利用してみてください。

また、認証情報をバージョン管理しないように、.gitignoreに追加することを忘れないようにしてください。

GitHubで編集を提案

Discussion