Когато пишете статия във вашия блог, често ще ви се налага да показвате снимки между текстовете, обикновено с цел илюстрация. CKEditor ви помага да постигнете това, но може да бъде малко сложно или трудно да се работи, ако не използвате плъгин. Причината е, че CKEditor приема само URL на изображението за вмъкване в текста на публикацията и изображението трябва вече да съществува в интернет, а не на локалната ви машина.
Това, което трябва да направим сега, е да намерим начин да качим изображението в директория с изображения в нашия проект, докато все още пишем публикацията; след като изображението бъде качено, URL адресът на изображението ще бъде изпратен обратно, който след това можем да използваме в нашия CKEditor.
Първото нещо е, че ще добавим бутон, който при щракване преглежда локалния компютър на потребителя за изображения (по същия начин, по който щракване върху елемент ). След като потребителят избере изображение, това изображение незабавно се качва на заден план с помощта на Ajax (без презареждане на страницата) в събитие onChange и URL адресът на това конкретно изображение се връща от сървъра. Върнатият URL адрес се показва в изскачащ модален прозорец, който се копира в клипборда, когато потребителят щракне върху него. Потребителят вече може да щракне върху иконата на изображението в CKEditor и да постави URL адреса на изображението в него.
Нека приложим това в мини-проект и да видим как работи.
Създайте папка, наречена ckeditor-images и в тази папка създайте подпапка, наречена images, и 4 файла, а именно:index.php, server.php, scripts.js и main.css.
Папката с изображения ще съдържа изображенията, качени от нашия CKEditor.
Отворете index.php и поставете следния код в него.
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">×</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>
Както можете да видите, ние добавихме bootstrap CSS и JS чрез CDN. Добавихме и JQuery, защото ще качваме изображенията с помощта на Ajax повиквания. И накрая, добавихме кода на плъгина CKEditor, който все още трябва да инициализираме в нашата текстова област във формата. scripts.js е мястото, където ще се намира скриптът на JQuery.
Точно след формуляра за публикация добавихме код за изскачащия модален с идентификатор, зададен на id="myModal". Този модал не се използва сега, но когато изображението бъде качено, върнатият URL адрес на изображението ще бъде показан на този модал. Така че забрави за това засега.
Ако отидете на http://localhost/ckeditor-images/index.php, ще видите показаната статична публикация и формуляра. Отворете main.css и нека добавим няколко стила към тази страница.
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;
}
Отворете scripts.js и добавете този код вътре:
scripts.js:
// initialize ckeditor
CKEDITOR.replace('body');
Обновете страницата и ще забележите известна промяна в стила, както и в текстовата област която сега е нашият CKEditor зареден с много икони.
Създайте база данни, наречена ckeditor-images. В тази база данни създайте таблица, наречена публикации с полета:
- id - INT(11)
- заглавие - VARCHAR(255)
- тяло - VARCHAR(255)
Сега вмъкнете една или повече фиктивни публикации в таблицата с публикации, за да можем да я запитаме и да покажем на страницата.
Свързване с база данни
Отворете server.php и въведете този код в него:
<?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);
?>
Този код извлича публикациите, които са в базата данни, в променлива $posts. Тази променлива е достъпна в нашия index.php файл чрез изявлението за включване на първия ред на кода в index.php - реда, който включва файла server.php в index.php.
Във файла index.php премахнете целия div елемент, който има атрибут class="post" и го заменете с този код:
// ... 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
Както можете да видите, всяка публикация, когато се щракне върху нейното заглавие, води до details.php предавайки й идентификатора на публикацията. Създайте файл с име details.php и поставете този код в него:
details.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>
В горната секция се свързваме с базата данни, грабваме идентификатора на публикацията, който е изпратен от страницата index.php и правим заявка за тази конкретна публикация. След това публикацията се съхранява в променливата $post, която след това се показва на страницата.
Сега можем да започнем да кодираме динамиката на реалното качване на изображението в CKEditor. Отворете scripts.js и заменете всичко вътре с това:
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);
}
});
});
});
});
Следвайте коментарите в този код и ще разберете стъпките. Първо, потребителят щраква върху бутона "качване на изображение". Това задейства събитие на щракване върху входния файл, чийто дисплей е настроен на никакъв. След като потребителят избере изображение от своя локален компютър, на входния файл се задейства събитие onChange и тук качваме изображението с помощта на Ajax.
В този момент нашето изображение вече се изпраща на сървъра в Ajax заявка. Но досега в нашия server.php сме се свързвали само с базата данни. Все още не сме написали кода, за да получим изображението от заявката на Ajax и да го качим в папката с изображения. Нека го направим сега.
Отворете още веднъж файла server.php и добавете този код към него:
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();
}
}
Този код приема заявката на Ajax, която идва с изображението, качва изображението в папката с изображения и връща напълно квалифициран URL към изображението. Не забравяйте, че в този момент потребителят все още е зает да пише публикацията си във формуляра за създаване на публикация и всичко това се случва на заден план.
URL адресът, който е върнат от сървъра, след това се показва в изскачащ модален прозорец, който се появява, за да може потребителят да копира URL адреса. Когато модалният изскача и потребителят щракне върху показания URL адрес, той се копира в клипборда и потребителят може да продължи да използва този URL адрес на изображение в CKEditor, като постави този URL на подходящото място.
До голяма степен сме готови с основната концепция на този урок. Когато остава сега, е да натиснем submit, за да бъде изпратена публикацията ни на сървъра и запазена в базата данни. За да направим това, ще докоснем само един файл.
Отворете server.php и добавете този код в края на файла:
// ... 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");
}
И това ни довежда до края на този урок. Надявам се, че сте разбрали добре нашата цел в този урок и как сме се справили с нея.
По-отблизо
В този момент изглежда, че всичко работи добре. Качваме изображение и използваме URL адреса му в нашия CKEditor напълно добре, но колко ефективна е тази система. Да приемем, че започвате да пишете публикация и по пътя се чувствате изтощени, след като сте качили няколко изображения, как да отмените качванията. Как да освободите място на вашия сървър? Решение, което бих предложил, е да създадете таблица с изображения в базата данни, която приема само postID и името на изображението. Всеки път, когато качвате изображение, вие запазвате името на изображението в таблицата с изображения с null като postID. Ако промените решението си и накрая не запазите публикацията, нулата остава в таблицата с изображения. След това можете да напишете скрипт, който ще запитва всички изображения на базата данни, които имат null като свързани постID. Предизвикайте себе си с това и го кодирайте. Ако срещнете някакви затруднения, оставете ги в коментарите по-долу и помощ ще дойде.
Както винаги, благодаря за отделеното време. Надявам се да намерите това за полезно. Ако тази публикация ви е харесала, моля, разгледайте другите ми уроци и моля споделете и препоръчайте сайта ми на приятелите си.
С най-добри пожелания!