Laravel 12 File Uploads: Single, Multiple, with Progress Bar

Hi there! I’m excited to share with you a simple guide on how to handle file uploads in Laravel 12. Whether you’re building a website that needs users to upload a single image or multiple files at once, Laravel makes it super easy.

Plus, I’ll show you how to add a cool progress bar to make the upload process more interactive. In this article, I’ll walk you through everything step-by-step, from setting up your Laravel project to adding a progress bar for a better user experience.

Step-by-Step Guide to Laravel 12 File Uploads

Step 1: Set Up Your Laravel 12 Project

First, I need to create a new Laravel 12 project. If you haven’t installed Laravel yet, you can do so using Composer. Open your terminal and run:

composer create-project laravel/laravel laravel-file-upload

Once the project is set up, navigate to the project directory:

cd laravel-file-upload

Next, I’ll set up the database. Open the .env file and configure your database connection:

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=laravel_file_upload
DB_USERNAME=your_username
DB_PASSWORD=your_password

Run the migration to set up the default tables:

php artisan migrate

Step 2: Create the File Upload Form

Now, I’ll create a form to allow users to upload files. I’ll use Bootstrap for styling to keep things simple. Create a new Blade file at resources/views/upload.blade.php:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Laravel 12 File Upload</title>
    <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
    <div class="container mt-5">
        <h2>Laravel 12 File Upload</h2>
        @if (session('success'))
            <div class="alert alert-success">{{ session('success') }}</div>
        @endif
        @if ($errors->any())
            <div class="alert alert-danger">
                <ul>
                    @foreach ($errors->all() as $error)
                        <li>{{ $error }}</li>
                    @endforeach
                </ul>
            </div>
        @endif
        <form action="{{ route('file.upload') }}" method="POST" enctype="multipart/form-data">
            @csrf
            <div class="mb-3">
                <label for="file" class="form-label">Choose File (Single)</label>
                <input type="file" name="file" class="form-control">
            </div>
            <div class="mb-3">
                <label for="files" class="form-label">Choose Files (Multiple)</label>
                <input type="file" name="files[]" class="form-control" multiple>
            </div>
            <button type="submit" class="btn btn-primary">Upload</button>
        </form>
    </div>
</body>
</html>

This form allows users to upload a single file or multiple files at once.

Step 3: Define Routes

I’ll define routes to display the form and handle the file upload. Open routes/web.php and add:

use App\Http\Controllers\FileUploadController;

Route::get('/upload', [FileUploadController::class, 'showForm'])->name('upload.form');
Route::post('/upload', [FileUploadController::class, 'upload'])->name('file.upload');

Step 4: Create the Controller

Next, I’ll create a controller to handle the form submission and file storage. Run this Artisan command to generate a controller:

php artisan make:controller FileUploadController

Open app/Http/Controllers/FileUploadController.php and add the following code:

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Storage;

class FileUploadController extends Controller
{
    public function showForm()
    {
        return view('upload');
    }

    public function upload(Request $request)
    {
        // Validate single file
        $request->validate([
            'file' => 'nullable|file|max:2048', // Max 2MB
            'files.*' => 'nullable|file|max:2048', // Max 2MB per file
        ]);

        // Handle single file upload
        if ($request->hasFile('file')) {
            $file = $request->file('file');
            $fileName = time() . '_' . $file->getClientOriginalName();
            $file->storeAs('uploads', $fileName, 'public');
        }

        // Handle multiple file uploads
        if ($request->hasFiles('files')) {
            foreach ($request->file('files') as $file) {
                $fileName = time() . '_' . $file->getClientOriginalName();
                $file->storeAs('uploads', $fileName, 'public');
            }
        }

        return back()->with('success', 'Files uploaded successfully!');
    }
}

This controller validates and stores both single and multiple files in the public/storage/uploads directory.

Step 5: Configure File Storage

To make uploaded files accessible, I’ll link the storage directory. Run:

php artisan storage:link

This creates a symbolic link from public/storage to storage/app/public. Files will be stored in storage/app/public/uploads.

Step 6: Add a Progress Bar

