Uploading and storing files
Avatars, product photos, attachments — users upload files in almost every app. Laravel takes care of validation, naming and saving, and the code does not depend on whether the files live on the server or in cloud storage.
The form
The form needs the enctype attribute:
<form method="POST" action="/avatar" enctype="multipart/form-data">
@csrf
<input type="file" name="avatar">
<button type="submit">Upload</button>
</form>Validating and saving
A file is validated with the same rules as other fields. The store() method makes up a random name and returns the path:
public function update(Request $request)
{
$request->validate([
'avatar' => 'required|image|max:2048',
]);
$path = $request->file('avatar')->store('avatars', 'public');
$request->user()->update(['avatar' => $path]);
return back()->with('status', 'Avatar updated');
}The image rule checks the content of the file, max:2048 the size in kilobytes. Only the path is saved in the database, for example avatars/Hk3f9a.jpg.
Disks
A disk is a storage location. Disks are described in config/filesystems.php:
| Disk | Where the files live | Reachable from the browser |
|---|---|---|
local | storage/app/private | No |
public | storage/app/public | Yes, once the link is created |
s3 | Cloud storage | Depends on the storage settings |
For files on the public disk to open in a browser, a link from the public folder is created once:
php artisan storage:linkA link to a file
The Storage facade returns the address of a file:
use Illuminate\Support\Facades\Storage;
$url = Storage::disk('public')->url($user->avatar);<img src="{{ Storage::disk('public')->url($user->avatar) }}" alt="Avatar">Other operations
Storage::disk('public')->put('notes/today.txt', 'Note text');
$text = Storage::disk('public')->get('notes/today.txt');
$exists = Storage::disk('public')->exists('notes/today.txt');
Storage::disk('public')->delete($user->avatar);Downloading a private file
Files that must not be served to everyone are kept on the local disk and served through a controller after a permission check:
public function download(Invoice $invoice)
{
abort_unless($invoice->user_id === auth()->id(), 403);
return Storage::download($invoice->file_path);
}Common mistake
When a file is replaced, the old one stays on the disk, and the storage slowly fills with junk. Delete the previous file before saving the new one:
if ($user->avatar) {
Storage::disk('public')->delete($user->avatar);
}
$user->update(['avatar' => $request->file('avatar')->store('avatars', 'public')]);