Table of contents
No headings in the article.
As a full-stack web developer, I've always needed to implement a file upload feature in my projects. Today, I'll show you how it's easy to upload files to the server with Laravel Framework.
Step 1
Let's run the following artisan command to create a controller called FileUploadController. This controller will be used along the tutorial to show the file upload page to the users and store the uploaded files on the server.
php artisan make:controller FileUploadController
Step 2
Since we created our controller in step 1, in this step we will create a route in web.php to show the page to the users.
Route::get('/file-upload-test', [FileUploadController::class, 'index'])->name('file-upload.index');
Step 3
In step 2 we created a route with the URL of file-upload-test which calls the index method in FileUploadController to show a page to the users.
But we didn't create this method yet. So, let's create this index method in the FileUploadController which will render a blade file that we named as file-upload.blade.php to show the file upload page.
<?php
namespace App\Http\Controllers;
use Illuminate\Contracts\Foundation\Application;
use Illuminate\Contracts\View\Factory;
use Illuminate\Contracts\View\View;
class FileUploadController extends Controller
{
public function index(): Factory|View|Application
{
return view('file-upload');
}
}
Step 4
In step 3 we created the index method in FileUploadController which renders a blade file called file-upload.blade.php to show the file upload page.
But we didn't create the file-upload.blade.php file yet. Let's create this file in the resources/views folder and put the following HTML into the file.
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
.flex {
display: flex;
}
.flex-col {
flex-direction: column;
}
.mt-2 {
margin-top: 20px;
}
</style>
</head>
<body>
<form action="{{ route('file-upload.store') }}" enctype="multipart/form-data" method="POST">
@csrf
<div class="flex flex-col shadow">
<label for="file_selector">Select a file to upload</label>
<input type="file" id="file_selector" name="file">
</div>
<button type="submit" class="mt-2">Upload File</button>
</form>
</body>
</html>
Once this blade file is rendered we see the following page. (If you visit file-upload-test URL now you will get an error, move to the step 5)
Basically, we have a simple form with a label, an input field with the file type, and a button used to submit the form.
Let's explore the following form element a little bit to understand what's going on.
<form action="{{ route('file-upload.store') }}" enctype="multipart/form-data" method="POST">
@csrf
<div class="flex flex-col shadow">
<label for="file_selector">Select a file to upload</label>
<input type="file" id="file_selector" name="uploaded_file">
</div>
<button type="submit" class="mt-2">Upload File</button>
</form>
We need an endpoint on the form element to send the submitted data to some URL in our app. So, we put action={{ route('file-upload.store') }} which means that whenever the form is submitted the data will be sent to this route (we didn't create it yet).
Since we are aiming to upload a file we put enctype="multipart/form-data" otherwise the file is not submitted to the back-end.
The method=POST attribute is specified in the form because we are going to send a POST request to the endpoint.
In order to pass CSRF validation on Laravel we call ** @csrf** blade directive in the form element which creates a hidden CSRF token field.
Step 5
In step 4 we created an HTML form in the file-upload.blade.php file and now we are going to create a route named file-upload.store in the web.php file.
Route::get('/file-upload-test', [FileUploadController::class, 'index'])->name('file-upload.index');
Route::post('/file-upload', [FileUploadController::class, 'store'])->name('file-upload.store');
Step 6
In step 5 we created a route file-upload.store in web.php and we know that the route will call store method in the FileUploadController. So, let's create this method in the controller to upload the file.
public function store(Request $request)
{
if ($request->hasFile('uploaded_file')) {
$uploadedFile = $request->file('uploaded_file'); // the file uploaded
$extension = $request->file('uploaded_file')->getClientOriginalExtension(); //jpg, jpeg, png
$fileName = Str::uuid() . '.' . $extension; // de3f31db-85f8-4b9b-a3b9-a4b45b551322.jpg
Storage::disk('public')->putFileAs('uploaded_files', $uploadedFile, $fileName);
}
return redirect()->back();
}
Let's explore how this method work.
First of all we check if the request has a file in the uploaded_file parameter.
If there is a file then we store it in the uploadedFile variable.
Then we get the uploaded file extension using $request->file('uploaded_file')->getClientOriginalExtension();
We need a name to store the file in our file system. So, the Str::uuid() helper is used to create a universal unique identifier for the file name and appended the file extension to the end of it.
There are three different disk options on Laravel as default local, public, and s3. Since we want to show the uploaded file in our application later we use public disk.
In the last part, we upload the file into the uploaded_files folder in the public disk (if uploaded_files folder does not exist, it will be automatically created) using Storage::disk helper in Laravel.
This is how actually we upload a file in the Laravel Framework.
If you like to upload a file but also want to save the path into the database, then basically you just need to save the fileName variable as the path and later on, you can use this path to show the file.
Example;
<img src="{{ asset('storage/uploaded_files/7818704d-088b-4236-b3fb-dcc15bf57cc6.jpeg') }}" alt="">
Note: Since we use the public disk of the framework we should run the following artisan command to make sure the uploaded_files folder in the storage folder of the application is linked to the public as a symbolic link. Otherwise, the uploaded files will not be publicly available.
php artisan storage:link