darvis/laravel-uploads

This package gives a Laravel application one place for every file people upload. A file becomes a row in the uploads table that knows which model it belongs to, which collection it is in (photos, files, attachments, whatever you name), whether it is public or private, who uploaded it and whatever extra data you want to keep with it. From that one row the package makes the thumbnails you configured, renders a PDF to an image per page, hands out permanent or signed URLs, and cleans up the files when the upload is deleted for good.

It is a light alternative to a full media library: one table, one model, one trait, one action, and an optional pair of Livewire components for the upload form and the administration.

Where to start

Who it is for

Laravel developers who want files attached to their own models with as little ceremony as possible, on local disks or S3, with private files that are only reachable through a link that expires, and with an overview of what is stored where.

What it does not do

  • It does not resize on the fly. Conversions are generated once by a queued job and stored next to the original; add a conversion to the config and run the job again for existing uploads, see Conversions & PDF pages.
  • It does not serve images through PHP for public uploads; those are plain URLs of the disk.
  • It does not ship a file picker, a cropper or a drag and drop zone; the Livewire upload manager is a file input with a list, see Livewire components.
  • It does not render Word or Excel documents; only images and PDF files get conversions.

Requirements

  • PHP 8.2 or higher with the GD extension
  • Laravel 11, 12 or 13
  • Livewire 3 or 4 for the two components (optional)
  • Imagick with Ghostscript, or the pdftoppm binary from poppler, for PDF pages (optional)

Install

composer require darvis/laravel-uploads
php artisan migrate
php artisan storage:link

Then follow Installation & configuration to check that it works.

Features

  • One model: Upload with uploadable (polymorphic, optional), collection, disk, path, name, mime_type, size, is_public, sort_order, meta, conversions and processed_at
  • HasUploads trait: $product->addUpload($file, 'photos', public: true), uploadsIn('photos'), firstUpload('photos'), reorderUploads()
  • Public or private per upload: a permanent URL for public files, a signed link that expires for private files, with a policy you can replace
  • Conversions from config: named sizes in jpg, png or webp, cover or contain, generated by a queued job and stored next to the original on the same disk
  • PDF pages: a PDF is rendered to one image per page and gets a thumbnail from its first page
  • Extra data: a meta JSON column, read with meta('caption') and written with setMeta()
  • Soft and hard delete: delete() moves an upload to the trash and keeps the files, forceDelete() removes everything, uploads:prune empties the trash after a number of days
  • Administration: UploadStatistics with totals per disk and collection, and a Livewire overview with filters and the trash
  • Livewire upload manager: upload, caption, sort by dragging and remove, for one collection of one model, with direct uploads to S3 when Livewire is set up for it
  • Dutch translation of the components, and a Laravel Boost guideline and skill for AI tooling in your app