PHP & MySQL, Tutorials, elFinder, CKEditor

In order to add drag and drop image upload to CKEditor make sure you've included the Upload Image plugin to CKEditor.

To enable drag and drop and file uploads there are 2 settings that need to be enabled. go to ckeditor/config.js and add these settings:

In this case, I'm using elFinder for the filemanager

config.filebrowserUploadUrl = '/elfinder/php/upload.php?type=file';
config.imageUploadUrl = '/elfinder/php/upload.php?type=image';

The filebrowserUploadUrl is for enabling file uploads from the link and image dialog boxes.
The imageUploadUrl is for allowing drag and drop uploads.

You could send these to different files, I've chosen to deal with both cases in the same file called upload.php that I've placed in elfinder/php/upload.php

The first task to take care of is ensuring the post request has come from CKEditor and not somewhere else. CKEditor comes with CSRF token out the box so we can use that and compare the value it stores in a cookie against the post request:

//if csrf passes
if ($_COOKIE['ckCsrfToken'] == $_POST['ckCsrfToken']) {

Now define sizes so we can later use them for calculating file upload sizes. 

Also set up the base variables:

//define file sizes
define('KB', 1024);
define('MB', 1048576);
define('GB', 1073741824);
define('TB', 1099511627776);

//set variables 
$tmpName  	   = $_FILES['upload']['tmp_name'];
$filename 	   = $_FILES['upload']['name'];
$size 		   = $_FILES['upload']['size'];
$filePath      = "../files/" . date('d-m-Y-H-i-s').'-'.$filename;
$fileExtension = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
$type 		   = $_GET['type'];
$funcNum 	   = isset($_GET['CKEditorFuncNum']) ? $_GET['CKEditorFuncNum']: null;

$tmpName - the tempory name assigned to uploaded files.
$filename - is the name of the file eg logo.png.
$size - is the size in bytes of the file.
$filePath - is where you want to store the file, This code goes up a directory into the files folder and applies a datetime to the start of the filename (optional).
$fileExtension - is the extension of the file.
$type - will be either file or image depending on the action on the editor.
$funcNum - comes from CKEditor and is needed when using the file callback.

Depending on the type set the file extensions allowed to be uploaded.

if ($type == 'image') {
	$allowedfileExtensions = array('jpg', 'jpeg', 'gif', 'png');
} else {
	//file
	$allowedfileExtensions = array('jpg', 'jpeg', 'gif', 'png', 'pdf', 'doc', 'docx');
}

Now check if the file/image is allowed otherwise set the error message and when its a file echo a javascript passing in the $funcNum, $filePath and $message. CKEditor will use these to alert the user. 
For drag and drop uploads return an array containing uploaded 0 for fail, error with an array containing the error message.

//contrinue only if file is allowed
if (in_array($fileExtension, $allowedfileExtensions)) {

} else {

	$error = 'The file type uploaded is not allowed.';

	if ($type == 'file') {
		$funcNum = $_GET['CKEditorFuncNum'];
		$message = $error;

		echo "<script type='text/javascript'>window.parent.CKEDITOR.tools.callFunction($funcNum, '$filePath', '$message');</script>";
		exit();
	}

    
    $data = array('uploaded' => 0, 'error' => array('message' => $error));

}

Check the size of the upload, I've chosen to let uploads no bigger than 20MB (bear in mind your server but be allowed to upload files as big as you've set here)

//contunie if file is less then the desired size
if ($size < 20*MB) {


} else {

	$error = 'The file must be less than 20MB';

	if ($type == 'file') {
		$message = $error;

		echo "<script type='text/javascript'>window.parent.CKEDITOR.tools.callFunction($funcNum, '$filePath', '$message');</script>";
		exit();
	}

	$data = array('uploaded' => 0, 'error' => array('message' => $error));

}

Attempt to upload the file/image

Since the $filePath will contain ../files the end URL will be ../files/logo.png I prefer to have absolute paths so using str_replace to remove ../ and add the domain address to the $filePath

