Mysql
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> Mysql

Tải lên hình ảnh trong CKEditor mà không cần sử dụng plugin

Khi viết một bài báo trên blog của bạn, bạn thường sẽ cần hiển thị hình ảnh ở giữa các văn bản, thường là cho mục đích minh họa. CKEditor giúp bạn đạt được điều này nhưng nó có thể hơi phức tạp hoặc khó làm việc nếu bạn không sử dụng plugin. Lý do là CKEditor chỉ chấp nhận URL của hình ảnh để chèn vào văn bản bài đăng và hình ảnh phải tồn tại trên internet chứ không phải trên máy cục bộ của bạn.

Việc chúng ta cần làm bây giờ là tìm cách tải ảnh lên thư mục images trong dự án của chúng ta khi chúng ta vẫn đang viết bài; khi hình ảnh đã được tải lên, URL của hình ảnh sẽ được gửi lại mà sau đó chúng tôi có thể sử dụng trong CKEditor của mình.

Điều đầu tiên là chúng ta sẽ thêm một nút mà khi nhấp vào sẽ duyệt qua máy tính cục bộ của người dùng để tìm hình ảnh (giống như cách nhấp vào phần tử ). Khi người dùng chọn một hình ảnh, hình ảnh đó ngay lập tức được tải lên trong nền bằng Ajax (mà không cần tải lại trang) trong sự kiện onChange và URL của hình ảnh cụ thể đó được trả về từ máy chủ. URL trả về được hiển thị trong một phương thức bật lên được sao chép vào khay nhớ tạm khi người dùng nhấp vào nó. Bây giờ người dùng có thể nhấp vào biểu tượng hình ảnh trên CKEditor và dán URL của hình ảnh vào đó.

Hãy thực hiện điều này trên một dự án nhỏ và xem nó hoạt động như thế nào.

Tạo một thư mục có tên là ckeditor-images và bên trong thư mục này, tạo một thư mục con có tên là hình ảnh và 4 tệp cụ thể là:index.php, server.php, scripts.js và main.css.

Thư mục hình ảnh sẽ chứa các hình ảnh được tải lên từ CKEditor của chúng tôi.

Mở index.php lên và đặt mã sau vào đó.

index.php:

<?php include('server.php') ?>

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>Uploading images in CKEditor using PHP</title>
	<!-- Bootstra CSS -->
	<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.min.css" />

	<!-- Custom styling -->
	<link rel="stylesheet" href="main.css">
</head>
<body>
	
<div class="container">
	<div class="row">
		<div class="col-md-8 col-md-offset-2 post-div">

			<!-- Display a list of posts from database -->
			<?php foreach ($posts as $post): ?>
				<div class="post">
					<h3>
						<a href="details.php?id=<?php echo $post['id'] ?>"><?php echo $post['title']; ?></a>
					</h3>
					<p>
						<?php echo html_entity_decode(preg_replace('/\s+?(\S+)?$/', '', substr($post["body"], 0, 200))); ?>
						
					</p>
				</div>				
			<?php endforeach ?>

			<!-- Form to create posts -->
			<form action="index.php" method="post" enctype="multipart/form-data" class="post-form">
				<h1 class="text-center">Add Blog Post</h1>
				<div class="form-group">
					<label for="title">Title</label>
					<input type="text" name="title" class="form-control" >
				</div>

				<div class="form-group" style="position: relative;">
					<label for="post">Body</label>
					
					<!-- Upload image button -->
					<a href="#" class="btn btn-xs btn-default pull-right upload-img-btn" data-toggle="modal" data-target="#myModal">upload image</a>

					<!-- Input to browse your machine and select image to upload -->
					<input type="file" id="image-input" style="display: none;">

					<textarea name="body" id="body" class="form-control" cols="30" rows="5"></textarea>

					</div>
					<div class="form-group">
						<button type="submit" name="save-post" class="btn btn-success pull-right">Save Post</button>
					</div>
			</form>

			<!-- Pop-up Modal to display image URL -->
			<div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
			  <div class="modal-dialog" role="document">
			    <div class="modal-content">
			      <div class="modal-header">
			        <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
			        <h4 class="modal-title" id="myModalLabel">Click below to copy image url</h4>
			      </div>
			      <div class="modal-body">
					<!-- returned image url will be displayed here -->
					<input 
						type="text" 
						id="post_image_url" 
						onclick="return copyUrl()" 
						class="form-control"
						>
					<p id="feedback_msg" style="color: green; display: none;"><b>Image url copied to clipboard</b></p>
			      </div>
			    </div>
			  </div>
			</div>
		</div>

	</div>
