Wanneer u een artikel op uw blog schrijft, moet u vaak afbeeldingen tussen de teksten plaatsen, meestal ter illustratie. CKEditor helpt je dit te bereiken, maar het kan een beetje lastig of moeilijk zijn om mee te werken als je geen plug-in gebruikt. De reden is dat CKEditor alleen de URL accepteert van de afbeelding die in de berichttekst moet worden ingevoegd, en de afbeelding moet al op internet bestaan en niet op uw lokale computer.
Wat we nu moeten doen, is een manier vinden om de afbeelding te uploaden naar een afbeeldingenmap in ons project terwijl we het bericht nog aan het schrijven zijn; zodra de afbeelding is geüpload, wordt de URL van de afbeelding teruggestuurd die we vervolgens kunnen gebruiken in onze CKEditor.
Het eerste is dat we een knop toevoegen die, wanneer erop wordt geklikt, door de lokale computer van de gebruiker naar afbeeldingen bladert (op dezelfde manier als een klik op een -element zou doen). Zodra de gebruiker een afbeelding selecteert, wordt die afbeelding onmiddellijk op de achtergrond geüpload met Ajax (zonder de pagina opnieuw te laden) in een onChange-gebeurtenis en wordt de URL van die specifieke afbeelding geretourneerd door de server. De geretourneerde URL wordt weergegeven in een pop-upmodel dat naar het klembord wordt gekopieerd wanneer de gebruiker erop klikt. De gebruiker kan nu op het afbeeldingspictogram op de CKEditor klikken en de URL van de afbeelding erin plakken.
Laten we dit in een miniproject implementeren en kijken hoe het werkt.
Maak een map met de naam ckeditor-images en maak in deze map een submap met de naam afbeeldingen en 4 bestanden, namelijk:index.php, server.php, scripts.js en main.css.
De afbeeldingenmap bevat de afbeeldingen die zijn geüpload vanuit onze CKEditor.
Open index.php en plaats de volgende code erin.
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>
Zoals je kunt zien, hebben we bootstrap CSS en JS toegevoegd via CDN. We hebben ook JQuery toegevoegd omdat we de afbeeldingen gaan uploaden met Ajax-oproepen. Ten slotte hebben we de CKEditor-plug-incode toegevoegd die we nog moeten initialiseren op ons tekstgebied in het formulier. scripts.js is waar het JQuery-script zich zal bevinden.
Net na het postformulier hebben we wat code toegevoegd voor de pop-up modal met id ingesteld op id="myModal". Deze modal wordt nu niet gebruikt, maar wanneer de afbeelding is geüpload, wordt de geretourneerde URL van de afbeelding op deze modal weergegeven. Dus vergeet het maar voor nu.
Als je naar http://localhost/ckeditor-images/index.php gaat, zie je het statische bericht en het formulier. Open main.css en laten we een paar stijlen aan deze pagina toevoegen.
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;
}
Open scripts.js en voeg deze code erin toe:
scripts.js:
// initialize ckeditor
CKEDITOR.replace('body');
Vernieuw de pagina en je zult een verandering in de stijl opmerken, evenals het tekstgebied dat nu onze CKEditor is, geladen met veel pictogrammen.
Maak een database met de naam ckeditor-images. Maak in deze database een tabel met de naam posts met velden:
- id - INT(11)
- titel - VARCHAR(255)
- lichaam - VARCHAR(255)
Voeg nu een of meer dummy-berichten in de berichtentabel in, zodat we deze kunnen opvragen en op de pagina kunnen weergeven.
Verbinding maken met database
Open server.php en voer deze code erin in:
<?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);
?>
Deze code haalt de berichten in de database op in een $posts-variabele. Deze variabele wordt beschikbaar gemaakt in ons index.php-bestand door de include-instructie op de eerste regel code in index.php -- de regel die het server.php-bestand in index.php bevat.
Verwijder in het index.php-bestand het volledige div-element met attribuut class="post" en vervang het door deze code:
// ... 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
Zoals je kunt zien, leidt elk bericht, wanneer op de titel wordt geklikt, ertoe dat de details.php de id van het bericht eraan doorgeeft. Maak een bestand met de naam details.php en plak deze code erin:
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>
In het bovenste gedeelte maken we verbinding met de database, pakken de post-ID die is verzonden vanaf de index.php-pagina en zoeken naar dat specifieke bericht. Het bericht wordt vervolgens opgeslagen in de $post variabele die vervolgens op de pagina wordt weergegeven.
Nu kunnen we beginnen met het coderen van de dynamiek van het daadwerkelijk uploaden van de afbeelding in de CKEditor. Open scripts.js en vervang alles erin door dit:
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);
}
});
});
});
});
Volg de opmerking in deze code en u zult de stappen begrijpen. Eerst klikt de gebruiker op de knop "afbeelding uploaden". Dit activeert een klikgebeurtenis op de bestandsinvoer waarvan de weergave is ingesteld op geen. Zodra de gebruiker een afbeelding van zijn lokale computer selecteert, wordt een onChange-gebeurtenis geactiveerd bij de bestandsinvoer, en dit is waar we de afbeelding uploaden met Ajax.
Op dit moment wordt onze afbeelding al naar de server gestuurd in een Ajax-verzoek. Maar tot nu toe hebben we in onze server.php alleen verbinding gemaakt met de database. We hebben nog niet de code geschreven om de afbeelding van het Ajax-verzoek te ontvangen en te uploaden naar de afbeeldingenmap. Laten we dat nu doen.
Open het bestand server.php nog een keer en voeg deze code eraan toe:
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();
}
}
Deze code accepteert het Ajax-verzoek dat bij de afbeelding wordt geleverd, uploadt de afbeelding naar de afbeeldingenmap en retourneert een volledig gekwalificeerde URL naar de afbeelding. Onthoud dat de gebruiker op dit moment nog steeds bezig is met het schrijven van zijn bericht op het formulier voor het maken van berichten en dat dit alles op de achtergrond gebeurt.
De URL die door de server is geretourneerd, wordt vervolgens weergegeven in een pop-upmodel dat verschijnt zodat de gebruiker de URL kan kopiëren. Wanneer de modal verschijnt en de gebruiker op de weergegeven URL klikt, wordt deze gekopieerd naar het klembord en kan de gebruiker deze afbeeldings-URL in CKEditor gebruiken door deze URL op de juiste plaats te plakken.
We zijn zo goed als klaar met het kernconcept van deze tutorial. Wanneer er nu nog rest, moeten we op Verzenden drukken om ons bericht naar de server te verzenden en in de database op te slaan. Om dat te doen, raken we slechts één bestand aan.
Open server.php en voeg deze code toe aan het einde van het bestand:
// ... 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");
}
En dat brengt ons bij het einde van deze tutorial. Ik hoop dat je ons doel in deze tutorial goed hebt begrepen en hoe we het hebben aangepakt.
Een nadere blik
Op dit moment lijkt alles goed te werken. We zijn een afbeelding aan het uploaden en gebruiken de URL in onze CKEditor best goed, maar hoe efficiënt is dit systeem. Laten we zeggen dat je begint met het schrijven van een bericht en dat je je gaandeweg uitgeput voelt nadat je een paar afbeeldingen hebt geüpload, hoe maak je de uploads ongedaan? Hoe maak je ruimte vrij op je server? Een oplossing die ik zou voorstellen, is dat je een afbeeldingentabel in de database maakt die alleen de postID en de naam van de afbeelding bevat. Elke keer dat u een afbeelding uploadt, slaat u de afbeeldingsnaam op in de afbeeldingentabel met null als postID. Als je van gedachten verandert en het bericht uiteindelijk niet opslaat, blijft de nul in de afbeeldingentabel. Vervolgens kunt u een script schrijven dat alle databaseafbeeldingen met null als bijbehorende post-ID's zal opvragen. Daag jezelf hiermee uit en codeer het. Als je problemen ondervindt, laat het dan achter in de reacties hieronder en er zal hulp komen.
Zoals altijd, bedankt voor uw tijd. Ik hoop dat je dit nuttig vindt. Als je dit bericht leuk vond, bekijk dan alsjeblieft mijn andere tutorials en deel en beveel mijn site aan met je vrienden.
Met vriendelijke groet!