概要
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の設定について
下記の設定ファイルがあります。
'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ファイルで値を調整する。
# [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
ソースコードを書いてみる。
<?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設定を追加します。
Route::namespace('App\Http\Controllers')->group(function () {
Route::group(['middleware' => ['api']], function () {
Route::get('/directories', 'FindDirectoryController')->name('api.directories'); // ← 追加!!
});
});
リクエストしてみると以下のレスポンスが返ってきました。
{
"path":"/static",
"directories":[
"static/hoge",
"static/fuga"
]
}
ファイル一覧を取得する
ファイル一覧を返すAPIを作ってみる。
$ ./sail artisan make:controller FindFileController --invokable
ソースコードを書いてみる。
<?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設定を追加します。
Route::namespace('App\Http\Controllers')->group(function () {
Route::group(['middleware' => ['api']], function () {
...
Route::get('/files', 'FindFileController')->name('api.files'); // ← 追加!!
});
});
リクエストしてみると以下のレスポンスが返ってきました。
{
"path":"/static/hoge",
"files":[
"static/hoge/.gitkeep",
"static/hoge/sample.txt"
]
}
ファイルをダウンロードする
ファイルをダウンロードするAPIを作ってみる。
$ ./sail artisan make:controller DownloadFileController --invokable
ソースコードを書いてみる。
<?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設定を追加します。
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
ソースコードを書いてみる。
<?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設定を追加します。
Route::namespace('App\Http\Controllers')->group(function () {
Route::group(['middleware' => ['api']], function () {
...
Route::post('/files/sample.txt', 'UploadFileController')->name('api.files.upload'); // ← 追加!!
});
});
リクエストしてみると以下のレスポンスが返ってきました。
{
"path":"/static/fuga/sample.txt",
"file":"xxxxxxxx.txt"
}
参考サイト
- Unable to download file from s3 using return response()->download($file);
- Laravel5でAmazon S3からファイルをダウンロードする方法
- Help with minio and Laravel 6
- Laravelのファイル保存先をS3に変更してみた
- 超簡単!LaravelでS3を利用する手順
- Laravel で amazon S3 のファイル操作を行うメソッド一覧
以上