【ゼロから】Laravelで画像アップロード&プレビュー機能を作ってみた
1.はじめに
Laravelで画像アップロード機能を作りたい!と思ったとき、初心者の方が最初につまずくのが「何をどうやって作ればいいの?」という全体の流れではないでしょうか?さらに、「アップロード前に画像のプレビューを表示したい」となると、JavaScriptとの連携も必要になってきて、いきなりハードルが上がったように感じる方も多いはずです。
この記事では、Laravel初心者でもつまずかずに、画像のアップロード機能とプレビュー機能をステップバイステップで実装できるように、やさしく丁寧に解説していきます。
最終的には、以下のような機能を実現します:
- フォームから画像ファイルを選択
- 選択した画像のプレビューをその場で表示
- 「アップロード」ボタンを押すと、画像がサーバーに保存される
- アップロード後、保存された画像が画面上に表示される
Laravelでの基本的なファイルアップロードの流れに加え、JavaScriptを使ったプレビュー処理まで含めて解説することで、「画像アップロードの仕組み」が一通り理解できるようになるはずです。
それでは、さっそく始めていきましょう!
2. 開発環境の前提・準備
Laravelでの画像アップロードとプレビュー機能の実装に取り組む前に、まずは開発環境と前提条件の確認を行いましょう。ここでは、設定しておきたいポイントや必要なツールについて説明します。
【Laravelのバージョン】
この解説では、Laravel 8.x または 9.x 系を想定しています。ご利用の環境が異なる場合は、バージョンに合わせた設定や記述の違いに注意してください。
【開発環境】
- ローカル開発環境:XAMPPやLaravel Homesteadなど、お好みの環境で構いません。
- Composer:Laravelのプロジェクト作成やパッケージのインストールに必須です。
- Node.js & npm/yarn:フロントエンド関連の設定やJavaScriptのビルドに使用する場合があります。
【Laravelプロジェクトの作成】
もしまだプロジェクトを作成していない場合は、以下のコマンドで新規作成してください:
composer create-project --prefer-dist laravel/laravel laravel-upload-preview
【ディレクトリ構成とストレージ設定】
- プロジェクト直下の
public
ディレクトリは、アップロードした画像の公開先となることが多いため、パーミッション設定に注意しましょう。 - Laravelが提供する
Storage
ファサードを利用する場合は、storage:link
コマンドでシンボリックリンクを作成しておくのが便利です:
php artisan storage:link
【必要に応じたパッケージの導入】
今回の実装では、基本的なLaravelの機能とシンプルなJavaScriptで十分ですが、より高度な画像操作や加工が必要な場合は、サードパーティ製のパッケージも選択肢に入れてください。
このセクションを通して、すべての準備が整えば、次に実際のフォーム作成など、実装に入ることができるようになります。これで基本的な環境設定はバッチリです!
3. 画像アップロード用のフォームを作成する
画像アップロード機能を実現するには、まず「ユーザーが画像ファイルを選択して送信するためのフォーム」が必要です。このセクションでは、ルーティング、コントローラー、そしてBladeテンプレートを使ったフォームの作成までを順を追って解説します。
✅ 1. ルーティングの作成(web.php)
まずはルートを設定します。画像アップロード画面の表示と、実際のアップロード処理用のルートをそれぞれ定義します。
// routes/web.php
use App\Http\Controllers\ImageUploadController;
Route::get('/upload', [ImageUploadController::class, 'showForm'])->name('upload.form');
Route::post('/upload', [ImageUploadController::class, 'uploadImage'])->name('upload.image');
✅ 2. コントローラーの作成
次に、コントローラーを作成します。ターミナルで以下の Artisan コマンドを実行してください。
php artisan make:controller ImageUploadController
作成された app/Http/Controllers/ImageUploadController.php
に、次のようにメソッドを追加します。
// app/Http/Controllers/ImageUploadController.php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class ImageUploadController extends Controller
{
// フォームの表示
public function showForm()
{
return view('upload');
}
// アップロード処理(後のセクションで実装)
public function uploadImage(Request $request)
{
// 後ほど実装します
}
}
✅ 3. フォーム(Bladeファイル)の作成
次に、フォームを表示するBladeテンプレートを作成します。resources/views/upload.blade.php
というファイルを新規作成してください。
<!-- resources/views/upload.blade.php -->
<!DOCTYPE html>
<html>
<head>
<title>画像アップロード</title>
</head>
<body>
<h1>画像をアップロード</h1>
<form action="{{ route('upload.image') }}" method="POST" enctype="multipart/form-data">
@csrf
<input type="file" name="image" accept="image/*" onchange="previewImage(event)">
<br><br>
<img id="preview" src="" style="max-width: 300px; display: none;">
<br><br>
<button type="submit">アップロード</button>
</form>
<script>
function previewImage(event) {
const reader = new FileReader();
reader.onload = function(){
const output = document.getElementById('preview');
output.src = reader.result;
output.style.display = 'block';
};
reader.readAsDataURL(event.target.files[0]);
}
</script>
</body>
</html>
このフォームでは、画像ファイルを選択するとJavaScriptでその場でプレビューが表示されるようになっています。次のセクションでは、選択された画像を実際にサーバーにアップロードして保存する処理を実装していきます!
4.アップロード処理を実装する(保存・バリデーション)
画像アップロードのフォームが完成したら、次は実際に画像を保存する処理を実装していきます。あわせて、アップロードされる画像に対して**バリデーション(検証)**も行うことで、安全性の高い処理にしましょう。
✅ 1. バリデーションの追加
まずは、アップロードされる画像ファイルが正しい形式であるかをチェックするために、uploadImage
メソッドにバリデーションを追加します。
// app/Http/Controllers/ImageUploadController.php
use Illuminate\Support\Facades\Storage;
public function uploadImage(Request $request)
{
// バリデーションルールの設定
$request->validate([
'image' => 'required|image|mimes:jpeg,png,jpg,gif|max:2048',
]);
// アップロード処理(次で解説)
}
ここでは、以下の内容をチェックしています:
- required:画像が選択されていること
- image:画像ファイルであること(MIMEタイプに基づく)
- mimes:許可する拡張子(jpeg, png, jpg, gif)
- max:ファイルサイズ上限(2MB)
✅ 2. ファイルを保存する
バリデーションを通過したら、画像を storage/app/public
ディレクトリに保存します。保存にはLaravelの store
メソッドを使用するのが便利です。
// 保存処理の追加
// ファイルの保存
$path = $request->file('image')->store('public/images');
// パスを整形してビューに渡す
$filename = basename($path);
return view('upload')->with('filename', $filename);
このコードでは、画像を storage/app/public/images/
に保存し、そのファイル名を取得して upload.blade.php
に渡しています。
※
php artisan storage:link
を忘れていると、保存しても画像が表示されません。前のセクションで実施したことを思い出してください!
✅ 3. アップロード結果を画面に表示する(Blade修正)
upload.blade.php
にアップロード後の画像を表示するコードを追加しましょう。
@if(isset($filename))
<h2>アップロードされた画像</h2>
<img src="{{ asset('storage/images/' . $filename) }}" style="max-width: 300px;">
@endif
これで、アップロード後に画像が画面に表示されるようになります!
ここまでで、画像ファイルをアップロードし、保存&表示するところまでが完成しました。次は、JavaScriptでリアルタイムに画像のプレビューを表示する方法をさらに詳しく見ていきます!
5.JavaScriptでプレビュー機能を追加する
画像アップロードフォームでは、画像を選んだ時点で「ちゃんと選べたか」「どんな画像か」が分かると安心ですよね。そこで今回は、JavaScriptを使ってリアルタイムで画像のプレビューを表示する機能を実装します。
✅ 1. JavaScriptでFileReaderを使う
フォームの <input type="file">
に画像を選んだタイミングで処理を実行するには、JavaScriptの FileReader
オブジェクトを使います。
upload.blade.php
に以下のコードがすでにあると思いますが、あらためて説明します👇
<input type="file" name="image" accept="image/*" onchange="previewImage(event)">
<img id="preview" src="" style="max-width: 300px; display: none;">
<script>
function previewImage(event) {
const reader = new FileReader();
reader.onload = function(){
const output = document.getElementById('preview');
output.src = reader.result;
output.style.display = 'block';
};
reader.readAsDataURL(event.target.files[0]);
}
</script>
このコードでは以下の流れでプレビューを表示しています:
- ユーザーが画像を選択
onchange
イベントでpreviewImage()
関数が実行FileReader
で画像ファイルを読み込み、DataURL(画像のbase64データ)を生成<img>
タグにsrc
として読み込んだ画像を設定display: block
にして画像を表示
✅ 2. プレビュー表示を見やすく整える
最低限の見た目調整をして、選択時のUIをわかりやすくしましょう。たとえば、CSSを少し加えるとより親切です。
<style>
#preview {
margin-top: 10px;
border: 1px solid #ccc;
padding: 5px;
}
</style>
このように、JavaScriptを使うことでファイルを送信する前に内容を確認できるようになり、ユーザーの安心感がぐっと高まります!
次のセクションでは、アップロードされた画像の保存・表示がうまくいっているかどうかを確認し、よくあるエラーや落とし穴についても解説していきます!
6.アップロードされた画像を表示する
画像のアップロードが成功しても、ユーザーにとっては「本当にアップロードできたの?」が気になるところ。そこで、保存した画像を画面に表示して、確認できるようにしましょう!
✅ 1. storage:link で画像表示の準備をする
Laravelでは、アップロードされたファイルは通常 storage/app/public
に保存されます。しかしこのままではブラウザからアクセスできないため、public/storage
というシンボリックリンクを作成する必要があります。
これは前のセクションでも説明しましたが、念のためもう一度おさらいしておきます。
php artisan storage:link
このコマンドにより、storage/app/public
の中身に、public/storage
経由でアクセスできるようになります。
✅ 2. Bladeテンプレートで画像を表示する
アップロード完了後の画面で、保存された画像が表示されるように、Bladeテンプレート(upload.blade.php
)に以下のようなコードを追加しましょう。
@if(isset($filename))
<h2>アップロードされた画像</h2>
<img src="{{ asset('storage/images/' . $filename) }}" style="max-width: 300px;">
@endif
ここで使っている asset()
関数は、public
ディレクトリ以下のファイルへのURLを生成してくれるLaravelの便利関数です。
たとえば、画像が storage/app/public/images/sample.jpg
に保存された場合、上記のコードにより、ブラウザ上では:
http://your-app.test/storage/images/sample.jpg
のようなURLで表示されるようになります。
✅ 3. 表示されないときのチェックポイント
storage:link
を忘れていないか- 保存先が
public
ディレクトリ配下(storage/app/public/...
)になっているか - ファイル名やパスのスペルミスがないか
これで、アップロード → 保存 → 表示 の一連の流れが完成しました!🎉
次のセクションでは、初心者がつまずきやすいエラーやトラブルとその対処法を紹介していきます。
7.よくあるエラーとその対処法(おまけ)
Laravelで画像アップロード機能を実装していると、「なぜかうまくいかない…!」という場面にぶつかることがあります。ここでは、初心者がよくハマりがちなエラーや落とし穴をまとめて紹介します。
❗1. アップロードは成功してるのに画像が表示されない!
原因: storage:link
コマンドを実行していない
対処法: 以下のコマンドで、storage
ディレクトリのシンボリックリンクを作成しましょう。
php artisan storage:link
❗2. 「The image field is required.」と表示される
原因: ファイルが選ばれていないままフォームを送信している
対処法: <input type="file">
にファイルを選択してから送信しましょう。
また、バリデーションに required
を設定しているため、空だとエラーになります。
❗3. 「The image must be an image.」というエラーが出る
原因: 画像以外のファイルを選択している
対処法: image
バリデーションにより、JPEGやPNGなどの画像でなければ弾かれます。
拡張子が画像でも中身が画像でないとNGになることもあります。
❗4. 「The image may not be greater than 2048 kilobytes.」
原因: ファイルサイズが2MBを超えている
対処法: バリデーションの max:2048
による制限です。制限を緩めたい場合は、バリデーションの値を変更しましょう。
'max' => 5120 // 5MBに変更
❗5. プレビューが表示されない
原因の候補:
- JavaScriptが読み込まれていない
<script>
が正しく動作していない<img>
タグのid
が違っている
対処法: ブラウザの開発者ツール(F12)でエラーを確認してみましょう。特に previewImage
関数が動作していない場合、consoleにヒントがあるはずです。
こうしたエラーも、ひとつひとつ原因を探っていけば必ず解決できます。トラブルも成長のチャンスと思って、焦らず対処していきましょう🔥
8.まとめ
今回は、Laravel初心者でも安心して取り組めるように、画像アップロード機能+プレビュー機能の実装をステップバイステップで解説しました。
あらためて、今回の記事でやったことを振り返ってみましょう:
- Laravelのルーティングとコントローラーで、アップロード処理の受け口を作成
- フォームで画像ファイルを選び、JavaScriptを使ってリアルタイムにプレビューを表示
- バリデーションで安全なファイルのみを許可し、
storage
に保存 - アップロードされた画像を画面上に表示
- つまずきやすいポイントも事前にチェック!
これらを順番に進めることで、**「画像を選ぶ→その場で確認→アップロード→表示」**という一連の流れを実現できました。
✅ 次のステップへ
今回の内容は、シンプルな「単一画像アップロード」ですが、次のステップとして以下のような応用も考えられます:
- 複数画像の同時アップロード
- アップロード後の画像リサイズ(Intervention Imageなどのライブラリ活用)
- データベースとの連携(画像名を保存してユーザーに紐づけるなど)
このような機能も、今回のベースがあれば発展的に挑戦していけるはずです!
🎉最後に
「Laravelで画像アップロードって意外とできるかも!」と思ってもらえたなら嬉しいです!
自分で動かして、手応えを感じながら少しずつステップアップしていきましょう💪