在正文之前要说一下,
其实我觉得在留言板用文字编辑器不是个好主意,
反而应该放在心情随笔的地方,
(但也不是不行, 譬如像Facebook这样, 有点像结合了留言板跟心情随笔功能)
不过因为之前有过失败的经验,
所以把最困难的放在最後面,
这两天研究很久终於研究出来了...
今天要解决的是图片上传,
用之前的程序虽然可以成功完成文字编辑器的编辑,
但是缺少了图片上传的部分,
感觉好像少了什麽?
所以今天要来做图片上传的部分,
收集了各种各样的资料,
剪剪贴贴修修补补之後,
终於完成了其中一种方式,
(有提供好几种, 但有的没想尝试, 有的尝试失败)
我把参考资料放在最後面,
有兴趣可以自己研究其他方式.
顺带一提,
我使用的是CKEditor 5,
跟以往的版本可能会有些许的不同.
首先js的部分加入一个自定义的物件
class MyUploadAdapter {
constructor(loader) {
// The file loader instance to use during the upload.
this.loader = loader;
}
// Starts the upload process.
upload() {
return this.loader.file.then(
file =>
new Promise((resolve, reject) => {
this._initRequest();
this._initListeners(resolve, reject, file);
this._sendRequest(file);
})
);
}
// Aborts the upload process.
abort() {
if (this.xhr) {
this.xhr.abort();
}
}
// Initializes the XMLHttpRequest object using the URL passed to the constructor.
_initRequest() {
const xhr = (this.xhr = new XMLHttpRequest());
// Note that your request may look different. It is up to you and your editor
// integration to choose the right communication channel. This example uses
// a POST request with JSON as a data structure but your configuration
// could be different.
xhr.open("POST", "/image", true);
xhr.setRequestHeader('X-CSRF-TOKEN', '<?PHP echo csrf_token() ?>');
xhr.responseType = "json";
}
// Initializes XMLHttpRequest listeners.
_initListeners(resolve, reject, file) {
const xhr = this.xhr;
const loader = this.loader;
const genericErrorText = `无法上传档案: ${file.name}.`;
xhr.addEventListener("error", () => reject(genericErrorText));
xhr.addEventListener("abort", () => reject());
xhr.addEventListener("load", () => {
const response = xhr.response;
console.log('response', response);
// This example assumes the XHR server's "response" object will come with
// an "error" which has its own "message" that can be passed to reject()
// in the upload promise.
//
// Your integration may handle upload errors in a different way so make sure
// it is done properly. The reject() function must be called when the upload fails.
if (!response || response.error) {
return reject(response && response.error ? response.error.message : genericErrorText);
}
// If the upload is successful, resolve the upload promise with an object containing
// at least the "default" URL, pointing to the image on the server.
// This URL will be used to display the image in the content. Learn more in the
// UploadAdapter#upload documentation.
resolve({
default: response.url,
});
});
// Upload progress when it is supported. The file loader has the #uploadTotal and #uploaded
// properties which are used e.g. to display the upload progress bar in the editor
// user interface.
if (xhr.upload) {
xhr.upload.addEventListener("progress", evt => {
if (evt.lengthComputable) {
loader.uploadTotal = evt.total;
loader.uploaded = evt.loaded;
}
});
}
}
// Prepares the data and sends the request.
_sendRequest(file) {
// Prepare the form data.
const data = new FormData();
data.append("upload", file);
console.log('file:', file);
// Important note: This is the right place to implement security mechanisms
// like authentication and CSRF protection. For instance, you can use
// XMLHttpRequest.setRequestHeader() to set the request headers containing
// the CSRF token generated earlier by your application.
// Send the request.
this.xhr.send(data);
}
}
// ...
function MyCustomUploadAdapterPlugin(editor) {
editor.plugins.get("FileRepository").createUploadAdapter = loader => {
// Configure the URL to the upload script in your back-end here!
return new MyUploadAdapter(loader);
};
}
其中
xhr.open("POST", "/image", true);
里面的路径要写後端上传档案的路径
xhr.setRequestHeader('X-CSRF-TOKEN', '<?PHP echo csrf_token() ?>');
这是Laravel需要的SCRF的验证
另外也可以自己修改错误讯息(但是除非是500 Server Error, 如果传送成功, 错误讯息是从後端过来)
const genericErrorText = `无法上传档案: ${file.name}.`;
并且JavaScript要加入CKEditor的宣告
ClassicEditor
.create(document.querySelector("#editor"), {
extraPlugins: [MyCustomUploadAdapterPlugin],
toolbar: ["heading", "|", "alignment:left", "alignment:center", "alignment:right", "alignment:adjust", "|", "bold", "italic", "blockQuote", "link", "|", "bulletedList", "numberedList", "imageUpload", "|", "undo", "redo"],
})
.then(editor => {
myEditor = editor;
})
.catch(error => {
console.error(error);
});
然後要写後端接收的部分,
首先是web.php的部分
Route::group(['prefix' => '/'], function(){
//上传图片
Route::any('/image', 'HomeController@imageProcess');
});
然後是图片接收的函式
app/Http/Controllers/HomeController.php
//接收档案上传
public function imageProcess()
{
header('Content-Type: application/pdf');
Log::notice('接收图片资料');
//接收输入资料
$input = request()->all();
$result = array();
Log::notice('接收图片'.print_r($input, true));
if(isset($input['upload']))
{
$upload = $input['upload'];
//档案副档名
$extension = $upload->getClientOriginalExtension();
//产生随机档案名称
$filename = uniqid().'.'.$extension;
//相对路径
$relative_path = 'images/upload/'.$filename;
//取得public目录下的完整位置
$fullpath = base_path('public_html/'.$relative_path);
//允许的档案格式
switch($upload->getMimeType())
{
case 'image/jpeg':
case 'image/png':
break;
default:
$result['error'] = array(
'message' => '很抱歉,只接受JPG和PNG档案',
);
echo json_encode($result);
exit;
}
//移动档案位置并改名称
move_uploaded_file($upload->getRealPath(),$relative_path);
$result['url'] = '/'.$relative_path;
echo json_encode($result);
}
else
{
$result['error'] = array(
'message' => '很抱歉,上传档案失败了',
);
echo json_encode($result);
}
}
最後再附上成果图
到这里这个系列的文章差不多结束了,
虽然还有些东西想写,
不过就等年底再说了.
参考资料:
Simple upload adapter(官方文件)
[笔记]CKEditor加上CKFinder上传图档更方便
如何套用 CKEditor5 上传图片
CKEditor 5图片的上传方式
CKEditor 5 教学(三),上传图片至 Amazon S3
不怎麽重要的前言 上一篇介绍了while loop的概念,让大家在回圈的使用上可以相对的弹性。 这次...
先来看一下题目 Given an array of positive integers (repre...
昨天讲到了阵列,那今天要讲怎麽让阵列的资料呈现在网页上 在阵列里,第一个资料的位置不是1而是0 所以...
Day 27: 暴力破解 WPA/WPA2 加密 wifi 密码 tags: Others 自我挑战...
Aloha!又是我少女人妻 Uerica!昨晚跟朋友聊天突然发现,如果没有最终目标或目标不够明确,那...