From 141291c29306391f91e7ceee57ff4d6e9907ab1d Mon Sep 17 00:00:00 2001 From: polo Date: Fri, 21 Mar 2025 00:47:16 +0100 Subject: dossier public --- src/service/ckeditor5/CKEditor.php | 204 +++++++++++++++++++++++++++++++++ src/service/ckeditor5/image_upload.php | 65 +++++++++++ src/service/ckeditor5/view.php | 181 +++++++++++++++++++++++++++++ 3 files changed, 450 insertions(+) create mode 100644 src/service/ckeditor5/CKEditor.php create mode 100644 src/service/ckeditor5/image_upload.php create mode 100644 src/service/ckeditor5/view.php (limited to 'src/service') diff --git a/src/service/ckeditor5/CKEditor.php b/src/service/ckeditor5/CKEditor.php new file mode 100644 index 0000000..3adf223 --- /dev/null +++ b/src/service/ckeditor5/CKEditor.php @@ -0,0 +1,204 @@ +php_ini_max_size = $this->returnBytes(ini_get('upload_max_filesize')); // = 2M par défaut dans le php.ini + $this->css_outside_editor_tag = ''; + $this->server_root = $_SERVER['SERVER_NAME'] . self::SERVER_PATH; + } + + // getters + public function getPage(): string + { + return $this->page; + } + public function getFrom(): string + { + return $this->from; + } + public function getCSSOutsideEditorTag(): string + { + return $this->css_outside_editor_tag; + } + public function getCSSEditorTag(): string + { + return $this->css_editor_tag; + } + public function getStorageMode(): string + { + return $this->storage_mode; + } + + // setters + public function setPage(string $page): void + { + $this->page = $page; + } + public function setFrom(string $from): void + { + $this->from = $from; + } + public function setStorageMode($mode): void + { + $this->storage_mode = $mode; + } + + public function setLanguage(string $language): void + { + $this->toolbar_language = $language; + $this->makeTranslationSymLink(); + } + + public function checkAjaxRequest(): void + { + // dans un fichier à part parce que trop de lignes + require self::INTEGRATION_PATH . 'image_upload.php'; + die; + } + + public function displayNewArticleButton(): string + { + $html = '
+ +
'; + return $html; + } + public function displayArticle(string $id, string $texte): string + { + $html = '
' . $texte . '
+ + '; + return $html; + } + + public function openEditor(string $id = '', string $texte = ''): string + { + // version "minifiée" + $this->css_editor_tag = ''; + // version normale aérée et commentée" + $this->css_editor_tag = ''; + + require self::INTEGRATION_PATH . 'view.php'; // html + JS + return $editeurHTML; + } + + //public function deleteSideEffects(string $id){} + + public function checkSubmitPOST(): string + { + return $this->getAndCleanEditorOutput($_POST["contenu"]); // manipule $_POST['contenu']; + + // enregistrement des données + //var_dump($html_from_editor); // debug + //echo "ce programme n'enregistre rien, faîtes-le dans votre application et supprimer cette ligne dans index.php"; die; + + /*header('Location: ' . $this->from); + die;*/ + } + + /* lien symbolique des traductions + l'éditeur recherche un dans module/ckeditor5/dist/browser/translations + un fichier se trouvant dans module/ckeditor5/dist/translations + c'est le meilleur moyen que j'ai trouvé de gérer ça (il y a surement mieux) */ + private function makeTranslationSymLink(): void + { + $target = '../translations'; + $link = '../node_modules/ckeditor5/dist/browser/translations'; + + if(!file_exists($link)) + { + if(PHP_OS_FAMILY === 'Linux') + { + symlink($target, $link); + } + elseif(PHP_OS_FAMILY === 'Windows') // note: PHP_OS = WINNT + { + // on peut créer une jointure sans droit d'admin + $target = '..\node_modules\ckeditor5\dist\translations'; + exec('mklink /J ' . str_replace('/', '\\', $link) . ' ' . $target); + } + else + { + echo "erreur dans " . self::INTEGRATION_PATH . "CKEditor.php: système d'exploitation n'a pas été reconnu"; + } + // autres valeurs possibles pour PHP_OS_FAMILY: 'BSD', 'Darwin', 'Solaris', 'Unknown' + } + } + + // conversion des 2M du php.ini en 2000000 + // note: les kibi, mébi et gibi sont inutiles ici + private function returnBytes(string $size_str): int // chaine du style '2M' + { + switch(substr($size_str, -1)) + { + case 'Ki': case 'ki': return (int)$size_str * 1024; + case 'Mi': case 'mi': return (int)$size_str * 1048576; + case 'Gi': case 'gi': return (int)$size_str * 1073741824; + case 'K': case 'k': return (int)$size_str * 1000; + case 'M': case 'm': return (int)$size_str * 1000000; + case 'G': case 'g': return (int)$size_str * 1000000000; + default: return (int)$size_str; + } + } + + private function getAndCleanEditorOutput(string $html): string + { + // bugs possibles sans trim() lorsqu'on insère le HTML dans l'éditeur + $html = trim($html); + + //$this->checkContentInFile($html, 'avant'); + + // sécurisation du HTML (faille XSS) + require '../vendor/htmlawed/htmlawed/htmLawed.php'; + $configHtmLawed = array( + 'safe'=>1, // protection contre les élements et attributs dangereux + + // balises autorisées + 'elements'=>'h2, h3, h4, p, span, i, strong, u, s, mark, blockquote, li, ol, ul, a, figure, hr, img, figcaption, table, tbody, tr, td', + // note: change en + + // attributs interdits + 'deny_attribute'=>'id', // 'class' et 'style' sont conservés pour le ckeditor + ); + $specHtmLawed = ''; // optionnel: faire qu'un certain élément puisse n'avoir que certains attributs + $html = htmLawed($html, $configHtmLawed, $specHtmLawed); + + //$this->checkContentInFile($html, 'après'); + + return $html; + } + + + private function checkContentInFile($html, $file_name): void + { + $nom_fichier = $file_name . ".html"; + $fichier = fopen(self::DATA_PATH . '/' . $nom_fichier, 'w'); // w peut créer un fichier, si il existe déjà, il est effacé par le nouveau contenu + fputs($fichier, $html); + fclose($fichier); + chmod(self::DATA_PATH . '/' . $nom_fichier, 0666); + } +} diff --git a/src/service/ckeditor5/image_upload.php b/src/service/ckeditor5/image_upload.php new file mode 100644 index 0000000..5cef369 --- /dev/null +++ b/src/service/ckeditor5/image_upload.php @@ -0,0 +1,65 @@ + + +$erreur = ''; +if($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_FILES['upload']) + && strpos($_SERVER['CONTENT_TYPE'], 'multipart/form-data') !== false) // le "simple upload adapter" envoie des "form-data" +{ + if($_FILES['upload']['error'] == 0) // 0 signifie ok + { + if($_FILES['upload']['size'] <= $this->php_ini_max_size) + { + $infos = pathinfo ($_FILES['upload']['name']); + $extension = $infos['extension']; + $extautorisées = ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp', 'tiff']; + // on prend la même liste que celle côté javascript, le SVG est bloqué pour raison de sécurité (javascript à l'intérieur) + if(in_array($extension, $extautorisées)) + { + move_uploaded_file ($_FILES['upload']['tmp_name'], self::DATA_PATH . '/images/' . $_FILES['upload']['name']); + chmod(self::DATA_PATH . '/images/' . $_FILES['upload']['name'], 0666); + } + else + { + $erreur = 'mauvais format, veuillez utiliser une image comportant un de ces formats: jpg ou jpeg, png, gif, bmp, webp, tiff
le format svg n\'est pas supporté'; + } + } + else + { + $erreur = 'fichier trop lourd'; + } + } + else + { + $erreur = $_FILES['upload']['error']; + } + + if(empty($erreur)) + { + $chemin = '{"url": "' . self::DATA_PATH . '/images/' . $_FILES['upload']['name'] . '"}'; + echo $chemin; + } + else + { + echo $erreur; + } +} +else +{ + echo "erreur: téléchargement non identifié"; +} + +/* les erreurs retournées avec $_FILES['upload']['error']: +0 pas d'erreur +1 taille du fichier supérieure à la valeur de upload_max_filesize dans le fichier php.ini (par défaut = 2 MO) +2 taille du fichier supérieure à la valeur de MAX_FILE_SIZE dans le formulaire HTML +3 fichier partiellement téléchargé +4 pas de fichier du tout +6 pas de dossier temporaire pour mettre le fichier +7 echec de l'écriture sur le DD +8 envoi arrêté par une extension de PHP mais on ne nous dit pas pourquoi => diagnostic avec la fonction phpinfo() */ \ No newline at end of file diff --git a/src/service/ckeditor5/view.php b/src/service/ckeditor5/view.php new file mode 100644 index 0000000..57115d1 --- /dev/null +++ b/src/service/ckeditor5/view.php @@ -0,0 +1,181 @@ +page . '&action=submit_editor&id=' . $id; + +$cancel_button = 'index.php?page=' . $this->page; +//$cancel_button .= !empty($id) ? '&id=' . $id : ''; // à ajouter si on a besoin de revenir sur un article spécifique + +$delete_button = $id != '' ? '' : ''; + +$upload_ajax = 'index.php?action=upload_image_editor'; +$upload_ajax .= !empty($id) ? '&id=' . $id : ''; + +ob_start(); +?> +
+
+ + + + + + +
+
+