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

Ckeditor Filetools Bundle Laravel Package

stinger/ckeditor-filetools-bundle

stinger/ckeditor-filetools-bundle is a Symfony bundle that integrates CKEditor file tools into your application. It helps configure file browsing and upload support for CKEditor, simplifying backend wiring so users can manage and insert files directly from the editor with minimal setup.

View on GitHub
Deep Wiki
Context7

Getting Started

The first thing to internalize is that this is a Symfony2 bundle, not a Laravel package. There is no service provider, no facade, no config/ckeditor-filetools.php. If you are coming from Laravel, "getting started" means deciding which of two things you actually want from it:

  1. The plugin assets and wiring (the CKEditor "File Tools" plugin: drag-and-drop image upload, paste-from-clipboard upload, client-side upload progress).
  2. The bundle glue (container registration, asset publishing, default config for the upload endpoint).

For 95% of day-to-day work you want #1 only. The bundle is a thin integration layer around the CKEditor plugin, which ships inside standard CKEditor 4.5+ builds anyway.

If you genuinely are on Symfony 2.x/3.x:

composer require stinger/ckeditor-filetools-bundle
// app/AppKernel.php
$bundles = array(
    // ...
    new Stinger\CKEditorFileToolsBundle\StingerCKEditorFileToolsBundle(),
);

Then publish assets:

app/console assets:install web --symlink
app/console assetic:dump
app/console cache:clear

Where to look first, in this order:

  • DependencyInjection/Configuration.php — this is the authoritative list of configurable keys. If it isn't there, it isn't configurable.
  • Resources/config/services.yml — tells you whether the bundle registers a controller/service at all, or is purely an asset shim. For a 1-star 2015 bundle, expect "asset shim."
  • Resources/public/ or Resources/vendor/ — the actual CKEditor plugin files. This is the part you will end up copying.
  • The README, but do not trust it over the code; last release was 2015.

First use case — end-to-end drag-and-drop image upload in CKEditor:

CKEDITOR.replace('body', {
    extraPlugins: 'filetools,uploadimage,uploadwidget',
    filebrowserUploadUrl: '/uploads/ckeditor',
    filebrowserUploadMethod: 'form'
});

Your endpoint must respond with the contract CKEditor expects:

{ "uploaded": 1, "fileName": "photo.jpg", "url": "/storage/uploads/photo.jpg" }

or on failure:

{ "uploaded": 0, "error": { "message": "File too large" } }

In Laravel that is:

Route::post('/uploads/ckeditor', [CkeditorUploadController::class, 'store'])
    ->middleware('auth');
public function store(Request $request)
{
    $request->validate(['upload' => 'required|image|max:5120']);
    $path = $request->file('upload')->store('uploads', 'public');

    return response()->json([
        'uploaded' => 1,
        'fileName' => basename($path),
        'url'      => Storage::disk('public')->url($path),
    ]);
}

Implementation Patterns

