エンジニア初心者の投稿であるため、間違っている箇所が多くあるかと思います。
間違っているなどあればご教授いただけると幸いです。
はじめに
laravelを使った画像の受け渡しAPI作成を行なっているときに、『MinIO』と呼ばれるストレージ・サーバーがあることを知りました。調べてみると、『MinIO』はAWSのS3を擬似体験(表現が正しくないかもしれません)をできるということでした。今回は安易に『MinIO』に手を出した初心者の記録を残したいと思います。同じように『MinIO』を使ってみたい方の参考になればと思います。
MinIOとは
openStandiaに書かれているところから引用させていただくと
MinIOは、Go言語で実装されたAmazon S3クラウド・ストレージ・サービスと互換性のあるオブジェクト・ストレージ・サーバーです。
MinIOはAmazon S3と互換性があるため、Amazon S3と全く同じインタフェース(AWS CLIや、AWS SDK)からもアクセスが可能です(ただし一部、MinIOではサポートしていないAPIもあります)。そのため、本番環境ではAmazon S3を使用するが、開発時には、MinIOで開発/テストを行うなどの用途で利用することができます。
簡単にいうと、Amazon S3を擬似体験できる!と解釈しています、私は!
Laravelを使って、MinIOのデータをやり取りする手順
今回説明する方法は実際に実装するにはセキュリティ面で問題が多いです。個人で利用することをお勧めします。
MiniO以外の環境設定
Laravel 9系を使用します。具体的な環境構築が完了している前提で話を進めさせていただきます。
docker環境を用いるので、私が構築の際に利用したサイトを貼っておきます。
MiniOの環境設定
MiniOの環境設定についても以下のものを見るとわかりやすいです。下記のサイト通りに作成をすると利用が可能になります。
この画面が表示できていれば準備万端です。
ここから画像のアップロードと表示を説明します。
画像のアップロードと表示
DBの設定
php artisan make:model Post --migration
今回は特にPost.phpについては変更を加えません。簡易的な作成なためご許しを・・・。
日付_create_posts_table.phpはDBとやり取りをするために変更を加えます。画像を呼び出すために必要なるので必ず設定してください。
return new class extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
//変更箇所
Schema::create('posts', function (Blueprint $table) {
$table->id();
$table->string('image');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('posts');
}
};
マイグレーションファイルの設定は完了したので、DBに反映させます。
php artisan migrate
DB内に入って、Postsテーブルができていることを確認してください。
ここまでできていれば用意完璧です。
画像をアップロードする画面の作成
簡易的なものであるため、見た目がひどいですが、温かい目で見守ってください。
今回はindex.blade.phpという名前のファイルに作成します。
<form action="{{ route('upload') }}" method="post" enctype="multipart/form-data">
{{ csrf_field() }}
<input type="file" name="file">
<button type="submit">保存</button>
</form>
<a href="{{ route('show') }}">ここをクリックしてな</a>
ザックリ説明すると、画像を送信するためのformタグがあり、画像を表示する画面へ遷移するaタグがある形になっています。routeの中身である、「update」と「show」は後ほど記述します。
ここで注意してほしい点が一つあります。formタグの属性である【enctype="multipart/form-data"】は忘れずにつけてください。ファイルの送信に利用する属性です。
画像を表示する画面の作成
今回はshow.blade.phpという名前のファイルに作成します。
<img src="{{ $memo['image'] }}"/>
これだけ!?と思う方がいるかと思いますが、簡易版です。温かい目で…(n回目)。
webファイルの修正(ルーティングの修正)
Viewの部分が完成したので、一度確認の意味を込めてルーティングを設定して、画面に表示できるようにしたいと思います。
//画像をアップロードする画面のルーティング
Route::get('/', function () {
return view('index');
});
この設定をしたときにこの画面が出てくれば大成功です(私はポートの関係で8088になっています)。
controllerの設定
今回のcontroller名はPhotControllerに設定をします。
php artisan make:controller PhotController
コマンドで作成できたPhotController.phpを編集します。
また、今回はlaravelを用いてMiniOを操作するので、AWS SDKをインストールする必要があります。これをインストールすることで画像の保存を【Storage::disk('s3')】という簡単なコードで行うことができるようになります。
composer require league/flysystem-aws-s3-v3:^3.0
今回の例ではlaravel 9系の場合でのコマンドです。laravelのバージョンによっては使えない可能性があるので、エラーが発生した場合はまず、依存関係を確かめてください。
<?php
namespace App\Http\Controllers;
use App\Models\Post;
use Illuminate\Http\Request;
//Storageは呼び出さないと利用ができません
use Illuminate\Support\Facades\Storage;
class PhotController extends Controller
{
public function upload(Request $request)
{
//index.blade.phpのformタグで受け取った画像を変数にいれる
$file = $request->file('file');
//この一文だけでMiniOには保存ができます。
//Storage::disk('s3')->putFile('/', $file, 'public');
//今回はDBにURLを保存するため、先頭に$pathをつけることで画像のパスを変数に代入するとができます
$path = Storage::disk('s3')->putFile('/', $file, 'public');
//パスからURLに変更しています
$path = Storage::disk('minio')->url($path);
//ここについては後述しますが、非常に重要なポイントです。
$pathArray = explode('/', $path);
$pathArray[2] = 'localhost:9000';
$newPathArray = implode('/', $pathArray);
//DBに画像を開くためのURLを挿入します
Post::insert([
'image' => $newPathArray,
]);
//index.blade.phpに戻るための処理です
return redirect('/');
}
}
先ほど出てきたこちらのコードについて説明します。長ったらしく、URLを変更していますが意味があります。
//①パスをそのまま取得している
$path = Storage::disk('minio')->url($path);
//②パスの一部を修正している
$pathArray = explode('/', $path);
$pathArray[2] = 'localhost:9000';
$newPathArray = implode('/', $pathArray);
//①のコードで取得できるパス
http://minio:9000/develop/◯◯.jpg
//②のコードで取得できるパス
http://localhost:9000/develop/◯◯.jpg
見ていただくとわかるように『minio:9000』を『localhost:9000』に変更しています。
これはminioに直接レスポンスが送れない仕様になっているので、docker経由でレスポンスを行っています。
これについてはこちらの記事がわかりやすいです。
実際の実務では一定期間有効なURLを発行することで画像の受け渡しをしており、今回のような受け取り方はよろしくないとのことでした。
画像を表示するためのcontrollerも必要になるため、定義していきます。上記の内容に追加で付け足してください。
public function show()
{
//idが1である画像を表示するための記述です。
$memo = Post::where('id', 1)->first();
return view('show', compact('memo'));
}
web.phpに追加
controllerの設定ができたので、web.phpにルーティングをしましょう。
//画像をアップロードする画面のルーティング
Route::get('/', function () {
return view('index');
});
Route::namespace('App\Http\Controllers')->group(function () {
//画像を送信するためのルーティング
Route::post('/upload', 'PhotController@upload')->name('upload');
//画像を表示する画面のルーティング
Route::get('/show', 'PhotController@show')->name('show');
});
実際に試してみる
ここまでうまくできていればおそらく画像の受け渡しが可能になっているはずです。実際に画像を使って見てみましょう。
選択されていませんが画像の名前に変更される。保存をクリック。
mysqlのpostsにURLが送信される(idが5になっていますが、初めての方は1になります)。
おわりに
MiniOを使って簡単な画像の受け渡しを再現しました。今回の実装は自分で遊ぶようのものになっているのでセキュリティ面がガバガバです。実際に実務で使うレベルには程遠いですが、MiniOの使い方を学ぶにはちょうどいい重さの実装でした。AWSはものすごい勢いでアップデートしており、今の方法がいつまで使えるかわかりませんが(現在2024/6/11)サッと試したい方は真似して作ってみてください。