การใช้ CKEditor 5 แบบ CDN รองรับการอัปโหลดไฟล์ อย่างง่าย

บทความใหม่ เดือนนี้ โดย Ninenik Narkdee
ckeditor ckeditor5 image upload paste to upload

คำสั่ง การ กำหนด รูปแบบ ตัวอย่าง เทคนิค ลูกเล่น การประยุกต์ การใช้งาน เกี่ยวกับ ckeditor ckeditor5 image upload paste to upload

ดูแล้ว 625 ครั้ง




เนื้อหานี้เป็นแนวทางการประยุกต์ใช้งาน CKEditor แบบอย่างง่าย
ให้เราสามารถสร้างส่วนของ ฟอร์มสำหรับบันทึกข้อมูลลงฐานข้อมูล
ซึ่งปกติ สมมติเราต้องการบันทึกรายละเอียดข้อมูล ถ้าใช้แค่ textarea
ก็จะสามารถบันทึกได้เฉพาะ เนื้อหาที่เป็นข้อความ แต่ถ้านำ CKEditor
มาใช้ ก็จะสะดวก และเพิ่มความสามารถมากยิ่งขึ้น และยิ่งเราใช้รูปแบบ
แบบ CDN ก็ทำให้ง่ายไปอีก โดยไม่ต้องดาวน์โหลดหรือติดตั้งไฟล์ใดๆ เพิ่ม
เติม ก็สามารถใช้งานได้ทันที
 
นอกจากนี้ เรายังประยุกต์ให้สามารถทำการอัปโหลดรูปภาพ เพื่อแสดงใน
ฟอร์มข้อมูลได้อีกด้วย การอัปโหลด สามารถทำได้ทั้งการเลือกไฟล์รุปที่ต้องการ
หรือจะใช้วิธีการ จับภาพหน้าจอ ในส่วนที่ต้องการ หรือจะคัดลอกรูปภาพจาก
แหล่งข้อมูลอื่น แล้วมาวางใน ckeditor ตัวโปรแกรม ก็จะทำการอัปโหลดให้
และแสดงผลลัพธ์ให้โดยอัตโนมัติ รองรับการอัปโหลดพร้อมกันหลายไฟล์
หรือจากลากไฟล์มาวางพร้อมกันหลายๆ ไฟล์ก็ได้

 
ในตัวอย่างจะใช้แค่ไฟล์เดียว สามารถนำไปปรับประยุกต์ตามต้องการได้ โดยหลัก
การอัปโหลดไฟล์ กรณี เราเลือกอัปโหลดไฟล์เอง สมมติ อัปโหลดไฟล์ชื่อ mypic.jpg
ในเดือน 4 ปี 2024 เมื่อทำการอัปโหลด ไฟล์ก็จะถูกอัปโหลดไปยังโฟลเดอร์ 
 
uploads/202404/mypic.jpg
 
โฟลเดอร์ uploads สามารถเปลี่ยนไปยัง path ที่ต้องการได้ 
 
กรณีเราอัปโหลดรูปซ้ำชื่อเดิม ในเดือนเดิม ซึ่งชื่อจะซ้ำกัน ก็จะถูกเปลี่ยนเป็นชื่อใหม่
ในรูปแบบ
 
uploads/202404/mypic_1.jpg
uploads/202404/mypic_2.jpg
......
 
ในกรณีที่เป็นคัดลอกรูปมาวาง หรือการ จับภาพหน้าจอมาวาง ข้อมูลที่ถูกนำมาใช้งาน
จะไม่ได้เป็นไฟล์ แต่จะเป็นข้อมูลรูปภาพ เมื่อเรามาวาง ก็จะทำการสร้างไฟล์ชื่อ image.png
ให้อัตโนมัติ ชื่อไฟล์ที่จัดเก็บก็จะเป็น
 
uploads/202404/image_1.png
uploads/202404/image_2.png
......
 
