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

Elfinder Builds Laravel Package

barryvdh/elfinder-builds

Prebuilt, versioned elFinder assets for Laravel. Ships compiled JavaScript and CSS for the elFinder file manager, so you can add a browser-based file manager to your app without running the front-end build yourself.

View on GitHub
Deep Wiki
Context7

Getting Started

Understand what you are installing first. barryvdh/elfinder-builds contains no PHP: no service provider, no routes, no config, no commands. It is a Composer-shaped tarball of prebuilt elFinder 2.1 client assets — js/, css/, img/, sounds/, js/i18n/, themes — copied out of upstream Studio-42/elFinder builds. Everything you actually interact with day-to-day (routes, connector, volumes, ACLs) comes from barryvdh/laravel-elfinder and your own config. Treat this package as vendored static files, not as a library.

Minimal steps.

composer require barryvdh/laravel-elfinder   # pulls elfinder-builds transitively

# pin the asset bundle explicitly so it can't float under you
composer require barryvdh/elfinder-builds:2.1.* --save-exact

php artisan vendor:publish                # copies config + views
# and publishes the bundle into public/vendor/elfinder

The exact publish tag varies by laravel-elfinder version — run php artisan vendor:publish interactively (or read the provider's publishes() array) before scripting it into CI. What you want to end up with:

  • public/vendor/elfinder/{js,css,img,sounds} populated
  • config/elfinder.php present
  • a route group serving the connector

Where to look first, in this order:

  1. vendor/barryvdh/elfinder-builds/ — confirm the version in composer.json, the license header in js/elfinder.min.js, and that i18n files match the same release. This is the only provenance audit you get.
  2. config/elfinder.php — defaults.roots[] is the whole game: driver, path, URL, accessControl.
  3. vendor/barryvdh/laravel-elfinder/resources/views/ — the shipped Blade views (elfinder::elfinder standalone, elfinder::standalonepopup, plus editor-picker variants) show you the canonical asset-include order. Copy that, don't improvise.
  4. Your connector route — verify it is behind auth before you browse anything.

First use case (an afternoon). A read-only admin browser over storage/app/public:

// config/elfinder.php
'defaults' => [
    'roots' => [[
        'driver'  => 'LocalFileSystem',
        'path'    => storage_path('app/public'),
        'URL'     => config('app.url').'/storage',
        'accessControl' => fn($attr, $path, $data, $volume) => false, // read-only spike
    ]],
],
Route::middleware(['web', 'auth'])->prefix('admin')->group(function () {
    Route::get('elfinder/{path?}', [ElfinderController::class, 'showIndex'])->where('path', '.*');
    Route::any('elfinder/connector', [ElfinderController::class, 'showConnector'])
        ->name('elfinder.connector');
});

php artisan storage:link first. Ship this read-only variant before enabling writes — it validates CSP, auth, and listing performance without exposing an upload surface.

Implementation Patterns

Think in three layers, and keep them separate.

Layer Owned by Changes how often
Assets in public/vendor/elfinder this package (published once) only on upgrade
Routes / views / connector glue laravel-elfinder rarely
Roots, ACL, upload policy your config whenever the product changes

Almost every production incident here comes from blurring layers 1 and 3 — patching the minified JS instead of the config.

Asset delivery: pick one and write it down. Three viable strategies:

  • Committed artifacts — un-ignore public/vendor/elfinder in .gitignore and commit it. Deploys can't drift; vendor:publish behaviour becomes irrelevant. Best default for a single app.
  • CI-published — publish during build and assert no diff:
    php artisan vendor:publish --force
    git diff --exit-code public/vendor/elfinder
    
  • Versioned CDN — serve /vendor/elfinder/2.1.63/... from object storage. Only worth it across multiple apps.

Whatever you pick, add a cache-busting query string keyed to the bundle version (?v={{ $elfinderVersion }}), because these files are served straight from public/ with no Vite hashing.

Standalone page pattern. Serve elFinder as a full page load, from a Blade view, with a fixed-height container. Do not embed it in a shell that swaps DOM later.

@extends('layouts.admin')
@section('content')
  <div id="elfinder"></div>
  <script>
    document.addEventListener('DOMContentLoaded', function () {
      $('#elfinder').elfinder({
        url: @json(route('elfinder.connector')),
        lang: 'en',
        height: 600,
        soundPath: @json(asset('vendor/elfinder/sounds')),
      });
    });
  </script>
@endsection

Multi-volume console. One root per storage policy, each with its own accessControl. This is the pattern that earns its keep — local uploads, an S3 media bucket, and a read-only shared-assets volume in a single tree:

'roots' => [
    ['driver' => 'LocalFileSystem', 'path' => storage_path('app/public/media'),
     'URL' => config('app.url').'/storage/media',
     'accessControl' => 'App\Elfinder\Acl@media'],

    ['driver' => 'LocalFileSystem', 'path' => '/mnt/shared/brand',
     'URL' => config('app.url').'/storage/brand', 'readonly' => true,
     'accessControl' => 'App\Elfinder\Acl@brandReadOnly'],
],

Keep ACL logic in a small class, not a closure in config — closures can't be cached and can't be tested.

Picker pattern (the actual day-to-day win). For an "Insert media" button behind CKEditor/TinyMCE or a custom form field, open a popup and hand the selection back via getFileCallback:

$('#elfinder').elfinder({
  url: route,
  getFileCallback: function (file) {
    window.opener?.setMediaUrl?.(file.url);
    window.close();
  },
});

Pass any scoping context (user id, tenant, target folder) through customData on the connector request and read it in your accessControl/root config. That is the cleanest way to get per-user folders without forking views.

Harden the connector as a code change, not a checklist. Everything risky lives here:

'roots' => [[
    'driver'   => 'LocalFileSystem',
    'path'     => storage_path('app/public/uploads'),
    'URL'      => config('app.url').'/storage/uploads',
    'uploadAllow' => ['image/jpeg', 'image/png', 'application/pdf'],
    'uploadDeny'  => ['all'],
    'uploadOrder' => ['allow', 'deny'],
    'disabled'    => ['archive', 'extract', 'mkfile', 'chmod'],
    'tmbPath'     => storage_path('app/elfinder-thumbs'),
    'tmbPathMode' => 0775,
]],

And a test that fails loudly if the route ever loses its guard:

public function test_connector_requires_authentication(): void
{
    $this->get('/admin/elfinder/connector')->assertRedirect('/login');
}

Gotchas and Tips

Version skew is the failure mode. The JS bundle and the connector must be from the same elFinder generation. A mismatch typically surfaces as an unhelpful invalid backend response in a modal, or a silent empty tree. Before debugging anything else, open DevTools → Network → the connector POST and look at the raw response: if it's HTML (a 419, a 500 stack trace, a login redirect), the problem is server-side; if it's JSON with an unexpected error, it's a connector/config problem; if it's JSON that looks fine but the UI misbehaves, it's skew.

vendor:publish --force will silently overwrite your edits. If you must patch a published asset (e.g. a theme tweak), keep the patch as a diff file in resources/ and reapply, or better, add an override CSS/JS file loaded after the bundle and never edit public/vendor/elfinder in place. Also check whether your public/.gitignore excludes vendor/ — a very common cause of "works locally, broken in prod" after a deploy.

CSP will bite on day one. elFinder 2.1 needs inline styles and blob workers. Expect to add something like style-src 'unsafe-inline' and worker-src blob: scoped to the file-manager route only — don't loosen the policy site-wide. Document the exception with a link to this assessment; it will be questioned.

jQuery duplication breaks the widget layer. elFinder expects its own jQuery/jQuery-UI. If your admin layout already loads a different jQuery version, expect sorting, dialogs, and context menus to misbehave intermittently. Load the file-manager page as a bare layout with only elFinder's dependencies.

Partial-page navigation destroys it. Livewire wire:navigate, Turbo Drive, and Inertia client-side transitions will leave a half-initialized tree. Opt the page out (data-turbo="false", or render it outside the SPA shell) and let it be a full reload.

Large directories hang the connector. elFinder 2.1 lists a root eagerly and has no real pagination. A volume with tens of thousands of files will produce a slow connector scan and browser stalls. Keep roots shallow and folder-per-entity (media/{user_id}/, media/{year}/{month}/) rather than one flat bucket.

web middleware or nothing. The connector is a stateful, session-authenticated POST. Putting it on the api group (or VerifyCsrfToken exceptions without session) reliably yields 419s or unauthenticated connector calls. Long upload sessions can also outlive session.lifetime — check that before blaming file size.

Uploads that "do nothing" are usually PHP/nginx limits, not elFinder: upload_max_filesize, post_max_size, client_max_body_size, and the temp dir. Check those before touching config.

S3 roots: verify the driver class. elFinder 2.1's classic S3 driver assumes an older AWS SDK; if your app ships SDK v3, prefer a Flysystem-backed root or mount the bucket locally. Do not discover this mid-sprint.

Sound and thumbnail 404s are noise, not bugs. sounds/ and tmbPath requests will 404 until configured. Remove the sound path or set a writable tmbPath — thumbnails regenerated on every request are a sneaky performance tax.

Supply-chain visibility is your job. This is checked-in minified third-party JS: Dependabot and SCA won't see it, and the wrapper does not patch upstream. Put a quarterly calendar reminder against Studio-42/elFinder security releases, and know your exit: npm i elfinder, add a Vite entry that exposes the same global, and swap the asset() calls in your one Blade view. That's the whole migration — which is exactly why keeping elFinder confined to a single full-page view is worth the discipline.

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.
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
cgv/localized-resource
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation
bypersoft/signbox
pairus/product-data
fayne/laravel-filament-cms-core