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

Laravel Filemanager Laravel Package

singlequote/laravel-filemanager

singlequote/laravel-filemanager provides a web-based file manager for Laravel applications, letting users browse, upload, and organize files and folders. It is suited to admin panels and editor integrations that need straightforward media and asset management with a simple interface for common file...

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal steps

composer require singlequote/laravel-filemanager:2.0.2
php artisan vendor:publish --provider="Singlequote\FileManager\FileManagerServiceProvider"
php artisan storage:link
php artisan migrate   # only if the package ships tables — check the published migrations

Publish tags typically include config, views, assets, and possibly lang. Run php artisan vendor:publish with no args first and read the prompt — do not blindly publish everything.

Where to look first, in this order

  1. config/filemanager.php — this is the entire contract of the package. Disk names, allowed extensions, max upload size, base directory, route prefix, and middleware all live here. Read it end to end before touching anything else.
  2. routes/web.php in the package (or php artisan route:list --path=filemanager) — confirm the URI prefix and, critically, whether the package ships its own auth middleware or none at all.
  3. The controller — it is the only place that touches the filesystem; skim it to learn how it resolves paths from user input (this determines your path-traversal exposure).
  4. resources/views/vendor/filemanager/ after publishing — the Blade UI is intentionally thin, so overriding layouts is cheap.

First use case

The realistic day-one use is not "give users a file manager." It is "replace the hand-rolled upload form in an admin panel with a browse-and-pick modal." Concretely: an authenticated route group renders the file manager in an iframe or a modal, the user picks a file, the path is written into a hidden input on the parent form, and your own controller persists that relative path to a media or attachments table.

Route::middleware(['auth', 'can:manage-files'])
    ->prefix('admin/filemanager')
    ->group(function () {
        // package routes get re-registered here, or set the prefix in config
    });

Scope the spike: one authenticated admin screen, one local disk, upload + rename + delete. If the package does not install cleanly on your Laravel version in that window, stop — it is archived, and you are now maintaining it.

Implementation Patterns

Never mount the package routes naked. The single most common integration is also the single most common mistake: letting the package register its own routes with its own (or no) middleware. Set the middleware and prefix in config/filemanager.php explicitly:

'middleware' => ['web', 'auth', 'can:access-filemanager'],
'route_prefix' => 'admin/filemanager',

Then define the access-filemanager gate. The package is a filesystem browser — treat it as an admin surface, not a user-facing feature.

Disk-per-context, not one global disk. Point the package at a dedicated uploads disk rather than your default disk, and derive public URLs in your own code from that disk's config. This keeps the package from being able to see application files it has no business listing:

// config/filesystems.php
'uploads' => [
    'driver' => 'local',
    'root' => storage_path('app/uploads'),
    'url' => env('APP_URL').'/uploads',
    'visibility' => 'public',
],

For S3, expect the package to use Storage::disk($name)->url(), which returns a temporary URL. Do not persist what the UI hands back — persist the relative key and generate URLs on read.

Store relative paths, resolve on render. The package returns a path relative to the disk root. Persist exactly that string. Absolute URLs go stale the moment you change bucket, domain, or CDN.

// migration: attachments.path — string, relative to the uploads disk
// accessor
public function getUrlAttribute(): string
{
    return Storage::disk('uploads')->url($this->path);
}

Picker-modal pattern. The file manager UI is Blade-rendered and self-contained, so the loosest coupling is an iframe plus postMessage:

window.addEventListener('message', (e) => {
  if (e.origin !== window.location.origin) return;
  if (e.data?.type !== 'filemanager:selected') return;
  document.querySelector('#attachment_path').value = e.data.path;
  document.querySelector('#picker').close();
});

You will need to add that postMessage call yourself via a published view override — the package predates any picker-mode convention, so do not expect one.

Tenant / per-user scoping. The package has no concept of ownership. If multiple users share the file manager, enforce scoping by giving each tenant its own disk root (a per-tenant root path or an S3 prefix) rather than trying to filter the package's directory listing after the fact. Filtering after the fact is where directory-listing leaks happen.

