乌徒帮技术范儿WordPressWordPress开发 › 整合kindeditor到wordpress,特别是图片上传部分

整合kindeditor到wordpress,特别是图片上传部分

分类:WordPress开发

在我的一个项目中,需要在wordpress前台构建一个在线投稿的功能,为了提供丰富的在线编辑功能,我使用了kindeditor作为投稿页面文章内容的编辑器。但和我们一般的项目不同的是,我是在BAE(百度云)上进行的php开发,因此无法完成kindeditor的直接上传。(包括SAE在内的云空间都没有可写权限。)因此我选择了使用wordpress本身的wp_handle_upload来实现上传。于此同时的另一个问题是,如何将kindeditor的上传与wordpress结合起来,也就是说kindeditor上传的附件也可以在wordpress后台进行编辑和使用?解决这个问题的思路也很清晰:将kindeditor的上传处理文件进行修改,使用wordpress的上传机制(这个机制在我以前的文章中已经阐述过,可以在本博客中搜索相关文章),既可以解决BAE上传的问题,同时实现问题二的功能。

首先,kindeditor的上传机制非常简单。

在kindeditor中进行上传,通过点击编辑器中的图片或附件按钮,激活上传窗口。这个过程全部由脚本来实现。我们可以通过修改KE的kindeditor\plugins\image\image.js来修改弹出窗口的布局和内容。在选择好图片开始上传之后,这个窗口通过脚本的形式像一个隐藏的iframe发送$_POST内容。上传就是这样来完成的。iframe中使用了一个php文件来处理接收到的信息,并以JSON的形式返回处理结果。上传弹出窗口接收到处理结果之后,做出错误提示,或者将上传好的图片插入到文本编辑器中。

其次,实现KE整合到WP的后端处理。

其实这个后端处理就是修改上文所指的那个iframe中的php处理文件,修改之后,这个php完成文件文件的上传和数据库的写入。这个文件即kindeditor\php\upload_json.php。我们打开之后发现里面已经有很多注释,根据这些注释我们可以知道它们都完成哪些工作。但是我们要修改它,以实现我们自己的目的。我把修改好的文件贴在下面,以提供参考:

[payfor price="2"]array('gif', 'jpg', 'jpeg', 'png', 'bmp'),
	//'flash' => array('swf', 'flv'),
	//'media' => array('swf', 'flv', 'mp3', 'wav', 'wma', 'wmv', 'mid', 'avi', 'mpg', 'asf', 'rm', 'rmvb'),
	'file' => array('doc','docx','xls','xlsx','ppt','txt','zip','rar','wps','pdf')
);
//最大文件大小
$max_size = 1000000;

//PHP上传失败
if (!empty($_FILES['imgFile']['error'])) {
	switch($_FILES['imgFile']['error']){
		case '1':
			$error = '超过php.ini允许的大小。';
			break;
		case '2':
			$error = '超过表单允许的大小。';
			break;
		case '3':
			$error = '图片只有部分被上传。';
			break;
		case '4':
			$error = '请选择图片。';
			break;
		case '6':
			$error = '找不到临时目录。';
			break;
		case '7':
			$error = '写文件到硬盘出错。';
			break;
		case '8':
			$error = 'File upload stopped by extension。';
			break;
		case '999':
		default:
			$error = '未知错误。';
	}
	alert($error);
}

//检查文件大小
if($_FILES['imgFile']['size'] > $max_size)alert("上传文件大小超过限制。\n最大能上传".int($max_size/1000)."kb的文件。");

//获得文件扩展名
$temp_arr = explode(".",$_FILES['imgFile']['name']);
$file_ext = array_pop($temp_arr);
$file_ext = trim($file_ext);
$file_ext = strtolower($file_ext);
//检查扩展名
if(in_array($file_ext, $ext_arr['image']) === false && in_array($file_ext, $ext_arr['file']) === false){
	alert("上传文件扩展名是不允许的扩展名。\n只允许" . implode(",", $ext_arr['image']) .'和'.implode(",", $ext_arr['file']).'格式。');
}

