summaryrefslogtreecommitdiff
path: root/src/controller/ajax_admin.php
diff options
context:
space:
mode:
Diffstat (limited to 'src/controller/ajax_admin.php')
-rw-r--r--src/controller/ajax_admin.php636
1 files changed, 0 insertions, 636 deletions
diff --git a/src/controller/ajax_admin.php b/src/controller/ajax_admin.php
deleted file mode 100644
index b69be77..0000000
--- a/src/controller/ajax_admin.php
+++ /dev/null
@@ -1,636 +0,0 @@
1<?php
2// src/controller/ajax_admin.php
3
4declare(strict_types=1);
5
6use App\Entity\Page;
7use App\Entity\Node;
8use App\Entity\Article;
9
10// mettre ça ailleurs
11function imagickCleanImage(string $image_data, string $local_path, string $format = 'jpeg'): bool // "string" parce que file_get_contents...
12{
13 try{
14 $imagick = new Imagick();
15 $imagick->readImageBlob($image_data);
16 $imagick->stripImage(); // nettoyage métadonnées
17 $imagick->setImageFormat($format);
18 if($format === 'jpeg'){
19 $imagick->setImageCompression(Imagick::COMPRESSION_JPEG);
20 $imagick->setImageCompressionQuality(85); // optionnel
21 }
22 $imagick->writeImage($local_path); // enregistrement
23 $imagick->clear();
24 $imagick->destroy();
25 return true;
26 }
27 catch(Exception $e){
28 return false;
29 }
30}
31function curlDownloadImage(string $url, $maxRetries = 3, $timeout = 10): string|false
32{
33 $attempt = 0;
34 $imageData = false;
35
36 while($attempt < $maxRetries){
37 $ch = curl_init($url); // instance de CurlHandle
38 curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
39 curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
40 curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout);
41 curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
42 curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
43 curl_setopt($ch, CURLOPT_USERAGENT, 'TinyMCE-Image-Downloader');
44
45 $imageData = curl_exec($ch);
46 $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
47 //$curlError = curl_error($ch);
48
49 curl_close($ch);
50
51 if($imageData !== false && $httpCode >= 200 && $httpCode < 300){
52 return $imageData;
53 }
54
55 $attempt++;
56 sleep(1);
57 }
58
59 return false; // échec après trois tentatives
60}
61
62function imageUploadTinyMce(): void
63{
64 if(isset($_FILES['file'])){
65 $file = $_FILES['file'];
66 $dest = 'images/';
67 $dest_mini = 'images-mini/';
68
69 // Vérifier si les répertoires existent, sinon les créer
70 if(!is_dir($dest)) {
71 mkdir($dest, 0700, true);
72 }
73 if(!is_dir($dest_mini)) {
74 mkdir($dest_mini, 0700, true);
75 }
76
77 $allowed_extensions = ['jpg', 'jpeg', 'png', 'gif', 'webp', 'tiff', 'tif'];
78 $name = Security::secureFileName(pathinfo($file['name'], PATHINFO_FILENAME));
79 $extension = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION));
80 if(!in_array($extension, $allowed_extensions) || $extension === 'jpg'){
81 $extension = 'jpeg';
82 }
83 $file_path = $dest . $name . '_' . uniqid() . '.' . $extension;
84
85 // créer une miniature de l'image
86 //
87
88 if(imagickCleanImage(file_get_contents($file['tmp_name']), $file_path, $extension)){ // recréer l’image pour la nettoyer
89 echo json_encode(['location' => $file_path]); // renvoyer l'URL de l'image téléchargée
90 }
91 else{
92 http_response_code(500);
93 echo json_encode(['message' => 'Erreur image non valide']);
94 }
95 }
96 else{
97 http_response_code(400);
98 echo json_encode(['message' => 'Erreur 400: Bad Request']);
99 }
100 die;
101}
102
103// détection des requêtes d'upload d'image de tinymce
104if(strpos($_SERVER['CONTENT_TYPE'], 'multipart/form-data') !== false && isset($_GET['action']) && $_GET['action'] === 'upload_image')
105{
106 imageUploadTinyMce();
107}
108// cas du collage d'un contenu HTML, réception d'une URL, téléchargement par le serveur et renvoie de l'adresse sur le serveur
109elseif(isset($_GET['action']) && $_GET['action'] == 'upload_image_url')
110{
111 $json = json_decode(file_get_contents('php://input'), true);
112
113 if(isset($json['image_url'])){
114 $image_data = curlDownloadImage($json['image_url']); // téléchargement de l’image par le serveur avec cURL au lieu de file_get_contents
115 $dest = 'images/';
116
117 if(!is_dir($dest)) { // Vérifier si le répertoire existe, sinon le créer
118 mkdir($dest, 0777, true);
119 }
120
121 if($image_data === false){
122 http_response_code(400);
123 echo json_encode(['message' => "Erreur, le serveur n'a pas réussi à télécharger l'image."]);
124 die;
125 }
126
127 $allowed_extensions = ['jpg', 'jpeg', 'png', 'gif', 'webp', 'tiff', 'tif'];
128 $url_path = parse_url($json['image_url'], PHP_URL_PATH);
129 $name = Security::secureFileName(pathinfo($url_path, PATHINFO_FILENAME));
130 $extension = strtolower(pathinfo($url_path, PATHINFO_EXTENSION));
131 if(!in_array($extension, $allowed_extensions) || $extension === 'jpg'){
132 $extension = 'jpeg';
133 }
134 $local_path = $dest . $name . '_' . uniqid() . '.' . $extension;
135
136 if(imagickCleanImage($image_data, $local_path, $extension)){ // recréer l’image pour la nettoyer
137 echo json_encode(['location' => $local_path]); // nouvelle adresse
138 }
139 else{
140 http_response_code(500);
141 echo json_encode(['message' => 'Erreur image non valide']);
142 }
143 }
144 else{
145 echo json_encode(['message' => 'Erreur 400: Bad Request']);
146 }
147 die;
148}
149// cas du collage d'une image (code base64) non encapsulée dans du HTML
150elseif(isset($_GET['action']) && $_GET['action'] == 'upload_image_base64')
151{
152 $json = json_decode(file_get_contents('php://input'), true);
153 $dest = 'images/';
154
155 if(!is_dir('images')){
156 mkdir('images', 0777, true);
157 }
158
159 // détection de data:image/ et de ;base64, et capture du format dans $type
160 if(!isset($json['image_base64']) || !preg_match('/^data:image\/(\w+);base64,/', $json['image_base64'], $type)){
161 http_response_code(400);
162 echo json_encode(['message' => 'Données image base64 manquantes ou invalides']);
163 die;
164 }
165
166 $allowed_extensions = ['jpg', 'jpeg', 'png', 'gif', 'webp', 'tiff', 'tif'];
167 $extension = strtolower($type[1]);
168 if(!in_array($extension, $allowed_extensions) || $extension === 'jpg'){
169 $extension = 'jpeg';
170 }
171
172 $image_data = base64_decode(substr($json['image_base64'], strpos($json['image_base64'], ',') + 1)); // découpe la chaine à la virgule puis convertit en binaire
173 if($image_data === false){
174 http_response_code(400);
175 echo json_encode(['message' => 'Décodage base64 invalide']);
176 die;
177 }
178
179 $local_path = $dest . 'pasted_image_' . uniqid() . '.' . $extension;
180
181 if(imagickCleanImage($image_data, $local_path)){
182 echo json_encode(['location' => $local_path]);
183 }
184 else{
185 http_response_code(500);
186 echo json_encode(['message' => 'Erreur image non valide']);
187 }
188 die;
189}
190
191// détection des requêtes de type XHR, y en a pas à priori
192/*elseif(isset($_SERVER['HTTP_X_REQUESTED_WITH']) && $_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest'){
193 echo "requête XHR reçue par le serveur";
194 die;
195}*/
196
197
198// détection des requêtes envoyées avec fetch (application/json) et récupération du JSON
199if($_SERVER['CONTENT_TYPE'] === 'application/json')
200{
201 $data = file_get_contents('php://input');
202 $json = json_decode($data, true);
203
204 if(isset($_GET['action']))
205 {
206 if($_GET['action'] === 'editor_submit' && isset($json['id']) && isset($json['content']))
207 {
208 if(json_last_error() === JSON_ERROR_NONE)
209 {
210 $id = $json['id'];
211 $director = new Director($entityManager);
212
213 // cas d'une nouvelle "news"
214 if(is_array($json['content'])){
215 foreach($json['content'] as $one_input){
216 $one_input = Security::secureString($one_input);
217 }
218 $content = $json['content'];
219 }
220 else{
221 $content = Security::secureString($json['content']);
222 }
223
224 // nouvel article
225 if($id[0] === 'n')
226 {
227 $section_id = (int)substr($id, 1); // id du bloc <section>
228 $director->findNodeById($section_id);
229 $director->makeSectionNode();
230 $node = $director->getNode(); // = <section>
231
232 if(is_array($content)){
233 $date = new \DateTime($content['d']);
234 $article = new Article($content['i'], $date, $content['t'], $content['p']);
235 $article_node = new Node('new', 'i' . (string)$date->getTimestamp(), [], count($node->getChildren()) + 1, $node, $node->getPage(), $article);
236
237 // id_node tout juste généré
238 //$article_node->getId();
239 }
240 else{
241 $timestamp = time();
242 $date = new \DateTime;
243 $date->setTimestamp($timestamp);
244
245 $article = new Article($content, $date); // le "current" timestamp est obtenu par la BDD
246 $article_node = new Node('article', 'i' . (string)$timestamp, [], count($node->getChildren()) + 1, $node, $node->getPage(), $article);
247 }
248
249 $entityManager->persist($article_node);
250 $entityManager->flush();
251
252 echo json_encode(['success' => true, 'article_id' => $article_node->getArticleTimestamp()]);
253 die;
254 }
255 // modification article
256 else{
257 $id[0] = 'i'; // id de l'article node
258 }
259
260 if($director->makeArticleNode($id)) // une entrée est trouvée
261 {
262 $node = $director->getArticleNode(); // article
263 switch($json['id'][0]){
264 case 'i':
265 $node->getArticle()->setContent($content);
266 break;
267 case 'p':
268 $node->getArticle()->setPreview($content); // html de l'éditeur
269 break;
270 case 't':
271 $node->getArticle()->setTitle($content); // html de l'éditeur
272 break;
273 case 'd':
274 echo json_encode(['success' => false, 'message' => 'l\'action editor_submit ne supporte pas les dates, utiliser date_submit.']);
275 die;
276 default:
277 echo json_encode(['success' => false, 'message' => 'identifiant non utilisable']);
278 die;
279 }
280 $entityManager->flush();
281 echo json_encode(['success' => true]);
282 }
283 else
284 {
285 echo json_encode(['success' => false, 'message' => 'article non identifié']);
286 }
287 }
288 else{
289 echo json_encode(['success' => false, 'message' => 'Erreur de décodage JSON']);
290 }
291 die;
292 }
293 elseif($_GET['action'] === 'delete_article' && isset($json['id']))
294 {
295 $director = new Director($entityManager);
296 $director->makeArticleNode($json['id'], true);
297 $article = $director->getArticleNode();
298 $section = $director->getNode();
299
300 $entityManager->remove($article);
301 $section->removeChild($article);
302 $section->sortChildren(true); // régénère les positions
303 $entityManager->flush();
304
305 // test avec une nouvelle requête qui ne devrait rien trouver
306 if(!$director->makeArticleNode($json['id']))
307 {
308 echo json_encode(['success' => true]);
309
310 // on pourrait afficher une notification "toast"
311 }
312 else{
313 http_response_code(500);
314 echo json_encode(['success' => false, 'message' => 'Erreur lors de la suppression de l\'article.']);
315 }
316 die;
317 }
318 // inversion de la position de deux noeuds
319 elseif($_GET['action'] === 'switch_positions' && isset($json['id1']) && isset($json['id2']))
320 {
321 $director = new Director($entityManager);
322 $director->makeArticleNode($json['id1'], true);
323 $article1 = $director->getArticleNode();
324 $section = $director->getNode();
325
326 $section->sortChildren(true); // régénère les positions avant inversion
327
328 $article2;
329 foreach($section->getChildren() as $child){
330 if($child->getArticleTimestamp() === $json['id2']) // type string
331 {
332 $article2 = $child;
333 break;
334 }
335 }
336
337 // inversion
338 $tmp = $article1->getPosition();
339 $article1->setPosition($article2->getPosition());
340 $article2->setPosition($tmp);
341 $entityManager->flush();
342
343 echo json_encode(['success' => true]);
344 die;
345 }
346 elseif($_GET['action'] === 'date_submit' && isset($json['id']) && isset($json['date']))
347 {
348 $id = $json['id'];
349 $id[0] = 'i';
350 $date = new DateTime($json['date']);
351
352 $director = new Director($entityManager);
353 $director->makeArticleNode($id);
354 $node = $director->getArticleNode();
355 $node->getArticle()->setDateTime($date);
356 $entityManager->flush();
357
358 echo json_encode(['success' => true]);
359 die;
360 }
361
362
363 /* -- bloc Formulaire -- */
364 elseif($_GET['action'] === 'recipient_email'){
365 $email = htmlspecialchars(trim($json['email']));
366
367 if((filter_var($email, FILTER_VALIDATE_EMAIL) // nouvel e-mail
368 || ($json['email'] === '' && !empty(Config::$email_dest))) // e-mail par défaut
369 && isset($json['hidden']) && empty($json['hidden']))
370 {
371 $form_data = $entityManager->find('App\Entity\NodeData', $json['id']);
372 $form_data->updateData('email', $email);
373 $entityManager->persist($form_data);
374 $entityManager->flush();
375
376 echo json_encode(['success' => true]);
377 }
378 else{
379 echo json_encode(['success' => false]);
380 }
381 die;
382 }
383 elseif($_GET['action'] === 'test_email'){
384 // destinataire = e-mail par défaut dans config.ini OU choisi par l'utilisateur
385 $form_data = $entityManager->find('App\Entity\NodeData', $json['id']);
386 $recipient = $form_data->getData()['email'] ?? Config::$email_dest;
387
388 if(sendEmail($recipient, false, 'nom du visiteur', 'adresse@du_visiteur.fr', "TEST d'un envoi d'e-mail depuis le site web")){
389 echo json_encode(['success' => true]);
390 }
391 else{
392 echo json_encode(['success' => false]);
393 }
394 die;
395 }
396 }
397
398
399 /* -- page Menu et chemins -- */
400 elseif(isset($_GET['menu_edit']))
401 {
402 // récupération des données
403 $data = file_get_contents('php://input');
404 $json = json_decode($data, true);
405 Director::$menu_data = new Menu($entityManager);
406
407 // flèche gauche <=: position = position du parent + 1, parent = grand-parent, recalculer les positions
408 if($_GET['menu_edit'] === 'move_one_level_up' && isset($json['id'])){
409 $id = $json['id'];
410 $page = Director::$menu_data->findPageById((int)$id);
411
412 $parent = $page->getParent(); // peut être null
413 if($parent === null){
414 // 1er niveau: ne rien faire
415 echo json_encode(['success' => false]);
416 die;
417 }
418 // BDD
419 else{
420 $page->setPosition($parent->getPosition() + 1); // nouvelle position
421
422 // 2ème niveau: le parent devient $menu_data, puis null après tri
423 if($parent->getParent() === null){
424 // connexion dans les deux sens
425 $page->setParent(Director::$menu_data); // => pour la persistance
426
427 //Director::$menu_data->addChild($page); // => pour sortChildren
428 $page->getParent()->addChild($page); // => pour sortChildren
429 //Director::$menu_data->sortChildren(true); // positions décaléees des nouveaux petits frères
430 $page->getParent()->sortChildren(true); // positions décaléees des nouveaux petits frères
431 $page->setParent(null);
432
433 // affichage
434 $page->setPagePath($page->getEndOfPath());
435 $page->fillChildrenPagePath();
436 }
437 // 3ème niveau et plus
438 else{
439 $page->setParent($parent->getParent()); // nouveau parent
440 $page->getParent()->addChild($page); // => pour sortChildren
441 $page->getParent()->sortChildren(true); // positions décaléees des nouveaux petits frères
442 $page->fillChildrenPagePath($page->getParent()->getPagePath());
443 }
444 //$parent->sortChildren(true); // positions des enfants restants, inutile si la fonction est récursive?
445 $entityManager->flush();
446
447 // affichage
448 $parent->removeChild($page);
449 $nav_builder = new NavBuilder();
450 $menu_builder = new MenuBuilder(null, false);
451 echo json_encode(['success' => true, 'nav' => $nav_builder->render(), 'menu_buttons' => $menu_builder->render()]);
452 die;
453 }
454 }
455
456 // flèche droite =>: position = nombre d'éléments de la fraterie + 1, l'élément précédent devient le parent
457 if($_GET['menu_edit'] === 'move_one_level_down' && isset($json['id'])){
458 $id = $json['id'];
459 $page = Director::$menu_data->findPageById((int)$id);
460
461 $parent = $page->getParent(); // peut être null
462 if($parent == null){
463 $parent = Director::$menu_data;
464 }
465
466 // BDD
467 $parent->sortChildren(true); // trie et réindexe par sécurité: 1, 2, 3...
468 if($page->getPosition() > 1){
469 foreach($parent->getChildren() as $child){
470 if($child->getPosition() === $page->getPosition() - 1){
471 $page->setParent($child);
472 break;
473 }
474 }
475 $page->setPosition(count($page->getParent()->getChildren()) + 1);
476 }
477 $entityManager->flush();
478
479 // affichage
480 $parent->removeChild($page);
481 $page->getParent()->addChild($page);
482 $page->fillChildrenPagePath($page->getParent()->getPagePath()); // variable non mappée $page_path
483 $nav_builder = new NavBuilder();
484 $menu_builder = new MenuBuilder(null, false);
485
486 echo json_encode(['success' => true, 'nav' => $nav_builder->render(), 'menu_buttons' => $menu_builder->render()]);
487 die;
488 }
489
490 if($_GET['menu_edit'] === 'switch_positions' && isset($json['id1']) && isset($json['id2']))
491 {
492 $id1 = $json['id1'];
493 $id2 = $json['id2'];
494
495 // vérifier qu'ils ont le même parent
496 $page1 = Director::$menu_data->findPageById((int)$id1);
497 $page2 = Director::$menu_data->findPageById((int)$id2);
498
499 // double le contrôle fait en JS
500 if($page1->getParent() === $page2->getParent()) // comparaison stricte d'objet (même instance du parent?)
501 {
502 // inversion
503 $tmp = $page1->getPosition();
504 $page1->setPosition($page2->getPosition());
505 $page2->setPosition($tmp);
506 Director::$menu_data->sortChildren(true); // modifie tableau children
507 $entityManager->flush();
508
509 // nouveau menu
510 $nav_builder = new NavBuilder();
511 echo json_encode(['success' => true, 'nav' => $nav_builder->render()]);
512 }
513 else{
514 echo json_encode(['success' => false]);
515 }
516
517 die;
518 }
519
520 if($_GET['menu_edit'] === 'displayInMenu' && isset($json['id']) && isset($json['checked']))
521 {
522 $id = $json['id'];
523 $checked = $json['checked'];
524
525 $page = Director::$menu_data->findPageById((int)$id);
526 if($page->isHidden() === $checked){
527 $page->setHidden(!$checked);
528 $entityManager->flush();
529
530 // nouveau menu
531 $nav_builder = new NavBuilder();
532 echo json_encode(['success' => true, 'nav' => $nav_builder->render()]);
533 }
534 else{
535 echo json_encode(['success' => false]);
536 }
537 die;
538 }
539 }
540
541
542 /* -- mode Modification d'une page -- */
543
544 // partie "page"
545 elseif(isset($_GET['page_edit']))
546 {
547 // récupération des données
548 $data = file_get_contents('php://input');
549 $json = json_decode($data, true);
550
551 // titre de la page
552 if($_GET['page_edit'] === 'page_title'){
553 $page = $entityManager->find('App\Entity\Page', $json['page_id']);
554 $page->setPageName(htmlspecialchars($json['title']));
555 $entityManager->flush();
556 echo json_encode(['success' => true, 'title' => $page->getPageName()]);
557 }
558 // titre en snake_case pour le menu
559 /*elseif($_GET['page_edit'] === 'page_menu_path'){
560 $page = $entityManager->find('App\Entity\Page', $json['page_id']);
561 $page->setEndOfPath(htmlspecialchars($json['page_menu_path']));
562 $entityManager->flush();
563 echo json_encode(['success' => true, 'page_name_path' => $page->getEndOfPath()]);
564 }*/
565 // description dans les métadonnées
566 elseif($_GET['page_edit'] === 'page_description'){
567 $node_data = $entityManager->find('App\Entity\NodeData', $json['node_data_id']);
568 $node_data->updateData('description', htmlspecialchars($json['description']));
569 $entityManager->flush();
570 echo json_encode(['success' => true, 'description' => $node_data->getData()['description']]);
571 }
572 die;
573 }
574
575 // partie "blocs"
576 elseif(isset($_GET['bloc_edit']))
577 {
578 // renommage d'un bloc
579 if($_GET['bloc_edit'] === 'rename_page_bloc')
580 {
581 if(isset($json['bloc_title']) && $json['bloc_title'] !== null && isset($json['bloc_id']) && is_int($json['bloc_id'])){
582 $director = new Director($entityManager);
583 $director->findNodeById($json['bloc_id']);
584
585 // le titre (du JSON en BDD) est récupéré sous forme de tableau, modifié et renvoyé
586 $data = $director->getNode()->getNodeData()->getData();
587 $data['title'] = htmlspecialchars($json['bloc_title']);
588 $director->getNode()->getNodeData()->updateData('title', htmlspecialchars($json['bloc_title']));
589
590 $entityManager->flush();
591 echo json_encode(['success' => true, 'title' => $data['title']]);
592 }
593 else{
594 echo json_encode(['success' => false]);
595 }
596 die;
597 }
598 // inversion des positions de deux blocs
599 elseif($_GET['bloc_edit'] === 'switch_blocs_positions')
600 {
601 if(isset($json['id1']) && is_int($json['id1']) && isset($json['id2']) && is_int($json['id2']) && isset($_GET['page'])){
602 $director = new Director($entityManager, true);
603 $director->findUniqueNodeByName('main');
604 $director->findItsChildren();
605 $main = $director->getNode();
606 $main->sortChildren(true); // régénère les positions avant inversion
607
608 $bloc1; $bloc2;
609 foreach($main->getChildren() as $child){
610 if($child->getId() === $json['id1']){
611 $bloc1 = $child;
612 break;
613 }
614 }
615 foreach($main->getChildren() as $child){
616 if($child->getId() === $json['id2']){
617 $bloc2 = $child;
618 break;
619 }
620 }
621
622 // inversion
623 $tmp = $bloc1->getPosition();
624 $bloc1->setPosition($bloc2->getPosition());
625 $bloc2->setPosition($tmp);
626
627 $entityManager->flush();
628 echo json_encode(['success' => true]);
629 }
630 else{
631 echo json_encode(['success' => false]);
632 }
633 die;
634 }
635 }
636} \ No newline at end of file