Wrap, don't call. Do not have your application controllers hit the package's HTTP routes internally. Write your own FileStorage service that uses Storage::disk('uploads') directly for anything programmatic (thumbnails, imports, cleanup), and keep the package strictly as the human-facing UI. This means a future rip-out is a route + view deletion, not a refactor.

Deploy checklist, every deploy:

php artisan config:cache
php artisan route:cache   # verify this works — closure routes in the package will break it

If route:cache fails, that is a hard signal the package is not cleanly written; you will have to exclude it or fork it.

Gotchas and Tips

It is archived. Treat the version pin as sacred. composer require without a constraint will resolve to 2.0.2 today and to whatever a future maintainer pushes tomorrow — except there will be no future push, so the real risk is a transitive dependency moving underneath it. Pin singlequote/laravel-filemanager:2.0.2 exactly, commit the lock diff, and read that diff. The lock diff is the actual changelog.

"Supports Laravel 8" in a patch release almost certainly means a widened constraint, not a bug fix. That has two consequences. First, illuminate/* and probably php constraints were loosened — check whether the PHP floor dropped, because a dropped floor can silently break a container build that assumed PHP 8.1+. Second, there is no evidence the Laravel 8 path is CI-tested. Your first integration is the test suite. Run it on a branch with a real composer.lock diff before it touches main.

Laravel 9+ compatibility is not claimed. Expect friction in the specific places framework majors broke packages: string-based controller route actions, the removal of Route::namespace(), $namespace on the service provider, and str_*/array_* helper migrations to Illuminate\Support\Str. These fail at runtime (class-not-found, facade errors), not at install, which makes them easy to miss in a green CI run. Smoke-test one upload, one rename, one delete on every Laravel upgrade.

Upload validation is the package's, not yours. The package validates against its own config (allowed_extensions, max size). Your application's validation rules do not apply inside the file manager. Keep the config allowlist narrow, and re-validate the path in your own controller before persisting — a client can post any string into the hidden input you populated from the picker.

Path traversal is the thing to actually test. Send ?path=../../.env, ?path=/etc/passwd, and a Unicode-normalized ..%2f..%2f at the listing and download endpoints. An unmaintained 2022-era filesystem package is exactly the profile of code where this is not handled perfectly. If it fails, add a normalizing middleware in front of the route prefix that rejects any path containing .. after rawurldecode, and never rely on the package's own sanitization.

Symlinks and permissions. storage:link is required for local public disks, and it does not survive a fresh container build unless it is in your deploy script. Writes go as the PHP-FPM user — a root-owned storage/app/uploads from a Docker build will fail with a bare "unable to write" that looks like a package bug and is not one.

Config caching bites on publish. If you published the config before setting env values, php artisan config:cache will freeze the old values. Always config:clear after editing config/filemanager.php, and keep env-driven values (FILEMANAGER_DISK) out of the published file where possible.

Debugging entry points, in order:

  • php artisan route:list --path=<prefix> — is it even mounted, and behind which middleware?
  • php artisan vendor:publish --provider=... --tag=config again to diff your config against the shipped default
  • Storage::disk(config('filemanager.disk'))->allFiles() in tinker — does the disk see what the UI claims to see?
  • Laravel log — the package's error messages for permission and missing-directory failures are usually literal and accurate

Extension points worth knowing. Three only: the config file (disks, extensions, middleware, prefix), published Blade views (layout, picker hooks), and the option of disabling the package's route registration entirely and writing your own thin controller over Storage for the four operations you need. For a small package like this, that last option is frequently the cheaper path than fighting the shipped UI — and it leaves you with code you can maintain after the archived dependency becomes untenable.

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.
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
frankyso/ipaymu
3mdikram/worldmoneywords
snowsoft/config
itmosoft/laravel-subscriptions
larva/laravel-ai-qwen
adachsoft/api-version-bundle
cgv/localized-resource
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation
bypersoft/signbox
pairus/product-data
fayne/laravel-filament-cms-core