Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Downloads Module Laravel Package

wirelab/downloads-module

wirelab/downloads-module is a Laravel package for managing downloadable files and tracking download activity. It helps organize downloads, control access, and integrate file delivery into your application with minimal setup. Suitable for projects that need a simple downloads area or file distributio...

View on GitHub
Deep Wiki
Context7

Getting Started

Install the package with Composer and publish its config:

composer install vendor/downloads
php artisan vendor:publish --tag=downloads-config

Look at config/downloads.php first — the disk, base path, response type (inline vs attachment), and any route/middleware options all live there. When upgrading to 1.4.2, pay particular attention to the path/folder setting: the package no longer restricts downloads to one configured folder, so that key now acts as a default rather than a hard boundary. If you previously relied on it as a whitelist, re-check your code before deploying.

The fastest first use case is serving a private file through a controller:

Route::get('/invoices/{invoice}/pdf', function (Invoice $invoice) {
    return Downloads::file($invoice->pdf_path);
})->middleware('auth');

Because 1.4.2 removes the folder constraint, $invoice->pdf_path can point anywhere on the disk — a storage/app/private/invoices file, a tenant-specific folder, or an object on an S3 disk — without extra configuration.

Implementation Patterns

Stream large files instead of loading them. Use the package's streaming response so a 200 MB export doesn't get buffered into memory:

return Downloads::disk('s3')->download($path, $filename);

Keep authorization in your own layer. The package returns bytes; it does not decide whether the current user may have them. Wrap every download route in auth plus a policy or Gate::authorize() check against the underlying model, and derive the path server-side rather than accepting it from the request.

Use per-disk calls for multi-tenant or multi-bucket setups. With the folder restriction gone in 1.4.2, the clean pattern is one download route parameterised by disk and a trusted, policy-checked path:

return Downloads::disk($tenant->disk)
    ->download($tenant->pathFor($document), $document->name);

Prefer inline responses for previews and attachments for exports. Set the disposition at the call site so a single config default doesn't force PDFs to download when you want them rendered in the browser.

Combine with signed URLs for email links. Generate a temporary signed route to your own controller, then let the package stream the file. This keeps expiry and authorisation logic in Laravel rather than in the package.

Test with Storage::fake(). Put sample files on the fake disk, assert assertDownload() on the response, and assert that unauthorised users receive a 403. This is the most reliable way to catch a path that used to be inside the configured folder but now isn't.

Gotchas and Tips

  • 1.4.2 is a security-relevant relaxation. Removing the folder restriction means any path you pass is now fair game. Validate that the resolved path is inside the directory you expect (e.g. compare realpath() against an allowed prefix) whenever the path is influenced by user input or database content you don't fully control.
  • Watch for path traversal. A naive Downloads::file($request->path) now has a much larger blast radius than before. Whitelist extensions and reject .. segments.
  • Config caching. After changing the default folder or disk, run php artisan config:clear. Stale cached config is the usual cause of "it still can't find the file."
  • Disk vs absolute path. Downloads::file() typically expects a path relative to a configured disk root; Downloads::response()-style helpers may take a full path. Mixing them up produces "file not found" errors that look like permission problems.
  • Filesystem permissions still apply. On local disks the web user needs read access to the new locations you're now free to point at — a common post-upgrade surprise.
  • Filename encoding. Non-ASCII names can break Content-Disposition; pass a plain ASCII fallback and let the package's filename handling do the rest.
  • Extension point: override the package's download controller or bind a custom response class if you need audit logging, watermarking, or download counters — preferable to duplicating the streaming logic.
  • Check the changelog for 1.4.x patch releases before rolling out broadly; a follow-up patch to 1.4.2 may add back an opt-in restriction for teams that want the old behaviour.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
abbasudo/artisan-route
mirvan/ippanel
ignibyte/aic-framework
glavweb/data-schema-bundle
glavweb/datagrid-bundle
tacticmedia/scim-server
uni-method/frame
neika-ai/sdk
adachsoft/php-code-style
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
adachsoft/api-version-bundle
cgv/localized-resource
noith/settings
kda/laravel-package