Skip to content

Laravel - File Uploading

Laravel makes it easy to handle file uploads from users. This typically involves creating an HTML form for file selection and a controller action to process and store the uploaded file.

To allow file uploads, your HTML form must have its enctype attribute set to multipart/form-data.

Example View (resources/views/upload.blade.php):

@extends('layouts.app') {{-- Assuming a layout file --}}
@section('content')
<div class="container">
<h2>Upload a File</h2>
@if (session('success'))
<div class="alert alert-success">
{{ session('success') }}
@if (session('filePath'))
<br>Uploaded file path: <a href="{{ session('filePath') }}" target="_blank">{{ session('filePath') }}</a>
@endif
</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.post') }}" method="POST" enctype="multipart/form-data">
@csrf {{-- CSRF protection token --}}
<div class="mb-3">
<label for="fileInput" class="form-label">Select file:</label>
<input type="file" class="form-control" id="fileInput" name="user_file" required>
</div>
<button type="submit" class="btn btn-primary">Upload File</button>
</form>
</div>
@endsection

Key elements in the form:

  • method="POST": File uploads should use the POST method.
  • enctype="multipart/form-data": Essential for file uploads.
  • @csrf: Laravel’s CSRF protection directive.
  • <input type="file" name="user_file">: The file input field. The name attribute (user_file here) is used to access the file in the controller.

Create a controller to handle the file upload request. Let’s call it FileUploadController.

php artisan make:controller FileUploadController

In app/Http/Controllers/FileUploadController.php:

<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Http\RedirectResponse;
use Illuminate\View\View;
use Illuminate\Support\Facades\Storage; // Important for file storage
class FileUploadController extends Controller
{
/**
* Display the file upload form.
*/
public function showUploadForm(): View
{
return view('upload');
}
/**
* Handle the uploaded file.
*/
public function storeUpload(Request $request): RedirectResponse
{
// 1. Validate the uploaded file
$request->validate([
'user_file' => 'required|file|mimes:jpg,jpeg,png,pdf,doc,docx|max:2048', // Example validation rules
]);
// 2. Check if a file was uploaded
if ($request->hasFile('user_file')) {
$file = $request->file('user_file');
// 3. Get file information (optional, for display or logging)
$originalName = $file->getClientOriginalName();
$extension = $file->getClientOriginalExtension();
$size = $file->getSize(); // Size in bytes
$mimeType = $file->getMimeType();
// 4. Store the file
// Option A: Store in the 'public' disk (typically storage/app/public)
// The `store` method generates a unique filename to avoid conflicts.
// Ensure you run `php artisan storage:link` to make these files publicly accessible.
$path = $file->store('uploads', 'public'); // Stores in 'storage/app/public/uploads'
$publicUrl = Storage::disk('public')->url($path);
// Option B: Store with original name (be cautious of name conflicts)
// $filename = time() . '_' . $originalName;
// $path = $file->storeAs('uploads', $filename, 'public');
// $publicUrl = Storage::disk('public')->url($path);
// Option C: Move to public directory directly (less common with Storage facade)
// $destinationPath = public_path('/user_uploads');
// $safeName = time() . '_' . $file->getClientOriginalName();
// $file->move($destinationPath, $safeName);
// $publicUrl = asset('user_uploads/' . $safeName);
// For demonstration, we'll pass back some info
return back()
->with('success', 'File uploaded successfully!')
->with('fileName', $originalName)
->with('filePath', $publicUrl) // Pass the accessible URL
->with('fileSize', round($size / 1024, 2) . ' KB')
->with('fileMimeType', $mimeType);
} else {
return back()->withErrors(['user_file' => 'No file was uploaded.']);
}
}
}

Explanation of Controller Logic:

  • Validation: Crucial for security and application stability. Use Laravel’s validation rules (file, mimes, max size in kilobytes).
  • $request->hasFile('user_file'): Checks if a file with the given name was part of the request.
  • $request->file('user_file'): Retrieves an instance of Illuminate\Http\UploadedFile.
  • File Information: Methods like getClientOriginalName(), getClientOriginalExtension(), getSize(), getMimeType() provide details about the uploaded file.
  • Storing Files: - The store('directory', 'disk') method on the UploadedFile object is the recommended way. It handles unique naming and uses Laravel’s Filesystem configuration (config/filesystems.php). - The 'public' disk usually maps to storage/app/public. You must run php artisan storage:link to create a symbolic link from public/storage to storage/app/public, making these files web-accessible via asset('storage/path_to_file') or Storage::url('path_to_file').
  • Feedback: Redirect back with a success message and optionally file details.

Define routes in routes/web.php for displaying the form and handling the POST request:

use App\Http\Controllers\FileUploadController;
// Route to show the upload form
Route::get('/upload-file', [FileUploadController::class, 'showUploadForm'])->name('file.upload.form');
// Route to handle the file upload POST request
Route::post('/upload-file', [FileUploadController::class, 'storeUpload'])->name('file.upload.post');
  1. Run php artisan storage:link if you haven’t already (only needs to be done once per project setup).

  2. Navigate to http://your-app.test/upload-file in your browser.

  3. Select a file using the form and click “Upload File”.

  4. You should see a success message, and the file should be stored in storage/app/public/uploads (or the directory you specified). The success message should also display the public URL to access the file.

Practical Application: User Avatars or Document Management

File uploading is essential for features like:

  • User profile pictures (avatars).
  • Attaching documents to records (e.g., invoices, reports).
  • Content management systems where users upload images or other media.

Common Learning Obstacle: File Permissions and storage:link

A common point of confusion is file visibility. Files stored in storage/app are not directly web-accessible. For files that need to be public (like images shown on a website), store them on the 'public' disk and ensure you’ve run php artisan storage:link. Also, ensure your web server has write permissions to the storage/app directory and its subdirectories.