diff options
Diffstat (limited to 'src/service/ckeditor5/CKEditor.php')
| -rw-r--r-- | src/service/ckeditor5/CKEditor.php | 204 |
1 files changed, 204 insertions, 0 deletions
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 @@ | |||
| 1 | <?php | ||
| 2 | // src/integration/ckeditor5/CKEditor.php | ||
| 3 | |||
| 4 | declare(strict_types=1); | ||
| 5 | |||
| 6 | class CKEditor | ||
| 7 | { | ||
| 8 | public const string INTEGRATION_PATH = '../src/service/ckeditor5/'; | ||
| 9 | public const string DATA_PATH = '../data/page'; | ||
| 10 | //public const string SERVER_PATH = '/'; | ||
| 11 | private const string SERVER_PATH = '/ckeditor5/'; | ||
| 12 | |||
| 13 | private string $server_root; // pour les "imports" en javascript | ||
| 14 | // pour l'importmap: j'ai modifié la version "installation avec CDN de la doc pour utiliser les fichiers locaux | ||
| 15 | // l'"importmap" permet d'utiliser "import" (ça ressemble pas mal au python) dans le navigateur comme n'importe quel langage de programmation normal | ||
| 16 | |||
| 17 | private string $storage_mode = 'files'; | ||
| 18 | private string $page = 'accueil'; | ||
| 19 | private string $from = ''; | ||
| 20 | |||
| 21 | private int $php_ini_max_size; | ||
| 22 | private string $css_editor_tag = ''; | ||
| 23 | private string $css_outside_editor_tag = ''; | ||
| 24 | private string $toolbar_language = 'en'; | ||
| 25 | |||
| 26 | |||
| 27 | public function __construct() | ||
| 28 | { | ||
| 29 | $this->php_ini_max_size = $this->returnBytes(ini_get('upload_max_filesize')); // = 2M par défaut dans le php.ini | ||
| 30 | $this->css_outside_editor_tag = '<link rel="stylesheet" href="css/article_hors_editeur.css" />'; | ||
| 31 | $this->server_root = $_SERVER['SERVER_NAME'] . self::SERVER_PATH; | ||
| 32 | } | ||
| 33 | |||
| 34 | // getters | ||
| 35 | public function getPage(): string | ||
| 36 | { | ||
| 37 | return $this->page; | ||
| 38 | } | ||
| 39 | public function getFrom(): string | ||
| 40 | { | ||
| 41 | return $this->from; | ||
| 42 | } | ||
| 43 | public function getCSSOutsideEditorTag(): string | ||
| 44 | { | ||
| 45 | return $this->css_outside_editor_tag; | ||
| 46 | } | ||
| 47 | public function getCSSEditorTag(): string | ||
| 48 | { | ||
| 49 | return $this->css_editor_tag; | ||
| 50 | } | ||
| 51 | public function getStorageMode(): string | ||
| 52 | { | ||
| 53 | return $this->storage_mode; | ||
| 54 | } | ||
| 55 | |||
| 56 | // setters | ||
| 57 | public function setPage(string $page): void | ||
| 58 | { | ||
| 59 | $this->page = $page; | ||
| 60 | } | ||
| 61 | public function setFrom(string $from): void | ||
| 62 | { | ||
| 63 | $this->from = $from; | ||
| 64 | } | ||
| 65 | public function setStorageMode($mode): void | ||
| 66 | { | ||
| 67 | $this->storage_mode = $mode; | ||
| 68 | } | ||
| 69 | |||
| 70 | public function setLanguage(string $language): void | ||
| 71 | { | ||
| 72 | $this->toolbar_language = $language; | ||
| 73 | $this->makeTranslationSymLink(); | ||
| 74 | } | ||
| 75 | |||
| 76 | public function checkAjaxRequest(): void | ||
| 77 | { | ||
| 78 | // dans un fichier à part parce que trop de lignes | ||
| 79 | require self::INTEGRATION_PATH . 'image_upload.php'; | ||
| 80 | die; | ||
| 81 | } | ||
| 82 | |||
| 83 | public function displayNewArticleButton(): string | ||
| 84 | { | ||
| 85 | $html = '<article> | ||
| 86 | <a href="index.php?page=' . $this->page . '&action=open_editor"><button>Nouvel article</button></a> | ||
| 87 | </article>'; | ||
| 88 | return $html; | ||
| 89 | } | ||
| 90 | public function displayArticle(string $id, string $texte): string | ||
| 91 | { | ||
| 92 | $html = '<article>' . $texte . '</article> | ||
| 93 | <a href="index.php?page=' . $this->page . '&action=open_editor&id=' . $id . '"><button>Modifier</button></a> | ||
| 94 | <a href="index.php?page=' . $this->page . '&action=delete_article&id=' . $id . '"><button>Supprimer</button></a>'; | ||
| 95 | return $html; | ||
| 96 | } | ||
| 97 | |||
| 98 | public function openEditor(string $id = '', string $texte = ''): string | ||
| 99 | { | ||
| 100 | // version "minifiée" | ||
| 101 | $this->css_editor_tag = '<link rel="stylesheet" href="../node_modules/ckeditor5/dist/browser/ckeditor5.css" />'; | ||
| 102 | // version normale aérée et commentée" | ||
| 103 | $this->css_editor_tag = '<link rel="stylesheet" href="../node_modules/ckeditor5/dist/ckeditor5.css" />'; | ||
| 104 | |||
| 105 | require self::INTEGRATION_PATH . 'view.php'; // html + JS | ||
| 106 | return $editeurHTML; | ||
| 107 | } | ||
| 108 | |||
| 109 | //public function deleteSideEffects(string $id){} | ||
| 110 | |||
| 111 | public function checkSubmitPOST(): string | ||
| 112 | { | ||
| 113 | return $this->getAndCleanEditorOutput($_POST["contenu"]); // manipule $_POST['contenu']; | ||
| 114 | |||
| 115 | // enregistrement des données | ||
| 116 | //var_dump($html_from_editor); // debug | ||
| 117 | //echo "ce programme n'enregistre rien, faîtes-le dans votre application et supprimer cette ligne dans index.php"; die; | ||
| 118 | |||
| 119 | /*header('Location: ' . $this->from); | ||
| 120 | die;*/ | ||
| 121 | } | ||
| 122 | |||
| 123 | /* lien symbolique des traductions | ||
| 124 | l'éditeur recherche un dans module/ckeditor5/dist/browser/translations | ||
| 125 | un fichier se trouvant dans module/ckeditor5/dist/translations | ||
| 126 | c'est le meilleur moyen que j'ai trouvé de gérer ça (il y a surement mieux) */ | ||
| 127 | private function makeTranslationSymLink(): void | ||
| 128 | { | ||
| 129 | $target = '../translations'; | ||
| 130 | $link = '../node_modules/ckeditor5/dist/browser/translations'; | ||
| 131 | |||
| 132 | if(!file_exists($link)) | ||
| 133 | { | ||
| 134 | if(PHP_OS_FAMILY === 'Linux') | ||
| 135 | { | ||
| 136 | symlink($target, $link); | ||
| 137 | } | ||
| 138 | elseif(PHP_OS_FAMILY === 'Windows') // note: PHP_OS = WINNT | ||
| 139 | { | ||
| 140 | // on peut créer une jointure sans droit d'admin | ||
| 141 | $target = '..\node_modules\ckeditor5\dist\translations'; | ||
| 142 | exec('mklink /J ' . str_replace('/', '\\', $link) . ' ' . $target); | ||
| 143 | } | ||
| 144 | else | ||
| 145 | { | ||
| 146 | echo "erreur dans " . self::INTEGRATION_PATH . "CKEditor.php: système d'exploitation n'a pas été reconnu"; | ||
| 147 | } | ||
| 148 | // autres valeurs possibles pour PHP_OS_FAMILY: 'BSD', 'Darwin', 'Solaris', 'Unknown' | ||
| 149 | } | ||
| 150 | } | ||
| 151 | |||
| 152 | // conversion des 2M du php.ini en 2000000 | ||
| 153 | // note: les kibi, mébi et gibi sont inutiles ici | ||
| 154 | private function returnBytes(string $size_str): int // chaine du style '2M' | ||
| 155 | { | ||
| 156 | switch(substr($size_str, -1)) | ||
| 157 | { | ||
| 158 | case 'Ki': case 'ki': return (int)$size_str * 1024; | ||
| 159 | case 'Mi': case 'mi': return (int)$size_str * 1048576; | ||
| 160 | case 'Gi': case 'gi': return (int)$size_str * 1073741824; | ||
| 161 | case 'K': case 'k': return (int)$size_str * 1000; | ||
| 162 | case 'M': case 'm': return (int)$size_str * 1000000; | ||
| 163 | case 'G': case 'g': return (int)$size_str * 1000000000; | ||
| 164 | default: return (int)$size_str; | ||
| 165 | } | ||
| 166 | } | ||
| 167 | |||
| 168 | private function getAndCleanEditorOutput(string $html): string | ||
| 169 | { | ||
| 170 | // bugs possibles sans trim() lorsqu'on insère le HTML dans l'éditeur | ||
| 171 | $html = trim($html); | ||
| 172 | |||
| 173 | //$this->checkContentInFile($html, 'avant'); | ||
| 174 | |||
| 175 | // sécurisation du HTML (faille XSS) | ||
| 176 | require '../vendor/htmlawed/htmlawed/htmLawed.php'; | ||
| 177 | $configHtmLawed = array( | ||
| 178 | 'safe'=>1, // protection contre les élements et attributs dangereux | ||
| 179 | |||
| 180 | // balises autorisées | ||
| 181 | 'elements'=>'h2, h3, h4, p, span, i, strong, u, s, mark, blockquote, li, ol, ul, a, figure, hr, img, figcaption, table, tbody, tr, td', | ||
| 182 | // note: change <s></s> en <span style="text-decoration: line-through;"></span> | ||
| 183 | |||
| 184 | // attributs interdits | ||
| 185 | 'deny_attribute'=>'id', // 'class' et 'style' sont conservés pour le ckeditor | ||
| 186 | ); | ||
| 187 | $specHtmLawed = ''; // optionnel: faire qu'un certain élément puisse n'avoir que certains attributs | ||
| 188 | $html = htmLawed($html, $configHtmLawed, $specHtmLawed); | ||
| 189 | |||
| 190 | //$this->checkContentInFile($html, 'après'); | ||
| 191 | |||
| 192 | return $html; | ||
| 193 | } | ||
| 194 | |||
| 195 | |||
| 196 | private function checkContentInFile($html, $file_name): void | ||
| 197 | { | ||
| 198 | $nom_fichier = $file_name . ".html"; | ||
| 199 | $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 | ||
| 200 | fputs($fichier, $html); | ||
| 201 | fclose($fichier); | ||
| 202 | chmod(self::DATA_PATH . '/' . $nom_fichier, 0666); | ||
| 203 | } | ||
| 204 | } | ||
