sql >> Base de Datos >  >> RDS >> Mysql

Subir imágenes en CKEditor sin usar un complemento

Al escribir un artículo en su blog, a menudo necesitará mostrar imágenes entre textos, generalmente con fines ilustrativos. CKEditor lo ayuda a lograr esto, pero puede ser un poco complicado o difícil trabajar con él si no está usando un complemento. La razón es que CKEditor solo acepta la URL de la imagen para insertarla en el texto de la publicación, y la imagen ya debe existir en Internet y no en su máquina local.

Lo que debemos hacer ahora es encontrar una manera de cargar la imagen en un directorio de imágenes en nuestro proyecto mientras todavía estamos escribiendo la publicación; una vez que se haya cargado la imagen, se enviará la URL de la imagen, que luego podremos usar en nuestro CKEditor.

Lo primero es que agregaremos un botón que, cuando se hace clic, busca imágenes en la computadora local del usuario (de la misma manera que lo haría un clic en un elemento ). Una vez que el usuario selecciona una imagen, esa imagen se carga inmediatamente en segundo plano usando Ajax (sin recargar la página) en un evento onChange y la URL de esa imagen en particular se devuelve desde el servidor. La URL devuelta se muestra en un modal emergente que se copia en el portapapeles cuando el usuario hace clic en él. El usuario ahora puede hacer clic en el ícono de la imagen en CKEditor y pegar la URL de la imagen en él.

Implementemos esto en un miniproyecto y veamos cómo funciona.

Cree una carpeta llamada ckeditor-images y dentro de esta carpeta, cree una subcarpeta llamada imágenes y 4 archivos, a saber:index.php, server.php, scripts.js y main.css.

La carpeta de imágenes contendrá las imágenes cargadas desde nuestro CKEditor.

Abra index.php y coloque el siguiente código en él.

índice.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 puede ver, hemos agregado bootstrap CSS y JS a través de CDN. También agregamos JQuery porque vamos a cargar las imágenes mediante llamadas Ajax. Por último, agregamos el código del complemento CKEditor que aún debemos inicializar en nuestra área de texto en el formulario. scripts.js es donde residirá el script JQuery.

Justo después del formulario de publicación, agregamos un código para el modal emergente con id establecido en id="myModal". Este modal no se está utilizando ahora, pero cuando se haya cargado la imagen, la URL devuelta de la imagen se mostrará en este modal. Así que olvídalo por ahora.

Si va a http://localhost/ckeditor-images/index.php, verá la publicación estática que se muestra y el formulario. Abra main.css y agreguemos algunos estilos a esta página.

principal.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 y agregue este código dentro:

secuencias de comandos.js:

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

Actualice la página y notará algunos cambios en el estilo, así como en el área de texto que ahora es nuestro CKEditor cargado con muchos íconos.

Cree una base de datos llamada ckeditor-images. En esta base de datos, cree una tabla llamada publicaciones con campos:

  • id - INT(11)
  • título - VARCHAR(255)
  • cuerpo - VARCHAR(255)

Ahora inserte una o más publicaciones ficticias en la tabla de publicaciones para que podamos consultarlas y mostrarlas en la página.

Conectando a la base de datos

Abra server.php e ingrese este código en él:

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

Este código recupera las publicaciones que están en la base de datos en una variable $posts. Esta variable está disponible en nuestro archivo index.php mediante la declaración de inclusión en la primera línea de código en index.php, la línea que incluye el archivo server.php dentro de index.php.

En el archivo index.php, elimine todo el elemento div que tiene el atributo class="post" y reemplácelo con 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 puede ver, cada publicación, cuando se hace clic en su título, conduce a detalles.php y le pasa la identificación de la publicación. Cree un archivo llamado detalles.php y pegue este código en él:

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

En la sección superior, nos conectamos a la base de datos, tomamos la identificación de la publicación que se envió desde la página index.php y consultamos esa publicación en particular. Luego, la publicación se almacena en la variable $post que luego se muestra en la página.

Ahora podemos comenzar a codificar la dinámica de cargar la imagen en el CKEditor. Abra scripts.js y reemplace todo lo que contiene con esto:

secuencias de comandos.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 los comentarios en este código y comprenderá los pasos. Primero, el usuario hace clic en el botón "cargar imagen". Esto desencadena un evento de clic en la entrada del archivo cuya visualización se ha establecido en ninguno. Una vez que el usuario selecciona una imagen de su computadora local, se activa un evento onChange en la entrada del archivo, y aquí es donde cargamos la imagen usando Ajax.

En este punto, nuestra imagen ya se está enviando al servidor en una solicitud de Ajax. Pero hasta ahora en nuestro server.php, solo nos hemos conectado a la base de datos. Todavía no hemos escrito el código para recibir la imagen de la solicitud de Ajax y subirla a la carpeta de imágenes. Hagámoslo ahora.

Abra el archivo server.php una vez más y agréguele este código:

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

Este código acepta la solicitud de Ajax que viene con la imagen, carga la imagen en la carpeta de imágenes y devuelve una URL completa a la imagen. Recuerda que en este momento el usuario todavía está ocupado escribiendo su publicación en el formulario de creación de publicaciones y todo esto sucede en segundo plano.

La URL que se ha devuelto desde el servidor se muestra en un modal emergente que aparece para que el usuario copie la URL. Cuando aparece el modal y el usuario hace clic en la URL mostrada, se copia en el portapapeles y el usuario puede proceder a usar esta URL de imagen en CKEditor pegando esta URL en el lugar apropiado.

Casi hemos terminado con el concepto central de este tutorial. Lo que queda ahora es que presionemos enviar para que nuestra publicación se envíe al servidor y se guarde en la base de datos. Para ello, solo tocaremos un archivo.

Abra server.php y agregue este código al final del archivo:

// ... 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");
}

Y eso nos lleva al final de este tutorial. Espero que haya entendido bien nuestro objetivo en este tutorial y cómo lo hemos abordado.

 Una mirada más cercana

En este punto, todo parece estar funcionando bien. Estamos cargando una imagen y usando su URL en nuestro CKEditor bastante bien, pero cuán eficiente es este sistema. Digamos que comienzas a escribir una publicación y en el camino te sientes agotado después de haber subido algunas imágenes, ¿cómo deshaces las cargas? ¿Cómo liberas espacio en tu servidor? Una solución que propondría es que cree una tabla de imágenes en la base de datos que tome solo el ID de la publicación y el nombre de la imagen. Cada vez que carga una imagen, guarda el nombre de la imagen en la tabla de imágenes con nulo como postID. Si cambia de opinión y no guarda la publicación al final, el nulo permanece en la tabla de imágenes. Luego puede escribir una secuencia de comandos que consultará todas las imágenes de la base de datos que tienen nulo como sus ID de publicación asociados. Ponte a prueba con esto y codificarlo. Si encuentra alguna dificultad, déjela en los comentarios a continuación y recibirá ayuda.

Como siempre, gracias por tu tiempo. Espero que encuentres esto útil. Si disfrutó de esta publicación, consulte mis otros tutoriales y comparta y recomiende mi sitio con sus amigos.

¡Un saludo!