Set the $data array to uploaded 1 meaning success and the filename and url.

if (move_uploaded_file($tmpName, $filePath)) {

	$filePath = str_replace('../', 'http://filemanager.localhost/elfinder/', $filePath);
    $data = ['uploaded' => 1, 'fileName' => $filename, 'url' => $filePath];

    if ($type == 'file') {

		echo "<script type='text/javascript'>window.parent.CKEDITOR.tools.callFunction($funcNum, '$filePath');</script>";
		exit();
	}

} else {

    $error = 'There has been an error, please contact support.';

    if ($type == 'file') {
		$message = $error;

		echo "<script type='text/javascript'>window.parent.CKEDITOR.tools.callFunction($funcNum, '$filePath', '$message');</script>";
		exit();
	}

    $data = array('uploaded' => 0, 'error' => array('message' => $error));

}

The last item is to return the $data and json_encode it.

echo json_encode($data);

Putting it all Together:

<?php
//if csrf passes
if ($_COOKIE['ckCsrfToken'] == $_POST['ckCsrfToken']) {

	//define file sizes
	define('KB', 1024);
	define('MB', 1048576);
	define('GB', 1073741824);
	define('TB', 1099511627776);

	//set variables 
	$tmpName  	   = $_FILES['upload']['tmp_name'];
	$filename 	   = $_FILES['upload']['name'];
	$size 		   = $_FILES['upload']['size'];
	$filePath      = "../files/" . date('d-m-Y-H-i-s').'-'.$filename;
	$fileExtension = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
	$type 		   = $_GET['type'];
	$funcNum 	   = isset($_GET['CKEditorFuncNum']) ? $_GET['CKEditorFuncNum']: null;

	if ($type == 'image') {
		$allowedfileExtensions = array('jpg', 'jpeg', 'gif', 'png');
	} else {
		//file
		$allowedfileExtensions = array('jpg', 'jpeg', 'gif', 'png', 'pdf', 'doc', 'docx');
	}

	//contrinue only if file is allowed
	if (in_array($fileExtension, $allowedfileExtensions)) {

		//contunie if file is less then the desired size
		if ($size < 20*MB) {

			if (move_uploaded_file($tmpName, $filePath)) {

				$filePath = str_replace('../', 'http://filemanager.localhost/elfinder/', $filePath);
			    $data = ['uploaded' => 1, 'fileName' => $filename, 'url' => $filePath];

			    if ($type == 'file') {

					echo "<script type='text/javascript'>window.parent.CKEDITOR.tools.callFunction($funcNum, '$filePath');</script>";
					exit();
				}

			} else {

			    $error = 'There has been an error, please contact support.';

			    if ($type == 'file') {
					$message = $error;

					echo "<script type='text/javascript'>window.parent.CKEDITOR.tools.callFunction($funcNum, '$filePath', '$message');</script>";
					exit();
				}

			    $data = array('uploaded' => 0, 'error' => array('message' => $error));

			}

		} else {

			$error = 'The file must be less than 20MB';

			if ($type == 'file') {
				$message = $error;

				echo "<script type='text/javascript'>window.parent.CKEDITOR.tools.callFunction($funcNum, '$filePath', '$message');</script>";
				exit();
			}

			$data = array('uploaded' => 0, 'error' => array('message' => $error));

		}

	} else {

		$error = 'The file type uploaded is not allowed.';

		if ($type == 'file') {
			$funcNum = $_GET['CKEditorFuncNum'];
			$message = $error;

			echo "<script type='text/javascript'>window.parent.CKEDITOR.tools.callFunction($funcNum, '$filePath', '$message');</script>";
			exit();
		}

	    
	    $data = array('uploaded' => 0, 'error' => array('message' => $error));

	}

	//return response
	echo json_encode($data);
}

Now when you can drag and drop images on CKEditor then the uplpad.php script will be triggered and upload the file to the elfinder/php/files folder.