ตัว ckeditor จะเป็นตัวช่วยสร้างข้อมูลแบบ html ให้เราสามารถนำไปบันทึกลงฐานข้อมูล
และสามารถนำมาแสดงผล ได้ผลลัพธ์เหมือนตอนจัดการกับข้อมูล
 

ไฟล์ตัวอย่าง  ckeditor_upload.php


<?php
/** Error reporting ใช้ตอนพัฒนา ปิดเมื่อนำไปใช้งาน */
error_reporting(E_ALL);
ini_set('display_errors', TRUE);
ini_set('display_startup_errors', TRUE);
// ฟังก์ชั่นสำหรับตรวจสอบไม่ให้อัพโหลดทับไฟล์เดิม กรณีชื่อไฟล์ซ้ำ
function getUniqueFileName($directory, $filename)
{
	// ถ้ายังไม่มีชื่อไฟล์นี้อยู่ ก็ให้ให้ใช้ชื่อไฟล์เริ่มต้น 
	if (!file_exists($directory . $filename)) {
		return $filename;
	}

	// กรณีมีชื่อไฟล์นี้อยู่แล้ว ตรวจสอบข้อมูลไฟล์
	$extension = pathinfo($filename, PATHINFO_EXTENSION);
	$basename = pathinfo($filename, PATHINFO_FILENAME);

	// สร้างตัวแปรนับจำนวนไฟล์ที่ชื่อซ้ำ เพื่อใช้เป็นตัวเลข ต่อไปในชื่อไฟล์นั้นๆ
	$counter = 1;
	// วนลูปไปจนกว่าจะไม่ซ้ำกับไฟล์ใดๆก่อนหน้า
	while (file_exists($directory . $basename . '_' . $counter . '.' . $extension)) {
		$counter++;
	}

	// ส่งกลับชื่อไฟล์ที่ไม่ซ้ำกลับไปใช้งาน
	return $basename . '_' . $counter . '.' . $extension;
}
// ตรวจสอบว่ามีการเลือกไฟล์เพื่ออัพโหลดหรือไม่ ชื่อ upload จะเป็นชื่อของ ข้อมูลไฟล์ที่ ckeditor สร้างให้
if (isset($_FILES['upload']['name'])) {
	// มีการเลือกไฟล์ และไม่ใช่ค่าว่าง
	if (isset($_FILES['upload']['name']) && $_FILES['upload']['name'] != "" ) {
		$file_name = $_FILES['upload']['name'];  // ชื่อไฟล์
		$file_tmp = $_FILES['upload']['tmp_name']; // ข้อมูลไฟล์
		$file_size = $_FILES['upload']['size']; // ขนาดไฟล์

		// กำหนดตัวแปร กรณ๊เกิดข้อผิดพลาด
		$error_message = '';
		// ตรวจสอบข้อมูลไฟล์ว่าเป็นรูปภาพหรือไม่
		$check = getimagesize($file_tmp);
		if ($check !== false) {
			$uploadOk = 1;
		} else {
			$error_message =  "File is not an image.";
			$uploadOk = 0;
		}

		// กรณีกำหนดขนาดไฟล์ไม่่เกิน 500 Kb หรือ 0.5 MB
		if ($file_size > 500000) {
			$error_message =  "Sorry, your file is too large.";
			$uploadOk = 0;
		}

		// กรณีกำหนดเงื่อนไขว่าต้องเป็นไฟล์นามสกุล ที่กำหนดเท่านั้น
		$allowedFormats = array("jpg", "jpeg", "png", "gif");
		$fileExtension = strtolower(pathinfo($file_name, PATHINFO_EXTENSION));
		if (!in_array($fileExtension, $allowedFormats)) {
			$error_message =  "Sorry, only JPG, JPEG, PNG & GIF files are allowed.";
			$uploadOk = 0;
		}

		// กรณีไม่ผ่านเงื่อนไขการตรวจสอบไฟล์ก่อนอัปโหลด
		if ($uploadOk == 0) {
			$error_message =  "Sorry, your file was not uploaded.";
			$response = array(
				'uploaded' => false,
				'error' => $error_message
			);
		} else { // กรณีเงื่อนไขผ่าน พร้อมอัปโหลด
			// กำหนดโฟลเดอร์ สำหรับเก็บไฟล์
			$upload_dir = "uploads/";

			// สร้างตัวแปรวันที่สำหรับ ใช้สร้างโฟลเดอร์ย่อย แยกตามเดือนและปี ณ ขณะนั้น
			$currentYear = date("Y");
			$currentMonth = date("m");

			// จัดรูปแบบ ปีเดือน เช่น 202401 เป็นโฟลเดอร์ข้อมูล ปี 2024 เดือน 01 รูปทั้งหมด
			// ที่อัปโหลดช่วงนี้ จะถูกจัดเก็บไว้ในนี้
			$folderName = $currentYear . sprintf("%02d", $currentMonth);

			// ตรวจสอบว่ามีโฟลเดอร์ดังกล่าว อยู่แล้วหรือไม่ ถ้าไม่มีให้ทำการสร้างขึ้นมา
			if (!file_exists($upload_dir . $folderName)) {
				mkdir($upload_dir . $folderName, 0777, true);
				$upload_dir = $upload_dir . $folderName . "/";
			} else {
				$upload_dir = $upload_dir . $folderName . "/";
			}

			// นำชื่อไฟล์ไปตรวจสอบ ว่ามีชื่อไฟล์นี้อยู่แล้วหรือไม่ ถ้ามีซ้า ก็จะทำการเพิ่มตัวเลขต่อท้ายเข้าไป
			$file_name = getUniqueFileName($upload_dir, $file_name);

			// ทำการย้ายข้อมูลไฟล์ที่อัปโหลดไปไว้ในโฟลเดอร์ และ ชื่อไฟล์ที่กำหนด
			if (move_uploaded_file($file_tmp, $upload_dir . $file_name)) {
				// ส่งกลับข้อมูลที่อยู่หรือ url ของไฟล์รูปภาพที่อัปโหลด พร้อมสถานะการอัปโหลดที่สำเร็จ
				$file_url = $_SERVER['REQUEST_SCHEME'] . '://' . $_SERVER['HTTP_HOST'] . dirname($_SERVER['REQUEST_URI']) . '/' . $upload_dir . $file_name;
				$response = array(
					'uploaded' => true,
					'url' => $file_url
				);
			} else {
				// เกิดข้อผิดพลาดไม่สามารถย้ายข้อมูลไฟล์ หรืออัปโหลดไฟล์ได้ เช่น ถูกปิด permission
				$response = array(
					'uploaded' => false,
					'error' => 'Failed to move uploaded file.'
				);
			}
		}
	} else {
		// ไม่มีการเลือกไปล์เพื่อผัปโหลด
		$response = array(
			'uploaded' => false,
			'error' => 'No file uploaded.'
		);
	}
	// คืนค่าข้อมูลเป็น json เพื่อไปให้ ckeditor จัดการ
	header('Content-Type: application/json');
	echo json_encode($response);
	exit;
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<title>CKEditor Image Upload Example</title>
	<script src="https://cdn.ckeditor.com/ckeditor5/41.2.1/classic/ckeditor.js"></script>
	<style type="text/css">
		/* กำหนดความสูงง่ายๆ ผ่าน css */	
		.ck-editor__editable {
			min-height: 250px;
		}
	</style>
</head>

<body>
	<h2>Upload Image</h2>
	<form action="temp_upload.php" method="post" enctype="multipart/form-data">
		<input type="file" name="image" accept="image/*" required>
		<button type="submit" name="submit">Upload</button>
	</form>

	<h1>CKEditor Image Upload Example</h1>
	<textarea name="message" id="editor"></textarea>

	<script>
		ClassicEditor
			.create(document.querySelector('#editor'), {
				ckfinder: {
					uploadUrl: '/ckeditor_upload.php' // กำหนด path ส่วนของไฟล์อัปโหลด
				}
			})
			.catch(error => {
				console.error(error);
			});
	</script>
</body>
</html>

 


   เพิ่มเติมเนื้อหา ครั้งที่ 1 วันที่ 20-04-2024


เพิ่มเติมส่วนการตั้งค่าใช้งานร่วมกับ JavaScript

 
เราสามารถกำหนดการอ้างอิงค่าจาก editor ที่สร้างด้วย CKEditor 5 CDN โดยเพิ่ม
การกำหนดค่า instance เข้าไป ผ่านแปร global ของ window สมมติเช่น เราต้องการ
กำหนด property ของ window เป็น ckeditorInstance  ก็จะได้เป็น
 
window.ckeditorInstance
 
เราสามารถกำหนดเป็นชื่อใดๆ ก็ได้ตามต้องการ จากนั้นเอาไปรับค่า editor ที่สร้างจาก 
CKEditor 5 CDN ก็จะได้เป็น
 
window.ckeditorInstance = editor;
 
ตัวอย่างการกำหนดในการตั้งค่า
 
    <script>
        ClassicEditor
            .create(document.querySelector('#editor'), {
                ckfinder: {
                    uploadUrl: '/ckeditor_upload.php' // กำหนด path ส่วนของไฟล์อัปโหลด
                }
            })
            .then( editor => {
                // กำหนด ckeditorInstance property ให้กับ global window เพื่ออ้างอิง
                // สำหรับใช้เป็น CKEditor instance
                window.ckeditorInstance = editor;
            })			
            .catch(error => {
                console.error(error);
            });
    </script>
 
จากนั้นในส่วนของ JavaScript ถ้าเราจะเรียกใช้งาน เช่น ดึงข้อมูลใน editor มาใช้ก็จะเป็นดังนี้
 
// ดึงข้อมูลของ editor มาไว้ในตัวแปร editorContent เพื่อนำไปใช้งาน
const editorContent = window.ckeditorInstance.getData();
 
หรือกรณีเราต้องการตรวจสอบก่อนว่ามี instance แล้วหรือไม่ก่อนเรียกใช้ก็สามารถใช้เป็น
 
    if (window.ckeditorInstance) {
        // ดึงข้อมูลของ editor มาไว้ในตัวแปร editorContent เพื่อนำไปใช้งาน
        const editorContent = window.ckeditorInstance.getData();		
    } else {
        console.error('CKEditor instance is not available.');
    }


   เพิ่มเติมเนื้อหา ครั้งที่ 2 วันที่ 20-04-2024


การเรียกใช้งาน Event เมื่อมีการแก้ไขข้อมูลใน Editor 

 
เราสามารถกำหนดการทำงาน กรณีมีการแก้ไขข้อมูลใน Editor คล้ายกับ onChange
โดยเฉพาะกรณีนำไปใช้งานกับ ajax ก็สามารถแทรกส่วนนี้ลงไปได้
 
// เมื่อมีการเปลี่ยนแปลงแก้ไขข้อมูลใน editor
editor.model.document.on('change:data', () => {
    const newContent = editor.getData(); // ดึงข้อมูลมาเก็บไว้ในตัวแปรเพื่อนำไปใช้งาน
    // console.log(newContent);
});
 
โดยแทรกในส่วนของการเรียกใช้ดังนี้
 
    <script>
        ClassicEditor
            .create(document.querySelector('#editor'), {
                ckfinder: {
                    uploadUrl: '/ckeditor_upload.php' // กำหนด path ส่วนของไฟล์อัปโหลด
                }
            })
            .then( editor => {
                // กำหนด ckeditorInstance property ให้กับ global window เพื่ออ้างอิง
                // สำหรับใช้เป็น CKEditor instance
                window.ckeditorInstance = editor;
                // เมื่อมีการเปลี่ยนแปลงแก้ไขข้อมูลใน editor
                editor.model.document.on('change:data', () => {
                     const newContent = editor.getData(); // ดึงข้อมูลมาเก็บไว้ในตัวแปรเพื่อนำไปใช้งาน
                     // console.log(newContent);
                });		
            })			
            .catch(error => {
                console.error(error);
            });
    </script>


   เพิ่มเติมเนื้อหา ครั้งที่ 3 วันที่ 20-04-2024


ถ้ามีการใช้งาน Editor หลายตัวพร้อมกัน ในหน้าเดียว

 
เราสามารถเรียกใช้งาน Editor พร้อมกันได้หลายอันในหน้าเดียวตามความเหมาะสม คือไม่มาก
จนเกินไป โดยสามารถกำหนด และใช้งานร่วมกับ JavaScript ได้ดังนี้
<textarea id="editor1"></textarea>
<textarea id="editor2"></textarea>  

  <script>
        ClassicEditor
            .create(document.querySelector('#editor1'), {
                ckfinder: {
                    uploadUrl: '/ckeditor_upload.php' // กำหนด path ส่วนของไฟล์อัปโหลด
                }
            })
            .then( editor1 => {
                // กำหนด ckeditorInstance1 property ให้กับ global window เพื่ออ้างอิง
                // สำหรับใช้เป็น CKEditor instance
                window.ckeditorInstance1 = editor1;
                // เมื่อมีการเปลี่ยนแปลงแก้ไขข้อมูลใน editor
                editor.model.document.on('change:data', () => {
                     const newContent1 = editor1.getData(); // ดึงข้อมูลมาเก็บไว้ในตัวแปรเพื่อนำไปใช้งาน
                     // console.log(newContent1);
                });		
            })			
            .catch(error => {
                console.error(error);
            });
			
        ClassicEditor
            .create(document.querySelector('#editor2'), {
                ckfinder: {
                    uploadUrl: '/ckeditor_upload.php' // กำหนด path ส่วนของไฟล์อัปโหลด
                }
            })
            .then( editor2 => {
                // กำหนด ckeditorInstance property ให้กับ global window เพื่ออ้างอิง
                // สำหรับใช้เป็น CKEditor instance
                window.ckeditorInstance2 = editor2;
                // เมื่อมีการเปลี่ยนแปลงแก้ไขข้อมูลใน editor
                editor.model.document.on('change:data', () => {
                     const newContent2 = editor2.getData(); // ดึงข้อมูลมาเก็บไว้ในตัวแปรเพื่อนำไปใช้งาน
                     // console.log(newContent2);
                });		
            })			
            .catch(error => {
                console.error(error);
            });			
    </script>




กด Like หรือ Share เป็นกำลังใจ ให้มีบทความใหม่ๆ เรื่อยๆ น่ะครับ











URL สำหรับอ้างอิง





คำแนะนำ และการใช้งาน

สมาชิก กรุณา ล็อกอินเข้าระบบ เพื่อตั้งคำถามใหม่ หรือ ตอบคำถาม สมาชิกใหม่ สมัครสมาชิกได้ที่ สมัครสมาชิก


  • ถาม-ตอบ กรุณา ล็อกอินเข้าระบบ
  • เปลี่ยน


    ( หรือ เข้าใช้งานผ่าน Social Login )







เว็บไซต์ของเราให้บริการเนื้อหาบทความสำหรับนักพัฒนา โดยพึ่งพารายได้เล็กน้อยจากการแสดงโฆษณา โปรดสนับสนุนเว็บไซต์ของเราด้วยการปิดการใช้งานตัวปิดกั้นโฆษณา (Disable Ads Blocker) ขอบคุณครับ