CKEditor и загрузка графических файлов

«CKEditor — лучший текстовый редактор для каждого» (c) (The best web text editor for everyone). CKEditor — бесплатный визуальный кросплатформенный браузерный редактор — часто используется для внесения форматированного текста в различных системах управления контента (CMS). Редактор хорошо настраиваемый, но в последней редакции (версия 4 на момент написания поста) нет функционала загрузки фотографий через сам редактор. Сейчас мы с вами размеремся, как исправить это недостаток.

Загрузка картинок не представлена, потому что редактор вообще не имеет серверных скриптов, необходимых для загруки файлов на сервер. Непонятно какие причины подвигли авторов редактора отключение этого функционала (в предыдущих версиях он существовал), но без загрузки изображений редактор доьтавляет определенные проблемы в офромлении текста. К счастью возможноть подлючения своих серверных сриптов осталась, нужно только включить ее. Не будем вдаваться в подробности конфигурирования редактора, а сразу укажем какие опции надо добавить для этого.

Итак открываем файл config.php, который находится в корне папки редактора и добавляем две строки (38, 39)

/**
 * @license Copyright (c) 2003-2014, CKSource - Frederico Knabben. All rights reserved.
 * For licensing, see LICENSE.html or http://ckeditor.com/license
 */

CKEDITOR.editorConfig = function( config ) {
	// Define changes to default configuration here.
	// For the complete reference:
	// http://docs.ckeditor.com/#!/api/CKEDITOR.config

	// The toolbar groups arrangement, optimized for two toolbar rows.
	config.toolbarGroups = [
		{ name: 'clipboard',   groups: [ 'clipboard', 'undo' ] },
		{ name: 'editing',     groups: [ 'find', 'selection', 'spellchecker' ] },
		{ name: 'links' },
		{ name: 'insert' },
		{ name: 'forms' },
		{ name: 'tools' },
		{ name: 'document',	   groups: [ 'mode', 'document', 'doctools' ] },
		{ name: 'others' },
		'/',
		{ name: 'basicstyles', groups: [ 'basicstyles', 'cleanup' ] },
		{ name: 'paragraph',   groups: [ 'list', 'indent', 'blocks', 'align', 'bidi' ] },
		{ name: 'styles' },
		{ name: 'colors' },
		{ name: 'about' }
	];

	// Remove some buttons, provided by the standard plugins, which we don't
	// need to have in the Standard(s) toolbar.
	config.removeButtons = 'Underline,Subscript,Superscript';

	// Se the most common block elements.
	config.format_tags = 'p;h1;h2;h3;pre';

	// Make dialogs simpler.
	config.removeDialogTabs = 'image:advanced;link:advanced';
	config.filebrowserImageUploadUrl = '/js/ckeditor/php/imageupload.php';
	config.filebrowserImageBrowseUrl = '/js/ckeditor/php/imagebrowse.php';
};

Строка 38 указывает редактору подключить функционала загрузки файла в диалоге ввода картинки, строка 39 подключает функционал выбора уже загруженной картинки.

У нас редактор установлен в папку /js/ckeditor/ сайта. Там же мы создали папку php для наших серверных скриптов, эта папка должна иметь разрешение на выполнение для php скриптов.

Скрипт загрузки изображений imageupload.php.

<?php
/*
	Внимание! Для безопасности надо вставить строки проверки авторизации.
	Они зависят от используемой CMS.
	В противном случае любой посетитель сайта может вам загрузить файлы.
*/
$full_path = ''; // src вставленной картинки для тега <img>
$upload_dir = '/images'; // папка куда сохраняются картинки, должна доступна на запись

// разрешенные форматы графических файлов (см. описание фукнции image_type_to_mime_type
$images_exts = array(
	IMAGETYPE_GIF => 'gif', 
	IMAGETYPE_JPEG => 'jpg',
	IMAGETYPE_PNG => 'png'
);

