Laravel File Upload

Laravel File Upload: A Complete Tutorial and Guide

Spread the love

Last Updated on February 15, 2024

Working with files in any application is a crucial part of any system. Laravel provides a filesystem from where we can interact with files be it file uploads, file storage, or file retrievals.

If you have your application deployed to production using one of the hosting providers, It is important to know how to manage your resources wisely and minimize the size of your videos or images. One important thing we could do is compress the files/images so that they do not occupy a lot of space in your server or any storage service such as Amazon S3, Google Cloud Storage, or any other external disk services.

In this article, I am going to show you how to upload and compress files in Laravel before storing them.

How do you Upload Files in Laravel?

To upload files in Laravel we can follow the following steps:

Step 1: Create a Laravel Project

We can use the Laravel new command or composer

laravel new test 

Or

composer create-project laravel/laravel test

Step 2: Add Auth Scaffolding

In this step, we can use Laravel breeze to scaffold authentication and all other necessary requirements such as password reset and email confirmation logic.

composer require laravel/breeze --dev

php artisan breeze:install
php artisan migrate
npm install
npm run dev

Step 3: Add Model and Migration

The next step is to create a migration file that will contain the file name and folder. We can use artisan to create a model and migration file.

php artisan make:model Files -m

The -m flag creates a migration file for the Files Model. We can add the following logic to the Model

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Files extends Model
{
    use HasFactory;

    protected $fillable = ['path'];
}

We can then specify the columns in the files table

<?php

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

return new class extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('files', function (Blueprint $table) {
            $table->id();
            $table->string('path');
            $table->timestamps();
        });
    }

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

Step 4: Create a generic File Upload Trait

Traits help us reuse code across multiple classes. This trait will contain the logic for Uploading the file, Renaming the File, Storing the Files in User Specified Folders, and Delete Files from storage

For example, in an e-commerce system, we may want to separate Images into Folders; Main Images, Secondary Images, Banners, etc.

To do so we will use Illuminate\Http\UploadedFile class to work with the files.

We can also make the trait to be usable with any external disk such as Amazon S3.

Laravel supports local file storage and Amazon S3 out of the box. If you want to use Google Cloud Storage as your storage then you can consider using this package.

Either way, whichever storage service you decide to use, the trait should be able to handle it without adding any extra implementations.

We can create an App\Traits folder in the App directory which will contain all our traits.

<?php

namespace App\Traits;

use Illuminate\Support\Str;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\Storage;

trait Upload
{
    public function UploadFile(UploadedFile $file, $folder = null, $disk = 'public', $filename = null)
    {
        $FileName = !is_null($filename) ? $filename : Str::random(10);
        return $file->storeAs(
            $folder,
            $FileName . "." . $file->getClientOriginalExtension(),
            $disk
        );
    }

    public function deleteFile($path, $disk = 'public')
    {
        Storage::disk($disk)->delete($path);
    }
}

To compress the images upon upload, we can use one of Spatie’s Packages

composer require spatie/laravel-image-optimizer 

We can have the images compressed automatically when they are uploaded thereby reducing their file size before uploading them to storage. To set it up, we will first need to register it as route middleware in the app/Http/Kernel.php file.

// app/Http/Kernel.php   
protected $routeMiddleware = [   
     'optimizeImages' => \Spatie\LaravelImageOptimizer\Middlewares\OptimizeImages::class,   
   ]; 

We will then assign the middleware later to the file upload route.

Step 5: Handle File uploads using a Controller

The next step is to Receive Files through a POST request. We will use the store method in the file upload controller to do so.

We can also check the validations to ensure that the files uploaded are of the correct type and are the allowed files.

The file path is also stored in the file table. The file path is returned from our trait after it has been renamed the file to be uploaded. The format of the file path will be Folder/filename and extension i.e Products/HIDvPbozwW.png

<?php

namespace App\Http\Controllers;

use App\Models\Files;
use App\Traits\Upload; //import the trait
use Illuminate\Http\Request;

