Mysql
 sql >> Base de Dados >  >> RDS >> Mysql

Carregar imagens no CKEditor sem usar um plugin


Ao escrever um artigo em seu blog, muitas vezes você precisará exibir imagens entre os textos, geralmente para fins de ilustração. O CKEditor ajuda você a conseguir isso, mas pode ser um pouco complicado ou difícil de trabalhar se você não estiver usando um plug-in. O motivo é que o CKEditor só aceita o URL da imagem a ser inserida no texto da postagem, e a imagem já deve existir na Internet e não em sua máquina local.

O que precisamos fazer agora é encontrar uma maneira de fazer o upload da imagem para um diretório de imagens em nosso projeto enquanto ainda estamos escrevendo a postagem. uma vez que a imagem tenha sido carregada, a URL da imagem será enviada de volta para que possamos usar em nosso CKEditor.

A primeira coisa é que adicionaremos um botão que, quando clicado, procura imagens no computador local do usuário (da mesma forma que um clique em um elemento faria). Depois que o usuário seleciona uma imagem, ela é carregada imediatamente em segundo plano usando Ajax (sem recarregar a página) em um evento onChange e o URL dessa imagem específica é retornado do servidor. A URL retornada é exibida em um modal pop-up que é copiado para a área de transferência quando o usuário clica nela. O usuário agora pode clicar no ícone da imagem no CKEditor e colar a URL da imagem nele.

Vamos implementar isso em um miniprojeto e ver como funciona.

Crie uma pasta chamada ckeditor-images e dentro desta pasta, crie uma subpasta chamada images, e 4 arquivos a saber:index.php, server.php, scripts.js e main.css.



A pasta de imagens conterá as imagens enviadas do nosso CKEditor.

Abra index.php e coloque o seguinte código nele.

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>

Como você pode ver, adicionamos CSS e JS de bootstrap através do CDN. Também adicionamos JQuery porque faremos o upload das imagens usando chamadas Ajax. Por último, adicionamos o código do plugin CKEditor que ainda devemos inicializar em nossa área de texto no formulário. scripts.js é onde o script JQuery residirá.





Logo após o formulário de postagem, adicionamos algum código para o modal pop-up com id definido como id="myModal". Este modal não está sendo usado agora, mas quando a imagem for carregada, o URL retornado da imagem será exibido neste modal. Então esqueça isso por enquanto.

Se você acessar http://localhost/ckeditor-images/index.php, verá a postagem estática exibida e o formulário. Abra main.css e vamos adicionar alguns estilos a esta página.

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;
}

Abra scripts.js e adicione este código dentro dele:

scripts.js:
// initialize ckeditor
CKEDITOR.replace('body');

Atualize a página e você notará algumas mudanças no estilo, bem como na área de texto que agora é nosso CKEditor carregado com muitos ícones.

Crie um banco de dados chamado ckeditor-images. Nesse banco de dados, crie uma tabela chamada posts com os campos:
  • id - INT(11)
  • título - VARCHAR(255)
  • corpo - VARCHAR(255)

Agora insira uma ou mais postagens fictícias na tabela de postagens para que possamos consultá-la e exibi-la na página.

Conectando ao banco de dados


Abra server.php up e insira este código nele:
<?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);
?>

Esse código recupera as postagens que estão no banco de dados em uma variável $posts. Essa variável é disponibilizada em nosso arquivo index.php pela instrução include na primeira linha de código em index.php -- a linha que inclui o arquivo server.php dentro de index.php.

No arquivo index.php, remova todo o elemento div que tem o atributo class="post" e substitua-o por este código:
// ... 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

Como você pode ver, cada postagem, quando clicada em seu título, leva ao details.php passando o id da postagem para ele. Crie um arquivo chamado details.php e cole este código nele:

detalhes.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>

Na seção superior, nos conectamos ao banco de dados, pegamos o ID do post que foi enviado da página index.php e consultamos esse post específico. A postagem é então armazenada na variável $post que é exibida na página.

Agora podemos começar a codificar a dinâmica de realmente carregar a imagem no CKEditor. Abra scripts.js e substitua tudo por isso:

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);
				}
			});
		});

	});
});

Siga os comentários neste código e você entenderá as etapas. Primeiro, o usuário clica no botão "upload de imagem". Isso aciona um evento de clique na entrada de arquivo cuja exibição foi definida como nenhuma. Uma vez que o usuário seleciona uma imagem de seu computador local, um evento onChange é acionado na entrada do arquivo, e é aqui que carregamos a imagem usando Ajax.

Neste ponto, nossa imagem já está sendo enviada ao servidor em uma requisição Ajax. Mas até agora em nosso server.php, apenas conectamos ao banco de dados. Ainda não escrevemos o código para receber a imagem da solicitação Ajax e carregá-la na pasta de imagens. Vamos fazer isso agora.

Abra o arquivo server.php mais uma vez e adicione este código a ele:

servidor.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();
  	}
}

Esse código aceita a solicitação Ajax que acompanha a imagem, carrega a imagem na pasta de imagens e retorna um URL totalmente qualificado para a imagem. Lembre-se de que, neste momento, o usuário ainda está ocupado escrevendo a postagem no formulário de criação de postagem e tudo isso está acontecendo em segundo plano.

O URL que foi retornado do servidor é exibido em um modal pop-up que aparece para que o usuário copie o URL. Quando o modal aparece e o usuário clica no URL exibido, ele é copiado para a área de transferência e o usuário pode continuar a usar este URL de imagem no CKEditor colando este URL no local apropriado.

Estamos praticamente concluídos com o conceito central deste tutorial. Quando resta agora é clicar em enviar para que nosso post seja enviado ao servidor e salvo no banco de dados. Para fazer isso, tocaremos apenas em um arquivo.

Abra server.php e adicione este código no final do arquivo:
// ... 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");
}

E isso nos leva ao final deste tutorial. Espero que você tenha entendido bem nosso objetivo neste tutorial e como o abordamos.

 Um olhar mais atento


Neste ponto, tudo parece estar funcionando bem. Estamos fazendo upload de uma imagem e usando seu URL em nosso CKEditor muito bem, mas quão eficiente é este sistema. Digamos que você comece a escrever um post e ao longo do caminho você se sinta exausto depois de ter carregado algumas imagens, como você desfaz os uploads. Como você libera espaço no seu servidor? Uma solução que eu proponho é que você crie uma tabela de imagens no banco de dados que leve apenas o postID e o nome da imagem. Cada vez que você carrega uma imagem, você salva o nome da imagem na tabela de imagens com null como postID. Se você mudar de ideia e não salvar o post no final, o null permanece na tabela de imagens. Então você pode escrever um script que irá consultar todas as imagens de banco de dados que têm null como seus postIDs associados. Desafie-se com isso e codifique-o. Se você encontrar alguma dificuldade, deixe nos comentários abaixo e a ajuda virá.

Como sempre, obrigado pelo seu tempo. Espero que você ache isto útil. Se você gostou deste post, confira meus outros tutoriais e compartilhe e recomende meu site com seus amigos.

Atenciosamente!