How to Upload a File in Laravel 10

To upload a file in Laravel 10, use the “Storage::disk(‘local’)->putFileAs( ‘file name’)” function. Laravel Flysystem integration delivers simple drivers for working with local filesystems, SFTP, and Amazon S3.

Here is the step-by-step guide to uploading a file in Laravel.

Step 1: Install Laravel

laravel new fileupload

Go inside the folder.

Install Laravel UI Package using the below command.

composer require laravel/ui --dev

Now add Bootstrap with auth scaffolding.

php artisan ui bootstrap --auth

Run the below commands one by one.

npm install

npm run build

Step 2: Create a file table.

We need to create a File model and migrations using the following command.

php artisan make:model File -m

Define the schema inside the newly created migration file.

// create_files_table

<?php

use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class CreateFilesTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up(): void
    {
        Schema::create('files', function (Blueprint $table) {
            $table->id();
            $table->integer('user_id')->unsigned()->index();
            $table->string('title');
            $table->text('overview');
            $table->decimal('price', 6, 2);
            $table->timestamps();
            $table->softDeletes();
            $table->foreign('user_id')
                  ->references('id')
                  ->on('users')
                  ->onDelete('cascade');
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('files');
    }
}

Migrate using the following command.

php artisan migrate

The next step is to build a relationship between the User and File models.

Inside File.php, write the following code.

<?php

// File.php

namespace App;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;

class File extends Model
{
    use SoftDeletes;

    protected $fillable = [
      'title',
      'overview',
      'price'
    ];

    public function user()
    {
      return $this->belongsTo(User::class);
    }
}

Here we have stated that every file belongs to a particular User.

Define the Relationship inside the User.php model.

<?php

// User.php

namespace App;

use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;

class User extends Authenticatable
{
    use Notifiable;

    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    protected $fillable = [
        'name', 'email', 'password',
    ];

    /**
     * The attributes that should be hidden for arrays.
     *
     * @var array
     */
    protected $hidden = [
        'password', 'remember_token',
    ];

    public function files()
    {
      return $this->hasMany(File::class);
    }
}

Step 3: Create a View and Route for uploading files.

The base app.blade.php file looks like this:

<!doctype html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
 <meta charset="utf-8">
 <meta name="viewport" content="width=device-width, initial-scale=1">

 <!-- CSRF Token -->
 <meta name="csrf-token" content="{{ csrf_token() }}">

 <title>{{ config('app.name', 'Laravel') }}</title>

 <!-- Fonts -->
 <link rel="dns-prefetch" href="//fonts.bunny.net">
 <link href="https://fonts.bunny.net/css?family=Nunito" rel="stylesheet">

 <!-- Scripts -->
 @vite(['resources/sass/app.scss', 'resources/js/app.js'])
</head>
<body>
 <div id="app">
  <nav class="navbar navbar-expand-md navbar-light bg-white shadow-sm">
   <div class="container">
    <a class="navbar-brand" href="{{ url('/') }}">
     {{ config('app.name', 'Laravel') }}
    </a>
    <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="{{ __('Toggle navigation') }}">
      <span class="navbar-toggler-icon"></span>
    </button>

 <div class="collapse navbar-collapse" id="navbarSupportedContent">
 <!-- Left Side Of Navbar -->
 <ul class="navbar-nav me-auto">

 </ul>

 <!-- Right Side Of Navbar -->
 <ul class="navbar-nav ms-auto">
 <!-- Authentication Links -->
 @guest
  @if (Route::has('login'))
   <li class="nav-item">
    <a class="nav-link" href="{{ route('login') }}">{{ __('Login') }}</a>
   </li>
 @endif

 @if (Route::has('register'))
  <li class="nav-item">
   <a class="nav-link" href="{{ route('register') }}">{{ __('Register') }}</a>
  </li>
 @endif
 @else
  <li class="nav-item dropdown">
    <a id="navbarDropdown" class="nav-link dropdown-toggle" href="#" role="button" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false" v-pre>
      {{ Auth::user()->name }}
    </a>

 <div class="dropdown-menu dropdown-menu-end" aria-labelledby="navbarDropdown">
   <a class="dropdown-item" href="{{ route('logout') }}"
      onclick="event.preventDefault();
      document.getElementById('logout-form').submit();">
         {{ __('Logout') }}
   </a>

   <form id="logout-form" action="{{ route('logout') }}" method="POST" class="d-none">
      @csrf
   </form>
  </div>
 </li>
 @endguest
 </ul>
 </div>
 </div>
 </nav>

 <main class="py-4">
 @yield('content')
 </main>
 </div>
</body>
</html>

Create a FileController using the following command.

php artisan make:controller FileController

Inside the home.blade.php file, write the following code inside.

@extends('layouts.app')

@section('content')
<div class="container">
    <div class="row justify-content-center">
        <div class="col-md-8">
            <div class="card">
                <div class="card-header">File Upload</div>
                <div class="card-body">
                <form method="POST" action="{{ route('file.upload') }}" aria-label="{{ __('Upload') }}">
                        @csrf
                        <div class="form-group row">
                            <label for="title" class="col-sm-4 col-form-label text-md-right">{{ __('Title') }}</label>
                            <div class="col-md-6">
                                <input id="title" type="text" class="form-control{{ $errors->has('title') ? ' is-invalid' : '' }}" name="title" value="{{ old('title') }}" required autofocus />
                                @if ($errors->has('title'))
                                    <span class="invalid-feedback" role="alert">
                                        <strong>{{ $errors->first('title') }}</strong>
                                    </span>
                                @endif
                            </div>
                        </div>
                        <div class="form-group row">
                            <label for="overview" class="col-sm-4 col-form-label text-md-right">{{ __('Overview') }}</label>
                            <div class="col-md-6">
                                <textarea id="overview" cols="10" rows="10" class="form-control{{ $errors->has('overview') ? ' is-invalid' : '' }}" name="overview" value="{{ old('overview') }}" required autofocus></textarea>
                                @if ($errors->has('overview'))
                                    <span class="invalid-feedback" role="alert">
                                        <strong>{{ $errors->first('overview') }}</strong>
                                    </span>
                                @endif
                            </div>
                        </div>

                        <div class="form-group row">
                            <label for="price" class="col-md-4 col-form-label text-md-right">{{ __('Price') }}</label>
                            <div class="col-md-6">
                                <input id="price" type="text" class="form-control{{ $errors->has('price') ? ' is-invalid' : '' }}" name="price" required>
                                @if ($errors->has('price'))
                                    <span class="invalid-feedback" role="alert">
                                        <strong>{{ $errors->first('price') }}</strong>
                                    </span>
                                @endif
                            </div>
                        </div>
                        <div class="form-group row mb-0">
                            <div class="col-md-8 offset-md-4">
                                <button type="submit" class="btn btn-primary">
                                    {{ __('Upload') }}
                                </button>
                            </div>
                        </div>
                    </form>
                </div>
            </div>
        </div>
    </div>
</div>
@endsection

Also, you need to define the Post route inside routes >> web.php file.

<?php

// web.php

Route::get('/', function () {
    return view('welcome');
});

Auth::routes();

Route::get('/home', 'HomeController@index')->name('home');

Route::post('file/upload', 'FileController@store')->name('file.upload');

Save the file and register the user; you can see this page.

Laravel File Upload Example

You can see that we have not yet used any file form field from the form. We will do it in a minute, but this is our primary form setup.

Step 4: Storing the form data.

We need to write the store function to save the data in the Database.

<?php

// FileController.php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class FileController extends Controller
{
    public function store(Request $request)
    {
       $request->validate([
        'title' => 'required:max:255',
        'overview' => 'required',
        'price' => 'required|numeric'
      ]);

      auth()->user()->files()->create([
        'title' => $request->get('title'),
        'overview' => $request->get('overview'),
        'price' => $request->get('price')
      ]);

      return back()->with('message', 'Your file is submitted Successfully');
    }
}

We have also included the validation for our form fields.

Also, we need to update our view to see the flash message.

// home.blade.php 

@if(session()->get('message'))
    <div class="alert alert-success">
       {{ session()->get('message') }}
    </div>
@endif

Step 5: Setup File Upload Relationship.

We will create another model and migration for the uploading files.

Type the following command to generate the model and migration.

php artisan make:model Upload -m

Write the following schema inside <timestamp>create_uploads_table.php file.

// create_uploads_table.php

public function up(): void
{
        Schema::create('uploads', function (Blueprint $table) {
            $table->increments('id');
            $table->integer('user_id')->unsigned()->index();
            $table->string('filename');
            $table->softDeletes();
            $table->timestamps();

            $table->foreign('user_id')
                  ->references('id')
                  ->on('users')
                  ->onDelete('cascade');
        });
}

Migrate the Database using the following command.

php artisan migrate

Now we need to set up the relationships.

Inside the Upload.php file, write the following code.

<?php

// Upload.php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Upload extends Model
{

  protected $fillable = [
    'filename'
  ];

    public function user()
    {
      return $this->belongsTo(User::class);
    }
}

Here, Upload is belongsTo File and User.

Write the following relationship methods inside the User.php model.

// User.php

public function files()
{
   return $this->hasMany(File::class);
}

public function uploads()
{
   return $this->hasMany(Upload::class);
}

Finally, write the following relationships inside the File.php model.

// File.php

public function user()
{
   return $this->belongsTo(User::class);
}

Step 6: Set up the Dropzone.

Install the Dropzone library using the following command.

npm install dropzone --save

Include this library inside resources >> assets >> js >> bootstrap.js file.

We need to add the code inside that file.

// bootstrap.js

/**
 * Dropzone
 */

 window.Dropzone = require('dropzone');
 Dropzone.autoDiscover = false;

We need to import the Dropzone CSS files. So inside resources >> assets >> sass >> app.scss file, add the following code.

// app.scss

// Fonts
@import url('https://fonts.googleapis.com/css?family=Nunito');

// Variables
@import 'variables';

// Bootstrap
@import '~bootstrap/scss/bootstrap';

// Dropzone
@import '~dropzone/dist/min/dropzone.min.css';

.dropzone {
  margin-bottom: 20px;
  min-height: auto;
}

Compile the file using the following command.

npm run dev

We need to use the Dropzone library inside the home.blade.php file.

@extends('layouts.app')

@section('content')
<div class="container">
    <div class="row justify-content-center">
        <div class="col-md-8">
            @if(session()->get('message'))
            <div class="alert alert-success">
              {{ session()->get('message') }}
            </div>
            @endif
            <div class="card">
                <div class="card-header">File Upload</div>
                <div class="card-body">
                <form method="POST" action="{{ route('file.upload') }}" aria-label="{{ __('Upload') }}">
                      @csrf
                      <div class="form-group row ">
                        <label for="title" class="col-sm-4 col-form-label text-md-right">{{ __('File Upload') }}</label>
                        <div class="col-md-6">
                          <div id="file" class="dropzone"></div>
                        </div>    
                      </div>
                        <div class="form-group row">
                            <label for="title" class="col-sm-4 col-form-label text-md-right">{{ __('Title') }}</label>
                            <div class="col-md-6">
                                <input id="title" type="text" class="form-control{{ $errors->has('title') ? ' is-invalid' : '' }}" name="title" value="{{ old('title') }}" required autofocus />
                                @if ($errors->has('title'))
                                    <span class="invalid-feedback" role="alert">
                                        <strong>{{ $errors->first('title') }}</strong>
                                    </span>
                                @endif
                            </div>
                        </div>
                        <div class="form-group row">
                            <label for="overview" class="col-sm-4 col-form-label text-md-right">{{ __('Overview') }}</label>
                            <div class="col-md-6">
                                <textarea id="overview" cols="10" rows="10" class="form-control{{ $errors->has('overview') ? ' is-invalid' : '' }}" name="overview" value="{{ old('overview') }}" required autofocus></textarea>
                                @if ($errors->has('overview'))
                                    <span class="invalid-feedback" role="alert">
                                        <strong>{{ $errors->first('overview') }}</strong>
                                    </span>
                                @endif
                            </div>
                        </div>

                        <div class="form-group row">
                            <label for="price" class="col-md-4 col-form-label text-md-right">{{ __('Price') }}</label>
                            <div class="col-md-6">
                                <input id="price" type="text" class="form-control{{ $errors->has('price') ? ' is-invalid' : '' }}" name="price" required>
                                @if ($errors->has('price'))
                                    <span class="invalid-feedback" role="alert">
                                        <strong>{{ $errors->first('price') }}</strong>
                                    </span>
                                @endif
                            </div>
                        </div>
                        <div class="form-group row mb-0">
                            <div class="col-md-8 offset-md-4">
                                <button type="submit" class="btn btn-primary">
                                    {{ __('Upload') }}
                                </button>
                            </div>
                        </div>
                    </form>
                </div>
            </div>
        </div>
    </div>
</div>
@endsection

@section('scripts')
  <script>
    var drop = new Dropzone('#file', {
      url: "{{ route('upload') }}"
    });
  </script>
@endsection

Also, define the POST route to upload a file.

// web.php

Route::post('upload', 'FileController@upload')->name('upload');

Create an upload function inside the FileController.php file.

// FileController.php

public function upload()
{
   return 'x';
}

Save the file and go to http://fileupload.test/home.

Laravel Dropzone File Upload Example

Step 7: Handling File Upload Process.

We must first add the headers while sending a POST request to the server.

// home.blade.php

@section('scripts')
  <script>
    var drop = new Dropzone('#file', {
      createImageThumbnails: false,
      addRemoveLinks: true,
      url: "{{ route('upload') }}",
      headers: {
        'X-CSRF-TOKEN': document.head.querySelector('meta[name="csrf-token"]').content
      }
    });
  </script>
@endsection

The final code for the FileController.php file looks like below.

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Storage;
use App\Upload;

class FileController extends Controller
{
    public function store(Request $request)
    {
       $request->validate([
        'title' => 'required:max:255',
        'overview' => 'required',
        'price' => 'required|numeric'
      ]);

      auth()->user()->files()->create([
        'title' => $request->get('title'),
        'overview' => $request->get('overview'),
        'price' => $request->get('price')
      ]);

      return back()->with('message', 'Your file is submitted Successfully');
    }

    public function upload(Request $request)
    {
      $uploadedFile = $request->file('file');
      $filename = time().$uploadedFile->getClientOriginalName();

      Storage::disk('local')->putFileAs(
        'files/'.$filename,
        $uploadedFile,
        $filename
      );

      $upload = new Upload;
      $upload->filename = $filename;

      $upload->user()->associate(auth()->user());

      $upload->save();

      return response()->json([
        'id' => $upload->id
      ]);
    }
}

Laravel 5.6 File Upload Example Tutorial

The uploaded file is inside the Storage >> app >> files folder.

That’s it for this tutorial.

12 thoughts on “How to Upload a File in Laravel 10”

  1. use dropzone cdn

    $(document).ready(function () {
    var drop = new Dropzone(‘.dropzone’, {
    uploadMultiple: true,
    parallelUploads: 2,
    maxFilesize: 16,
    previewTemplate: document.querySelector(‘#preview’).innerHTML,
    addRemoveLinks: true,
    dictRemoveFile: ‘Remove file’,
    dictFileTooBig: ‘Image is larger than 16MB’,
    timeout: 10000,

    init: function () {
    this.on(“removedfile”, function (file) {
    $.post({
    url: ‘/images-delete’,
    data: {id: file.name, _token: $(‘[name=”_token”]’).val()},
    dataType: ‘json’,
    success: function (data) {
    total_photos_counter–;
    $(“#counter”).text(“# ” + total_photos_counter);
    }
    });
    });
    },
    success: function (file, done) {
    total_photos_counter++;
    $(“#counter”).text(“# ” + total_photos_counter);
    }
    })
    var total_photos_counter = 0;

    })

    Reply
  2. Thank you for this good tutorial. Please note that you forgot to add enctype=”multipart/form-data” to the form, so the file field won’t be sent.

    Reply
  3. Hello, i made this in Laravel 10 and get a Error 500 after Step 3.
    If i open the subpage /home i just see the 500error 🙁

    Any Ideas?

    Reply

Leave a Comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.