class FilesController extends Controller
{
    use Upload;//add this trait

    public function store(Request $request)
    {
        if ($request->hasFile('file')) {
            $path = $this->UploadFile($request->file('file'), 'Products');//use the method in the trait
            Files::create([
                'path' => $path
            ]);
            return redirect()->route('files.index')->with('success', 'File Uploaded Successfully');
        }
    }
}
Laravel File upload
File paths in the database

Step 6: Add the Route

We can add the route to the routes/web.php file. We can use the middleware we created earlier in our route

Route::post('upload-files', [FileController::class,'store'])->middleware('optimizeImages'); 

Step 7: Add File Upload UI

We can create a view file and add a file upload form

Laravel File Upload Form
File Upload Form

Step 8: Add Storage Link(Optional)

Files uploaded using the public disk option are always stored in the storage/app/public folder. We can use the storage:link command to create a symlink to the public folder.

php artisan storage:link 

Step 9: View Uploaded Files

Once the files are uploaded to your preferred storage, you can view the file. If you are using the public folder, you can use the asset helper or public_path helper to return the file path. If you are using a third-party storage system such as S3 or Google Cloud storage, you can use the Storage facade

Using public folder

asset('storage/'.$file->path)

Using S3 or GCS

use Illuminate\Support\Facades\Storage;
Storage::disk('s3')->url($file->path)

You can then append the path as your image source and display them on your application.

<img src="{{asset('storage/'.$file->path)}}" alt="file name">
//or
<img src="{{$file->path}}" alt="file name">
Laravel File Upload
Display Files

How can I update Files in Laravel?

By default, there is no intrinsic way to update files/images using the default PUT or PATCH request based on this issue. Therefore, we need to look for another way to do so. We could use a POST request but then delete a previous file if it exists and then upload a new file and update the file path in the database.

 public function update_file(Request $request) //POST
    {
        //get the file id and retrieve the file record from the database
        $file_id = $request->input('file_id');
        $file = Files::where('id', $file_id)->first();
        //check if the request has a file
        if ($request->hasFile('file')) {
            //check if the existing file is present and delete it from the storage
            if (!is_null($file->path)) {
                $this->deleteFile($file->path);
            }
            //upload the new file
            $path = $this->UploadFile($request->file('file'), 'Products');
        }
        //upadate the file path in the database
        $file->update(['path' => $path]);

        //redirect with the success message
        return redirect()->back()->with('success', 'File Updated Successfully');
    }

We can then define the route to update the file.

Route::post('update-file', [FilesController::class, 'update_file'])->middleware('optimizeImages');

How do I upload multiple Files and Images in Laravel?

It is pretty easy. We can reuse our trait and use a foreach loop to upload and store the path in the database.

We will first update the File Controller to allow for multiple files.

<?php

namespace App\Http\Controllers;

use App\Models\Files;
use App\Traits\Upload;
use Illuminate\Http\Request;


class FilesController extends Controller
{
    use Upload;

    public function store(Request $request)
    {

        $file_details = [];

        //check if request has files
        if ($request->hasFile('files')) {
          // loop through each file and upload it

            foreach ($request->file('files') as $key => $file) {
                //Upload to Storage
                $path = $this->UploadFile($file, 'Products');

                //reformat the file details
                array_push($file_details, [
                    'path' => $path,
                ]);
            }

            //add each file details to database
            foreach ($file_details as $key => $value) {
                Files::create($value);
            }
            //clear the file details array
            $file_details = [];
        }
    }
}

The store method now allows for multiple files to be uploaded.

How do I resize files in Laravel?

You can resize files before storing them using the Intervention Image package. This package can help you resize images before storing them.

use Intervention\Image\Facades\Image;
Image::make($file->path)->resize(200, 200);

Conclusion

Working with files and images can be a daunting task in any application but Laravel makes it easy to work with multiple Storage services using their inbuilt APIs and other third-party packages. Thank you for reading

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *