4
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

LaravelでStorageでS3(minio)へアクセスする

Last updated at Posted at 2021-12-16

概要

LaravelのStorageを使ってAWS S3(minIO)へアクセスすることがありました。
その際に調べた内容をメモしておく。

お知らせ
minIOのバージョンがアップされています。
この記事のminIOは1つ前のものです。
※ 最新のminIOの場合、異なる部分があると思うのでご注意ください

<参考サイト>
MinIOを使ってローカルで外部ストレージをAmazonS3から置き換える

ファイル構成

下記ローカルS3環境を構築して使っております。

├ docker
│ └ minio
│   ├ config               ... minio設定 (git管理対象外)
│   ├ data                 ... minioデータ (git管理対象外) 
│   ├ export
│   │ └ static             ... 起動時に取り込むファイル
│   │   ├ hoge
│   │   │  └ sample.txt
│   │   └ fuga
│   └ policies
│     └ buckets
│        └ static
│           └ policy.json  ... staticバケットのポリシー定義
│
├ src                      ... Laravelのソースコード
│ ├ app
│ ├ config
│ ├ routes
│   ...
│
│.gitignore
├ docker-compose.yml
└ REAMDE.md

※ローカルS3環境(minio)を構築については、こちらを参照ください

Laravelの設定について

下記の設定ファイルがあります。

./src/config/filesystems.php
's3' => [
    'driver'   => 's3',
    'key'      => env('AWS_ACCESS_KEY_ID'),
    'secret'   => env('AWS_SECRET_ACCESS_KEY'),
    'region'   => env('AWS_DEFAULT_REGION', 'ap-northeast-1'),
    'bucket'   => env('AWS_BUCKET'),
    'url'      => env('AWS_URL'),
    'endpoint' => env('AWS_ENDPOINT'),
    'use_path_style_endpoint' => env('AWS_USE_PATH_STYLE_ENDPOINT', false),
],

ローカル環境で、minIOを使うため、envファイルで値を調整する。

./src/.env
# [AWS設定]
AWS_ACCESS_KEY_ID=minio
AWS_SECRET_ACCESS_KEY=minio123
AWS_DEFAULT_REGION=ap-northeast-1
AWS_BUCKET=static
AWS_USE_PATH_STYLE_ENDPOINT=true
AWS_ENDPOINT=http://minio:9000

StorageのS3ドライバーについて

公式サイトを参考に、下記ライブラリをインスールする。
※ 参考サイト: Laravel 8.x ファイルストレージ

$ ./sail composer require --with-all-dependencies league/flysystem-aws-s3-v3 "^1.0"

フォルダ一覧を取得する

フォルダ一覧を返すAPIを作ってみる。

$ ./sail artisan make:controller FindDirectoryController --invokable

ソースコードを書いてみる。

./src/app/Http/Controllers/FindDirectoryController.php
<?php

namespace APP\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Http\JsonResponse;
use Illuminate\Support\Facades\Storage;
use App\Http\Controllers\Controller;

class FindDirectoryController extends Controller
{
    /**
     * @param  Request $request
     * @return JsonResponse
     */
    public function __invoke(Request $request): JsonResponse
    {
        $path = '/static';
        $directories = Storage::disk('s3')->directories($path);
        return response()->json([
            'path'      => $path,
            'directories' => $directories,
        ]);
    }
}

Routes設定を追加します。

./src/routes/api.php
Route::namespace('App\Http\Controllers')->group(function () {
    Route::group(['middleware' => ['api']], function () {
        Route::get('/directories', 'FindDirectoryController')->name('api.directories'); // ← 追加!!
    });
});

リクエストしてみると以下のレスポンスが返ってきました。

GET /api/directories
{
  "path":"/static",
  "directories":[
    "static/hoge",
    "static/fuga"
  ]
}

ファイル一覧を取得する

ファイル一覧を返すAPIを作ってみる。

$ ./sail artisan make:controller FindFileController --invokable

ソースコードを書いてみる。

./src/app/Http/Controllers/FindFileController.php
<?php