// 上传成功,处理图片
if(empty($_FILES['imgFile']) === false && $_FILES['imgFile']['error'] == 0) :

	if($_FILES['imgFile']['size'] == 0)alert('上传的文件是空的,或已经被破坏,请检查后重新上传。');

	include_once(ABSPATH.'/wp-admin/includes/file.php');
	$filename = $_FILES['imgFile']['name'];
	$_FILES['imgFile']['name'] = iconv('UTF-8','GBK',$_FILES['imgFile']['name']);
	$uploaded_file = wp_handle_upload($_FILES['imgFile'],array('test_form' => false));

	$file = $uploaded_file['file'];
	$new_file = iconv('GBK','UTF-8',$file);
	$url = iconv('GBK','UTF-8',$uploaded_file['url']);
	$type = $uploaded_file['type'];
	if(isset($uploaded_file['error']))alert($uploaded_file['error']);
	$attachment = array(
		'guid' => $url, 
		'post_mime_type' => $type,
		'post_title' => $filename,
		'post_content' => '',
		'post_status' => 'inherit'
	);
	wp_update_post(array(
		'ID' => $_POST['post_id'],
		'post_title' => $filename,
		'post_status' => 'pending'
	));
	$attach_id = wp_insert_attachment($attachment,$new_file,$_POST['post_id']);

	include_once(ABSPATH.'wp-admin/includes/image.php');
	$attach_data = wp_generate_attachment_metadata($attach_id,$file);
	$attach_data['file'] = iconv('GBK','UTF-8',$attach_data['file']);
	if(!empty($attach_data['sizes']))foreach($attach_data['sizes'] as $key => $sizes){
		$sizes['file'] = iconv('GBK','UTF-8',$sizes['file']);
		$attach_data['sizes'][$key]['file'] = $sizes['file'];
	}
	wp_update_attachment_metadata($attach_id,$attach_data);

	// 要将最后的结果打印给浏览器
	header('Content-type: text/html; charset=UTF-8');
	$json = new Services_JSON();
	echo $json->encode(array('error' => 0, 'url' => $url));
	exit;
else :
	alert('可能内部出错,请稍后重试。');
endif;

function alert($msg) {
	header('Content-type: text/html; charset=UTF-8');
	$json = new Services_JSON();
	echo $json->encode(array('error' => 1, 'message' => $msg));
	exit;
}[/payfor]

上面这段php代码就是我的修改之后的文件的所有代码。读者可以自己仔细研读。而之所以要使用wp_handle_upload,是因为BAE没有可写权限,使用KE的上传铁定是不行,而有开发者根据BAE的bucket存储机制,修改了wp_handle_upload,以完成图片的上传,我们无需去了解BAE上具体怎么完成这个动作,只需要使用这个函数来上传文件即可。

第三,前台需要更多的配合。

虽然后端处理的思路是非常清晰的,然而这需要前端的配合。投稿页面需要付出更多的努力,才能让后端放心大胆的去完成自己的图片和数据库处理。在我的项目中,前端还需要做这样一些工作:

1、获取当前投稿文章的ID号。虽然一个投稿还没有发布,但是wordpress提供了预创建的机制,即这个投稿没有发布的情况下,建立的默认的数据库记录,我要获得这个记录的ID号,这样才能确认上传的图片将会属于哪一篇文章。这在后台》多媒体中你可以清晰的看到每张图片所在的文章。
2、要将这个ID号传递到处理页。看上去这件事很好办,但我尝试了多种方法,最终均宣告失败,只能选择一种最笨的方法,即使用javascript(jQuery)的setInterval来为弹出窗口中的特定部分增加一个input[type=hidden,value=post_id],这种方法其实是最笨的。
3、当心你的安全性漏洞。在自己撰写的程序中,漏洞常常非常多,包括:情况考虑不到,出现提示性错误;代码执行效率低,内存溢出;未知领域,黑客后门漏洞;等。当然,像由于手误敲错了单词引起的错误我们都没有算在内。wordpress本身其实还存在一些漏洞,因此在自己撰写程序时,应当非常注意这些问题,以防发生毁灭性的灾害。

最后,远远不止这些,还有很多需要自己开发。

看上去上面的代码已经非常完整了(完整的一个php文档),然而其实远远不止。如果你不是在寻找资料,你一定不知道需要怎么去完成这个项目,当然限于篇幅,我也不可能在这里将项目全部写下来。就来简单阐释下前端应该注意的几个问题。

首先,作为有权限的投稿,在文档开头应该首先判断用户是否登录,并检查他是否拥有投稿的权限,如果没有的话,应该提示登录或提升等级。其次,需要有比较可靠的文章发布机制,使用wp_update_post来处理这种发布,但并不提供文章的public权限,而是pending待审状态。再次,在文章内容的地方,使用stripslashes($getPost->post_content)而非不处理的输出,这样才能保证KE编辑器读取时显示正确。再次,我们通过下面的一段jQuery代码来实现上文所述的post:post_id的功能。

setInterval(function(){
	if($('input[name=imgFile]').length > 0)$('input[name=imgFile]').after('');
},500);
填写个人信息,赶快回复吧!