</div>

<!-- JQuery -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<!-- Bootstrap JS -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/js/bootstrap.min.js"></script>
<!-- CKEditor -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/ckeditor/4.8.0/ckeditor.js"></script>

<!-- custom scripts -->
<script src="scripts.js"></script>

</body>
</html>

Như bạn có thể thấy, chúng tôi đã thêm CSS và JS bootstrap thông qua CDN. Chúng tôi cũng đã thêm JQuery vì chúng tôi sẽ tải các hình ảnh lên bằng cách gọi Ajax. Cuối cùng, chúng tôi đã thêm mã plugin CKEditor mà chúng tôi vẫn đang khởi tạo trên vùng văn bản của chúng tôi trong biểu mẫu. scripts.js là nơi tập lệnh JQuery sẽ cư trú.

Ngay sau biểu mẫu bài đăng, chúng tôi đã thêm một số mã cho phương thức bật lên với id được đặt thành id ="myModal". Phương thức này hiện không được sử dụng nhưng khi hình ảnh đã được tải lên, URL trả về của hình ảnh sẽ được hiển thị trên phương thức này. Vì vậy, hãy quên nó đi ngay bây giờ.

Nếu bạn truy cập http://localhost/ckeditor-images/index.php, bạn sẽ thấy bài đăng tĩnh được hiển thị và biểu mẫu. Mở main.css và thêm một vài kiểu vào trang này.

main.css:

p {
	font-size: 1.1em;
}
.post {
	border: 1px solid #ccc;
	padding: 10px;
	margin-top: 15px;
}
.post h3 {
	margin: 0px;
}
.post-div {
	border: 1px solid #ccc;
	margin-top: 30px;
	margin-bottom: 30px;
	padding: 20px;
}
.post-form {
	margin-top: 80px;
}
/*DETAILS PAGE*/
.post-details p {
	text-align: justify;
	margin: 20px auto;
	font-size: 1.2em;
}
.upload-img-btn {
	position: absolute; 
	z-index: 9; 
	top: 35px;
	right: 5px;
}

Mở scripts.js và thêm mã này vào bên trong nó:

scripts.js:

// initialize ckeditor
CKEDITOR.replace('body');

Làm mới trang và bạn sẽ nhận thấy một số thay đổi về kiểu dáng cũng như vùng văn bản mà bây giờ là CKEditor của chúng tôi được tải với nhiều biểu tượng.

Tạo một cơ sở dữ liệu có tên là ckeditor-images. Trong cơ sở dữ liệu này, hãy tạo một bảng có tên là bài đăng với các trường:

  • id - INT (11)
  • tiêu đề - VARCHAR (255)
  • nội dung - VARCHAR (255)

Bây giờ, hãy chèn một hoặc nhiều bài đăng giả vào bảng bài đăng để chúng tôi có thể truy vấn nó và hiển thị trên trang.

Kết nối với cơ sở dữ liệu

Mở server.php lên và nhập mã này vào đó:

<?php 
	// connect to database
	$db = mysqli_connect("localhost", "root", "", "ckeditor-images");

	// retrieve posts from database
	$result = mysqli_query($db, "SELECT * FROM posts");
	$posts = mysqli_fetch_all($result, MYSQLI_ASSOC);
?>

Mã này truy xuất các bài đăng có trong cơ sở dữ liệu thành một biến $ posts. Biến này được tạo sẵn trong tệp index.php của chúng tôi bằng câu lệnh include ở dòng mã đầu tiên trong index.php - dòng bao gồm tệp server.php bên trong index.php.

Trong tệp index.php, hãy xóa toàn bộ phần tử div có thuộc tính class ="post" và thay thế nó bằng mã sau:

// ... more code here

<?php if (isset($posts)): ?>
	<?php foreach ($posts as $post): ?>
		<div class="post">
			<h3>
				<a href="details.php?id=<?php echo $post['id'] ?>"><?php echo $post['title'] ?></a>
			</h3>
			<p><?php echo $post['body']; ?></p>
		</div>
	<?php endforeach ?>
<?php else: ?>
	<h2>No posts available</h2>
<?php endif ?>

// ... more code here

Như bạn có thể thấy, mỗi bài đăng khi được nhấp vào tiêu đề của nó, dẫn đến tệp details.php chuyển id của bài đăng đó đến nó. Tạo một tệp có tên là details.php và dán mã này vào đó:

chi tiết.php:

