How to Upload and Store Files with Laravel 8

If you need to create a form that requires users to provide a picture or some other media, this article will prove useful to you. We will be taking a look at how you create a form with a drop zone that allows users to drag-and-drop files they wish to upload as well as what you will need on your Laravel backend to store these files. This tutorial assumes you know your way around the file system of a Laravel project. Let’s do this!!!

Case Scenario

1. Create a new laravel project

composer create-project laravel/laravel students

Run the following line to navigate into the folder:

cd students

Don’t forget to update your .env file with the appropriate database name.

2. Create a “Student” model and its associated controller and migration file

php artisan make:model Student -cm

3. Create a view where you can show your form

4. Add jQuery and Dropzone CDNs to your view file

<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/dropzone/5.9.2/basic.css" integrity="sha512-+Vla3mZvC+lQdBu1SKhXLCbzoNCl0hQ8GtCK8+4gOJS/PN9TTn0AO6SxlpX8p+5Zoumf1vXFyMlhpQtVD5+eSw==" crossorigin="anonymous" /><script src="https://cdnjs.cloudflare.com/ajax/libs/dropzone/5.9.2/min/dropzone.min.js" integrity="sha512-VQQXLthlZQO00P+uEu4mJ4G4OAgqTtKG1hri56kQY1DtdLeIqhKUp9W/lllDDu3uN3SnUNawpW7lBda8+dSi7w==" crossorigin="anonymous"></script><script src="https://code.jquery.com/jquery-3.6.0.min.js" integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous"></script>

After adding the CDNs to your HTML layout in students.blade.php, your view file should look like this:

<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta http-equiv="X-UA-Compatible" content="ie=edge"><link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/dropzone/5.9.2/basic.css" integrity="sha512-+Vla3mZvC+lQdBu1SKhXLCbzoNCl0hQ8GtCK8+4gOJS/PN9TTn0AO6SxlpX8p+5Zoumf1vXFyMlhpQtVD5+eSw==" crossorigin="anonymous" /><title>Document</title></head><body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/dropzone/5.9.2/min/dropzone.min.js" integrity="sha512-VQQXLthlZQO00P+uEu4mJ4G4OAgqTtKG1hri56kQY1DtdLeIqhKUp9W/lllDDu3uN3SnUNawpW7lBda8+dSi7w==" crossorigin="anonymous"></script><script src="https://code.jquery.com/jquery-3.6.0.min.js" integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous"></script></body></html>

4. Edit your migration file

<?phpuse Illuminate\Database\Migrations\Migration;use Illuminate\Database\Schema\Blueprint;use Illuminate\Support\Facades\Schema;class CreateStudentsTable extends Migration{/*** Run the migrations.** @return void*/public function up(){Schema::create('students', function (Blueprint $table) {    $table->id();    $table->string('name');    $table->string('gender');    $table->string('file_path')->nullable();    $table->timestamps();  });}/*** Reverse the migrations.** @return void*/public function down(){  Schema::dropIfExists('students');}}

5. Run your migrations on the command line

php artisan migrate

6. Create your form