To enhance the user experience, I’ll add a progress bar using JavaScript and Axios. First, include Axios and add a progress bar to the form. Update resources/views/upload.blade.php:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Laravel 12 File Upload</title>
    <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
    <div class="container mt-5">
        <h2>Laravel 12 File Upload</h2>
        @if (session('success'))
            <div class="alert alert-success">{{ session('success') }}</div>
        @endif
        @if ($errors->any())
            <div class="alert alert-danger">
                <ul>
                    @foreach ($errors->all() as $error)
                        <li>{{ $error }}</li>
                    @endforeach
                </ul>
            </div>
        @endif
        <form id="uploadForm" action="{{ route('file.upload') }}" method="POST" enctype="multipart/form-data">
            @csrf
            <div class="mb-3">
                <label for="file" class="form-label">Choose File (Single)</label>
                <input type="file" name="file" class="form-control">
            </div>
            <div class="mb-3">
                <label for="files" class="form-label">Choose Files (Multiple)</label>
                <input type="file" name="files[]" class="form-control" multiple>
            </div>
            <div class="progress mb-3" style="display: none;">
                <div class="progress-bar" role="progressbar" style="width: 0%;" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100">0%</div>
            </div>
            <button type="submit" class="btn btn-primary">Upload</button>
        </form>
    </div>
    <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
    <script>
        document.getElementById('uploadForm').addEventListener('submit', function(e) {
            e.preventDefault();
            const form = this;
            const progressBar = document.querySelector('.progress');
            const progressBarInner = document.querySelector('.progress-bar');

            progressBar.style.display = 'block';
            progressBarInner.style.width = '0%';
            progressBarInner.textContent = '0%';

            const formData = new FormData(form);

            axios.post(form.action, formData, {
                onUploadProgress: function(progressEvent) {
                    const percentCompleted = Math.round((progressEvent.loaded * 100) / progressEvent.total);
                    progressBarInner.style.width = percentCompleted + '%';
                    progressBarInner.textContent = percentCompleted + '%';
                }
            })
            .then(response => {
                progressBar.style.display = 'none';
                window.location.reload(); // Refresh to show success message
            })
            .catch(error => {
                progressBar.style.display = 'none';
                alert('Error uploading files!');
            });
        });
    </script>
</body>
</html>

This code uses Axios to handle the form submission asynchronously and updates the progress bar as the upload progresses.

Step 7: Test the Application

Start the Laravel development server:

php artisan serve

Visit http://localhost:8000/upload in your browser. Try uploading a single file and multiple files. The progress bar will show the upload progress, and a success message will appear once the upload is complete.

Conclusion

In this guide, I’ve shown you how to implement single and multiple file uploads in Laravel 12 and add a progress bar to improve the user experience. Laravel’s built-in features, like the Storage facade and validation, make file handling a breeze. Adding a progress bar with Axios is a simple way to make your application more interactive. I hope this tutorial helps you add file upload functionality to your Laravel projects with ease!

Frequently Asked Questions(FAQs)

Q1: What file types can I upload with Laravel?
You can upload any file type, but you should validate the file types in the controller. For example, use mimes:jpg,png,pdf in the validation rules to allow only specific formats.

Q2: How do I increase the file size limit in Laravel?
To increase the file size limit, update upload_max_filesize and post_max_size in your php.ini file. For example, set upload_max_filesize=10M and post_max_size=10M. Then, restart your server.

Q3: Can I store files in cloud storage like Amazon S3?
Yes! Laravel supports cloud storage like Amazon S3. Configure the filesystems.php config file to use the s3 disk and set up your S3 credentials in the .env file.

Q4: Why is my progress bar not showing?
Ensure Axios is loaded correctly and your form has the enctype="multipart/form-data" attribute. Also, check the browser’s console for any JavaScript errors.

Q5: How can I secure file uploads in Laravel?
Always validate file types and sizes in your controller. Use Laravel’s built-in validation rules and consider adding antivirus scanning for uploaded files to enhance security.


You might also like :

techsolutionstuff

Techsolutionstuff | The Complete Guide

I'm a software engineer and the founder of techsolutionstuff.com. Hailing from India, I craft articles, tutorials, tricks, and tips to aid developers. Explore Laravel, PHP, MySQL, jQuery, Bootstrap, Node.js, Vue.js, and AngularJS in our tech stack.

RECOMMENDED POSTS

FEATURE POSTS