「アルバム機能」だと難しそうに感じますが、「プロフィール画像登録」は簡単にできそうですよね。ところが結構つまずくポイントが多かったので、今回は画像のアップロード方法についてシェアします!
基礎知識
画像はどこに保存すればいい?
Laravelには「public」ディレクトリが2つ存在します。
①public と ②storage/app/public です。
①にimgディレクトリがあるため、そこへ保存したくなりますが、①は ロゴやデザイン関係など サービス側の画像を保存するための場所で、ユーザーがアップロードした画像は②に保存するのが良いようです。
画像の表示方法
まず、②storage/app/publicに適当な画像ファイルを入れ、直接アクセスしてみましょう。
http://localhost/storage/app/public/ファイル名
表示に失敗してしまったかと思います。
これは、Laravelが①のpublicディレクトリ以外、外部からアクセスできないようになっているためです。
そこで「シンボリックリンク」というものを作成します。
①public内にショートカットディレクトリ「storage」を作成し、public/storageへのアクセスで②storage/app/publicの中身を表示するようにします。
難しく聞こえるかもしれませんが、パソコンのデスクトップにショートカットアイコンを作成するのと同じです。
リンクを張るのはとても簡単で、次のコマンドをたたくだけです。
php artisan storage:link
再度画像にアクセスし、表示されれば成功です!
プロフィール画像のアップロード機能を実装しよう
仕様
①入力フォーム …ユーザーが画像をアップロード
↓
②確認ページ …アップロードされた画像を表示、tempディレクトリに一時保存
↓
③登録完了 …DBに画像のファイル名を保存、ユーザーIDディレクトリに画像を移動
tempディレクトリは、storage/app/public/uploadにあらかじめ作成しておきます。
DBには画像そのものではなく、パスでもなく、ファイル名を保存します。
確認ページ
public function confirm(Request $request) {
// 略
$image = $request->file('image');
if ($image) {
// 画像をtempディレクトリに保存
$temp_path = $image->store('public/upload/temp');
$read_temp_path = str_replace('public/', 'storage/', $temp_path);
} else {
$read_temp_path = 'storage/default/noimage.png';
}
// 略
}
Webで表示するときはpublic/upload/tempではなくstorage/upload/tempにアクセスする必要があるため、str_replaceでパスの置換を行っています。
画像がアップロードされなかった場合は、noimage.pngを表示するようにします。
また、completeメソッドで画像ファイルのパスを取得したいので、confirm.blade.phpにhiddenを記述しておきます。
<input type=”hidden” name=”image” value=”{{ $read_temp_path }}”>
登録完了ページ
public function complete(Request $request) {
// 略
// ファイルのパスを取得
$read_temp_path = $request->input('image');
// DBにファイル名を保存
$user = new User();
if ($read_temp_path === 'storage/default/noimage.png') {
$image_file_name = NULL;
$user->img = 'noimage.png';
} else {
$image_file_name = str_replace('storage/upload/temp/', '', $read_temp_path);
$user->img = $image_file_name;
}
$user->save();
//ユーザーIDのフォルダを作成
Storage::makeDirectory('public/upload/user/' . $user->id);
// tempフォルダからユーザーIDフォルダへ画像を移動
$temp_path = str_replace('storage/', 'public/', $read_temp_path);
$image_file_path = 'public/upload/user/' . $user_id . $image_file_name;
if ($image_file_name) {
Storage::move($temp_path, $image_file_path);
}
// 略
}
おまけ:画像のバリデーション
画像も他の入力フォームと同様、バリデーションを行うことができます。
$request->validate([
'image' => 'file|image|mimes:jpeg,png,jpg|max:2048',
]);
file:アップロードに成功したファイルかどうか
image:画像かどうか(jpg、jpeg、png、bmp、gif、svg、webp)
mimes:指定されたいずれかの拡張子であるか
max:サイズオーバーしていないか
さいごに
publicとstorageだらけで混乱しますが、文字だけでなく実際にフォルダがどうなっているかを確認すると理解が深まると思います。少しでも参考になれば幸いです!