From 141291c29306391f91e7ceee57ff4d6e9907ab1d Mon Sep 17 00:00:00 2001 From: polo Date: Fri, 21 Mar 2025 00:47:16 +0100 Subject: dossier public --- data/page/html/1646148841.html | 2 +- data/page/html/1646148842.html | 2 +- index.php | 128 ------------- installation ckeditor.txt | 101 ++++++++++ installation dans une application PHP.txt | 100 ---------- public/css/article_hors_editeur.css | 38 ++++ public/index.php | 128 +++++++++++++ src/integration/ckeditor5/CKEditor.php | 204 --------------------- src/integration/ckeditor5/article_hors_editeur.css | 38 ---- src/integration/ckeditor5/image_upload.php | 65 ------- src/integration/ckeditor5/view.php | 181 ------------------ src/service/ckeditor5/CKEditor.php | 204 +++++++++++++++++++++ src/service/ckeditor5/image_upload.php | 65 +++++++ src/service/ckeditor5/view.php | 181 ++++++++++++++++++ 14 files changed, 719 insertions(+), 718 deletions(-) delete mode 100644 index.php create mode 100644 installation ckeditor.txt delete mode 100644 installation dans une application PHP.txt create mode 100644 public/css/article_hors_editeur.css create mode 100644 public/index.php delete mode 100644 src/integration/ckeditor5/CKEditor.php delete mode 100644 src/integration/ckeditor5/article_hors_editeur.css delete mode 100644 src/integration/ckeditor5/image_upload.php delete mode 100644 src/integration/ckeditor5/view.php 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 diff --git a/data/page/html/1646148841.html b/data/page/html/1646148841.html index 291f6d0..ecb0d54 100644 --- a/data/page/html/1646148841.html +++ b/data/page/html/1646148841.html @@ -1 +1 @@ -
image
image

hello

okokpeut-êtrebon

c'est pas

grave

on verra

plus tard

coucou

goodbye

\ No newline at end of file +
image

hello

okokpeut-êtrebon

c'est pas

grave

on verra

plus tard

coucou

goodbye

\ No newline at end of file diff --git a/data/page/html/1646148842.html b/data/page/html/1646148842.html index 78264ee..1572c1e 100644 --- a/data/page/html/1646148842.html +++ b/data/page/html/1646148842.html @@ -1 +1 @@ -
image
image

good bye

okah ouibon

c'est super

grave

on verra

plus tard

salut

goodbye

\ No newline at end of file +
image
image

good bye

okah ouibon

c'est super

grave

on verra

plus tard

salut

goodbye