Pattern 1 — Treat the bundle as a source of assets, not a dependency. Copy Resources/public/plugins/filetools/* into public/vendor/ckeditor/plugins/filetools/, add extraPlugins: 'filetools,uploadimage,uploadwidget', and delete the composer requirement. You get identical runtime behavior with no Symfony baggage. This is the pattern I would actually ship.

Pattern 2 — Config-driven endpoint injection (Symfony). In the Symfony world the bundle's value is that you define the upload route once in config.yml and render it into the editor config via Twig, rather than hardcoding a URL in JS:

CKEDITOR.replace('body', {
    filebrowserUploadUrl: "{{ path('ckeditor_upload') }}"
});

Mirror this in Laravel with a Blade partial or a @json blob in a layout:

<script>
window.ckeditorConfig = @json([
    'filebrowserUploadUrl' => route('ckeditor.upload'),
]);
</script>

Pattern 3 — Separate the upload service from the transport. Put validation, storage, and URL generation in a dedicated action/service. The bundle-era code tends to inline move_uploaded_file in a controller; don't inherit that. Your controller should be ~5 lines and delegate. This also lets you test the upload contract with UploadedFile::fake() without booting an editor.

Pattern 4 — CSRF exemption scoped tightly. Drag-and-drop uploads are XHRs from CKEditor; they do not carry your Blade _token unless you explicitly add it. The cleanest Laravel route is a global header:

CKEDITOR.on('instanceReady', function (e) {
    e.editor.on('fileUploadRequest', function (evt) {
        evt.data.fileLoader.xhr.setRequestHeader(
            'X-CSRF-TOKEN',
            document.querySelector('meta[name="csrf-token"]').content
        );
    });
});

Only fall back to VerifyCsrfToken::$except if the endpoint also enforces authentication — never exempt an unauthenticated upload route.

Pattern 5 — Per-editor configuration. If you have a "comment box" editor and a "long article" editor, don't share one upload endpoint. Pass a context field (comment, article) in the upload payload and branch server-side on allowed MIME types and max size. This is the one integration tip the bundle's era of codebase typically gets wrong by having a single global config.

Pattern 6 — Storage abstraction before editor integration. Wire the editor to a Laravel disk (public or s3) and return the disk's URL. Never return a raw filesystem path. The CKEditor JSON contract only cares about url, so the disk choice is invisible to the frontend.

Gotchas and Tips

The bundle is abandoned and near-zero-adoption. 1 star, 0 dependents, last release December 2015. Its composer constraints likely cap at Symfony 2.8 / PHP 5.x and will not install on a modern app. Do not add it to composer.json for a Laravel project — it will either fail resolution or drag in incompatible Symfony components. Fork-and-copy is the correct move.

A Laravel app cannot "register" a Symfony bundle. There is no equivalent of AppKernel bundle registration. If you install it via Composer anyway, nothing auto-wires: no routes, no controllers, no config. You are paying the Composer resolution cost for files you then have to copy manually.

Debug toolbars break the upload JSON. This is the single most common failure. Symfony's profiler (and Laravel Debugbar / Ignition) inject HTML into responses, so CKEditor receives {...}<div id="sfwdt..."> and silently reports "upload failed." In Laravel, exclude the route from Debugbar, and in Symfony use _format: json plus a plain Response rather than a rendered template. Verify with curl -X POST that the body is only JSON.

The upload response contract is strict and unforgiving. uploaded must be numeric 1/0, not true/false. url is required on success. error.message is required on failure. Any 4xx/5xx without the JSON envelope shows the generic "HTTP error" toast and hides your actual validation message — so return 200 with uploaded: 0 for user-visible validation errors, and reserve 4xx for genuine auth failures.

upload_max_filesize and post_max_size in php.ini are silent killers. CKEditor will show a progress bar to 100% and then fail with no useful message. Set both above your app-level max: rule, and check $_FILES/$request->file('upload') is non-null before validating — a post_max_size overflow gives you an empty request, not a validation error.

The assets:install step is easy to miss in Symfony. The bundle's Resources/public is not web-accessible until published. Symptom: 404s for plugins/filetools/plugin.js while the composer package is clearly installed. --symlink makes local development less painful.

CKEditor 4's File Tools needs companion plugins. filetools alone does not give you paste-image or drag-drop UI; pair it with uploadimage and uploadwidget. Also confirm the plugin directory name matches the extraPlugins entry exactly — mismatch produces a console warning and a silently disabled feature, not a hard error.

MIME sniffing vs. extension trust. Clients can send any filename. Validate with image/mimes:jpeg,png,gif,webp and, critically, do not re-use the client filename on disk — generate a ULID and store the original only as metadata. The CKEditor fileName field can echo the generated name; it does not need to match the upload.

Extension points, if you are stuck on Symfony. The bundle's service definition is the seam: override the service ID in your app's services.yml to swap in a custom upload handler, or decorate it. If services.yml defines nothing but a Twig extension for asset paths, there are no extension points and you should treat the bundle as a static file dump — which, again, points back to pattern 1.

Cache clearing after every config change. Symfony 2/3 config is compiled. Editing bundle config without cache:clear produces stale behavior that looks like a code bug. Laravel equivalents: php artisan config:clear and view:clear if you move the CKEditor config into a Blade partial.

Upgrade path. Since the bundle will never be maintained, plan to drop it entirely within your first sprint. Pin the CKEditor 4 plugin version explicitly (e.g., [email protected]) in your asset build so a future CKEditor 5 migration is a scoped, visible task rather than a surprise.

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.
frankyso/ipaymu
3mdikram/worldmoneywords
snowsoft/config
itmosoft/laravel-subscriptions
larva/laravel-ai-qwen
diephp/sequences
users-au/socialite-provider
twidpay/twid-logger
mrnewport/laravel-plaid
mrnewport/laravel-repo
mrnewport/laravel-docsign
mrnewport/laravel-stow
mrnewport/laravel-flow
mrnewport/laravel-priceable
mrnewport/laravel-nestedterms
fredmeng/laravel-apidoc-generator
itstructure/laravel-multilingual-tools
pdustdar/elasticsearch
markupai/php-sdk
rlacerda83/lumem-microservice-shipment