【Laravel】ファイルアップロードをStorageで実装する方法

当ページのリンクには広告が含まれています。
いずみ

こんな悩みを解決できる記事を書きました!

僕は現役フリーランスエンジニア(歴年)で、資格は個保有しています。

Laravelでアップロードしたファイルの保存先や管理方法に迷っている」とお感じではありませんか?

ファイルをどのディレクトリに置くか、ファイル名の重複をどう防ぐかで悩む場面は多いはずです。

Storageファサードを使えば、ローカルでもS3でも同じコードでファイルを保存・取得・削除できます

いずみ

フォーム画面のアップロードもAPIのアップロードも、やり方は共通なので順番に解説します。

ということで、本記事ではLaravelでファイルアップロードをStorageで実装する方法を解説します。

いずみ

すぐ読み終わるので、ぜひ最後までご覧ください。

スクロールできます
【当サイト】おすすめフリーランスエージェント3選
エージェント評価ポイント公式サイト
レバテックフリーランス

5.0
業界最大級のエージェント。
高単価案件が豊富。
公式
Midworks

4.8
満足度調査で
3年連続3冠を達成。
公式
ITプロパートナーズ

4.6
週2〜3向けの案件が豊富。公式
執筆者/監修者
  • フリーランスエンジニア(保有資格個、企業と直接契約
  • ブログ・アフィリエイト歴7年(2018年〜)
  • ブランドせどりで月利50万円⇨脱サラ
  • 投資(仮想通貨・FX)歴7年(2018年〜)
  • X(旧Twitter)フォロワー約1,900人
  • 運営者情報はこちら
いずみです
目次

【Laravel】ファイルアップロードをStorageで実装する方法

早速、LaravelでファイルアップロードをStorageで実装する手順を見ていきます。

Storageによるファイル保存の仕組み

LaravelのStorageファサードは、ファイルの保存先を「ディスク」という単位で抽象化します。

ディスクの定義はconfig/filesystems.phpにまとまっていて、localディスク・publicディスク・s3ディスクが最初から用意されています。

localディスクはstorage/app/privateに保存され、ブラウザから直接アクセスできません。

publicディスクはstorage/app/publicに保存され、シンボリックリンク経由でブラウザに公開できます。

いずみ

ユーザーがダウンロードするファイルはpublicディスク、非公開のファイルはlocalディスク、と使い分けます。

publicディスクを公開する準備

publicディスクに保存したファイルをブラウザから見えるようにするには、シンボリックリンクを作成します。

STEP
artisanコマンドでシンボリックリンクを作成する

ターミナルでstorage:linkコマンドを実行します。

php artisan storage:link

public/storage から storage/app/public へのリンクが張られます。

STEP
公開URLの形を確認する

保存したファイルには /storage/ファイルパス の形でアクセスできます。

本番環境へデプロイした直後も、storage:linkコマンドの実行が必要になります。

アップロードフォームを用意する

ファイルを送信するフォームには、enctype属性にmultipart/form-dataを指定します。

<form action="/documents" method="POST" enctype="multipart/form-data">
    @csrf
    <input type="file" name="document">
    <button type="submit">アップロード</button>
</form>

enctype属性を書き忘れるとファイルがサーバーに届かないので注意します。

バリデーションを設定する

アップロードされたファイルの種類とサイズは、FormRequestで検証します。

STEP
artisanコマンドでフォームリクエストを生成する
php artisan make:request StoreDocumentRequest

app/Http/Requests/StoreDocumentRequest.php が生成されます。

STEP
rulesメソッドにファイルの検証ルールを書く

Illuminate\Validation\Rules\FileクラスのtypesメソッドとmaxメソッドでMIMEタイプと最大サイズを指定します。

<?php

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Rules\File;

class StoreDocumentRequest extends FormRequest
{
    public function authorize(): bool
    {
        return true;
    }

    public function rules(): array
    {
        return [
            'document' => [
                'required',
                File::types(['pdf', 'jpg', 'png'])->max(5 * 1024),
            ],
        ];
    }
}

maxメソッドの引数はキロバイト単位で、5 * 1024 と書くと5MBになります。

いずみ

画像だけを許可したいときは File::image() が使えます。

Storageにファイルを保存する

検証を通過したファイルは、storeメソッドまたはstoreAsメソッドで保存します。

STEP
storeメソッドでファイル名を自動生成して保存する

storeメソッドは第1引数に保存先ディレクトリ、第2引数にディスク名を受け取ります。

ファイル名はLaravelが自動でユニークな文字列を生成するため、名前の重複を気にする必要がありません。

<?php

namespace App\Http\Controllers;

use App\Http\Requests\StoreDocumentRequest;
use App\Models\Document;

class DocumentController extends Controller
{
    public function store(StoreDocumentRequest $request)
    {
        $path = $request->file('document')->store('documents', 'public');

        $document = Document::create([
            'path' => $path,
            'original_name' => $request->file('document')->getClientOriginalName(),
        ]);

        return redirect()->route('documents.show', $document);
    }
}

storeメソッドの戻り値は documents/xxxx.pdf のような保存パスです。

STEP
保存パスをデータベースに記録する

戻り値の保存パスをカラムに保存しておくと、後からファイルを取り出せます。

元のファイル名を残したい場合は、getClientOriginalNameメソッドの結果を別カラムに保存します。

ファイル名を自分で決めたいときは storeAs メソッドを使います。

use Illuminate\Support\Str;

$file = $request->file('document');
$path = $file->storeAs(
    'documents',
    Str::uuid() . '.' . $file->extension(),
    'public'
);
いずみ

ファイル名にユーザーの入力値をそのまま使うと危険なので、UUIDやハッシュ値を使います。

保存したファイルを表示・ダウンロードする

publicディスクのファイルURLは Storage::url メソッドで取得します。

use Illuminate\Support\Facades\Storage;

// ビューで画像を表示する
<img src="{{ Storage::url($document->path) }}">

// ダウンロードダイアログを出す
return Storage::disk('public')->download($document->path, $document->original_name);

downloadメソッドの第2引数には、ダウンロード時に表示させたいファイル名を渡します。

不要になったファイルを削除する

レコードを削除するときは、Storageのファイルも合わせて削除します。

use Illuminate\Support\Facades\Storage;

Storage::disk('public')->delete($document->path);
$document->delete();

deleteメソッドは対象ファイルが存在しなくてもエラーを投げず、falseを返すだけです。

いずみ

モデルのdeletingイベントでファイル削除を呼ぶと、消し忘れを防げます。

スクロールできます
【当サイト】おすすめフリーランスエージェント3選
エージェント評価ポイント公式サイト
レバテックフリーランス

5.0
業界最大級のエージェント。
高単価案件が豊富。
公式
Midworks

4.8
満足度調査で
3年連続3冠を達成。
公式
ITプロパートナーズ

4.6
週2〜3向けの案件が豊富。公式

【厳選】フリーランスエンジニアにおすすめなエージェント3選

フリーランスエンジニアになるにはエージェントから案件をもらう必要があります。

僕が実際に利用しているおすすめエージェントを紹介しますね。

いずみ

エージェントは必ず複数登録してください。

担当者によっては「全然案件紹介してくれない…」みたいなこともあるので…

僕は実際に5つのエージェントを使い回していますよ。

フリーランスを始めるなら「

案件数マージン率単価
約88,000件非公開
初心者福利厚生申し込み
無料
Good Point
  • 業界最大級の案件数。
  • 業界トップクラスの高単価報酬、低マージン(平均年収862万円)。
  • 案件参画中のフォローの充実。

※詳細は「【業界最大手】レバテックフリーランスとは?メリットや利用手順を解説!」を参照。

は業界最大手のフリーランスエージェントです。

とにかく案件数が多いので、とりあえず登録しておけば間違いないエージェントです!

いずみ

僕もはじめてフリーランスの案件を貰ったのはです。

保有している案件数が多いので、業務経験がなくても何かしらの案件は紹介してもらえますよ(僕はJavaの経験3年でも案件を貰えました)。

手厚い保障を重視したいなら「

案件数マージン率単価
約10,000件非公開
初心者福利厚生申し込み
無料
Good Point
  • 手厚い保障で正社員並みの安心感。
  • 還元率60%超え&単価公開でクリアな契約。
  • 給与保障制度(審査あり)。

は手厚い保障が特徴のフリーランスエージェントです。

フリーランスを目指しているけど不安な方や保障を重視したい方におすすめです。

いずみ

僕も何度か案件を紹介してもらいました。

自分のスキルに合った案件を紹介してもらえましたし、電話のやり取りも非常に丁寧でした。

週2〜3日の案件探しなら「

案件数マージン率単価
約5,000件非公開
初心者福利厚生申し込み
経験者向け無料
Good Point
  • IT案件に特化したフリーランスエージェント。
  • 週2〜3日の案件が豊富。
  • リモート案件が多く、直エンドなので単価も高い。

※詳細は「【週2・3案件】ITプロパートナーズとは?メリットや利用手順を解説!」を参照。

はIT案件に特化したフリーランスエージェントです。

週2〜3日から参画できる案件が豊富なので、起業したい人にもおすすめです。

いずみ

週2〜3日の案件はある程度スキルがないと紹介してもらえない印象です。

とはいえ、週5の案件ももちろんありますし、僕が利用した時は迅速・丁寧に対応していただきました!

よくある質問

storage/app/public と public/storage はどう違いますか?

storage/app/public が実ファイルの保存先です。

public/storage は storage:link コマンドで作られるシンボリックリンクで、Webサーバーの公開ディレクトリから実ファイルへ橋渡しします。

アップロードできるファイルサイズの上限を大きくするには?

PHPの設定値である upload_max_filesize と post_max_size を php.ini で変更します。

Laravel側のバリデーションの max も忘れずに合わせて広げます。

保存先をS3に変えるときコードの修正は必要ですか?

storeメソッドやstoreAsメソッドのディスク名を s3 に変えるだけで動きます。

config/filesystems.php のs3ディスクにバケット名やリージョンを設定し、league/flysystem-aws-s3-v3 パッケージを追加します。

まとめ

今回は、LaravelでファイルアップロードをStorageで実装する方法について解説しました。

以下が本記事のまとめになります。

まとめ
  • Storageファサードは保存先をディスク単位で抽象化し、ローカルとS3を同じコードで扱える。
  • publicディスクのファイルは storage:link コマンドのシンボリックリンク経由でブラウザに公開する。
  • store メソッドはユニークなファイル名を自動生成するので、名前の重複を考えずに保存できる。
  • ファイルを削除するときは、データベースのレコードと Storage のファイルを両方消す。
まとめ
  • おすすめ本
¥2,673 (2023/07/23 15:53時点 | Amazon調べ)
\楽天ポイント4倍セール!/
楽天市場

Laravelの勉強なら「」が分かりやすくておすすめですよ♪

いずみ

最後までお読みいただき、ありがとうございました!

スクロールできます
【当サイト】おすすめフリーランスエージェント3選
エージェント評価ポイント公式サイト
レバテックフリーランス

5.0
業界最大級のエージェント。
高単価案件が豊富。
公式
Midworks

4.8
満足度調査で
3年連続3冠を達成。
公式
ITプロパートナーズ

4.6
週2〜3向けの案件が豊富。公式
  • クソおすすめ本
¥4,480 (2024/06/01 23:28時点 | Amazon調べ)
\楽天ポイント4倍セール!/
楽天市場
いずみ

海外のエンジニアがどういった思考で働いているかが理解できます。

海外に行く気はないけど海外エンジニアの動向が気になる雑魚エンジニアにおすすめです(本当におすすめな本しか紹介しないのでご安心を)。

この記事が気に入ったら
フォローしてね!

シェアしてね!
  • URLをコピーしました!
目次