🪣

【Laravel 9~】StorageクラスでS3内のバケット間でファイルコピーする

2024/06/27に公開

結論

config/filesystems.phpの設定が以下の通りだとして...

<?php

return [
    ...

    'disks' => [
        ...

        // コピー元のS3バケット
        's3_from' => [
            'driver' => 's3',
            'key' => env('AWS_ACCESS_KEY_ID') ?: null,
            'secret' => env('AWS_SECRET_ACCESS_KEY') ?: null,
            'region' => env('AWS_DEFAULT_REGION'),
            'bucket' => env('AWS_BUCKET_FROM'),
            'url' => env('AWS_URL'),
            'endpoint' => env('AWS_URL'),
        ],

        // コピー先のS3バケット
        's3_to' => [
            'driver' => 's3',
            'key' => env('AWS_ACCESS_KEY_ID') ?: null,
            'secret' => env('AWS_SECRET_ACCESS_KEY') ?: null,
            'region' => env('AWS_DEFAULT_REGION'),
            'bucket' => env('AWS_BUCKET_TO'),
            'url' => env('AWS_URL'),
            'endpoint' => env('AWS_URL'),
        ],
    ],
];

以下のようにすればOK

use Illuminate\Filesystem\AwsS3V3Adapter;

/** @var AwsS3V3Adapter $fromStoragen */
$fromStorage = Storage::drive('s3_from');
/** @var AwsS3V3Adapter $toStorage */
$toStorage = Storage::drive('s3_to');

// 異なるバケット間でファイルコピーを実行
$fromStorage->getClient()->copy(
    $fromStorage->getConfig()['bucket'], // コピー元バケット名
    'path/to/original_file.png', // コピー元バケット内のファイルパス
    $toStorage->getConfig()['bucket'], // コピー先バケット名
    'path/to/copied_file.png', // コピー先バケット内のファイルパス
    'public-read', // visibility設定(非公開なら'private'指定)
);

余談

S3Clientを直接操作したい

S3Clientを直接操作したい場合、以下のようにgetClient関数で取り出せる

use Aws\S3\S3Client;

/** @var S3Client $s3Client */
$s3Client = Storage::drive('s3_from')->getClient();

config/filesystems.phpの設定値はgetConfig()で取得できるので、あとは好き放題!

$diskConfig = Storage::drive('s3_from')->getConfig();
[
    'driver' => 's3',
    'key' => '...',
    'secret' => '...',
    'region' => 'ap-northeast-1',
    'bucket' => 'bukcet-name-from',
    'url' => 'https://...',
    'endpoint' => 'https://...',
];

Storageクラスの思想について

  • Laravelの思想的にStorageクラスの抽象化が進んでいる
  • ...ので、S3Clientを取り出して実装するのは本来的にあんまり良くない気がする
  • とはいえ必要に応じて直接S3Clientを使いたいケースはあるよね...という話

同一バケット内のコピーであれば、よりシンプルに実装可能

Storage::drive('s3_foo')->copy('old/file.jpg', 'new/file.jpg');

Discussion