namespace APP\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Http\JsonResponse;
use Illuminate\Support\Facades\Storage;
use App\Http\Controllers\Controller;

class FindFileController extends Controller
{
    /**
     * @param  Request $request
     * @return JsonResponse
     */
    public function __invoke(Request $request): JsonResponse
    {
        $path = '/static/hoge';
        $files = Storage::disk('s3')->files($path);
        return response()->json([
            'path'  => $path,
            'files' => $files,
        ]);
    }
}

Routes設定を追加します。

./src/routes/api.php
Route::namespace('App\Http\Controllers')->group(function () {
    Route::group(['middleware' => ['api']], function () {
        ...
        Route::get('/files', 'FindFileController')->name('api.files'); // ← 追加!!
    });
});

リクエストしてみると以下のレスポンスが返ってきました。

GET /api/files
{
  "path":"/static/hoge",
  "files":[
    "static/hoge/.gitkeep",
    "static/hoge/sample.txt"
  ]
}

ファイルをダウンロードする

ファイルをダウンロードするAPIを作ってみる。

$ ./sail artisan make:controller DownloadFileController --invokable

ソースコードを書いてみる。

./src/app/Http/Controllers/DownloadFileController.php
<?php

namespace APP\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\Contracts\Routing\ResponseFactory;
use Illuminate\Support\Facades\Storage;
use Illuminate\Contracts\Filesystem\FileNotFoundException;
use App\Http\Controllers\Controller;

class DownloadFileController extends Controller
{
    /**
     * @param  Request $request
     * @return Response|ResponseFactory
     * @throws FileNotFoundException
     */
    public function __invoke(Request $request)
    {
        $path = '/static/hoge/sample.txt';
        $name = 'sample.txt';

        // 存在確認
        if (empty($path) || ! Storage::disk('s3')->exists($path)) {
            throw new FileNotFoundException('file is not exists.');
        }

        $file = Storage::disk('s3')->get($path);
        $last_modified = Storage::disk('s3')->lastModified($path);

        return response($file, 200, [
            'filename'            => $name,
            'Content-Type'        => 'text/plain',
            'Last-Modified'       => gmdate('D, d M Y H:i:s', $last_modified) . ' GMT',
            'Etag'                => md5($last_modified),
            'Content-Disposition' => 'attachment; filename="' . $name . '"',
        ]);
    }
}

Routes設定を追加します。

./src/routes/api.php
Route::namespace('App\Http\Controllers')->group(function () {
    Route::group(['middleware' => ['api']], function () {
        ...
        Route::get('/files/sample.txt', 'DownloadFileController')->name('api.files.download'); // ← 追加!!
    });
});

リクエストしてみるとファイルがダウンロードされました。

ファイルをアップロードしてみる

POST送信で送られてきたファイルをS3へアップロードするAPIを追加してみる。

$ ./sail artisan make:controller UploadFileController --invokable

ソースコードを書いてみる。

./src/app/Http/Controllers/UploadFileController.php
<?php

namespace APP\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Http\JsonResponse;
use Illuminate\Support\Facades\Storage;
use App\Http\Controllers\Controller;

class UploadFileController extends Controller
{
    /**
     * @param  Request $request
     * @return JsonResponse
     */
    public function __invoke(Request $request): JsonResponse
    {
        $file = $request->file('file');

        // ファイルをリネームしてアップロードする
        $path = '/static/fuga'
        $name = 'sample.txt';
        Storage::disk('s3')->putFileAs($path, $file, $name);

        return response()->json([
            'path'  => $path . '/' . $name,
            'file'  => $file->getClientOriginalName(),
        ]);
    }
}

Routes設定を追加します。

./src/routes/api.php
Route::namespace('App\Http\Controllers')->group(function () {
    Route::group(['middleware' => ['api']], function () {
        ...
        Route::post('/files/sample.txt', 'UploadFileController')->name('api.files.upload'); // ← 追加!!
    });
});

リクエストしてみると以下のレスポンスが返ってきました。

POST /api/files/sample.txt
{
  "path":"/static/fuga/sample.txt",
  "file":"xxxxxxxx.txt"
}

参考サイト

以上

4
8
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?