<?php 
	// connect to database
    $db = mysqli_connect("localhost", "root", "", "ckeditor-images");

	if (isset($_GET['id'])) {
		$id = $_GET['id'];
		$result = mysqli_query($db, "SELECT * FROM posts WHERE id=$id");

		$post = mysqli_fetch_assoc($result);
	}
?>
<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>Uploading images in CKEditor using PHP</title>

	<!-- Bootstra -->
	<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.min.css" />

	<!-- Custom styling -->
	<link rel="stylesheet" href="main.css">

</head>
<body>
	
	<div class="container">
		<div class="row">
			<div class="col-md-8 col-md-offset-2 post-div">
				<div class="post-details">
					<h2><?php echo $post['title'] ?></h2>
					<p><?php echo html_entity_decode($post['body']); ?></p>
				</div>				
			</div>
		</div>
	</div>

<!-- JQuery -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<!-- Bootstrap JS -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/js/bootstrap.min.js"></script>

<!-- JQuery scripts -->
<script>

</script>

</body>
</html>

Ở phần trên cùng, chúng tôi kết nối với cơ sở dữ liệu, lấy id bài đăng được gửi từ trang index.php và truy vấn bài đăng cụ thể đó. Sau đó, bài đăng được lưu trữ trong biến $ post, sau đó được hiển thị trên trang.

Bây giờ chúng ta có thể bắt đầu mã hóa động lực của việc thực sự tải lên hình ảnh trong CKEditor. Mở scripts.js và thay thế mọi thứ bên trong bằng cái này:

scripts.js:

// initialize ckeditor
CKEDITOR.replace('body');

// Javascript function to copy image url to clipboard from modal
function copyUrl() {
  var copyText = document.getElementById("post_image_url");
  copyText.select();
  document.execCommand("Copy");

  // replace url with confirm message 
  $('#post_image_url').hide(1000);
  $('#feedback_msg').show();

  // hide modal after 2 seconds
  setTimeout(function(){
	  $('#myModal').modal('hide');
	  $('#feedback_msg').hide();
	  $('#post_image_url').show();
  }, 2000);
}

$(document).ready(function(){
	// When user clicks the 'upload image' button
	$('.upload-img-btn').on('click', function(){
		
		// Add click event on the image upload input
		// field when button is clicked
		$('#image-input').click();


		$(document).on('change', '#image-input', function(e){

			// Get the selected image and all its properties
			var image_file = document.getElementById('image-input').files[0];

			// Initialize the image name
			var image_name = image_file.name;

			
			// determine the image extension and validate image
			var image_extension = image_name.split('.').pop().toLowerCase();
			if (jQuery.inArray(image_extension, ['gif', 'png', 'jpg', 'jpeg']) == -1) {
				alert('That image type is not supported');
				return;
			} 

			// Get the image size. Validate size
			var image_size = image_file.size;
			if (image_size > 3000000) {
				alert('The image size is too big');
				return;
			} 


			// Compile form values from the form to send to the server
			// In this case, we are taking the image file which 
			// has key 'post_image' and value 'image_file'
			var form_data = new FormData();
			form_data.append('post_image', image_file);
			form_data.append('uploading_file', 1);

			// upload image to the server in an ajax call (without reloading the page)
			$.ajax({
				url: 'index.php',
				method: 'POST',
				data: form_data,
				contentType: false,
				cache: false,
				processData: false,
				beforeSend : function(){

				},
				success : function(data){
					// how the pop up modal
					$('#myModal').modal('show');

					// the server returns a URL of the uploaded image
					// show the URL on the popup modal
					$('#post_image_url').val(data);
				}
			});
		});

	});
});

Làm theo bình luận trong đoạn mã này và bạn sẽ hiểu các bước. Đầu tiên, người dùng nhấp vào nút "tải hình ảnh lên". Điều này kích hoạt sự kiện nhấp chuột trên đầu vào tệp có màn hình không được đặt thành không. Sau khi người dùng chọn hình ảnh từ máy tính cục bộ của họ, sự kiện onChange được kích hoạt trên đầu vào tệp và đây là nơi chúng tôi tải hình ảnh lên bằng Ajax.

Tại thời điểm này, hình ảnh của chúng tôi đã được gửi đến máy chủ trong một yêu cầu Ajax. Nhưng cho đến nay trong server.php của chúng tôi, chúng tôi chỉ kết nối với cơ sở dữ liệu. Chúng tôi chưa viết mã để nhận hình ảnh từ yêu cầu Ajax và tải nó lên thư mục hình ảnh. Hãy làm điều đó ngay bây giờ.

Mở tệp server.php một lần nữa và thêm mã này vào đó:

server.php:

// ... more code here ...

