Laravel File Upload: A Complete Tutorial and Guide
Tags: laravel, php, beginners, webdev
Published: 2022-09-12 06:17:31

---
title: Laravel File Upload: A Complete Tutorial and Guide
published: true
date: 2022-09-05 14:40:28 UTC
tags: laravel,php,beginner,webdev
canonical_url: https://www.iankumu.com/blog/laravel-file-upload/?utm_source=rss&utm_medium=rss&utm_campaign=laravel-file-upload
---

Working with files in any application is a crucial part of any system. Laravel provides a filesystem from where we can interact with files; file upload, storing or retrieving them.

If you have your application [deployed to production](https://www.iankumu.com/blog/how-to-deploy-laravel-on-apache-server/) using one of the [hosting providers](https://www.iankumu.com/blog/best-laravel-hosting/), It is important to know how to manage your resources wisely. 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](https://aws.amazon.com/s3/), [Google Cloud Storage](https://cloud.google.com/storage) or any other external disk services.

In this article, I am going to show you **how to upload** and [**compress files**](https://webtools.iankumu.com/image-compressor) **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

```bash
laravel new test 
```

Or

```bash
composer create-project laravel/laravel test
```

### Step 2: Add Auth Scaffolding

In this step, we can use [Laravel breeze](https://laravel.com/docs/9.x/starter-kits#laravel-breeze) to scaffold authentication and all other necessary requirements such as password reset and email confirmation logic.

```bash
composer require laravel/breeze
```

### 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.

```bash
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
<?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
<?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](https://www.php.net/manual/en/language.oop5.traits.php) 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](https://github.com/Superbalist/laravel-google-cloud-storage).

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
<?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](https://github.com/spatie/laravel-image-optimizer)

```bash
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.

```php
// 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](https://www.iankumu.com/blog/laravel-validation/) 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 renamed the file to be uploaded. The format of the file path will be **Folder/filename and extension** i.e **Products/HIDvPbozwW.png**

```php
<?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)
    {
        if ($request->hasFile('file')) {
            $path = $this->UploadFile($request->file('file'), 'Products');
            Files::create([
                'path' => $path
            ]);
            return redirect()->route('files.index')->with('success', 'File Uploaded Successfully');
        }
    }
}
```

![Laravel File upload](https://www.iankumu.com/blog/wp-content/uploads/2022/09/image-2-1024x552.png)
_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

```php
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](https://www.iankumu.com/blog/wp-content/uploads/2022/09/image-1024x390.png)
_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.

```bash
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 

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

#### Using S3 or GCS 

```php
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.

```php
<img src="{{asset('storage/'.$file->path)}}" alt="file name">
//or
<img src="{{$file->path}}" alt="file name">

```

![Laravel File Upload](https://www.iankumu.com/blog/wp-content/uploads/2022/09/image-1-1024x407.png)
_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](https://stackoverflow.com/questions/64887893/how-to-update-image-with-put-method-in-laravel-rest-api). 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.

```php
 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.

```php
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
<?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);
            }
        }
    }
}
```

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](https://github.com/Intervention/image). This package can help you resize images before storing them.

```php
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. 

If you enjoyed this article, you'd love the [Free Laravel Guide](https://www.iankumu.com/blog/newsletter/) I prepared for you. Be sure to get your guide today.
Thank you for reading

The post [Laravel File Upload: A Complete Tutorial and Guide](https://www.iankumu.com/blog/laravel-file-upload/) appeared first on [Ian Kumu's Blog](https://www.iankumu.com/blog).