2

Currently I am using angular-ckeditor to add CKEditor 4.

In my template, I display it as:

<div ng-repeat="editor in editors">
  <div ckeditor="options" ng-model="editor.content"></div>
</div>

I'm looking for a way to upload images to CKEditor from desktop. As far as I understand, angular-ckeditor and CKEditor libraries are separate, so I can add widgets and plugins easily.

The problem is that I can't seem to find the right plugins/widgets (that do NOT use jQuery), which will help me to upload an image from desktop. I made it work only with image links.

There is not a lot of documentation about it on the official website. They say to use PHP files that will upload and browse images, but don't really explain how, especially with angular-ckeditor. So I have several questions now:

  • Which plugins do I need for a simple image uploader, so that I can paste images into CKEditor?
  • How do I set it up with AngularJS?
  • What does a PHP file uploader(/browser) look like?

What I have tried so far doesn't even change the CKEditor tabs (it should change the image properties dialog by adding an "Upload" tab and some other UI). So clearly I'm missing a solid tutorial somewhere for all of this.

enter image description here

(I could also try to switch to ng-ckeditor, if a solution with this would be simpler)

Cy Rossignol
  • 16,216
  • 4
  • 57
  • 83
Aleksey Solovey
  • 4,153
  • 3
  • 15
  • 34
  • Is it version 5? – Stanislav Kvitash Jan 17 '18 at 17:41
  • @StanislavKvitash CKEditor version 4, AngularJS 1.6.X~ – Aleksey Solovey Jan 17 '18 at 18:03
  • 1
    Did you have a chance to try [`uploadimage` CKEditor plugin](https://ckeditor.com/cke4/addon/uploadimage) (just make sure you've downloaded all the required dependencies if you are not using [builder](https://ckeditor.com/cke4/builder) to create your CKEditor build, for me it was like `button`, `filetools`, `notification`, `notificationaggregator`, `toolbar`, `uploadwidget`, `widget`)? – Stanislav Kvitash Jan 17 '18 at 18:13
  • After adding this plugin just add it through the options like `extraPlugins: 'uploadimage', filebrowserImageUploadUrl: 'fileUploadUrl`. Your back-end should return a JSON response, examples are shown here: https://docs.ckeditor.com/ckeditor4/docs/#!/guide/dev_file_upload – Stanislav Kvitash Jan 17 '18 at 18:26
  • Just realized that JSON responses would not work with `uploadimage` (it expects plain html since it just inserts this html into result window - see `imageUpload.html` file), so the setup could look like https://plnkr.co/edit/0JQD4dznMP6do2LTBhn2 – Stanislav Kvitash Jan 17 '18 at 19:31
  • @StanislavKvitash I think at some point one of the dependencies requires jQuery. Can I set it up without it? Or is it 100% needed? (That plunker looks promising, I will try it with my backend) – Aleksey Solovey Jan 17 '18 at 21:40
  • You should be good to use it without jQuery (I removed jQuery from that plunker and it could be fully functional, if I know how to "simulate" post request to `imageUpload.html` in `plnkr` :) ). Just give it a try and share your results. – Stanislav Kvitash Jan 18 '18 at 08:35

1 Answers1

5

First, let's take a look at some basics without Angular. For CKEditor version 4, we can initialize an editor with the filebrowserImageUploadUrl configuration option, which enables functionality from the File Browser API:

CKEDITOR.replace('editor', { 
    filebrowserImageUploadUrl: '/upload.php?type=image' 
});

This just loads an editor instance onto a <textarea name="editor">. Because we set the filebrowserImageUploadUrl option, the Upload tab becomes available in the editor's image dialog. The example value, /upload.php?type=image, is the URL to the PHP script on the server that handles the uploaded image files.

When a user uploads an image, CKEditor will send the image to this URL on the server. The handler at this URL should validate the request, resize the image (if needed), and move the uploaded image to a permanent location on the server. Then, the handler sends an HTML response back to CKEditor with the image's public URL.

Of course, we can write the server-side handler in any language. Here's a basic example for PHP that we'll save as upload.php:

<?php 
$tempName = $_FILES['upload']['tmp_name'];
$fileName = uniqid() . $_FILES['upload']['name'];
$uploadPath = '/path/to/uploads/' . $fileName;
$imageUrl = 'http://example.com/uploads/' . $fileName;

$success = move_uploaded_file($tempName, $uploadPath);

$html = '<script>window.parent.CKEDITOR.tools.callFunction(%s, "%s", "%s");</script>';
$message = $success ? 'Uploaded successfully.' : 'Upload failed.';
echo sprintf($html, $_GET['CKEditorFuncNum'], $imageUrl, $message);

This script places an uploaded image into the web server's uploads/ directory so the browser can fetch the image. It passes back the CKEditorFuncNum parameter from the request to identify the appropriate callback for the upload. This example provides some basic protection against duplicate filenames, but, for a real-world application, we'd need to add security, validation, and error handling (authentication, CSRF, file type checking, max size, file name sanitization, etc.).


So far, this all works with CKEditor's standard, built-in functionality (no plugins, Angular, or jQuery needed). To enable users to drag-and-drop or paste images into the editor, we can add the Upload Image plugin to our CKEditor build (or use the standard-all distribution from the CKEditor CDN).

We need to declare the plugin when initializing the editor:

CKEDITOR.replace('editor', { 
    extraPlugins: 'uploadimage',
    filebrowserImageUploadUrl: '/upload.php?type=image' 
});

...and then extend our upload.php script to return the JSON response expected by the plugin. Add this block before the last three lines of the previous example:

if (isset($_GET['responseType']) && $_GET['responseType'] === 'json') {
    echo json_encode([
        'uploaded' => $success,
        'fileName' => $fileName,
        'url' => $imageUrl,
    ]);

    return;
}

The Upload Image plugin sends the responseType=json URL parameter that the server-side script can check for to determine which type of response to send back.


Finally, let's take a look at how to initialize an editor using the angular-ckeditor package described in the question:

<div ng-controller="EditorCtrl as editor">
    <textarea ckeditor="editor.options" ng-model="editor.content"></textarea>
</div>
var myApp = angular.module('myApp', ['ckeditor'])

myApp.controller('EditorCtrl', function () {
    this.options = {
        extraPlugins: 'uploadimage',
        filebrowserImageUploadUrl: '/image-upload.php?type=image'
    };
});

As we can see, we don't need to do much to "angularize" this. Once we create our template, we declare the same configuration options that we'd pass to the plain CKEDITOR.replace() on a controller that we reference on an element with the ckeditor directive.

Cy Rossignol
  • 16,216
  • 4
  • 57
  • 83
  • Works great. (just to confirm) **1.** Does `$imageUrl` have to be a url link? I made it work with a root directory. **2.** I would like to know what a string X stands for in `$_FILES[X]['tmp_name']`. And for that, how do I _echo_ anything out for testing purposes? **3.** Can an image be resized? Do I need a plugin for that and do I change anything in `upload.php`? – Aleksey Solovey Jan 23 '18 at 16:22
  • 1
    @Aleksey **1.** No, it does not. The full URL is just an example. Just passing a path component should work as long as the front end loads from the same domain as the server. **2.** *`X`* is the "name" attribute of the hidden file input field that CKEditor uses to upload the image (``). **2.5** `error_log()` will write a value to the server's log (depends on webserver). Also, try `var_dump()` and look in the browser's devtools. **3.** See [these answers](https://stackoverflow.com/q/14649645/5209322). You can do this in *upload.php* before moving the temp image. – Cy Rossignol Jan 23 '18 at 19:05