summaryrefslogtreecommitdiff
path: root/public
diff options
context:
space:
mode:
authorpolo <ordipolo@gmx.fr>2025-06-19 17:38:47 +0200
committerpolo <ordipolo@gmx.fr>2025-06-19 17:38:47 +0200
commitc8a8471a1c85a882f128ed172b1a9693e88bdc3c (patch)
tree12f43bf0015bd70a995a755ae0decc8780818412 /public
parent694ece4a86a7beecc936c1377ec928ca957f8d70 (diff)
downloadtinymce-c8a8471a1c85a882f128ed172b1a9693e88bdc3c.zip
téléchargement automatique d'images base64 non encapsulées dans du HTML
Diffstat (limited to 'public')
-rw-r--r--public/index.php97
1 files changed, 93 insertions, 4 deletions
diff --git a/public/index.php b/public/index.php
index 5f5d904..54ddb31 100644
--- a/public/index.php
+++ b/public/index.php
@@ -164,6 +164,45 @@ elseif(isset($_GET['action']) && $_GET['action'] == 'upload_image_url'){
164 } 164 }
165 die; 165 die;
166} 166}
167elseif(isset($_GET['action']) && $_GET['action'] == 'upload_image_base64'){
168 $json = json_decode(file_get_contents('php://input'), true);
169 $dest = 'images/';
170
171 if(!is_dir('images')){
172 mkdir('images', 0777, true);
173 }
174
175 // détection de data:image/ et de ;base64, et capture du format dans $type
176 if(!isset($json['image_base64']) || !preg_match('/^data:image\/(\w+);base64,/', $json['image_base64'], $type)){
177 http_response_code(400);
178 echo json_encode(['message' => 'Données image base64 manquantes ou invalides']);
179 die;
180 }
181
182 $allowed_extensions = ['jpg', 'jpeg', 'png', 'gif', 'webp', 'tiff', 'tif'];
183 $extension = strtolower($type[1]);
184 if(!in_array($extension, $allowed_extensions) || $extension === 'jpg'){
185 $extension = 'jpeg';
186 }
187
188 $image_data = base64_decode(substr($json['image_base64'], strpos($json['image_base64'], ',') + 1)); // découpe la chaine à la virgule puis convertit en binaire
189 if($image_data === false){
190 http_response_code(400);
191 echo json_encode(['message' => 'Décodage base64 invalide']);
192 die;
193 }
194
195 $local_path = $dest . 'pasted_image_' . uniqid() . '.' . $extension;
196
197 if(imagickCleanImage($image_data, $local_path)){
198 echo json_encode(['location' => $local_path]);
199 }
200 else{
201 http_response_code(500);
202 echo json_encode(['message' => 'Erreur image non valide']);
203 }
204 die;
205}
167?> 206?>
168<!DOCTYPE html> 207<!DOCTYPE html>
169<html lang="fr"> 208<html lang="fr">
@@ -188,6 +227,7 @@ elseif(isset($_GET['action']) && $_GET['action'] == 'upload_image_url'){
188 // Récupérer et sauvegarder le contenu d'origine de l'article 227 // Récupérer et sauvegarder le contenu d'origine de l'article
189 const articleContent = document.getElementById(articleId).innerHTML; 228 const articleContent = document.getElementById(articleId).innerHTML;
190 document.getElementById(articleId).setAttribute('data-original-content', articleContent); 229 document.getElementById(articleId).setAttribute('data-original-content', articleContent);
230 let skipPastePreProcess = false;
191 231
192 tinymce.init({ 232 tinymce.init({
193 selector: `#${articleId}`, 233 selector: `#${articleId}`,
@@ -211,7 +251,57 @@ elseif(isset($_GET['action']) && $_GET['action'] == 'upload_image_url'){
211 document.querySelector(`#cancel-${articleId}`).classList.remove('hidden'); 251 document.querySelector(`#cancel-${articleId}`).classList.remove('hidden');
212 document.querySelector(`#submit-${articleId}`).classList.remove('hidden'); 252 document.querySelector(`#submit-${articleId}`).classList.remove('hidden');
213 }); 253 });
214 editor.on('PastePreProcess', function (e){ // déclenchement au collage AVANT insertion dans l'éditeur 254 editor.on('Paste', function (e){ // déclenchement AVANT PastePreProcess et quelque que soit le contenu collé
255 const clipboardData = (e.clipboardData || e.originalEvent.clipboardData);
256 if(!clipboardData){
257 return;
258 }
259 const items = clipboardData.items;
260 let foundImage = false;
261
262 for(let i = 0; i < items.length; i++){
263 let item = items[i];
264
265 if(item.type.indexOf('image') !== -1){ // test type MIME contenant image
266 foundImage = true;
267
268 const file = item.getAsFile(); // presse-papier => fichier lisible
269 const reader = new FileReader();
270
271 reader.onload = function (event){ // fonction exécutée lorsque reader.readAsDataURL(file) est terminée
272 const base64Data = event.target.result; // données de l'image
273
274 fetch('index.php?action=upload_image_base64', {
275 method: 'POST',
276 headers: { 'Content-Type': 'application/json' },
277 body: JSON.stringify({ image_base64: base64Data })
278 })
279 .then(response => response.json())
280 .then(data => {
281 if(data.location){
282 editor.insertContent('<img src="' + data.location + '">');
283 }
284 })
285 .catch(error => {
286 console.error('Erreur lors de l’upload de l’image base64 :', error);
287 });
288 };
289 reader.readAsDataURL(file); // lecture asynchrone du fichier
290 }
291 }
292
293 if(foundImage){
294 e.preventDefault(); // supprime le collage automatiue
295 skipPastePreProcess = true; // désactiver le PastePreProcess pour ce collage
296 }
297 });
298 editor.on('PastePreProcess', function (e){ // déclenchement au collage AVANT insertion dans l'éditeur SI le contenu est du HTML
299 if(skipPastePreProcess){
300 skipPastePreProcess = false; // réinitialiser pour la prochaine fois
301 return; // ignorer ce traitement
302 }
303
304 console.log('PastePreProcess');
215 const parser = new DOMParser(); 305 const parser = new DOMParser();
216 const doc = parser.parseFromString(e.content, 'text/html'); 306 const doc = parser.parseFromString(e.content, 'text/html');
217 const images = doc.querySelectorAll('img'); 307 const images = doc.querySelectorAll('img');
@@ -221,9 +311,8 @@ elseif(isset($_GET['action']) && $_GET['action'] == 'upload_image_url'){
221 images.forEach(img => { 311 images.forEach(img => {
222 if(img.src.startsWith('file://')){ // détection d'images non insérables 312 if(img.src.startsWith('file://')){ // détection d'images non insérables
223 console.warn('Image locale non insérable dans tinymce :', img.src); 313 console.warn('Image locale non insérable dans tinymce :', img.src);
224 img.outerHTML = '<div style="border:1px solid red; padding:10px; margin:5px 0; background-color:#ffe6e6; color:#a94442; font-size:14px;">' + 314 img.outerHTML = `<div style="border:1px solid red; padding:10px; margin:5px 0; background-color:#ffe6e6; color:#a94442; font-size:14px;">
225 "Image locale non insérée (vient-elle de LibreOffice ?). Effacez cet encadré et copiez-collez l'image seule. Ensuite cliquez sur le bouton Insérer une image puis dans la nouvelle fenêtre sur Enregistrer." + 315 "Image locale non insérée (vient-elle d'un document LibreOffice ?). Effacez ce message rouge et copiez-collez l'image seule.</div>`;
226 '</div>';
227 } 316 }
228 else if(img.src.startsWith('http')){ // détection d'images web 317 else if(img.src.startsWith('http')){ // détection d'images web
229 const promise = fetch('index.php?action=upload_image_url', { // promesse d'un fichier téléchargeable sur le serveur 318 const promise = fetch('index.php?action=upload_image_url', { // promesse d'un fichier téléchargeable sur le serveur