Using the private disk file storage in Laravel

Using the private disk file storage in Laravel to store, delete and download files.

Creating the private disk, a private disk is one that is not designed to be used as an asset URL for media on websites such as a blog.

Instead the private disk is seen as a secure, download and delete file storage that the user can manage away from the public.

In config/filesystems.php you will need to create the private disk

'disks' => [
    'private' => [
        'driver' => 'local',
        'root' => storage_path('app/private'),
        'visibility' => 'private',
        'throw' => true,
    ],
],

When using the private disk the root directory is app/private.

Visibility is the default level assigned to any files placed in the private disk.

Storing and handling files

Store an uploaded file in the uploads folder as users_image.jpg

$file->storeAs("uploads", "users_image.jpg", "private");

Write contents into a file, the file automatically gets created

Storage::disk('private')->put("notes.text", $notes_string);

Check if the file exists, returns true or false

Storage::disk('private')->exists("uploads/users_image.jpg")

Get the file size in bytes

Storage::disk('private')->size("uploads/users_image.jpg");

Get the file contents

$image = Storage::disk('private')->get("uploads/users_image.jpg");

Copy the file

Storage::copy("private/uploads/users_image.jpg", "private/uploads/old_image.jpg");

Move the file

Storage::move("private/uploads/users_image.jpg", "private/uploads/old_image.jpg");

Delete the file

Storage::disk('private')->delete("uploads/users_image.jpg");

Downloading

Downloading a private file can be done by using a route and a user-owned or some other privilege system to ensure not just any logged-in user can download the file

Route::get('/images/{image}/download', [ImageController::class, 'downloadImage'])->middleware(['auth'])->name('image.download');

The controller function that checks the requesting user “owns” the image file.

public function downloadImage(Image $image): void
 {
   if (\Auth::id() === $image->user_id) {
      response()->download(storage_path("app/private/uploaded/{$image->id}.{$image->ext}"), "{$image->id}.{$image->ext}");
    }
        
    abort(401);//unauthorized
}

This will prompt the download through the browser with the file name being the image id and extension.

Using generated strings as identifiers adds even more protection to the file and this method to download.