Encodera

Thanks for reading!

Donate to the site — we work hard for you.

Contents

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:

DiskWhere the files liveReachable from the browser
localstorage/app/privateNo
publicstorage/app/publicYes, once the link is created
s3Cloud storageDepends 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:link

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')]);

Thanks for reading!

Donate to the site — we work hard for you.