ckfinder/ckfinder-laravel-package
Official CKFinder integration for Laravel: an artisan command publishes assets and config, plus easy setup for authentication and file browser routes. Lets you add a full-featured file manager to your app with minimal configuration.
CKFinder is a commercial file manager from CKSource; the Laravel package (ckfinder/ckfinder-laravel-package) is the glue between the CKFinder PHP connector and Laravel's routing, config, and auth. Treat it as a drop-in "browse server / upload" backend for CKEditor or a standalone file picker, not as a general-purpose Laravel media library.
Minimum steps:
composer require ckfinder/ckfinder-laravel-package
php artisan vendor:publish --tag=ckfinder # config/ckfinder.php
php artisan vendor:publish --tag=ckfinder-assets # public JS/HTML assets
php artisan storage:link # if you use the default local backend
The service provider is auto-discovered on Laravel 5.5+. On older versions add CKSource\CKFinderBridge\CKFinderServiceProvider::class to config/app.php (and the CKFinder facade/alias if you plan to use it).
Where to look first
config/ckfinder.php — it contains the connector route definition, the authentication callback, and the backends array. This is the only file you normally edit./ckfinder/connector by default). Hit GET /ckfinder/connector?command=Init in the browser after logging in; a JSON response means wiring is correct.public/vendor/ckfinder or public/js/ckfinder, depending on version) if you use the popup UI rather than CKEditor's built-in integration.First use case: a "Browse Server" button in CKEditor 5
// config/ckfinder.php (shape; verify keys against the file you publish)
return [
'connector' => [
'route' => [
'prefix' => 'ckfinder',
'middleware' => ['web', 'auth'], // never expose this unauthenticated
],
],
'backends' => [
'default' => [
'adapter' => 'local',
'root' => storage_path('app/public/media'),
'baseUrl' => '/storage/media',
],
],
];
// CKEditor 5
ClassicEditor.create(document.querySelector('#body'), {
plugins: [ /* ... */ CKFinder ],
ckfinder: {
uploadUrl: '/ckfinder/connector?command=QuickUpload&type=Images&responseType=json',
},
});
// CKEditor 4
CKEDITOR.replace('body', {
filebrowserBrowseUrl: '/ckfinder/ckfinder.html',
filebrowserImageBrowseUrl: '/ckfinder/ckfinder.html?type=Images',
filebrowserUploadUrl: '/ckfinder/connector?command=QuickUpload&type=Files',
});
Backend configuration per environment. Keep root under storage_path() and let baseUrl point at the matching public path (/storage/... for the local adapter). For S3/FTP/Dropbox backends, prefer the CKFinder-native adapter config (or a custom backend class) rather than trying to reuse Laravel's filesystems.php disks directly — the connector expects its own backend contract.
Per-user isolation. The common SaaS pattern is a dynamic root per tenant:
// AppServiceProvider::boot() or a dedicated CkfinderServiceProvider
config(['ckfinder.backends.default.root' =>
storage_path('app/public/users/'.auth()->id())]);
Combine this with the authentication option and middleware (auth, verified, can:upload-media) on the connector route so the browser UI and QuickUpload endpoints are both gated.
Resource types. Define separate Images, Files, and any custom types with their own directory, allowedExtensions, maxSize, and ACL. This is where you enforce "images only, 5 MB max" — do it in config, not in a controller.
CKEditor integration. For CKEditor 5, always append &responseType=json to the QuickUpload URL; the default XML response silently fails the upload adapter. For CKEditor 4, point browse URLs at the published ckfinder.html and the upload URL at the connector. For a standalone picker, instantiate CKFinder.widget() against the connector route.
Middleware and policies. Because the connector is a single endpoint handling many commands (Init, GetFiles, FileUpload, DeleteFile, ...), Laravel policies don't map cleanly. Do coarse-grained gating in middleware and fine-grained rules inside the CKFinder ACL/event layer.
Extension points. The connector exposes a Symfony-style event dispatcher; hook BEFORE_COMMAND_* events (via the CKFinder instance if the package registers it, or through the connector's bootstrap) to sanitize filenames, reject MIME mismatches, or push uploads through a virus scanner. This is the right place for cross-cutting upload rules — not a Laravel middleware.
Testing. Assert your middleware and auth callback separately, then do a manual smoke test against ?command=Init in each environment. Automated end-to-end upload tests are fragile because the connector's request format is CKFinder-specific.
web middleware group, POST commands like FileUpload will 419 unless you either add ckfinder/* to VerifyCsrfToken::$except or configure the CKFinder frontend to send X-CSRF-TOKEN. Excluding the prefix is the usual fix; if you do, make sure auth middleware still protects the route.config:cache and closures. The authentication option is often documented as a closure. Closures in config files break php artisan config:cache (and therefore production deploys). Use a class string or a service-provider-registered callback instead._thumbs almost always mean root and baseUrl don't describe the same directory as seen by the web server. Run php artisan storage:link and double-check the URL prefix.storage/app/public/... must be writable by that user; a root owned by your deploy user will fail silently with 500s on upload.php artisan route:clear && php artisan config:clear. Stale caches are a common "my middleware isn't applied" cause.composer update, re-publish with --force and clear browser caches./ckfinder/connector?command=GetFiles enumerates your tree. Auth middleware plus ACLs are mandatory, and allowedExtensions/maxSize should be locked down even for trusted users.spatie/laravel-medialibrary or UniSharp/laravel-filemanager before taking on the license and the connector's separate config model.?command=Init, then ?command=GetFiles&type=Images, and read the JSON error. CKFinder's errors are descriptive once you see the raw response.How can I help you explore Laravel packages today?