Laravelにおけるファイルアップロードの方法

2023年12月15日

アップロード先ディレクトリと設定

Laravelファイルマネージャーの設定はconfig/filessystems.phpに書いてあります。デフォルトではlocal、publicとs3という三つのdiskが定義されていて、localとpublicディスクのパスはそれぞれstorage/appとstorage/app/publicとなっています。デフォルトディスクはlocalに設定されているためファイルをアップロードすると/storage/appに保存され、ユーザから見えない設定となっています。

アップロードしたファイルがユーザから見えるようにするには、まずphp artisan storage:linkを実行し、public/storageからstorage/app/publicへのリンクを作成します。そしてファイル保存時に$request->file('filename’)->store('mydir’, 'public')のように保存先ディスクを指定して保存します。

/* config/filessystems.php */

return [
    'default' => env('FILESYSTEM_DRIVER', 'local'), 

    'disks' => [
        'local' => [
            'driver' => 'local',
            'root' => storage_path('app'),
        ],

        'public' => [
            'driver' => 'local',
            'root' => storage_path('app/public'),
            'url' => env('APP_URL').'/storage',
            'visibility' => 'public',
        ],

        's3' => [
            'driver' => 's3',
            'key' => env('AWS_ACCESS_KEY_ID'),
            'secret' => env('AWS_SECRET_ACCESS_KEY'),
            'region' => env('AWS_DEFAULT_REGION'),
            'bucket' => env('AWS_BUCKET'),
            'url' => env('AWS_URL'),
            'endpoint' => env('AWS_ENDPOINT'),
            'use_path_style_endpoint' => env('AWS_USE_PATH_STYLE_ENDPOINT', false),
        ],
    ],

    'links' => [
        public_path('storage') => storage_path('app/public'),
    ],
];

以下は図書データベースの新規エントリーの作成を例にファイルアップロードの具体的なやり方を説明しますが、まとめると以下の作業が必要です。

  1. フォームを提示するためのRouteエントリー('books/create’)、リクエストを受け付けるコントローラーメソッド('BookController@create’)と実際のフォームが書かれたビュー('books.create’)の用意。
  2. フォームを処理するためのRouteエントリー('books’)(フォームのactionのURLとなるもの)とコントローラーメソッド('BookController@store’)の作成。

Routeエントリーの作成

routes/web.phpファイルに以下の内容を追加します。

/* web.php */

use App\Http\Controllers\BookController;

Route::get('books/create', [BookControler::class, 'create']);
Route::post('books', [BookControler::class, 'store']);

// または以下のように書くこともできます。
Route::get('books/create', 'App\Http\Controllers\BookController@create');
Route::post('books', 'App\Http\Controllers\BookController@store');

コントローラメソッドの追加

app/Http/Controllers/BookController.phpのBookControllerクラスに以下の内容を追加します。ユーザ入力と実際のファイル保存のロジックは後ろの方に詳しく書きます。

/* app/Http/Controllers/BookController.phpのBookControllerクラス */

public function create() {
  return view('books.create');
}

public function store(Request $request) {
  // ここにユーザ入力のvalidationロジックを書く

 // ここにユーザ入力データとファイルの保存を書く
}

ユーザ入力用フォームの用意

resources/views/books/create.blade.phpにフォームの内容を追加します。注意点として

  • @csrfを忘れずに入れること。
  • enctype="multipart/form-data"をつけること。これがないと$request->file('cover_image’)がnullを返します。
/* create.blade.php */

@if ($errors->any())
    <ul id="errors">
        @foreach ($errors->all() as $error)
        <li>{{ $error }}</li>
        @endforeach
    </ul>
@endif

<form method="POST" action="/books" enctype="multipart/form-data">
    @csrf
    書名:<input type="text" name="title"> <br>
    著者:<input type="text" name="author"><br>
    出版社:<input type="text" name="publisher"><br>
    表紙画像:<input type="file" name="cover_image"><br><br>
    <input type="submit" value="作成">
</form>

//end here

ユーザ入力のValidationとデータの保存

以下は実際のコードとなります。画像ファイルサイズチェックのmax:10はキロバイト単位です。Validationが失敗するとValidationExceptionが発生し、エラーメッセージとともにフォームページに自動的にリダイレクトされます。特に何かをする必要はありません。ユーザが入力したデータも保存された状態です。

validationルールの詳細はhttps://laravel.com/docs/8.x/validation#available-validation-rulesを参照するとよいでしょう。

/* BookController.phpのBookControllerクラス */    

public function store(Request $request) {
    // user input validation
    $request->validate([
        'title' => 'required|max:255',
        'author' => 'required|max:255',
        'publisher' => 'max:255',
        'cover_image' => 'max:10|mimes:jpg,jpeg,png,gif'
    ]);
    
    // validate and store uploaded file.
    if ($request->hasFile('cover_image') && $request->file('cover_image')->isValid()) {
        $path = $request->cover_image->store('cover', 'public');
    }

    // create new book entry
    $fields = $request->only('title', 'author', 'publisher');
    $fields['cover_image'] = $path;
    Book::create( $fields);

    return redirect('/');
}
// end here

Laravel,PHP

Posted by deanza329