#17 Laravel基礎

ファイルアップロードとストレージ

ファイルアップロードの仕組み

ストレージ? ファイルの保存・取得を管理する仕組み。ローカルディスクやS3などを切り替え可能な統一APIで操作できる。 はファイルの保存・取得・削除を統一したAPIで操作できるLaravelの機能です。ローカルディスクやAmazon S3など複数のドライバーを切り替えられます。


フォームでファイルを受け取る

フォームには enctype="multipart/form-data" が必要です。

{{-- 📁 resources/views/posts/create.blade.php --}}

<form method="POST" action="{{ route('posts.store') }}" enctype="multipart/form-data">
    @csrf
    <input type="text" name="title">
    <textarea name="body"></textarea>
    <input type="file" name="thumbnail">
    <button type="submit">投稿する</button>
</form>

コントローラーでファイルを処理する

// 📁 app/Http/Controllers/PostController.php

public function store(Request $request)
{
    $request->validate([
        'title'     => 'required',
        'body'      => 'required',
        'thumbnail' => 'nullable|image|max:2048', // 2MBまでの画像
    ]);

    $thumbnailPath = null;

    if ($request->hasFile('thumbnail')) {
        // storage/app/public/thumbnails/ に保存
        $thumbnailPath = $request->file('thumbnail')
                                 ->store('thumbnails', 'public');
        // 戻り値は "thumbnails/xxxx.jpg" のようなパス
    }

    Post::create([
        'title'          => $request->title,
        'body'           => $request->body,
        'thumbnail_path' => $thumbnailPath,
        'user_id'        => auth()->id(),
    ]);

    return redirect()->route('posts.index');
}

ストレージのディスク設定

// 📁 config/filesystems.php

'disks' => [
    'local' => [
        'driver' => 'local',
        'root'   => storage_path('app/private'),
        // ブラウザからは直接アクセス不可
    ],

    'public' => [
        'driver' => 'local',
        'root'   => storage_path('app/public'),
        'url'    => env('APP_URL') . '/storage',
        // php artisan storage:link でpublic/storageからシンボリックリンクを張る
    ],

    's3' => [
        'driver' => 's3',
        'key'    => env('AWS_ACCESS_KEY_ID'),
        'secret' => env('AWS_SECRET_ACCESS_KEY'),
        'region' => env('AWS_DEFAULT_REGION'),
        'bucket' => env('AWS_BUCKET'),
    ],
],

public ディスクに保存したファイルをブラウザからアクセスできるようにするには:

php artisan storage:link

これで public/storagestorage/app/public のシンボリックリンクが作られます。


ファイルのURLを取得する

// public ディスクのファイルURL
$url = Storage::disk('public')->url($post->thumbnail_path);
// → https://example.com/storage/thumbnails/xxxx.jpg

// ビューで使う
asset('storage/' . $post->thumbnail_path)
// または
Storage::url($post->thumbnail_path)

ファイルの操作

use Illuminate\Support\Facades\Storage;

// 存在確認
Storage::disk('public')->exists('thumbnails/abc.jpg'); // true/false

// ファイルを削除
Storage::disk('public')->delete($post->thumbnail_path);

// ファイルを移動・コピー
Storage::move('old/path.jpg', 'new/path.jpg');

// ファイルの中身を取得
$contents = Storage::get('private/report.pdf');

// ファイルに書き込む
Storage::put('reports/today.txt', $content);

ファイル更新時の古いファイル削除

投稿のサムネイルを更新するときは、古いファイルを削除しましょう。

// 📁 app/Http/Controllers/PostController.php

public function update(Request $request, Post $post)
{
    $data = $request->only('title', 'body');

    if ($request->hasFile('thumbnail')) {
        // 古いファイルを削除
        if ($post->thumbnail_path) {
            Storage::disk('public')->delete($post->thumbnail_path);
        }
        // 新しいファイルを保存
        $data['thumbnail_path'] = $request->file('thumbnail')
                                           ->store('thumbnails', 'public');
    }

    $post->update($data);
    return redirect()->route('posts.show', $post);
}

まとめ

  • フォームに enctype="multipart/form-data" が必要
  • $request->file('field')->store('フォルダ', 'disk') でファイルを保存する
  • php artisan storage:link でpublicディスクのファイルをWebから公開できる
  • Storage::url() でファイルのURLを取得できる
  • ファイル更新時は古いファイルを Storage::delete() で削除する

次回はConfigとenvを使った設定管理を学びます。