diff --git a/index.php b/index.php deleted file mode 100644 index 3e89113..0000000 --- a/index.php +++ /dev/null @@ -1,128 +0,0 @@ -setLanguage('fr'); // attention, exécute une autre fonction qui peut échouer -$ckeditor->setStorageMode('files'); -$ckeditor->setPage($page); - - -// routage - -// upload images AJAX -if(isset($_GET['action']) && $_GET['action'] === 'upload_image_editor') -{ - $ckeditor->checkAjaxRequest(); -} - -// submit normal -if(isset($_GET['action']) && $_GET['action'] === 'submit_editor' && isset($_POST["contenu"])) // HTML envoyé par l'éditeur -{ - $ckeditor->setFrom($from); - $html_from_editor = $ckeditor->checkSubmitPOST(); - - if($id_article == '') // nouvel article - { - $id_article = time(); - } - - if($ckeditor->getStorageMode() === 'database') - { - // => modèle - } - elseif($ckeditor->getStorageMode() === 'files') - { - file_put_contents(CKEditor::DATA_PATH . '/html/' . $id_article . '.html', $html_from_editor); - } - - header('Location: index.php?page=' . $ckeditor->getFrom()); - die; -} - -// modèle - récupération des articles -$id_array = []; // noms des id en BBD ou des fichiers -$articles_content = []; // contenu HTML - -if(isset($_GET['action']) && $_GET['action'] === 'open_editor' && $id_article == '') -{ - $articles_content = $ckeditor->openEditor() . "\n"; -} -else -{ - $articles_content = $ckeditor->displayNewArticleButton() . "\n"; -} - -if($ckeditor->getStorageMode() === 'database') -{ - // => modèle -} -elseif($ckeditor->getStorageMode() === 'files') -{ - foreach(scandir(CKEditor::DATA_PATH . '/html/') as $file_name) - { - if(str_ends_with($file_name, '.html')) // filtre . et .. et d'éventuels autres fichiers - { - $id_array[] = rtrim($file_name, '.html'); - } - } - - // suppression et rechargement - if(isset($_GET['action']) && $_GET['action'] === 'delete_article') - { - if(in_array($id_article, $id_array)) - { - unlink(CKEditor::DATA_PATH . '/html/' . $id_article . '.html'); - //$ckeditor->deleteSideEffects(); - } - header('Location: index.php?page=' . $from); - die; - } - - // affichage - foreach($id_array as $id) - { - $texte = trim(file_get_contents(CKEditor::DATA_PATH . '/html/' . $id . '.html')); - //$texte = addslashes($texte); // échappe ', ", \ et NULL, je sais pas si c'est bien - - // vue - afficher des articles et éventuellement l'éditeur dans un des articles - if(isset($_GET['action']) && $_GET['action'] === 'open_editor') - { - if($id === $id_article) - { - $texte = addcslashes($texte, "'"); // échapper les simples quotes pour javascript - $articles_content .= $ckeditor->openEditor($id, $texte) . "\n"; - } - else - { - $articles_content .= $ckeditor->displayArticle($id, $texte) . "\n"; - } - } - else - { - $articles_content .= $ckeditor->displayArticle($id, $texte) . "\n"; - } - } -} -// vue -?> - - - - - - - getCSSOutsideEditorTag() ?> - getCSSEditorTag() ?> - - -
- -
- - diff --git a/installation ckeditor.txt b/installation ckeditor.txt new file mode 100644 index 0000000..08f19ae --- /dev/null +++ b/installation ckeditor.txt @@ -0,0 +1,101 @@ +1/ installation + +cd "mon projet" +git clone git@ordipolo.fr:ckeditor5 +copier tout son contenu (sauf le .git) dans le dossier racine de notre application et supprimer le dossier source +rm -r ckeditor5 --interactive=never +attention quand un index.php existe déjà + +les fichiers composer.json et package.json sont volontairement absents +faire un install (npm) et un require (composer) dans son projet, obtenir la dernière version de l'éditeur et essuyer les plâtres! +npm install ckeditor5 +composer require htmlawed/htmlawed + +les fichiers récupérés par le git clone, src/integration/ckeditor5/ est à insérer dans son projet: +src/integration/ckeditor5/CKEditor.php +src/integration/ckeditor5/view.php +src/integration/ckeditor5/image_upload.php +src/integration/ckeditor5/articles_hors_editeur.css +installation dans une application PHP.txt +index.php (appel des contrôleurs) +data/page/html/1646148841.html +data/page/html/1646148842.html +data/page/images/chirurgien jaune.jpg +data/page/images/garfield4.png + + +2/ lien symbolique nécéssaire pour trouver les traductions (commande pour debian): +un problème de chemin se produit à la ligne: import coreTranslations from 'ckeditor5/translations/fr.js'; dans lib/ckeditor5/template.php +gràce à un lien symbolique, le programme s'attend à trouver un dossier "translations" dans "browser" +le dossier concerné est node_modules/ckeditor5/dist/browser, on doit lui donner plus de droits + +PHP l'ajoute avec symlink dans index.php +si le lien symbolique /srv/http/ckeditor5/node_modules/ckeditor5/dist/browser/translations +n'a pas été créé correctement par PHP, permettre au serveur d'écrire dans "browser" ou le faire en BASH +la commande mklink permet de faire la même chose sur un serveur windows, l'option /J créée une jointure et fonctionne sans droit d'admin + +chemin absolu +ln -s /var/www/ckeditor5/node_modules/ckeditor5/dist/translations /var/www/ckeditor5/node_modules/ckeditor5/dist/browser/ +chemin relatif +ln -s ../translations node_modules/ckeditor5/dist/browser/ + + +3/ essai +les paramètres dans CKEditor.php et les fichiers dans data permettent normalement +- d'ouvrir l'éditeur +- de lire des données dans des fichiers et de les insérer dans l'éditeur pour modification + +la sortie au "submit" est nettoyée puis se retrouve dans $html_from_editor + + +4/ intégration à un projet + +a) insérer le dossier: src/integration/ckeditor5/ + +b) adapter les paramètres dans CKEditor.php, $storage_mode vaut soit 'files' soit 'database' + +c) les autres fichiers sont un exemple pour y prendre du code, +=> piocher dans index.php! + +d) le dossier data et ses sous-dossiers ont besoin de droits en écriture + +e) adapter la connexion à la BDD si nécéssaire + +f) insérer dans chaque page affichant des données créées avec l'éditeur: +getCSSOutsideEditorTag() ?> +l'éditeur ne génère pas de CSS mais seulement du HTML basique, ce CSS imite le rendu à l'intérieur de l'éditeur + +g) ajouter dans chaque page insérant l'éditeur: +getCSSEditorTag() ?> + + +ce qui suit est de l'information utile si on souhaite partir de zéro avec NPM et la doc + + + +5/ explication et choix des plugins +tout ça est déjà fait, mais vous pouvez toujours personnaliser l'éditeur en choisissant des plugins différents + +voici ce que j'ai fait dans: lib/ckeditor5/template.php + +a) créer une importmap avec les chemins des fichiers + + +b) charger une liste de plugins façon python +import { "liste de plugins" } from "ckeditor5"; + +c) rechoisir les plugins dans ClassicEditor.create(): +plugins: [ "liste de plugins" ] ... + +d) choisir les élément de la toolbar +toolbar; { items: [ "éléments" ], ... + +e) autres éléments: +toolbar des images et des tables, sécurité des envois AJAX diff --git a/installation dans une application PHP.txt b/installation dans une application PHP.txt deleted file mode 100644 index 76ec201..0000000 --- a/installation dans une application PHP.txt +++ /dev/null @@ -1,100 +0,0 @@ -1/ installation - -cd "mon projet" -git clone git@ordipolo.fr:ckeditor5 -copier tout son contenu (sauf le .git) dans le dossier racine de notre application et supprimer le dossier source -rm -r ckeditor5 --interactive=never -attention quand un index.php existe déjà - -les fichiers composer.json et package.json sont volontairement absents -faire un install (npm) et un require (composer) dans son projet, obtenir la dernière version de l'éditeur et essuyer les plâtres! -npm install ckeditor5 -composer require htmlawed/htmlawed - -les fichiers récupérés par le git clone, src/integration/ckeditor5/ est à insérer dans son projet: -src/integration/ckeditor5/CKEditor.php -src/integration/ckeditor5/view.php -src/integration/ckeditor5/image_upload.php -src/integration/ckeditor5/articles_hors_editeur.css -installation dans une application PHP.txt -index.php (appel des contrôleurs) -data/page/html/1646148841.html -data/page/html/1646148842.html -data/page/images/chirurgien jaune.jpg -data/page/images/garfield4.png - - -2/ lien symbolique nécéssaire pour trouver les traductions (commande pour debian): -un problème de chemin se produit à la ligne: import coreTranslations from 'ckeditor5/translations/fr.js'; dans lib/ckeditor5/template.php -gràce à un lien symbolique, le programme s'attend à trouver un dossier "translations" dans "browser" - -PHP l'ajoute avec symlink dans index.php -si le lien symbolique /srv/http/ckeditor5/node_modules/ckeditor5/dist/browser/translations -n'a pas été créé correctement par PHP, permettre au serveur d'écrire dans "browser" ou le faire en BASH -la commande mklink permet de faire la même chose sur un serveur windows, l'option /J créée une jointure et fonctionne sans droit d'admin - -chemin absolu -ln -s /var/www/ckeditor5/node_modules/ckeditor5/dist/translations /var/www/ckeditor5/node_modules/ckeditor5/dist/browser/ -chemin relatif -ln -s ../translations node_modules/ckeditor5/dist/browser/ - - -3/ essai -les paramètres dans CKEditor.php et les fichiers dans data permettent normalement -- d'ouvrir l'éditeur -- de lire des données dans des fichiers et de les insérer dans l'éditeur pour modification - -la sortie au "submit" est nettoyée puis se retrouve dans $html_from_editor - - -4/ intégration à un projet - -a) insérer le dossier: src/integration/ckeditor5/ - -b) adapter les paramètres dans CKEditor.php, $storage_mode vaut soit 'files' soit 'database' - -c) les autres fichiers sont un exemple pour y prendre du code, -=> piocher dans index.php! - -d) le dossier data et ses sous-dossiers ont besoin de droits en écriture - -e) adapter la connexion à la BDD si nécéssaire - -f) insérer dans chaque page affichant des données créées avec l'éditeur: -getCSSOutsideEditorTag() ?> -l'éditeur ne génère pas de CSS mais seulement du HTML basique, ce CSS imite le rendu à l'intérieur de l'éditeur - -g) ajouter dans chaque page insérant l'éditeur: -getCSSEditorTag() ?> - - -ce qui suit est de l'information utile si on souhaite partir de zéro avec NPM et la doc - - - -5/ explication et choix des plugins -tout ça est déjà fait, mais vous pouvez toujours personnaliser l'éditeur en choisissant des plugins différents - -voici ce que j'ai fait dans: lib/ckeditor5/template.php - -a) créer une importmap avec les chemins des fichiers - - -b) charger une liste de plugins façon python -import { "liste de plugins" } from "ckeditor5"; - -c) rechoisir les plugins dans ClassicEditor.create(): -plugins: [ "liste de plugins" ] ... - -d) choisir les élément de la toolbar -toolbar; { items: [ "éléments" ], ... - -e) autres éléments: -toolbar des images et des tables, sécurité des envois AJAX diff --git a/public/css/article_hors_editeur.css b/public/css/article_hors_editeur.css new file mode 100644 index 0000000..622b539 --- /dev/null +++ b/public/css/article_hors_editeur.css @@ -0,0 +1,38 @@ +article{width: 630px;} +article:after{content: ""; display: block; clear: both;} + +img{vertical-align: bottom;} +@media screen and (max-width: 1000px) +{img{max-width: 900px;}} + +.text-tiny{font-size: x-small;} +.text-small{font-size: small;} +.text-big{font-size: large;} +.text-huge{font-size: x-large;} + +blockquote{border-left: 5px #cccccc solid; margin: 14px 0px; padding: 2px 25px; font-style: italic;} + +.marker-yellow{background-color: #fdfd77;} +.marker-green{background-color: #62f962;} +.marker-pink{background-color: #fc7899;} +.marker-blue{background-color: #72ccfd;} +.pen-red{background-color: white; color: red;} +.pen-green{background-color: white; color: green;} + +ul{padding-left: 10px;} +.todo-list>li{list-style-type : none;} +input[type=checkbox]{-webkit-appearance: none;-moz-appearance: none;-ms-appearance: none; +height: 16px; width: 16px; border: 1px solid black; border-radius: 2px; position: relative; top: 5px; margin-right: 10px;} +input[type="checkbox"]:checked{border: none; background: #26ab33;} + +.table>table{border-collapse: collapse;} +.table td{border: 1px grey solid; padding: 7px; min-width: 30px;} +td p{margin: 0px;} + +.image{margin: 0px; text-align: center; display: inline-block;} +.image-style-side{float: right;} +.image img{max-width: 630px;} +.image-style-side img{max-width: 315px;} +.image>figcaption{margin: 0px 10px; padding: 7px; text-align: center; font-size: small; background-color: #f7f7f7;} + +iframe{min-width: 400px; min-height: 300px; max-width: 1200px; max-height: 900px;} diff --git a/public/index.php b/public/index.php new file mode 100644 index 0000000..f674f0f --- /dev/null +++ b/public/index.php @@ -0,0 +1,128 @@ +setLanguage('fr'); // attention, exécute une autre fonction qui peut échouer +$ckeditor->setStorageMode('files'); +$ckeditor->setPage($page); + + +// routage + +// upload images AJAX +if(isset($_GET['action']) && $_GET['action'] === 'upload_image_editor') +{ + $ckeditor->checkAjaxRequest(); +} + +// submit normal +if(isset($_GET['action']) && $_GET['action'] === 'submit_editor' && isset($_POST["contenu"])) // HTML envoyé par l'éditeur +{ + $ckeditor->setFrom($from); + $html_from_editor = $ckeditor->checkSubmitPOST(); + + if($id_article == '') // nouvel article + { + $id_article = time(); + } + + if($ckeditor->getStorageMode() === 'database') + { + // => modèle + } + elseif($ckeditor->getStorageMode() === 'files') + { + file_put_contents(CKEditor::DATA_PATH . '/html/' . $id_article . '.html', $html_from_editor); + } + + header('Location: index.php?page=' . $ckeditor->getFrom()); + die; +} + +// modèle - récupération des articles +$id_array = []; // noms des id en BBD ou des fichiers +$articles_content = []; // contenu HTML + +if(isset($_GET['action']) && $_GET['action'] === 'open_editor' && $id_article == '') +{ + $articles_content = $ckeditor->openEditor() . "\n"; +} +else +{ + $articles_content = $ckeditor->displayNewArticleButton() . "\n"; +} + +if($ckeditor->getStorageMode() === 'database') +{ + // => modèle +} +elseif($ckeditor->getStorageMode() === 'files') +{ + foreach(scandir(CKEditor::DATA_PATH . '/html/') as $file_name) + { + if(str_ends_with($file_name, '.html')) // filtre . et .. et d'éventuels autres fichiers + { + $id_array[] = rtrim($file_name, '.html'); + } + } + + // suppression et rechargement + if(isset($_GET['action']) && $_GET['action'] === 'delete_article') + { + if(in_array($id_article, $id_array)) + { + unlink(CKEditor::DATA_PATH . '/html/' . $id_article . '.html'); + //$ckeditor->deleteSideEffects(); + } + header('Location: index.php?page=' . $from); + die; + } + + // affichage + foreach($id_array as $id) + { + $texte = trim(file_get_contents(CKEditor::DATA_PATH . '/html/' . $id . '.html')); + //$texte = addslashes($texte); // échappe ', ", \ et NULL, je sais pas si c'est bien + + // vue - afficher des articles et éventuellement l'éditeur dans un des articles + if(isset($_GET['action']) && $_GET['action'] === 'open_editor') + { + if($id === $id_article) + { + $texte = addcslashes($texte, "'"); // échapper les simples quotes pour javascript + $articles_content .= $ckeditor->openEditor($id, $texte) . "\n"; + } + else + { + $articles_content .= $ckeditor->displayArticle($id, $texte) . "\n"; + } + } + else + { + $articles_content .= $ckeditor->displayArticle($id, $texte) . "\n"; + } + } +} +// vue +?> + + + + + + + getCSSOutsideEditorTag() ?> + getCSSEditorTag() ?> + + +
+ +
+ + diff --git a/src/integration/ckeditor5/CKEditor.php b/src/integration/ckeditor5/CKEditor.php deleted file mode 100644 index c53f236..0000000 --- a/src/integration/ckeditor5/CKEditor.php +++ /dev/null @@ -1,204 +0,0 @@ -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/integration/ckeditor5/article_hors_editeur.css b/src/integration/ckeditor5/article_hors_editeur.css deleted file mode 100644 index 622b539..0000000 --- a/src/integration/ckeditor5/article_hors_editeur.css +++ /dev/null @@ -1,38 +0,0 @@ -article{width: 630px;} -article:after{content: ""; display: block; clear: both;} - -img{vertical-align: bottom;} -@media screen and (max-width: 1000px) -{img{max-width: 900px;}} - -.text-tiny{font-size: x-small;} -.text-small{font-size: small;} -.text-big{font-size: large;} -.text-huge{font-size: x-large;} - -blockquote{border-left: 5px #cccccc solid; margin: 14px 0px; padding: 2px 25px; font-style: italic;} - -.marker-yellow{background-color: #fdfd77;} -.marker-green{background-color: #62f962;} -.marker-pink{background-color: #fc7899;} -.marker-blue{background-color: #72ccfd;} -.pen-red{background-color: white; color: red;} -.pen-green{background-color: white; color: green;} - -ul{padding-left: 10px;} -.todo-list>li{list-style-type : none;} -input[type=checkbox]{-webkit-appearance: none;-moz-appearance: none;-ms-appearance: none; -height: 16px; width: 16px; border: 1px solid black; border-radius: 2px; position: relative; top: 5px; margin-right: 10px;} -input[type="checkbox"]:checked{border: none; background: #26ab33;} - -.table>table{border-collapse: collapse;} -.table td{border: 1px grey solid; padding: 7px; min-width: 30px;} -td p{margin: 0px;} - -.image{margin: 0px; text-align: center; display: inline-block;} -.image-style-side{float: right;} -.image img{max-width: 630px;} -.image-style-side img{max-width: 315px;} -.image>figcaption{margin: 0px 10px; padding: 7px; text-align: center; font-size: small; background-color: #f7f7f7;} - -iframe{min-width: 400px; min-height: 300px; max-width: 1200px; max-height: 900px;} diff --git a/src/integration/ckeditor5/image_upload.php b/src/integration/ckeditor5/image_upload.php deleted file mode 100644 index 5cef369..0000000 --- a/src/integration/ckeditor5/image_upload.php +++ /dev/null @@ -1,65 +0,0 @@ - - -$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/integration/ckeditor5/view.php b/src/integration/ckeditor5/view.php deleted file mode 100644 index 57115d1..0000000 --- a/src/integration/ckeditor5/view.php +++ /dev/null @@ -1,181 +0,0 @@ -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(); -?> -
-
- - - - - - -
-
-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(); +?> +
+
+ + + + + + +
+
+