From 31d611267a90e44a30c3be975299b50bad3d5c06 Mon Sep 17 00:00:00 2001 From: Esenjin Date: Mon, 17 Feb 2025 20:16:46 +0100 Subject: [PATCH] =?UTF-8?q?il=20est=20de=20nouveau=20possible=20d'ajouter?= =?UTF-8?q?=20des=20images=20dans=20la=20page=20"=C3=A0=20propos"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- admin/api/about-image-upload.php | 193 +++++++++++++++++++++++++++++++ assets/js/options.js | 73 ++++++------ 2 files changed, 228 insertions(+), 38 deletions(-) create mode 100644 admin/api/about-image-upload.php diff --git a/admin/api/about-image-upload.php b/admin/api/about-image-upload.php new file mode 100644 index 0000000..f4cfb74 --- /dev/null +++ b/admin/api/about-image-upload.php @@ -0,0 +1,193 @@ +uploadDir = __DIR__ . '/../../assets/images/about/'; + $this->ensureUploadDirectory(); + } + + public function handleUpload($file) { + try { + // Vérifications de base + if ($file['error'] !== UPLOAD_ERR_OK) { + throw new Exception($this->getUploadErrorMessage($file['error'])); + } + + // Vérification du type MIME + $finfo = new finfo(FILEINFO_MIME_TYPE); + $mimeType = $finfo->file($file['tmp_name']); + if (!in_array($mimeType, $this->allowedTypes)) { + throw new Exception('Type de fichier non autorisé. Types acceptés : JPG, PNG, GIF, WEBP'); + } + + // Vérification de la taille + if ($file['size'] > $this->maxFileSize) { + throw new Exception('Fichier trop volumineux. Taille maximum : 5MB'); + } + + // Vérification et redimensionnement de l'image + [$width, $height, $type] = getimagesize($file['tmp_name']); + $needsResize = $width > $this->maxWidth || $height > $this->maxHeight; + + // Génération d'un nom de fichier unique + $extension = $this->getExtensionFromMimeType($mimeType); + $filename = uniqid() . '.' . $extension; + $targetPath = $this->uploadDir . $filename; + + if ($needsResize) { + // Calcul des nouvelles dimensions en conservant le ratio + $ratio = min($this->maxWidth / $width, $this->maxHeight / $height); + $newWidth = round($width * $ratio); + $newHeight = round($height * $ratio); + + // Création de la nouvelle image + $sourceImage = $this->createImageFromFile($file['tmp_name'], $mimeType); + $newImage = imagecreatetruecolor($newWidth, $newHeight); + + // Préservation de la transparence pour PNG + if ($mimeType === 'image/png') { + imagealphablending($newImage, false); + imagesavealpha($newImage, true); + } + + // Redimensionnement + imagecopyresampled( + $newImage, $sourceImage, + 0, 0, 0, 0, + $newWidth, $newHeight, + $width, $height + ); + + // Sauvegarde de l'image redimensionnée + $this->saveImage($newImage, $targetPath, $mimeType); + + // Libération de la mémoire + imagedestroy($sourceImage); + imagedestroy($newImage); + } else { + // Déplacement du fichier original si pas besoin de redimensionnement + if (!move_uploaded_file($file['tmp_name'], $targetPath)) { + throw new Exception('Erreur lors du déplacement du fichier uploadé'); + } + } + + // Retourner le chemin relatif pour l'éditeur + return [ + 'success' => true, + 'url' => '../assets/images/about/' . $filename, + 'width' => $needsResize ? $newWidth : $width, + 'height' => $needsResize ? $newHeight : $height + ]; + + } catch (Exception $e) { + return [ + 'success' => false, + 'error' => $e->getMessage() + ]; + } + } + + private function ensureUploadDirectory() { + if (!file_exists($this->uploadDir)) { + if (!mkdir($this->uploadDir, 0755, true)) { + throw new Exception('Impossible de créer le dossier d\'upload'); + } + } + + if (!is_writable($this->uploadDir)) { + throw new Exception('Le dossier d\'upload n\'est pas accessible en écriture'); + } + } + + private function createImageFromFile($file, $mimeType) { + switch ($mimeType) { + case 'image/jpeg': + return imagecreatefromjpeg($file); + case 'image/png': + return imagecreatefrompng($file); + case 'image/gif': + return imagecreatefromgif($file); + case 'image/webp': + return imagecreatefromwebp($file); + default: + throw new Exception('Type d\'image non supporté'); + } + } + + private function saveImage($image, $path, $mimeType) { + switch ($mimeType) { + case 'image/jpeg': + return imagejpeg($image, $path, 85); + case 'image/png': + return imagepng($image, $path, 8); + case 'image/gif': + return imagegif($image, $path); + case 'image/webp': + return imagewebp($image, $path, 85); + default: + throw new Exception('Type d\'image non supporté pour la sauvegarde'); + } + } + + private function getExtensionFromMimeType($mimeType) { + $map = [ + 'image/jpeg' => 'jpg', + 'image/png' => 'png', + 'image/gif' => 'gif', + 'image/webp' => 'webp' + ]; + return $map[$mimeType] ?? 'jpg'; + } + + private function getUploadErrorMessage($error) { + $errors = [ + UPLOAD_ERR_INI_SIZE => 'Le fichier dépasse la taille maximale autorisée par PHP', + UPLOAD_ERR_FORM_SIZE => 'Le fichier dépasse la taille maximale autorisée par le formulaire', + UPLOAD_ERR_PARTIAL => 'Le fichier n\'a été que partiellement uploadé', + UPLOAD_ERR_NO_FILE => 'Aucun fichier n\'a été uploadé', + UPLOAD_ERR_NO_TMP_DIR => 'Dossier temporaire manquant', + UPLOAD_ERR_CANT_WRITE => 'Échec de l\'écriture du fichier sur le disque', + UPLOAD_ERR_EXTENSION => 'Une extension PHP a arrêté l\'upload' + ]; + return $errors[$error] ?? 'Erreur inconnue lors de l\'upload'; + } +} + +// Point d'entrée du script +if ($_SERVER['REQUEST_METHOD'] !== 'POST') { + http_response_code(405); + exit(json_encode(['error' => 'Méthode non autorisée'])); +} + +// Vérification de l'authentification +if (!Auth::check()) { + http_response_code(401); + exit(json_encode(['error' => 'Non autorisé'])); +} + +// Traitement de l'upload +try { + $handler = new AboutImageUploadHandler(); + $result = $handler->handleUpload($_FILES['image']); + + if (!$result['success']) { + http_response_code(400); + } + + header('Content-Type: application/json'); + echo json_encode($result); +} catch (Exception $e) { + http_response_code(500); + echo json_encode([ + 'success' => false, + 'error' => 'Erreur serveur : ' . $e->getMessage() + ]); +} \ No newline at end of file diff --git a/assets/js/options.js b/assets/js/options.js index 069bef2..0553da9 100644 --- a/assets/js/options.js +++ b/assets/js/options.js @@ -19,50 +19,47 @@ document.addEventListener('DOMContentLoaded', function() { ['clean'] ], handlers: { - image: handleImageUpload + image: function() { + const input = document.createElement('input'); + input.setAttribute('type', 'file'); + input.setAttribute('accept', 'image/*'); + input.click(); + + input.onchange = async () => { + const file = input.files[0]; + if (file) { + const formData = new FormData(); + formData.append('image', file); + + try { + const response = await fetch('api/about-image-upload.php', { + method: 'POST', + body: formData + }); + + if (!response.ok) throw new Error('Upload failed'); + + const result = await response.json(); + if (result.success) { + const range = aboutEditor.getSelection(true); + aboutEditor.insertEmbed(range.index, 'image', result.url); + aboutEditor.setSelection(range.index + 1); + } else { + showNotification(result.error || 'Erreur lors de l\'upload', 'error'); + } + } catch (error) { + console.error('Error:', error); + showNotification('Erreur lors de l\'upload de l\'image', 'error'); + } + } + }; + } } } }, placeholder: 'Commencez à écrire le contenu de la page À propos...' }); - // Gestion de l'upload d'images - function handleImageUpload() { - const input = document.createElement('input'); - input.setAttribute('type', 'file'); - input.setAttribute('accept', 'image/*'); - input.click(); - - input.onchange = async () => { - const file = input.files[0]; - if (file) { - const formData = new FormData(); - formData.append('image', file); - - try { - const response = await fetch('api/upload-image.php', { - method: 'POST', - body: formData - }); - - if (!response.ok) throw new Error('Upload failed'); - - const result = await response.json(); - if (result.success) { - const range = aboutEditor.getSelection(true); - aboutEditor.insertEmbed(range.index, 'image', result.url); - aboutEditor.setSelection(range.index + 1); - } else { - showNotification(result.error || 'Erreur lors de l\'upload', 'error'); - } - } catch (error) { - console.error('Error:', error); - showNotification('Erreur lors de l\'upload de l\'image', 'error'); - } - } - }; - } - // Initialisation du contenu si existant const editorElement = document.getElementById('aboutEditor'); const initialContent = editorElement.getAttribute('data-initial-content');