// if 'upload image' buttton is clicked
if (isset($_POST['uploading_file'])) {
	// Get image name
  	$image = $_FILES['post_image']['name'];

  	// image file directory
  	$target = "images/" . basename($image);

  	if (move_uploaded_file($_FILES['post_image']['tmp_name'], $target)) {
  		echo "http://localhost/ckeditor-images/" . $target;
  		exit();
  	}else{
  		echo "Failed to upload image";
  		exit();
  	}
}

Mã này chấp nhận yêu cầu Ajax đi kèm với hình ảnh, tải hình ảnh lên thư mục hình ảnh và trả về một URL đủ điều kiện cho hình ảnh. Hãy nhớ rằng tại thời điểm này, người dùng vẫn đang bận viết bài của họ trên biểu mẫu tạo bài đăng và tất cả điều này đang diễn ra trong nền.

Sau đó, URL đã được trả về từ máy chủ sẽ được hiển thị trên một phương thức bật lên bật lên để người dùng sao chép URL. Khi phương thức bật lên và người dùng nhấp vào URL được hiển thị, nó sẽ được sao chép vào khay nhớ tạm và người dùng có thể tiếp tục sử dụng URL hình ảnh này trong CKEditor bằng cách dán URL này vào vị trí thích hợp.

Chúng tôi đã hoàn thành khá nhiều điều với khái niệm cốt lõi của hướng dẫn này. Khi còn lại bây giờ là để chúng tôi nhấn gửi để bài viết của chúng tôi được gửi đến máy chủ và lưu trong cơ sở dữ liệu. Để làm điều đó, chúng tôi sẽ chỉ chạm vào một tệp.

Mở server.php và thêm mã này vào cuối tệp:

// ... more code here ...

// if form save button is clicked, save post in the database
if (isset($_POST['save-post'])) {
	$title = mysqli_real_escape_string($db, $_POST['title']);
	$body = htmlentities(mysqli_real_escape_string($db, $_POST['body']));

	$sql = "INSERT INTO posts (title, body) VALUES ('$title', '$body')";
	mysqli_query($db, $sql);
	header("location: index.php");
}

Và điều đó đưa chúng ta đến phần cuối của hướng dẫn này. Tôi hy vọng bạn hiểu rõ mục tiêu của chúng tôi trong hướng dẫn này và cách chúng tôi giải quyết nó.

Xem xét kỹ hơn

Tại thời điểm này, mọi thứ dường như đang hoạt động tốt. Chúng tôi đang tải lên một hình ảnh và sử dụng URL của nó trong CKEditor của chúng tôi khá ổn, nhưng hệ thống này hiệu quả đến mức nào. Giả sử bạn bắt đầu viết một bài đăng và trong quá trình bạn cảm thấy kiệt sức sau khi tải lên một vài hình ảnh, làm cách nào để hoàn tác việc tải lên. Làm cách nào để bạn giải phóng dung lượng trên máy chủ của mình? Một giải pháp mà tôi đề xuất là bạn tạo một bảng hình ảnh trong cơ sở dữ liệu chỉ lấy postID và tên của hình ảnh. Mỗi lần bạn tải lên một hình ảnh, bạn lưu tên hình ảnh trong bảng hình ảnh với null là postID. Nếu bạn thay đổi ý định và cuối cùng không lưu bài đăng, thì giá trị rỗng vẫn còn trong bảng hình ảnh. Sau đó, bạn có thể viết một tập lệnh sẽ truy vấn tất cả các hình ảnh cơ sở dữ liệu có null làm postID được liên kết của chúng. Thử thách bản thân với điều này và mã hóa nó. Nếu bạn gặp bất kỳ khó khăn nào, hãy để lại trong phần bình luận bên dưới và chúng tôi sẽ giúp đỡ bạn.

Như mọi khi, cảm ơn bạn đã dành thời gian. Hy vọng bạn thấy điều này hữu ích. Nếu bạn thích bài đăng này, thì hãy xem các hướng dẫn khác của tôi và hãy chia sẻ và giới thiệu trang web của tôi với bạn bè của bạn.

Trân trọng!


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Làm cách nào để xuất và nhập tệp .sql từ dòng lệnh với các tùy chọn?

  2. Chèn mảng vào cơ sở dữ liệu MySQL bằng PHP

  3. Làm cách nào để chọn giữa ngày đầu tiên của tháng hiện tại và ngày hiện tại trong MySQL?

  4. Tính chênh lệch thời gian giữa hai hàng

  5. Có cả cột dấu thời gian được tạo và cập nhật lần cuối trong MySQL 4.0