💡

Laravel + GCS でstorage管理していたファイルをCGSで管理するようにした時の備忘録

5 min read

はじめに

この記事ではLaravelでファイルアップロードしたファイルをGCSで管理した時の備忘録です

やり方

事前準備:GCPのプロジェクト・バケットの作成

以下の記事を参考にしました🙇‍♂️

https://blog.capilano-fw.com/?p=3359

.envに登録したバケット名を入力する

.env
GCS_BUCKET_NAME="hoge-bucket"

.envの値をapp.phpから参照する

src/laravel/config/app.php
'gcp_bucket_name' => env('GCS_BUCKET_NAME', 'hoge-bucket'),

GCSを操作するパッケージをインストール

composer require google/cloud-storage

https://packagist.org/packages/google/cloud-storage

https://googleapis.github.io/google-cloud-php/#/

google/cloud-storageをインスタンス化する

  • 事前準備で作成したバケットの認証キーをstorage直下のディレクトリに移動します

Config('app.gcp_bucket_name');:app.phpからバケット名を参照します

$url = file_get_contents():事前準備で作成したキーファイルを参照します

new StorageClient([バケット名,サービスアカウントのキーファイル]):

$client->bucket();:バケットを生成します

src/laravel/app/Services/Utilities/UtilityService.php
class UtilityService
{

    public $bucket;
    public $bucketOptions;

    public function __construct()
    {
        $projectId = Config('app.gcp_bucket_name');
        $url = file_get_contents(storage_path('app/local-service-account.json', true));

        $client = new StorageClient([
            'projectId' => $projectId,
            'keyFile' => json_decode($url, true)
        ]);
        $this->bucket = $client->bucket($projectId);
        $this->bucketOptions = [
            'resumable' => true, // アップロードを再開可能に行うか
            'name' => '',
            'metadata' => [
                // 日本語化
                'contentLanguage' => 'ja'
            ]
        ];
    }

    /**
     * 仮登録GCS保存名を作成
     *
     * @param UploadedFile $file
     * @param string $dirName
     * @param string $uniqueKey
     * @param array $options
     * @return array
     */
    public function setBucketOptions(UploadedFile $file, string $dirName, string $uniqueKey, array $options): array {
        $extension = $file->extension();
        $fileName = "{$uniqueKey}_{$dirName}.{$extension}";

        // 保存ディレクトリ生成
        $options['name'] = "tmp/images/{$uniqueKey}/{$dirName}/{$fileName}";
        return $options;
    }
}

送信時にGCSに一時保存する

tmp/images/一意な値に保存するようにします

src/laravel/app/Services/SkillSheet/SkillSheetService.php
protected UtilityService $utilityService;

public function __construct()
{
    $this->utilityService = new UtilityService();
}
/**
 * GCSへの仮保存
 *
 * @param StoreSkillSheetRequest $request
 * @param string $uniqueKey
 * @return array
 */
public function tmpStorageToGcsBucket(StoreSkillSheetRequest $request, string $uniqueKey): array
{
    // バケットを生成
    $bucket = $this->utilityService->bucket;

    // 登録した保存名を保持していく
    $saveNames = [];

    // 写真・動画・その他画像を1件ずつ振り分けする
    foreach ($request->file() as $key => $files) {
        foreach ($files as $file) {
            $options = $this->utilityService->setBucketOptions(
                $file,
                $key,
                $uniqueKey,
                $this->utilityService->bucketOptions
            );

            $saveNames[$key] = $options['name'];

            $bucket->upload(
                fopen($file, 'rb'),
                $options
            );
        }
    }

    return $saveNames;
}

GCSに一時保存した画像を正式に保存する場所に移動します

images/一意な値・ユーザーIDに保存するようにします
セッションに一時保存したファイル名を保持している状態と仮定します

/**
 * GCS保存
 *
 * @param integer $id
 * @param SkillSheet $target
 * @param array $updSkillSheet
 * @return array
 */
public
function storageToGcsBucket(int $id, SkillSheet $target, array $updSkillSheet): array
{
    // セッションを破棄する
    $saveNames = Session('saveNames');
    session()->forget('saveNames');

    // バケットイニシャライズ
    $bucket = $this->utilityService->bucket;

    // 仮登録したデータをコピーして移動させてから削除する
    foreach ($saveNames as $key => $v) {
        // 仮登録したオブジェクトがバケットに存在する場合は移管する
        $targetObject = $bucket->object($v);
        $extension = pathinfo($v)['extension'];
        $name = "skill_sheet/{$id}/{$key}/{$id}_{$key}.{$extension}";

        // オブジェクトが存在する場合は仮置きからコピーして移動する・仮置きは削除する
        if ($targetObject->exists()) {
            $targetObject->copy($bucket, ['name' => $name]);
            $targetObject->delete();
        }

        // 登録データが既にある場合は差し替える(更新)
        if ($target->pr_image_path) {
            // 差し替え前のオブジェクトを取得
            $beforeObject = $bucket->object($target->pr_image_path);

            // 差し替え前のオブジェクトがあれば削除
            if ($beforeObject->exists()) {
                $beforeObject->delete();
            } else {
                // 差し替え前のオブジェクトがないのにDBに登録されている場合はリセットする
                $updSkillSheet['pr_image_path'] = null;
            }
        }
        $updSkillSheet['pr_image_path'] = $name;
    }

    return $updSkillSheet;
}

移動先にファイルの実体が移動されます

スクリーンショット 2022-01-02 21.31.33.png

Discussion

ログインするとコメントできます