$dir = $_SERVER['DOCUMENT_ROOT'].$upload_dir;
if(!isset($_FILES['upload']) && !is_uploaded_file($_FILES['upload']['tmp_name'])){
	$message = 'Вы не указали файл для загрузки';
}
else{
	$is = @getimagesize($_FILES['upload']['tmp_name']);
	if(!isset($images_exts[$is[2]])) {
		$message = 'Необходимо указать файл формата '.implode(', ', $images_exts);
	}
	else {
		$name = Transliteration($_FILES['upload']['name']);
		$d = $dir.'/'.$name;
		if(!@move_uploaded_file($_FILES['upload']['tmp_name'], $d)){
			$message = 'Невозможно сохранить файл, проверьте настройки папки для файлов '.$_FILES['upload']['name'];
		}
		else{
			$full_path = $upload_dir.'/'.$name;
			$message = '';
		}
	}
}
?>
<script>
window.parent.CKEDITOR.tools.callFunction(<?=$_GET['CKEditorFuncNum']?>, "<?=$full_path?>", "<?=mysql_real_escape_string(iconv('UTF-8', 'Windows-1251//IGNORE', $message))?>" );
</script>
<?php
function Transliteration($str){
	$transl = array(
	 "А"=>"A", "Б"=>"B", "В"=>"V", "Г"=>"G", "Д"=>"D", "Е"=>"E", "Ё"=>"YO", "Ж"=>"ZH", "З"=>"Z", "И"=>"I", "Й"=>"J", "К"=>"K", "Л"=>"L", "М"=>"M", 
	 "Н"=>"N", "О"=>"O", "П"=>"P", "Р"=>"R", "С"=>"S", "Т"=>"T", "У"=>"U", "Ф"=>"F", "Х"=>"H", "Ц"=>"TS", "Ч"=>"CH", "Ш"=>"SH", "Щ"=>"SCH", "Ь"=>"", 
	 "Ъ"=>"", "Ы"=>"Y", "Э"=>"E", "Ю"=>"YU", "Я"=>"YA", "а"=>"a", "б"=>"b", "в"=>"v", "г"=>"g", "д"=>"d", "е"=>"e", "ё"=>"yo", "ж"=>"zh", "з"=>"z", 
	 "и"=>"i", "й"=>"j", "к"=>"k", "л"=>"l", "м"=>"m", "н"=>"n", "о"=>"o", "п"=>"p", "р"=>"r", "с"=>"s", "т"=>"t", "у"=>"u", "ф"=>"f", "х"=>"h",
	 "ц"=>"ts", "ч"=>"ch", "ш"=>"sh", "щ"=>"sch", "ь"=>"", "ъ"=>"", "ы"=>"y", "э"=>"e", "ю"=>"yu", "я"=>"ya"
	);
	return preg_replace("/_+/", "_", strtolower(str_replace(array_keys($transl), array_values($transl), $str)));
}
exit();
?>

Скрипт выбора загруженных изображений imagebrowse.php.

<html>
<head>
<title>Выбор файла</title>
<style>
.img_list {
}
.img_list a {
	display:inline-block;
	position:relative;
	text-align:center;
	width:200px;
	height:200px;
	border:1px solid #ccc;
	vertical-align:middle;
	margin:0 5px 5px 0;
}
.img_list a img{
	max-width:200px;
	max-height:200px;
}
.img_list a div{
	position:absolute;
	background:rgba(255,255,255,0.5);
	color:#000;
	bottom:0;
	width:100%;
}

</style>
</head>
<body>
<div class="img_list">
<?php


$srcdir = '/images'; // папка c картинкам
$full_path = '';

$dir = $_SERVER['DOCUMENT_ROOT'].$srcdir;

$files = array();
if($DP = opendir($dir)){
	while($file = readdir($DP)){
		if(is_file($f = $dir.'/'.$file) && ($is = @getimagesize($f)) && isset($images_exts[$is[2]])){
			$src = htmlspecialchars($srcdir.'/'.$file, ENT_QUOTES);
			printf('<a href="%s" onclick="selectFile(this)" title="%s"><img src="%s"><div>%ux%u</div></a>', $src, htmlspecialchars($file, ENT_QUOTES), $src, $is[0], $is[1]);
		
		}
	}
	closedir($DP);
}

?>
</div>
<script>
function selectFile(a){
	window.opener.CKEDITOR.tools.callFunction(<?=$_GET['CKEditorFuncNum']?>, a.href, "" );
	self.close();
}
</script>
</body>
</html>

Скрипт imageupload.php очень простой, но функцию свою выполняет. Для большого количества файлов отображение списка файлов будет подтормаживать, кроме того миниатюры файлов сжимаются средствами браузера, поэтому интернет-трафик будет равняться трафику полноразмерных изображений. В идеале этот скрипт надо основательно переписать, но это уже выходит за рамки данного поста.