Laravel 11 Multiple File Upload

Implementing Multiple File Uploads in Laravel 11: A Complete Guide to Secure Storage

In this article you will learn about, Laravel 11 Multiple File Upload.

Handling multiple file uploads is a critical feature for modern applications, from document management systems to media galleries. With Laravel 11, you can implement this functionality efficiently while ensuring security and scalability. This guide walks through every step, integrating local storage and database registration.


Why Use Multiple File Uploads?

Beyond improving user experience, bulk uploads reduce interaction time and simplify workflows such as:

  • Batch submission of financial documents.
  • Uploading portfolios with images and PDFs.
  • Integration with automated backup systems.

Key Insight: Applications supporting multiple uploads see 40% higher engagement than single-file systems (Source: Smashing Magazine, 2024).


Step 1: Initial Project Setup

System Requirements

  • PHP 8.2 or higher (for null safety and fibers).
  • Composer 2.6+ (optimized dependency management).
  • Enabled fileinfo extension (MIME type validation).

Create the Project

composer create-project laravel/laravel file-manager-app  
cd file-manager-app 

Tip: Use php artisan serve --port=8080 to avoid port conflicts in local environments.


Step 2: Database Modeling

Create the Migration

Generate the migration for the files table:

php artisan make:migration create_files_table

Define the schema in the generated file (database/migrations/[...]_create_files_table.php):

public function up(): void  
{  
    Schema::create('files', function (Blueprint $table) {  
        $table->id();  
        $table->string('name')->comment('Physical file name');  
        $table->string('original_name')->comment('Original file name');  
        $table->string('mime_type')->comment('MIME type (e.g., image/png)');  
        $table->timestamps();  
    });  
} 

Improvement: Additional fields like original_name and mime_type enable advanced auditing and filtering.

Run the migration:

php artisan migrate 

Step 3: Defining the File Model

Create the model and specify fillable attributes:

php artisan make:model File 

In app/Models/File.php:

protected $fillable = [  
    'name',  
    'original_name',  
    'mime_type'  
];  

Security Note: Avoid including sensitive fields like user_id in $fillable. Use controlled mass assignment.


Step 4: Developing the Controller

Generate the Controller

php artisan make:controller FileController 

Upload Logic (store Method)

In app/Http/Controllers/FileController.php:

public function store(Request $request)  
{  
    $validated = $request->validate([  
        'files' => 'required|array|max:10',  
        'files.*' => 'required|file|mimes:pdf,xlsx,csv,png,jpeg|max:5120',  
    ]);  

    $uploadedFiles = [];  

    foreach ($request->file('files') as $file) {  
        $originalName = $file->getClientOriginalName();  
        $hashedName = Str::random(40) . '.' . $file->extension();  
        $mimeType = $file->getMimeType();  

        // Store in the 'public/uploads' directory  
        $file->storeAs('uploads', $hashedName, 'public');  

        $uploadedFiles[] = [  
            'name' => $hashedName,  
            'original_name' => $originalName,  
            'mime_type' => $mimeType  
        ];  
    }  

    File::insert($uploadedFiles);  

    return back()  
        ->with('success', count($uploadedFiles) . ' files saved!')  
        ->with('fileList', $uploadedFiles);  
} 

Optimizations:

  • Hashed filenames: Prevent conflicts and unauthorized access.
  • Upload limits: Maximum of 10 files per request (max:10).
  • Disk storage: Uses the public driver for easy future CDN integration.

Step 5: Configuring Routes

In routes/web.php:

use App\Http\Controllers\FileController;  

Route::controller(FileController::class)  
    ->prefix('files')  
    ->group(function () {  
        Route::get('/upload', 'index')->name('files.form');  
        Route::post('/upload', 'store')->name('files.store');  
    });  

Advantage: Route grouping simplifies maintenance and middleware application.


Step 6: Building the Blade View with Bootstrap

In resources/views/fileUpload.blade.php:

<div class="container">  
    <div class="card shadow-lg mt-5">  
        <div class="card-header bg-primary text-white">  
            <i class="fas fa-cloud-upload-alt"></i> Multiple File Upload  
        </div>  
        <div class="card-body">  
            @if (session('success'))  
                <div class="alert alert-success">  
                    {{ session('success') }}  
                    <ul class="mt-2">  
                        @foreach (session('fileList') as $file)  
                            <li>{{ $file['original_name'] }} ({{ $file['mime_type'] }})</li>  
                        @endforeach  
                    </ul>  
                </div>  
            @endif  

            <form method="POST" action="{{ route('files.store') }}" enctype="multipart/form-data">  
                @csrf  
                <div class="mb-4">  
                    <label class="form-label">  
                        <i class="fas fa-folder-open"></i> Select Files  
                    </label>  
                    <input  
                        type="file"  
                        name="files[]"  
                        multiple  
                        class="form-control"  
                        accept=".pdf,.xlsx,.csv,.png,.jpeg"  
                    >  
                    <small class="form-text text-muted">  
                        Allowed formats: PDF, Excel, CSV, PNG, JPEG (Max 5MB per file).  
                    </small>  
                </div>  
                <button type="submit" class="btn btn-success">  
                    <i class="fas fa-upload"></i> Upload  
                </button>  
            </form>  
        </div>  
    </div>  
</div> 

Additional Features:

  • Detailed feedback: Lists uploaded files with MIME types.
  • Accessibility: Font Awesome icons for better UX.

Step 7: Testing and Execution

Start the server:

php artisan serve

Visit http://localhost:8000/files/upload and test scenarios like:

  1. Success: 5 files within size limits.
  2. Failure: Uploading a .exe file (blocked by validation).
  3. Overload: Submitting 11 files (triggers limit error).

Future Enhancements (Roadmap)

  1. Cloud Storage: Integrate with Amazon S3 or DigitalOcean Spaces.
  2. Upload Progress Bar: Implement using JavaScript and Laravel Echo.
  3. File Compression: Auto-resize images via intervention/image.
  4. Security Scans: Virus checks using ClamAV or VirusTotal API.

Conclusion

This guide demonstrates how to implement multiple file uploads in Laravel 11 with professional techniques like filename hashing, granular validation, and optimized storage. To scale further:

  • Use async jobs for background processing.
  • Add retention policies for automatic deletion of old files.
  • Implement detailed logs for activity auditing.

With these strategies, your application will handle high-volume scenarios while maintaining performance and security.

Thanks for reading, Laravel 11 Multiple File Upload 🚀

Rolar para cima