<!DOCTYPE html><html lang="en"><head>  <meta charset="UTF-8">  <meta name="viewport" content="width=device-width, initial-scale=1.0">  <meta http-equiv="X-UA-Compatible" content="ie=edge">  <meta name="csrf-token" content="{{ csrf_token() }}">  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/dropzone/5.9.2/basic.css" integrity="sha512-+Vla3mZvC+lQdBu1SKhXLCbzoNCl0hQ8GtCK8+4gOJS/PN9TTn0AO6SxlpX8p+5Zoumf1vXFyMlhpQtVD5+eSw==" crossorigin="anonymous" />  <title>Add Student</title>  <style>    .dropzoneDragArea {      background-color: #fbfdff;      border: 1px dashed #c0ccda;      border-radius: 6px;      padding: 60px;      text-align: center;      margin-bottom: 15px;      cursor: pointer;    }    .dropzone{      box-shadow: 0px 2px 20px 0px #f2f2f2;      border-radius: 10px;    }</style></head><body>  <h1>Provide Your Details here</h1>  <form method="post" name="demoform" id="demoform" action="{{ route('student.add') }}" enctype="multipart/form-data">  @csrf    <input type="hidden" class="student_id" name="student_id" id="student_id" value=""><div><label>Name:</label><input type="text" name="name"></div><div><label>Gender:</label><label><input type="radio" name="gender" value="male"> Male </label><label><input type="radio" name="gender" value="female"> Female </label></div><br><div><div id="dropzoneDragArea" class="dz-default dz-message dropzoneDragArea"><span>Upload file</span></div><div class="dropzone-previews"></div></div><div class="form-group"><button type="submit" class="btn btn-md btn-primary">create</button></div></form><script src="https://cdnjs.cloudflare.com/ajax/libs/dropzone/5.9.2/min/dropzone.min.js" integrity="sha512-VQQXLthlZQO00P+uEu4mJ4G4OAgqTtKG1hri56kQY1DtdLeIqhKUp9W/lllDDu3uN3SnUNawpW7lBda8+dSi7w==" crossorigin="anonymous"></script><script src="https://code.jquery.com/jquery-3.6.0.min.js" integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous"></script><script>Dropzone.autoDiscover = false;// Dropzone.options.demoform = false;let token = $('meta[name="csrf-token"]').attr('content');$(function() {var myDropzone = new Dropzone("div#dropzoneDragArea", {paramName: "file",url: "{{ route('student.store_file') }}",previewsContainer: 'div.dropzone-previews',addRemoveLinks: true,autoProcessQueue: false,uploadMultiple: false,parallelUploads: 1,maxFiles: 1,params: {_token: token},// The setting up of the dropzoneinit: function() {var myDropzone = this;//form submission code goes here$("form[name='demoform']").submit(function(event) {//Make sure that the form isn't actully being sent.event.preventDefault();URL = $("#demoform").attr('action');formData = $('#demoform').serialize();$.ajax({type: 'POST',url: URL,data: formData,success: function(result){if(result.status == "success"){// fetch the useidvar student_id = result.student_id;$("#student_id").val(student_id); // inseting student_id into hidden input field//process the queuemyDropzone.processQueue();}else{console.log("error");}}});});//Gets triggered when we submit the image.this.on('sending', function(file, xhr, formData){//fetch the student id from hidden input field and send that studentid with our imagelet student_id = document.getElementById('student_id').value;formData.append('student_id', student_id);});this.on("success", function (file, response) {  alert("Student added successfully!!");  location.reload();});this.on("queuecomplete", function () {});}});});</script></body></html>

jQuery is used to submit the form data without the image after which it receives a response containing the student_id of the student whose information was just stored. It then submits the image from the drop zone along with the id received.

Make sure the meta csrf tag is added to your view or you might face problem.

7. Update your routes

//Route for showing the formRoute::get('add-student', [StudentController::class, 'create']);//Route for storing all form data except the fileRoute::post('store-student', [StudentController::class, 'store'])->name('student.add');//Route for storing the fileRoute::post('store-file', [StudentController::class, 'storeFile'])->name('student.store_file');

As explained in step 4, we will need to upload our picture seperately from the rest of the form data. Two different routes are therefore provided accordingly.

To access the form on your browser:

  1. Start the server from your command line with the following command:
php artisan serve

2. Type the following into the address bar of your browser and press enter

http://localhost:8000/add-student

8. Update your controller

<?phpnamespace App\Http\Controllers;use Illuminate\Http\Request;use App\Models\Student;class StudentController extends Controller{  public function create(){     return view('students');  }  // This method stores the form data (name and gender)  public function store(Request $request){    try {      $student = new Student();      $student->name =  $request->name;      $student->gender =  $request->gender;      $student->save();    }    catch (\Exception $e) {      return response()->json(['status'=>'exception', 'msg'=>$e->getMessage()]);    }    //The id of the student is returned in the response so it can be used to update the student's record with the file's path later on    return response()->json(['status'=>"success", 'student_id'=>$student->id]);  }
//This method stores the form image using the id returned to the view by the store() method public function storeFile(Request $request){ if($request->file('file')){ $student = new Student(); $student_id = $request->student_id; //we are storing request file in the folder named 'files'
$path = $request->file('file')->store('files');
// we are updating our file_path column by using student_id to find the right record $student->where('id', $student_id)->update(['file_path'=>$path]); return response()->json(['status'=>"success"]); } }}

9. Test it!! Fill the form and submit it

If you want to give a name to the file you are uploading, you can use storeAs() method instead of the store() method used in the controller.

The file path that is saved to your database will look something like this

files/A0wjnHie4xlNR1o6qxHihU259yblArpIToGIEps8.png

Happy Coding !!! All the best !!!

Related Articles

Laravel 8: MySQL Database Query Tip Sheet #1

Laravel 8: MySQL Database Query Tip Sheet #2

Laravel 8: MySQL Database Query Tip Sheet #3

Laravel 8: MySQL Database Query Tip Sheet #4