summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorpolo <ordipolo@gmx.fr>2025-07-04 00:43:35 +0200
committerpolo <ordipolo@gmx.fr>2025-07-04 00:43:35 +0200
commit2d7bacce891eab0adb0263d598bfe44418788f42 (patch)
tree4353250f80cc556a278640f22c194a0033d05829 /src
parentea3eaf84c6de3f96d6bb73e817147f8571fd6c1f (diff)
downloadcms-2d7bacce891eab0adb0263d598bfe44418788f42.zip
formulaire de contact 3
Diffstat (limited to 'src')
-rw-r--r--src/Config.php14
-rw-r--r--src/controller/ajax.php640
-rw-r--r--src/controller/ajax_admin.php626
-rw-r--r--src/controller/post.php463
-rw-r--r--src/model/entities/Email.php41
-rw-r--r--src/model/entities/Log.php2
-rw-r--r--src/view/FormBuilder.php37
-rw-r--r--src/view/templates/form.php31
8 files changed, 1011 insertions, 843 deletions
diff --git a/src/Config.php b/src/Config.php
index 500d6ea..caa91d0 100644
--- a/src/Config.php
+++ b/src/Config.php
@@ -7,9 +7,9 @@ class Config
7{ 7{
8 // BDD 8 // BDD
9 static public string $db_host = 'localhost'; 9 static public string $db_host = 'localhost';
10 static public string $database = 'nageurs'; 10 static public string $database = '';
11 static public string $db_driver = 'pdo_mysql'; 11 static public string $db_driver = 'pdo_mysql';
12 static public string $user = 'root'; 12 static public string $user = '';
13 static public string $password = ''; 13 static public string $password = '';
14 static public string $table_prefix = ''; 14 static public string $table_prefix = '';
15 15
@@ -18,6 +18,16 @@ class Config
18 static public string $index_path = ''; 18 static public string $index_path = '';
19 static public string $port = '80'; 19 static public string $port = '80';
20 20
21 // e-mails
22 static public string $smtp_host = '';
23 static public string $smtp_username = '';
24 static public string $smtp_password = '';
25 static public string $smtp_secure = 'tls'; // tls (smarttls) ou ssl (smtps)
26 static public string $email_from = '';
27 static public string $email_from_name = 'site web';
28 static public string $email_dest = '';
29 static public string $email_dest_name = 'destinataire formulaire';
30
21 // copier dans ce tableau les variables contenant des chemins 31 // copier dans ce tableau les variables contenant des chemins
22 static private array $path_vars = []; 32 static private array $path_vars = [];
23 33
diff --git a/src/controller/ajax.php b/src/controller/ajax.php
index ae43b75..7529fe6 100644
--- a/src/controller/ajax.php
+++ b/src/controller/ajax.php
@@ -3,511 +3,89 @@
3 3
4declare(strict_types=1); 4declare(strict_types=1);
5 5
6use App\Entity\Page; 6use PHPMailer\PHPMailer\PHPMailer;
7use App\Entity\Node; 7use PHPMailer\PHPMailer\Exception;
8use App\Entity\Article; 8use App\Entity\Email;
9 9
10 10// mettre ça ailleurs?
11// mettre ça ailleurs 11function sendEmail(bool $true_email, string $name = '', string $email = '', string $message = ''): bool
12function imagickCleanImage(string $image_data, string $local_path, string $format = 'jpeg'): bool // "string" parce que file_get_contents...
13{
14 try{
15 $imagick = new Imagick();
16 $imagick->readImageBlob($image_data);
17 $imagick->stripImage(); // nettoyage métadonnées
18 $imagick->setImageFormat($format);
19 if($format === 'jpeg'){
20 $imagick->setImageCompression(Imagick::COMPRESSION_JPEG);
21 $imagick->setImageCompressionQuality(85); // optionnel
22 }
23 $imagick->writeImage($local_path); // enregistrement
24 $imagick->clear();
25 $imagick->destroy();
26 return true;
27 }
28 catch(Exception $e){
29 return false;
30 }
31}
32function curlDownloadImage(string $url, $maxRetries = 3, $timeout = 10): string|false
33{
34 $attempt = 0;
35 $imageData = false;
36
37 while($attempt < $maxRetries){
38 $ch = curl_init($url); // instance de CurlHandle
39 curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
40 curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
41 curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout);
42 curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
43 curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
44 curl_setopt($ch, CURLOPT_USERAGENT, 'TinyMCE-Image-Downloader');
45
46 $imageData = curl_exec($ch);
47 $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
48 //$curlError = curl_error($ch);
49
50 curl_close($ch);
51
52 if($imageData !== false && $httpCode >= 200 && $httpCode < 300){
53 return $imageData;
54 }
55
56 $attempt++;
57 sleep(1);
58 }
59
60 return false; // échec après trois tentatives
61}
62
63
64// détection des requêtes d'upload d'image de tinymce
65if(strpos($_SERVER['CONTENT_TYPE'], 'multipart/form-data') !== false && isset($_GET['action']) && $_GET['action'] === 'upload_image')
66{ 12{
67 if(isset($_FILES['file'])){ 13 $mail = new PHPMailer(true); // true => exceptions
68 $file = $_FILES['file']; 14 $mail->CharSet = 'UTF-8';
69 $dest = 'images/';
70 $dest_mini = 'images-mini/';
71
72 // Vérifier si les répertoires existent, sinon les créer
73 if(!is_dir($dest)) {
74 mkdir($dest, 0700, true);
75 }
76 if(!is_dir($dest_mini)) {
77 mkdir($dest_mini, 0700, true);
78 }
79
80 $allowed_extensions = ['jpg', 'jpeg', 'png', 'gif', 'webp', 'tiff', 'tif'];
81 $name = Security::secureFileName(pathinfo($file['name'], PATHINFO_FILENAME));
82 $extension = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION));
83 if(!in_array($extension, $allowed_extensions) || $extension === 'jpg'){
84 $extension = 'jpeg';
85 }
86 $file_path = $dest . $name . '_' . uniqid() . '.' . $extension;
87 15
88 // créer une miniature de l'image 16 try{
89 // 17 // Paramètres du serveur
90 18 $mail->isSMTP();
91 if(imagickCleanImage(file_get_contents($file['tmp_name']), $file_path, $extension)){ // recréer l’image pour la nettoyer 19 $mail->Host = Config::$smtp_host;
92 echo json_encode(['location' => $file_path]); // renvoyer l'URL de l'image téléchargée 20 $mail->SMTPAuth = true;
93 } 21 $mail->Port = 25;
94 else{
95 http_response_code(500);
96 echo json_encode(['message' => 'Erreur image non valide']);
97 }
98 }
99 else{
100 http_response_code(400);
101 echo json_encode(['message' => 'Erreur 400: Bad Request']);
102 }
103 die;
104}
105// 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
106elseif(isset($_GET['action']) && $_GET['action'] == 'upload_image_url'){
107 $json = json_decode(file_get_contents('php://input'), true);
108
109 if(isset($json['image_url'])){
110 $image_data = curlDownloadImage($json['image_url']); // téléchargement de l’image par le serveur avec cURL au lieu de file_get_contents
111 $dest = 'images/';
112
113 if(!is_dir($dest)) { // Vérifier si le répertoire existe, sinon le créer
114 mkdir($dest, 0777, true);
115 }
116
117 if($image_data === false){
118 http_response_code(400);
119 echo json_encode(['message' => "Erreur, le serveur n'a pas réussi à télécharger l'image."]);
120 die;
121 }
122
123 $allowed_extensions = ['jpg', 'jpeg', 'png', 'gif', 'webp', 'tiff', 'tif'];
124 $url_path = parse_url($json['image_url'], PHP_URL_PATH);
125 $name = Security::secureFileName(pathinfo($url_path, PATHINFO_FILENAME));
126 $extension = strtolower(pathinfo($url_path, PATHINFO_EXTENSION));
127 if(!in_array($extension, $allowed_extensions) || $extension === 'jpg'){
128 $extension = 'jpeg';
129 }
130 $local_path = $dest . $name . '_' . uniqid() . '.' . $extension;
131 22
132 if(imagickCleanImage($image_data, $local_path, $extension)){ // recréer l’image pour la nettoyer 23 if($mail->SMTPAuth){
133 echo json_encode(['location' => $local_path]); // nouvelle adresse 24 $mail->Username = Config::$smtp_username; // e-mail
25 $mail->Password = Config::$smtp_password;
26 $mail->SMTPSecure = Config::$smtp_secure; // tls (starttls) ou ssl (smtps)
27 if($mail->SMTPSecure === 'tls'){
28 $mail->Port = 587;
29 }
30 elseif($mail->SMTPSecure === 'ssl'){
31 $mail->Port = 465;
32 }
134 } 33 }
135 else{ 34 //var_dump($mail->smtpConnect());die; // test de connexion
136 http_response_code(500);
137 echo json_encode(['message' => 'Erreur image non valide']);
138 }
139 }
140 else{
141 echo json_encode(['message' => 'Erreur 400: Bad Request']);
142 }
143 die;
144}
145// cas du collage d'une image (code base64) non encapsulée dans du HTML
146elseif(isset($_GET['action']) && $_GET['action'] == 'upload_image_base64'){
147 $json = json_decode(file_get_contents('php://input'), true);
148 $dest = 'images/';
149 35
150 if(!is_dir('images')){ 36 // Expéditeur et destinataire
151 mkdir('images', 0777, true); 37 $mail->setFrom(strtolower(Config::$email_from), Config::$email_from_name); // expéditeur
152 } 38 $mail->addAddress(strtolower(Config::$email_dest), Config::$email_dest_name); // destinataire
153
154 // détection de data:image/ et de ;base64, et capture du format dans $type
155 if(!isset($json['image_base64']) || !preg_match('/^data:image\/(\w+);base64,/', $json['image_base64'], $type)){
156 http_response_code(400);
157 echo json_encode(['message' => 'Données image base64 manquantes ou invalides']);
158 die;
159 }
160
161 $allowed_extensions = ['jpg', 'jpeg', 'png', 'gif', 'webp', 'tiff', 'tif'];
162 $extension = strtolower($type[1]);
163 if(!in_array($extension, $allowed_extensions) || $extension === 'jpg'){
164 $extension = 'jpeg';
165 }
166 39
167 $image_data = base64_decode(substr($json['image_base64'], strpos($json['image_base64'], ',') + 1)); // découpe la chaine à la virgule puis convertit en binaire 40 // Contenu
168 if($image_data === false){ 41 $mail->isHTML(true);
169 http_response_code(400); 42 if($true_email){
170 echo json_encode(['message' => 'Décodage base64 invalide']); 43 $mail->Subject = 'Message envoyé par: ' . $name . ' (' . $email . ') depuis le site web';
171 die; 44
172 } 45 }
173 46 else{
174 $local_path = $dest . 'pasted_image_' . uniqid() . '.' . $extension; 47 $mail->Subject = "TEST d'un envoi d'e-mail depuis le site web";
48 }
49 $mail->Body = $message;
50 $mail->AltBody = $message;
175 51
176 if(imagickCleanImage($image_data, $local_path)){ 52 $mail->send();
177 echo json_encode(['location' => $local_path]); 53 return true;
178 } 54 }
179 else{ 55 catch(Exception $e){
180 http_response_code(500); 56 return false;
181 echo json_encode(['message' => 'Erreur image non valide']); 57 //echo "Le message n'a pas pu être envoyé. Erreur : {$mail->ErrorInfo}";
182 } 58 }
183 die;
184} 59}
185 60
186// détection des requêtes de type XHR, y en a pas à priori
187/*elseif(isset($_SERVER['HTTP_X_REQUESTED_WITH']) && $_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest'){
188 echo "requête XHR reçue par le serveur";
189 die;
190}*/
191
192 61
193// détection des requêtes envoyées avec fetch (application/json) et récupération du JSON 62// détection des requêtes envoyées avec fetch (application/json) et récupération du JSON
194if($_SERVER['CONTENT_TYPE'] === 'application/json'){ 63if($_SERVER['CONTENT_TYPE'] === 'application/json')
64{
195 $data = file_get_contents('php://input'); 65 $data = file_get_contents('php://input');
196 $json = json_decode($data, true); 66 $json = json_decode($data, true);
197 67
198 // requêtes de tinymce ou touchant aux articles 68 // requêtes de tinymce ou touchant aux articles
199 if(isset($_GET['action'])) 69 if(isset($_GET['action']))
200 { 70 {
201 if($_GET['action'] === 'editor_submit' && isset($json['id']) && isset($json['content'])) 71 // e-mail envoyé par le formulaire de contact
202 { 72 if($_GET['action'] === 'send_email'){
203 if(json_last_error() === JSON_ERROR_NONE) 73 $captcha_solution = (isset($_SESSION['captcha']) && is_int($_SESSION['captcha'])) ? $_SESSION['captcha'] : 0;
204 { 74 $captcha_try = isset($json['captcha']) ? Captcha::controlInput($json['captcha']) : 0;
205 $id = $json['id']; 75
206 $director = new Director($entityManager); 76 // contrôles des entrées
207 77 $name = htmlspecialchars(trim($json['name']));
208 // cas d'une nouvelle "news" 78 $email = strtolower(htmlspecialchars(trim($json['email'])));
209 if(is_array($json['content'])){ 79 $message = htmlspecialchars(trim($json['message']));
210 foreach($json['content'] as $one_input){
211 $one_input = Security::secureString($one_input);
212 }
213 $content = $json['content'];
214 }
215 else{
216 $content = Security::secureString($json['content']);
217 }
218
219 // nouvel article
220 if($id[0] === 'n')
221 {
222 $section_id = (int)substr($id, 1); // id du bloc <section>
223 $director->findNodeById($section_id);
224 $director->makeSectionNode();
225 $node = $director->getNode(); // = <section>
226
227 if(is_array($content)){
228 $date = new \DateTime($content['d']);
229 $article = new Article($content['i'], $date, $content['t'], $content['p']);
230 $article_node = new Node('new', 'i' . (string)$date->getTimestamp(), [], count($node->getChildren()) + 1, $node, $node->getPage(), $article);
231
232 // id_node tout juste généré
233 //$article_node->getId();
234 }
235 else{
236 $timestamp = time();
237 $date = new \DateTime;
238 $date->setTimestamp($timestamp);
239
240 $article = new Article($content, $date); // le "current" timestamp est obtenu par la BDD
241 $article_node = new Node('article', 'i' . (string)$timestamp, [], count($node->getChildren()) + 1, $node, $node->getPage(), $article);
242 }
243
244 $entityManager->persist($article_node);
245 $entityManager->flush();
246
247 echo json_encode(['success' => true, 'article_id' => $article_node->getArticleTimestamp()]);
248 die;
249 }
250 // modification article
251 else{
252 $id[0] = 'i'; // id de l'article node
253 }
254
255 if($director->makeArticleNode($id)) // une entrée est trouvée
256 {
257 $node = $director->getArticleNode(); // article
258 switch($json['id'][0]){
259 case 'i':
260 $node->getArticle()->setContent($content);
261 break;
262 case 'p':
263 $node->getArticle()->setPreview($content); // html de l'éditeur
264 break;
265 case 't':
266 $node->getArticle()->setTitle($content); // html de l'éditeur
267 break;
268 case 'd':
269 echo json_encode(['success' => false, 'message' => 'l\'action editor_submit ne supporte pas les dates, utiliser date_submit.']);
270 die;
271 default:
272 echo json_encode(['success' => false, 'message' => 'identifiant non utilisable']);
273 die;
274 }
275 $entityManager->flush();
276 echo json_encode(['success' => true]);
277 }
278 else
279 {
280 echo json_encode(['success' => false, 'message' => 'article non identifié']);
281 }
282 }
283 else{
284 echo json_encode(['success' => false, 'message' => 'Erreur de décodage JSON']);
285 }
286 die;
287 }
288 elseif($_GET['action'] === 'delete_article' && isset($json['id']))
289 {
290 $director = new Director($entityManager);
291 $director->makeArticleNode($json['id'], true);
292 $article = $director->getArticleNode();
293 $section = $director->getNode();
294
295 $entityManager->remove($article);
296 $section->removeChild($article);
297 $section->sortChildren(true); // régénère les positions
298 $entityManager->flush();
299
300 // test avec une nouvelle requête qui ne devrait rien trouver
301 if(!$director->makeArticleNode($json['id']))
302 {
303 echo json_encode(['success' => true]);
304
305 // on pourrait afficher une notification "toast"
306 }
307 else{
308 http_response_code(500);
309 echo json_encode(['success' => false, 'message' => 'Erreur lors de la suppression de l\'article.']);
310 }
311 die;
312 }
313 // inversion de la position de deux noeuds
314 elseif($_GET['action'] === 'switch_positions' && isset($json['id1']) && isset($json['id2']))
315 {
316 $director = new Director($entityManager);
317 $director->makeArticleNode($json['id1'], true);
318 $article1 = $director->getArticleNode();
319 $section = $director->getNode();
320
321 $section->sortChildren(true); // régénère les positions avant inversion
322
323 $article2;
324 foreach($section->getChildren() as $child){
325 if($child->getArticleTimestamp() === $json['id2']) // type string
326 {
327 $article2 = $child;
328 break;
329 }
330 }
331
332 // inversion
333 $tmp = $article1->getPosition();
334 $article1->setPosition($article2->getPosition());
335 $article2->setPosition($tmp);
336 $entityManager->flush();
337
338 echo json_encode(['success' => true]);
339 die;
340 }
341 elseif($_GET['action'] === 'date_submit' && isset($json['id']) && isset($json['date']))
342 {
343 $id = $json['id'];
344 $id[0] = 'i';
345 $date = new DateTime($json['date']);
346
347 $director = new Director($entityManager);
348 $director->makeArticleNode($id);
349 $node = $director->getArticleNode();
350 $node->getArticle()->setDateTime($date);
351 $entityManager->flush();
352 80
353 echo json_encode(['success' => true]); 81 if($captcha_try != 0 && $captcha_solution != 0 && ($captcha_try === $captcha_solution)
354 die; 82 && filter_var($email, FILTER_VALIDATE_EMAIL) && isset($json['hidden']) && empty($json['hidden'])
355 } 83 && sendEmail(true, $name, $email, $message))
356 84 {
357 // config formulaire 85 $db_email = new Email(strtolower(Config::$email_from), strtolower(Config::$email_dest), $message);
358 elseif($_GET['action'] === 'recipient_email'){ 86 $entityManager->persist($db_email);
359 $form_data = $entityManager->find('App\Entity\NodeData', $json['id']);
360 $email = htmlspecialchars(trim($json['email']));
361
362 if(filter_var($email, FILTER_VALIDATE_EMAIL)){
363 $form_data->updateData('email', $json['email']);
364 $entityManager->persist($form_data);
365 $entityManager->flush();
366 echo json_encode(['success' => true]);
367 die;
368 }
369 else{
370 echo json_encode(['success' => false]);
371 die;
372 }
373 }
374 }
375
376
377 /* -- page Menu et chemins -- */
378 elseif(isset($_GET['menu_edit']))
379 {
380 // récupération des données
381 $data = file_get_contents('php://input');
382 $json = json_decode($data, true);
383 Director::$menu_data = new Menu($entityManager);
384
385 // flèche gauche <=: position = position du parent + 1, parent = grand-parent, recalculer les positions
386 if($_GET['menu_edit'] === 'move_one_level_up' && isset($json['id'])){
387 $id = $json['id'];
388 $page = Director::$menu_data->findPageById((int)$id);
389
390 $parent = $page->getParent(); // peut être null
391 if($parent === null){
392 // 1er niveau: ne rien faire
393 echo json_encode(['success' => false]);
394 die;
395 }
396 // BDD
397 else{
398 $page->setPosition($parent->getPosition() + 1); // nouvelle position
399
400 // 2ème niveau: le parent devient $menu_data, puis null après tri
401 if($parent->getParent() === null){
402 // connexion dans les deux sens
403 $page->setParent(Director::$menu_data); // => pour la persistance
404
405 //Director::$menu_data->addChild($page); // => pour sortChildren
406 $page->getParent()->addChild($page); // => pour sortChildren
407 //Director::$menu_data->sortChildren(true); // positions décaléees des nouveaux petits frères
408 $page->getParent()->sortChildren(true); // positions décaléees des nouveaux petits frères
409 $page->setParent(null);
410
411 // affichage
412 $page->setPagePath($page->getEndOfPath());
413 $page->fillChildrenPagePath();
414 }
415 // 3ème niveau et plus
416 else{
417 $page->setParent($parent->getParent()); // nouveau parent
418 $page->getParent()->addChild($page); // => pour sortChildren
419 $page->getParent()->sortChildren(true); // positions décaléees des nouveaux petits frères
420 $page->fillChildrenPagePath($page->getParent()->getPagePath());
421 }
422 //$parent->sortChildren(true); // positions des enfants restants, inutile si la fonction est récursive?
423 $entityManager->flush();
424
425 // affichage
426 $parent->removeChild($page);
427 $nav_builder = new NavBuilder();
428 $menu_builder = new MenuBuilder(null, false);
429 echo json_encode(['success' => true, 'nav' => $nav_builder->render(), 'menu_buttons' => $menu_builder->render()]);
430 die;
431 }
432 }
433
434 // flèche droite =>: position = nombre d'éléments de la fraterie + 1, l'élément précédent devient le parent
435 if($_GET['menu_edit'] === 'move_one_level_down' && isset($json['id'])){
436 $id = $json['id'];
437 $page = Director::$menu_data->findPageById((int)$id);
438
439 $parent = $page->getParent(); // peut être null
440 if($parent == null){
441 $parent = Director::$menu_data;
442 }
443
444 // BDD
445 $parent->sortChildren(true); // trie et réindexe par sécurité: 1, 2, 3...
446 if($page->getPosition() > 1){
447 foreach($parent->getChildren() as $child){
448 if($child->getPosition() === $page->getPosition() - 1){
449 $page->setParent($child);
450 break;
451 }
452 }
453 $page->setPosition(count($page->getParent()->getChildren()) + 1);
454 }
455 $entityManager->flush();
456
457 // affichage
458 $parent->removeChild($page);
459 $page->getParent()->addChild($page);
460 $page->fillChildrenPagePath($page->getParent()->getPagePath()); // variable non mappée $page_path
461 $nav_builder = new NavBuilder();
462 $menu_builder = new MenuBuilder(null, false);
463
464 echo json_encode(['success' => true, 'nav' => $nav_builder->render(), 'menu_buttons' => $menu_builder->render()]);
465 die;
466 }
467
468 if($_GET['menu_edit'] === 'switch_positions' && isset($json['id1']) && isset($json['id2']))
469 {
470 $id1 = $json['id1'];
471 $id2 = $json['id2'];
472
473 // vérifier qu'ils ont le même parent
474 $page1 = Director::$menu_data->findPageById((int)$id1);
475 $page2 = Director::$menu_data->findPageById((int)$id2);
476
477 // double le contrôle fait en JS
478 if($page1->getParent() === $page2->getParent()) // comparaison stricte d'objet (même instance du parent?)
479 {
480 // inversion
481 $tmp = $page1->getPosition();
482 $page1->setPosition($page2->getPosition());
483 $page2->setPosition($tmp);
484 Director::$menu_data->sortChildren(true); // modifie tableau children
485 $entityManager->flush(); 87 $entityManager->flush();
486 88 echo json_encode(['success' => true]);
487 // nouveau menu
488 $nav_builder = new NavBuilder();
489 echo json_encode(['success' => true, 'nav' => $nav_builder->render()]);
490 }
491 else{
492 echo json_encode(['success' => false]);
493 }
494
495 die;
496 }
497
498 if($_GET['menu_edit'] === 'displayInMenu' && isset($json['id']) && isset($json['checked']))
499 {
500 $id = $json['id'];
501 $checked = $json['checked'];
502
503 $page = Director::$menu_data->findPageById((int)$id);
504 if($page->isHidden() === $checked){
505 $page->setHidden(!$checked);
506 $entityManager->flush();
507
508 // nouveau menu
509 $nav_builder = new NavBuilder();
510 echo json_encode(['success' => true, 'nav' => $nav_builder->render()]);
511 } 89 }
512 else{ 90 else{
513 echo json_encode(['success' => false]); 91 echo json_encode(['success' => false]);
@@ -515,100 +93,4 @@ if($_SERVER['CONTENT_TYPE'] === 'application/json'){
515 die; 93 die;
516 } 94 }
517 } 95 }
518
519
520 /* -- mode Modification d'une page -- */
521
522 // partie "page"
523 elseif(isset($_GET['page_edit']))
524 {
525 // récupération des données
526 $data = file_get_contents('php://input');
527 $json = json_decode($data, true);
528
529 // titre de la page
530 if($_GET['page_edit'] === 'page_title'){
531 $page = $entityManager->find('App\Entity\Page', $json['page_id']);
532 $page->setPageName(htmlspecialchars($json['title']));
533 $entityManager->flush();
534 echo json_encode(['success' => true, 'title' => $page->getPageName()]);
535 }
536 // titre en snake_case pour le menu
537 /*elseif($_GET['page_edit'] === 'page_menu_path'){
538 $page = $entityManager->find('App\Entity\Page', $json['page_id']);
539 $page->setEndOfPath(htmlspecialchars($json['page_menu_path']));
540 $entityManager->flush();
541 echo json_encode(['success' => true, 'page_name_path' => $page->getEndOfPath()]);
542 }*/
543 // description dans les métadonnées
544 elseif($_GET['page_edit'] === 'page_description'){
545 $node_data = $entityManager->find('App\Entity\NodeData', $json['node_data_id']);
546 $node_data->updateData('description', htmlspecialchars($json['description']));
547 $entityManager->flush();
548 echo json_encode(['success' => true, 'description' => $node_data->getData()['description']]);
549 }
550 die;
551 }
552
553 // partie "blocs"
554 elseif(isset($_GET['bloc_edit']))
555 {
556 // renommage d'un bloc
557 if($_GET['bloc_edit'] === 'rename_page_bloc')
558 {
559 if(isset($json['bloc_title']) && $json['bloc_title'] !== null && isset($json['bloc_id']) && is_int($json['bloc_id'])){
560 $director = new Director($entityManager);
561 $director->findNodeById($json['bloc_id']);
562
563 // le titre (du JSON en BDD) est récupéré sous forme de tableau, modifié et renvoyé
564 $data = $director->getNode()->getNodeData()->getData();
565 $data['title'] = htmlspecialchars($json['bloc_title']);
566 $director->getNode()->getNodeData()->updateData('title', htmlspecialchars($json['bloc_title']));
567
568 $entityManager->flush();
569 echo json_encode(['success' => true, 'title' => $data['title']]);
570 }
571 else{
572 echo json_encode(['success' => false]);
573 }
574 die;
575 }
576 // inversion des positions de deux blocs
577 elseif($_GET['bloc_edit'] === 'switch_blocs_positions')
578 {
579 if(isset($json['id1']) && is_int($json['id1']) && isset($json['id2']) && is_int($json['id2']) && isset($_GET['page'])){
580 $director = new Director($entityManager, true);
581 $director->findUniqueNodeByName('main');
582 $director->findItsChildren();
583 $main = $director->getNode();
584 $main->sortChildren(true); // régénère les positions avant inversion
585
586 $bloc1; $bloc2;
587 foreach($main->getChildren() as $child){
588 if($child->getId() === $json['id1']){
589 $bloc1 = $child;
590 break;
591 }
592 }
593 foreach($main->getChildren() as $child){
594 if($child->getId() === $json['id2']){
595 $bloc2 = $child;
596 break;
597 }
598 }
599
600 // inversion
601 $tmp = $bloc1->getPosition();
602 $bloc1->setPosition($bloc2->getPosition());
603 $bloc2->setPosition($tmp);
604
605 $entityManager->flush();
606 echo json_encode(['success' => true]);
607 }
608 else{
609 echo json_encode(['success' => false]);
610 }
611 die;
612 }
613 }
614} \ No newline at end of file 96} \ No newline at end of file
diff --git a/src/controller/ajax_admin.php b/src/controller/ajax_admin.php
new file mode 100644
index 0000000..944e84b
--- /dev/null
+++ b/src/controller/ajax_admin.php
@@ -0,0 +1,626 @@
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
62
63// détection des requêtes d'upload d'image de tinymce
64if(strpos($_SERVER['CONTENT_TYPE'], 'multipart/form-data') !== false && isset($_GET['action']) && $_GET['action'] === 'upload_image')
65{
66 if(isset($_FILES['file'])){
67 $file = $_FILES['file'];
68 $dest = 'images/';
69 $dest_mini = 'images-mini/';
70
71 // Vérifier si les répertoires existent, sinon les créer
72 if(!is_dir($dest)) {
73 mkdir($dest, 0700, true);
74 }
75 if(!is_dir($dest_mini)) {
76 mkdir($dest_mini, 0700, true);
77 }
78
79 $allowed_extensions = ['jpg', 'jpeg', 'png', 'gif', 'webp', 'tiff', 'tif'];
80 $name = Security::secureFileName(pathinfo($file['name'], PATHINFO_FILENAME));
81 $extension = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION));
82 if(!in_array($extension, $allowed_extensions) || $extension === 'jpg'){
83 $extension = 'jpeg';
84 }
85 $file_path = $dest . $name . '_' . uniqid() . '.' . $extension;
86
87 // créer une miniature de l'image
88 //
89
90 if(imagickCleanImage(file_get_contents($file['tmp_name']), $file_path, $extension)){ // recréer l’image pour la nettoyer
91 echo json_encode(['location' => $file_path]); // renvoyer l'URL de l'image téléchargée
92 }
93 else{
94 http_response_code(500);
95 echo json_encode(['message' => 'Erreur image non valide']);
96 }
97 }
98 else{
99 http_response_code(400);
100 echo json_encode(['message' => 'Erreur 400: Bad Request']);
101 }
102 die;
103}
104// 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
105elseif(isset($_GET['action']) && $_GET['action'] == 'upload_image_url')
106{
107 $json = json_decode(file_get_contents('php://input'), true);
108
109 if(isset($json['image_url'])){
110 $image_data = curlDownloadImage($json['image_url']); // téléchargement de l’image par le serveur avec cURL au lieu de file_get_contents
111 $dest = 'images/';
112
113 if(!is_dir($dest)) { // Vérifier si le répertoire existe, sinon le créer
114 mkdir($dest, 0777, true);
115 }
116
117 if($image_data === false){
118 http_response_code(400);
119 echo json_encode(['message' => "Erreur, le serveur n'a pas réussi à télécharger l'image."]);
120 die;
121 }
122
123 $allowed_extensions = ['jpg', 'jpeg', 'png', 'gif', 'webp', 'tiff', 'tif'];
124 $url_path = parse_url($json['image_url'], PHP_URL_PATH);
125 $name = Security::secureFileName(pathinfo($url_path, PATHINFO_FILENAME));
126 $extension = strtolower(pathinfo($url_path, PATHINFO_EXTENSION));
127 if(!in_array($extension, $allowed_extensions) || $extension === 'jpg'){
128 $extension = 'jpeg';
129 }
130 $local_path = $dest . $name . '_' . uniqid() . '.' . $extension;
131
132 if(imagickCleanImage($image_data, $local_path, $extension)){ // recréer l’image pour la nettoyer
133 echo json_encode(['location' => $local_path]); // nouvelle adresse
134 }
135 else{
136 http_response_code(500);
137 echo json_encode(['message' => 'Erreur image non valide']);
138 }
139 }
140 else{
141 echo json_encode(['message' => 'Erreur 400: Bad Request']);
142 }
143 die;
144}
145// cas du collage d'une image (code base64) non encapsulée dans du HTML
146elseif(isset($_GET['action']) && $_GET['action'] == 'upload_image_base64')
147{
148 $json = json_decode(file_get_contents('php://input'), true);
149 $dest = 'images/';
150
151 if(!is_dir('images')){
152 mkdir('images', 0777, true);
153 }
154
155 // détection de data:image/ et de ;base64, et capture du format dans $type
156 if(!isset($json['image_base64']) || !preg_match('/^data:image\/(\w+);base64,/', $json['image_base64'], $type)){
157 http_response_code(400);
158 echo json_encode(['message' => 'Données image base64 manquantes ou invalides']);
159 die;
160 }
161
162 $allowed_extensions = ['jpg', 'jpeg', 'png', 'gif', 'webp', 'tiff', 'tif'];
163 $extension = strtolower($type[1]);
164 if(!in_array($extension, $allowed_extensions) || $extension === 'jpg'){
165 $extension = 'jpeg';
166 }
167
168 $image_data = base64_decode(substr($json['image_base64'], strpos($json['image_base64'], ',') + 1)); // découpe la chaine à la virgule puis convertit en binaire
169 if($image_data === false){
170 http_response_code(400);
171 echo json_encode(['message' => 'Décodage base64 invalide']);
172 die;
173 }
174
175 $local_path = $dest . 'pasted_image_' . uniqid() . '.' . $extension;
176
177 if(imagickCleanImage($image_data, $local_path)){
178 echo json_encode(['location' => $local_path]);
179 }
180 else{
181 http_response_code(500);
182 echo json_encode(['message' => 'Erreur image non valide']);
183 }
184 die;
185}
186
187// détection des requêtes de type XHR, y en a pas à priori
188/*elseif(isset($_SERVER['HTTP_X_REQUESTED_WITH']) && $_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest'){
189 echo "requête XHR reçue par le serveur";
190 die;
191}*/
192
193
194// détection des requêtes envoyées avec fetch (application/json) et récupération du JSON
195if($_SERVER['CONTENT_TYPE'] === 'application/json')
196{
197 $data = file_get_contents('php://input');
198 $json = json_decode($data, true);
199
200 // requêtes de tinymce ou touchant aux articles
201 if(isset($_GET['action']))
202 {
203 if($_GET['action'] === 'editor_submit' && isset($json['id']) && isset($json['content']))
204 {
205 if(json_last_error() === JSON_ERROR_NONE)
206 {
207 $id = $json['id'];
208 $director = new Director($entityManager);
209
210 // cas d'une nouvelle "news"
211 if(is_array($json['content'])){
212 foreach($json['content'] as $one_input){
213 $one_input = Security::secureString($one_input);
214 }
215 $content = $json['content'];
216 }
217 else{
218 $content = Security::secureString($json['content']);
219 }
220
221 // nouvel article
222 if($id[0] === 'n')
223 {
224 $section_id = (int)substr($id, 1); // id du bloc <section>
225 $director->findNodeById($section_id);
226 $director->makeSectionNode();
227 $node = $director->getNode(); // = <section>
228
229 if(is_array($content)){
230 $date = new \DateTime($content['d']);
231 $article = new Article($content['i'], $date, $content['t'], $content['p']);
232 $article_node = new Node('new', 'i' . (string)$date->getTimestamp(), [], count($node->getChildren()) + 1, $node, $node->getPage(), $article);
233
234 // id_node tout juste généré
235 //$article_node->getId();
236 }
237 else{
238 $timestamp = time();
239 $date = new \DateTime;
240 $date->setTimestamp($timestamp);
241
242 $article = new Article($content, $date); // le "current" timestamp est obtenu par la BDD
243 $article_node = new Node('article', 'i' . (string)$timestamp, [], count($node->getChildren()) + 1, $node, $node->getPage(), $article);
244 }
245
246 $entityManager->persist($article_node);
247 $entityManager->flush();
248
249 echo json_encode(['success' => true, 'article_id' => $article_node->getArticleTimestamp()]);
250 die;
251 }
252 // modification article
253 else{
254 $id[0] = 'i'; // id de l'article node
255 }
256
257 if($director->makeArticleNode($id)) // une entrée est trouvée
258 {
259 $node = $director->getArticleNode(); // article
260 switch($json['id'][0]){
261 case 'i':
262 $node->getArticle()->setContent($content);
263 break;
264 case 'p':
265 $node->getArticle()->setPreview($content); // html de l'éditeur
266 break;
267 case 't':
268 $node->getArticle()->setTitle($content); // html de l'éditeur
269 break;
270 case 'd':
271 echo json_encode(['success' => false, 'message' => 'l\'action editor_submit ne supporte pas les dates, utiliser date_submit.']);
272 die;
273 default:
274 echo json_encode(['success' => false, 'message' => 'identifiant non utilisable']);
275 die;
276 }
277 $entityManager->flush();
278 echo json_encode(['success' => true]);
279 }
280 else
281 {
282 echo json_encode(['success' => false, 'message' => 'article non identifié']);
283 }
284 }
285 else{
286 echo json_encode(['success' => false, 'message' => 'Erreur de décodage JSON']);
287 }
288 die;
289 }
290 elseif($_GET['action'] === 'delete_article' && isset($json['id']))
291 {
292 $director = new Director($entityManager);
293 $director->makeArticleNode($json['id'], true);
294 $article = $director->getArticleNode();
295 $section = $director->getNode();
296
297 $entityManager->remove($article);
298 $section->removeChild($article);
299 $section->sortChildren(true); // régénère les positions
300 $entityManager->flush();
301
302 // test avec une nouvelle requête qui ne devrait rien trouver
303 if(!$director->makeArticleNode($json['id']))
304 {
305 echo json_encode(['success' => true]);
306
307 // on pourrait afficher une notification "toast"
308 }
309 else{
310 http_response_code(500);
311 echo json_encode(['success' => false, 'message' => 'Erreur lors de la suppression de l\'article.']);
312 }
313 die;
314 }
315 // inversion de la position de deux noeuds
316 elseif($_GET['action'] === 'switch_positions' && isset($json['id1']) && isset($json['id2']))
317 {
318 $director = new Director($entityManager);
319 $director->makeArticleNode($json['id1'], true);
320 $article1 = $director->getArticleNode();
321 $section = $director->getNode();
322
323 $section->sortChildren(true); // régénère les positions avant inversion
324
325 $article2;
326 foreach($section->getChildren() as $child){
327 if($child->getArticleTimestamp() === $json['id2']) // type string
328 {
329 $article2 = $child;
330 break;
331 }
332 }
333
334 // inversion
335 $tmp = $article1->getPosition();
336 $article1->setPosition($article2->getPosition());
337 $article2->setPosition($tmp);
338 $entityManager->flush();
339
340 echo json_encode(['success' => true]);
341 die;
342 }
343 elseif($_GET['action'] === 'date_submit' && isset($json['id']) && isset($json['date']))
344 {
345 $id = $json['id'];
346 $id[0] = 'i';
347 $date = new DateTime($json['date']);
348
349 $director = new Director($entityManager);
350 $director->makeArticleNode($id);
351 $node = $director->getArticleNode();
352 $node->getArticle()->setDateTime($date);
353 $entityManager->flush();
354
355 echo json_encode(['success' => true]);
356 die;
357 }
358
359 // config formulaire
360 /*elseif($_GET['action'] === 'recipient_email'){
361 $email = htmlspecialchars(trim($json['email']));
362
363 if(filter_var($email, FILTER_VALIDATE_EMAIL) && isset($json['hidden']) && empty($json['hidden'])){
364 $form_data = $entityManager->find('App\Entity\NodeData', $json['id']);
365 $form_data->updateData('email', $json['email']);
366 $entityManager->persist($form_data);
367 $entityManager->flush();
368
369 echo json_encode(['success' => true]);
370 }
371 else{
372 echo json_encode(['success' => false]);
373 }
374 die;
375 }*/
376 // e-mail de test
377 elseif($_GET['action'] === 'test_email'){
378 if(sendEmail(false, 'nom du visiteur', 'adresse@du_visiteur.fr', "TEST d'un envoi d'e-mail depuis le site web")){
379 echo json_encode(['success' => true]);
380 }
381 else{
382 echo json_encode(['success' => false]);
383 }
384 die;
385 }
386 }
387
388
389 /* -- page Menu et chemins -- */
390 elseif(isset($_GET['menu_edit']))
391 {
392 // récupération des données
393 $data = file_get_contents('php://input');
394 $json = json_decode($data, true);
395 Director::$menu_data = new Menu($entityManager);
396
397 // flèche gauche <=: position = position du parent + 1, parent = grand-parent, recalculer les positions
398 if($_GET['menu_edit'] === 'move_one_level_up' && isset($json['id'])){
399 $id = $json['id'];
400 $page = Director::$menu_data->findPageById((int)$id);
401
402 $parent = $page->getParent(); // peut être null
403 if($parent === null){
404 // 1er niveau: ne rien faire
405 echo json_encode(['success' => false]);
406 die;
407 }
408 // BDD
409 else{
410 $page->setPosition($parent->getPosition() + 1); // nouvelle position
411
412 // 2ème niveau: le parent devient $menu_data, puis null après tri
413 if($parent->getParent() === null){
414 // connexion dans les deux sens
415 $page->setParent(Director::$menu_data); // => pour la persistance
416
417 //Director::$menu_data->addChild($page); // => pour sortChildren
418 $page->getParent()->addChild($page); // => pour sortChildren
419 //Director::$menu_data->sortChildren(true); // positions décaléees des nouveaux petits frères
420 $page->getParent()->sortChildren(true); // positions décaléees des nouveaux petits frères
421 $page->setParent(null);
422
423 // affichage
424 $page->setPagePath($page->getEndOfPath());
425 $page->fillChildrenPagePath();
426 }
427 // 3ème niveau et plus
428 else{
429 $page->setParent($parent->getParent()); // nouveau parent
430 $page->getParent()->addChild($page); // => pour sortChildren
431 $page->getParent()->sortChildren(true); // positions décaléees des nouveaux petits frères
432 $page->fillChildrenPagePath($page->getParent()->getPagePath());
433 }
434 //$parent->sortChildren(true); // positions des enfants restants, inutile si la fonction est récursive?
435 $entityManager->flush();
436
437 // affichage
438 $parent->removeChild($page);
439 $nav_builder = new NavBuilder();
440 $menu_builder = new MenuBuilder(null, false);
441 echo json_encode(['success' => true, 'nav' => $nav_builder->render(), 'menu_buttons' => $menu_builder->render()]);
442 die;
443 }
444 }
445
446 // flèche droite =>: position = nombre d'éléments de la fraterie + 1, l'élément précédent devient le parent
447 if($_GET['menu_edit'] === 'move_one_level_down' && isset($json['id'])){
448 $id = $json['id'];
449 $page = Director::$menu_data->findPageById((int)$id);
450
451 $parent = $page->getParent(); // peut être null
452 if($parent == null){
453 $parent = Director::$menu_data;
454 }
455
456 // BDD
457 $parent->sortChildren(true); // trie et réindexe par sécurité: 1, 2, 3...
458 if($page->getPosition() > 1){
459 foreach($parent->getChildren() as $child){
460 if($child->getPosition() === $page->getPosition() - 1){
461 $page->setParent($child);
462 break;
463 }
464 }
465 $page->setPosition(count($page->getParent()->getChildren()) + 1);
466 }
467 $entityManager->flush();
468
469 // affichage
470 $parent->removeChild($page);
471 $page->getParent()->addChild($page);
472 $page->fillChildrenPagePath($page->getParent()->getPagePath()); // variable non mappée $page_path
473 $nav_builder = new NavBuilder();
474 $menu_builder = new MenuBuilder(null, false);
475
476 echo json_encode(['success' => true, 'nav' => $nav_builder->render(), 'menu_buttons' => $menu_builder->render()]);
477 die;
478 }
479
480 if($_GET['menu_edit'] === 'switch_positions' && isset($json['id1']) && isset($json['id2']))
481 {
482 $id1 = $json['id1'];
483 $id2 = $json['id2'];
484
485 // vérifier qu'ils ont le même parent
486 $page1 = Director::$menu_data->findPageById((int)$id1);
487 $page2 = Director::$menu_data->findPageById((int)$id2);
488
489 // double le contrôle fait en JS
490 if($page1->getParent() === $page2->getParent()) // comparaison stricte d'objet (même instance du parent?)
491 {
492 // inversion
493 $tmp = $page1->getPosition();
494 $page1->setPosition($page2->getPosition());
495 $page2->setPosition($tmp);
496 Director::$menu_data->sortChildren(true); // modifie tableau children
497 $entityManager->flush();
498
499 // nouveau menu
500 $nav_builder = new NavBuilder();
501 echo json_encode(['success' => true, 'nav' => $nav_builder->render()]);
502 }
503 else{
504 echo json_encode(['success' => false]);
505 }
506
507 die;
508 }
509
510 if($_GET['menu_edit'] === 'displayInMenu' && isset($json['id']) && isset($json['checked']))
511 {
512 $id = $json['id'];
513 $checked = $json['checked'];
514
515 $page = Director::$menu_data->findPageById((int)$id);
516 if($page->isHidden() === $checked){
517 $page->setHidden(!$checked);
518 $entityManager->flush();
519
520 // nouveau menu
521 $nav_builder = new NavBuilder();
522 echo json_encode(['success' => true, 'nav' => $nav_builder->render()]);
523 }
524 else{
525 echo json_encode(['success' => false]);
526 }
527 die;
528 }
529 }
530
531
532 /* -- mode Modification d'une page -- */
533
534 // partie "page"
535 elseif(isset($_GET['page_edit']))
536 {
537 // récupération des données
538 $data = file_get_contents('php://input');
539 $json = json_decode($data, true);
540
541 // titre de la page
542 if($_GET['page_edit'] === 'page_title'){
543 $page = $entityManager->find('App\Entity\Page', $json['page_id']);
544 $page->setPageName(htmlspecialchars($json['title']));
545 $entityManager->flush();
546 echo json_encode(['success' => true, 'title' => $page->getPageName()]);
547 }
548 // titre en snake_case pour le menu
549 /*elseif($_GET['page_edit'] === 'page_menu_path'){
550 $page = $entityManager->find('App\Entity\Page', $json['page_id']);
551 $page->setEndOfPath(htmlspecialchars($json['page_menu_path']));
552 $entityManager->flush();
553 echo json_encode(['success' => true, 'page_name_path' => $page->getEndOfPath()]);
554 }*/
555 // description dans les métadonnées
556 elseif($_GET['page_edit'] === 'page_description'){
557 $node_data = $entityManager->find('App\Entity\NodeData', $json['node_data_id']);
558 $node_data->updateData('description', htmlspecialchars($json['description']));
559 $entityManager->flush();
560 echo json_encode(['success' => true, 'description' => $node_data->getData()['description']]);
561 }
562 die;
563 }
564
565 // partie "blocs"
566 elseif(isset($_GET['bloc_edit']))
567 {
568 // renommage d'un bloc
569 if($_GET['bloc_edit'] === 'rename_page_bloc')
570 {
571 if(isset($json['bloc_title']) && $json['bloc_title'] !== null && isset($json['bloc_id']) && is_int($json['bloc_id'])){
572 $director = new Director($entityManager);
573 $director->findNodeById($json['bloc_id']);
574
575 // le titre (du JSON en BDD) est récupéré sous forme de tableau, modifié et renvoyé
576 $data = $director->getNode()->getNodeData()->getData();
577 $data['title'] = htmlspecialchars($json['bloc_title']);
578 $director->getNode()->getNodeData()->updateData('title', htmlspecialchars($json['bloc_title']));
579
580 $entityManager->flush();
581 echo json_encode(['success' => true, 'title' => $data['title']]);
582 }
583 else{
584 echo json_encode(['success' => false]);
585 }
586 die;
587 }
588 // inversion des positions de deux blocs
589 elseif($_GET['bloc_edit'] === 'switch_blocs_positions')
590 {
591 if(isset($json['id1']) && is_int($json['id1']) && isset($json['id2']) && is_int($json['id2']) && isset($_GET['page'])){
592 $director = new Director($entityManager, true);
593 $director->findUniqueNodeByName('main');
594 $director->findItsChildren();
595 $main = $director->getNode();
596 $main->sortChildren(true); // régénère les positions avant inversion
597
598 $bloc1; $bloc2;
599 foreach($main->getChildren() as $child){
600 if($child->getId() === $json['id1']){
601 $bloc1 = $child;
602 break;
603 }
604 }
605 foreach($main->getChildren() as $child){
606 if($child->getId() === $json['id2']){
607 $bloc2 = $child;
608 break;
609 }
610 }
611
612 // inversion
613 $tmp = $bloc1->getPosition();
614 $bloc1->setPosition($bloc2->getPosition());
615 $bloc2->setPosition($tmp);
616
617 $entityManager->flush();
618 echo json_encode(['success' => true]);
619 }
620 else{
621 echo json_encode(['success' => false]);
622 }
623 die;
624 }
625 }
626} \ No newline at end of file
diff --git a/src/controller/post.php b/src/controller/post.php
index acad1ce..bcafe6f 100644
--- a/src/controller/post.php
+++ b/src/controller/post.php
@@ -9,261 +9,272 @@ use App\Entity\Page;
9use App\Entity\Image; 9use App\Entity\Image;
10use Doctrine\Common\Collections\ArrayCollection; 10use Doctrine\Common\Collections\ArrayCollection;
11 11
12if($_SERVER['REQUEST_METHOD'] === 'POST' && $_SESSION['admin'] === true) 12if($_SERVER['REQUEST_METHOD'] === 'POST'){
13{ 13 // POST ordinaires non admin
14 /* -- formulaires HTML classiques -- */ 14
15 if($_SERVER['CONTENT_TYPE'] === 'application/x-www-form-urlencoded') 15 // POST ajax non admin
16 require '../src/controller/ajax.php';
17
18 if($_SESSION['admin'] === true)
16 { 19 {
17 /* -- nouvelle page -- */ 20 /* -- formulaires HTML classiques -- */
18 if(isset($_POST['page_name']) && $_POST['page_name'] !== null 21 if($_SERVER['CONTENT_TYPE'] === 'application/x-www-form-urlencoded')
19 && isset($_POST['page_name_path']) && $_POST['page_name_path'] !== null
20 && isset($_POST['page_location']) && $_POST['page_location'] !== null
21 && isset($_POST['page_description']) && $_POST['page_description'] !== null
22 && isset($_POST['new_page_hidden']) && $_POST['new_page_hidden'] === '')
23 {
24 // titre et chemin
25 $director = new Director($entityManager, true);
26 //Director::$menu_data = new Menu($entityManager);
27 $previous_page = Director::$menu_data->findPageById((int)$_POST["page_location"]); // (int) à cause de declare(strict_types=1);
28 $parent = $previous_page->getParent();
29
30 $page = new Page(
31 trim(htmlspecialchars($_POST["page_name"])),
32 trim(htmlspecialchars($_POST["page_name_path"])),
33 true, true, false,
34 $previous_page->getPosition(),
35 $parent); // peut et DOIT être null si on est au 1er niveau
36
37 // on a donné à la nouvelle entrée la même position qu'à la précédente,
38 // addChild l'ajoute à la fin du tableau "children" puis on trie
39 // exemple avec 2 comme position demandée: 1 2 3 4 2 devient 1 2 3 4 5 et la nouvelle entrée sera en 3è position
40 if($parent == null){
41 $parent = Director::$menu_data;
42 }
43 $parent->addChild($page);
44 $parent->reindexPositions();
45
46 $page->setPagePath(ltrim($parent->getPagePath() . '/' . $page->getEndOfPath(), '/'));
47
48 // noeud "head"
49 $node = new Node(
50 'head',
51 null, [],
52 1, // position d'un head = 1
53 null, // pas de parent
54 $page);
55 $node->useDefaultAttributes(); // fichiers CSS et JS
56
57 $data = new NodeData([
58 // pas de titre, il est dans $page
59 'description' => trim(htmlspecialchars($_POST["page_description"]))],
60 $node);
61
62 $bulk_data = $entityManager
63 ->createQuery('SELECT n FROM App\Entity\Image n WHERE n.file_name LIKE :name')
64 ->setParameter('name', '%favicon%')
65 ->getResult();
66 $data->setImages(new ArrayCollection($bulk_data));
67
68 $entityManager->persist($page);
69 $entityManager->persist($node);
70 $entityManager->persist($data);
71 $entityManager->flush();
72
73 // page créée, direction la page en mode modification pour ajouter des blocs
74 header("Location: " . new URL(['page' => $page->getPagePath(), 'action' => 'modif_page']));
75 die;
76 }
77
78 /* -- suppression d'une page -- */
79 elseif(isset($_POST['page_id']) && $_POST['page_id'] !== null
80 && isset($_POST['submit_hidden']) && $_POST['submit_hidden'] === '')
81 { 22 {
82 $page = $entityManager->find('App\Entity\Page', (int)$_POST['page_id']); 23 /* -- nouvelle page -- */
83 $nodes = $entityManager->getRepository('App\Entity\Node')->findBy(['page' => $page]); 24 if(isset($_POST['page_name']) && $_POST['page_name'] !== null
84 $data = []; 25 && isset($_POST['page_name_path']) && $_POST['page_name_path'] !== null
85 foreach($nodes as $node){ 26 && isset($_POST['page_location']) && $_POST['page_location'] !== null
86 $data[] = $entityManager->getRepository('App\Entity\NodeData')->findOneBy(['node' => $node]); 27 && isset($_POST['page_description']) && $_POST['page_description'] !== null
87 $entityManager->remove($node); 28 && isset($_POST['new_page_hidden']) && $_POST['new_page_hidden'] === '')
88 } 29 {
89 foreach($data as $one_data){ 30 // titre et chemin
90 $entityManager->remove($one_data); 31 $director = new Director($entityManager, true);
91 } 32 //Director::$menu_data = new Menu($entityManager);
92 $entityManager->remove($page); // suppression en BDD 33 $previous_page = Director::$menu_data->findPageById((int)$_POST["page_location"]); // (int) à cause de declare(strict_types=1);
93 34 $parent = $previous_page->getParent();
94 $entityManager->flush(); 35
95 header("Location: " . new URL); 36 $page = new Page(
96 die; 37 trim(htmlspecialchars($_POST["page_name"])),
97 } 38 trim(htmlspecialchars($_POST["page_name_path"])),
39 true, true, false,
40 $previous_page->getPosition(),
41 $parent); // peut et DOIT être null si on est au 1er niveau
42
43 // on a donné à la nouvelle entrée la même position qu'à la précédente,
44 // addChild l'ajoute à la fin du tableau "children" puis on trie
45 // exemple avec 2 comme position demandée: 1 2 3 4 2 devient 1 2 3 4 5 et la nouvelle entrée sera en 3è position
46 if($parent == null){
47 $parent = Director::$menu_data;
48 }
49 $parent->addChild($page);
50 $parent->reindexPositions();
98 51
52 $page->setPagePath(ltrim($parent->getPagePath() . '/' . $page->getEndOfPath(), '/'));
99 53
100 /* -- mode Modification d'une page -- */ 54 // noeud "head"
55 $node = new Node(
56 'head',
57 null, [],
58 1, // position d'un head = 1
59 null, // pas de parent
60 $page);
61 $node->useDefaultAttributes(); // fichiers CSS et JS
101 62
102 // modification des titres, chemins et descriptions 63 $data = new NodeData([
103 elseif(isset($_POST['page_menu_path']) && $_POST['page_menu_path'] !== null 64 // pas de titre, il est dans $page
104 && isset($_POST['page_id']) && $_POST['page_id'] !== null 65 'description' => trim(htmlspecialchars($_POST["page_description"]))],
105 && isset($_POST['page_name_path_hidden']) && $_POST['page_name_path_hidden'] === '') 66 $node);
106 { 67
107 $director = new Director($entityManager, true); 68 $bulk_data = $entityManager
108 $page = Director::$page_path->getLast(); 69 ->createQuery('SELECT n FROM App\Entity\Image n WHERE n.file_name LIKE :name')
109 $path = htmlspecialchars($_POST['page_menu_path']); 70 ->setParameter('name', '%favicon%')
110 71 ->getResult();
111 // mise en snake_case: filtre caractères non-alphanumériques, minuscule, doublons d'underscore, trim des underscores 72 $data->setImages(new ArrayCollection($bulk_data));
112 $path = trim(preg_replace('/_+/', '_', strtolower(preg_replace('/[^a-zA-Z0-9]/', '_', $path))), '_'); 73
113 $page->setEndOfPath($path); 74 $entityManager->persist($page);
114 foreach(Director::$menu_data->getChildren() as $child){ 75 $entityManager->persist($node);
115 if($child->getEndOfPath() === Director::$page_path->getArray()[0]->getEndOfPath()){ 76 $entityManager->persist($data);
116 $child->fillChildrenPagePath(); // MAJ de $page_path 77 $entityManager->flush();
117 } 78
79 // page créée, direction la page en mode modification pour ajouter des blocs
80 header("Location: " . new URL(['page' => $page->getPagePath(), 'action' => 'modif_page']));
81 die;
118 } 82 }
119 $entityManager->flush(); 83
120 header("Location: " . new URL(['page' => $page->getPagePath(), 'action' => 'modif_page'])); 84 /* -- suppression d'une page -- */
121 die; 85 elseif(isset($_POST['page_id']) && $_POST['page_id'] !== null
122 } 86 && isset($_POST['submit_hidden']) && $_POST['submit_hidden'] === '')
123 // ajout d'un bloc dans une page
124 elseif(isset($_POST['bloc_title']) && $_POST['bloc_title'] !== null
125 && isset($_POST['bloc_select']) && $_POST['bloc_select'] !== null
126 && isset($_POST['bloc_title_hidden']) && $_POST['bloc_title_hidden'] === '') // contrôle anti-robot avec input hidden
127 {
128 $director = new Director($entityManager, true); // on a besoin de page_path qui dépend de menu_data
129 $page = Director::$page_path->getLast();
130 $director->findUniqueNodeByName('main');
131 $director->findItsChildren();
132 $main = $director->getNode();
133 $position = count($main->getChildren()) + 1; // position dans la fraterie
134
135 $blocks = ['blog', 'grid', 'calendar', 'galery', 'form']; // même liste dans FormBuilder.php
136 if(!in_array($_POST["bloc_select"], $blocks, true)) // 3è param: contrôle du type
137 { 87 {
138 header("Location: " . new URL(['page' => $_GET['page'], 'error' => 'bad_bloc_type'])); 88 $page = $entityManager->find('App\Entity\Page', (int)$_POST['page_id']);
89 $nodes = $entityManager->getRepository('App\Entity\Node')->findBy(['page' => $page]);
90 $data = [];
91 foreach($nodes as $node){
92 $data[] = $entityManager->getRepository('App\Entity\NodeData')->findOneBy(['node' => $node]);
93 $entityManager->remove($node);
94 }
95 foreach($data as $one_data){
96 $entityManager->remove($one_data);
97 }
98 $entityManager->remove($page); // suppression en BDD
99
100 $entityManager->flush();
101 header("Location: " . new URL);
139 die; 102 die;
140 } 103 }
141 104
142 if($_POST["bloc_select"] === 'calendar' || $_POST["bloc_select"] === 'form'){
143 $dql = 'SELECT n FROM App\Entity\Node n WHERE n.page = :page AND n.name_node = :name'; // noeud 'head' de la page
144 $bulk_data = $entityManager
145 ->createQuery($dql)
146 ->setParameter('page', $page)
147 ->setParameter('name', 'head')
148 ->getResult();
149 105
150 if(count($bulk_data) != 1){ // 1 head par page 106 /* -- mode Modification d'une page -- */
151 header("Location: " . new URL(['page' => $_GET['page'], 'error' => 'head_node_not_found']));
152 die;
153 }
154 107
155 $bulk_data[0]->addAttribute('css_array', $_POST["bloc_select"]); 108 // modification des titres, chemins et descriptions
156 $entityManager->persist($bulk_data[0]); 109 elseif(isset($_POST['page_menu_path']) && $_POST['page_menu_path'] !== null
110 && isset($_POST['page_id']) && $_POST['page_id'] !== null
111 && isset($_POST['page_name_path_hidden']) && $_POST['page_name_path_hidden'] === '')
112 {
113 $director = new Director($entityManager, true);
114 $page = Director::$page_path->getLast();
115 $path = htmlspecialchars($_POST['page_menu_path']);
116
117 // mise en snake_case: filtre caractères non-alphanumériques, minuscule, doublons d'underscore, trim des underscores
118 $path = trim(preg_replace('/_+/', '_', strtolower(preg_replace('/[^a-zA-Z0-9]/', '_', $path))), '_');
119 $page->setEndOfPath($path);
120 foreach(Director::$menu_data->getChildren() as $child){
121 if($child->getEndOfPath() === Director::$page_path->getArray()[0]->getEndOfPath()){
122 $child->fillChildrenPagePath(); // MAJ de $page_path
123 }
124 }
125 $entityManager->flush();
126 header("Location: " . new URL(['page' => $page->getPagePath(), 'action' => 'modif_page']));
127 die;
157 } 128 }
129 // ajout d'un bloc dans une page
130 elseif(isset($_POST['bloc_title']) && $_POST['bloc_title'] !== null
131 && isset($_POST['bloc_select']) && $_POST['bloc_select'] !== null
132 && isset($_POST['bloc_title_hidden']) && $_POST['bloc_title_hidden'] === '') // contrôle anti-robot avec input hidden
133 {
134 $director = new Director($entityManager, true); // on a besoin de page_path qui dépend de menu_data
135 $page = Director::$page_path->getLast();
136 $director->findUniqueNodeByName('main');
137 $director->findItsChildren();
138 $main = $director->getNode();
139 $position = count($main->getChildren()) + 1; // position dans la fraterie
140
141 $blocks = ['blog', 'grid', 'calendar', 'galery', 'form']; // même liste dans FormBuilder.php
142 if(!in_array($_POST["bloc_select"], $blocks, true)) // 3è param: contrôle du type
143 {
144 header("Location: " . new URL(['page' => $_GET['page'], 'error' => 'bad_bloc_type']));
145 die;
146 }
158 147
159 $bloc = new Node( 148 if($_POST["bloc_select"] === 'calendar' || $_POST["bloc_select"] === 'form'){
160 $_POST["bloc_select"], 149 $dql = 'SELECT n FROM App\Entity\Node n WHERE n.page = :page AND n.name_node = :name'; // noeud 'head' de la page
161 null, [], 150 $bulk_data = $entityManager
162 $position, 151 ->createQuery($dql)
163 $main, 152 ->setParameter('page', $page)
164 $page); 153 ->setParameter('name', 'head')
165 $data = new NodeData( 154 ->getResult();
166 ['title' => trim(htmlspecialchars($_POST["bloc_title"]))], 155
167 $bloc); 156 if(count($bulk_data) != 1){ // 1 head par page
168 157 header("Location: " . new URL(['page' => $_GET['page'], 'error' => 'head_node_not_found']));
169 $entityManager->persist($bloc); 158 die;
170 $entityManager->persist($data); 159 }
171 $entityManager->flush(); 160
172 header("Location: " . new URL(['page' => $_GET['page'], 'action' => 'modif_page'])); 161 $bulk_data[0]->addAttribute('css_array', $_POST["bloc_select"]);
173 die; 162 if($_POST["bloc_select"] === 'form'){
174 } 163 $bulk_data[0]->addAttribute('js_array', $_POST["bloc_select"]);
175 // suppression d'un bloc de page 164 }
176 elseif(isset($_POST['delete_bloc_id']) && $_POST['delete_bloc_id'] !== null 165 $entityManager->persist($bulk_data[0]);
177 && isset($_POST['delete_bloc_hidden']) && $_POST['delete_bloc_hidden'] === '') // contrôle anti-robot avec input hidden
178 {
179 $director = new Director($entityManager, true);
180 $director->findUniqueNodeByName('main');
181 $director->findItsChildren();
182 //$director->findNodeById((int)$_POST['delete_bloc_id']);
183 $main = $director->getNode();
184 $bloc;
185 foreach($main->getChildren() as $child){
186 if($child->getId() === (int)$_POST['delete_bloc_id']){
187 $bloc = $child;
188 break;
189 } 166 }
167
168 $bloc = new Node(
169 $_POST["bloc_select"],
170 null, [],
171 $position,
172 $main,
173 $page);
174 $data = new NodeData(
175 ['title' => trim(htmlspecialchars($_POST["bloc_title"]))],
176 $bloc);
177
178 $entityManager->persist($bloc);
179 $entityManager->persist($data);
180 $entityManager->flush();
181 header("Location: " . new URL(['page' => $_GET['page'], 'action' => 'modif_page']));
182 die;
190 } 183 }
191 $main->removeChild($bloc); // réindex le tableau $children au passage 184 // suppression d'un bloc de page
192 $main->reindexPositions(); 185 elseif(isset($_POST['delete_bloc_id']) && $_POST['delete_bloc_id'] !== null
186 && isset($_POST['delete_bloc_hidden']) && $_POST['delete_bloc_hidden'] === '') // contrôle anti-robot avec input hidden
187 {
188 $director = new Director($entityManager, true);
189 $director->findUniqueNodeByName('main');
190 $director->findItsChildren();
191 //$director->findNodeById((int)$_POST['delete_bloc_id']);
192 $main = $director->getNode();
193 $bloc;
194 foreach($main->getChildren() as $child){
195 if($child->getId() === (int)$_POST['delete_bloc_id']){
196 $bloc = $child;
197 break;
198 }
199 }
200 $main->removeChild($bloc); // réindex le tableau $children au passage
201 $main->reindexPositions();
193 202
194 $entityManager->remove($bloc); // suppression en BDD 203 $entityManager->remove($bloc); // suppression en BDD
195 $entityManager->flush(); 204 $entityManager->flush();
196 header("Location: " . new URL(['page' => $_GET['page'], 'action' => 'modif_page'])); 205 header("Location: " . new URL(['page' => $_GET['page'], 'action' => 'modif_page']));
197 die; 206 die;
198 } 207 }
199 208
200 209
201 /* -- page Menu et chemins -- */ 210 /* -- page Menu et chemins -- */
202 211
203 // création d'une entrée de menu avec une URL 212 // création d'une entrée de menu avec une URL
204 elseif(isset($_POST["label_input"]) && isset($_POST["url_input"]) && isset($_POST["location"])){ 213 elseif(isset($_POST["label_input"]) && isset($_POST["url_input"]) && isset($_POST["location"])){
205 Director::$menu_data = new Menu($entityManager); 214 Director::$menu_data = new Menu($entityManager);
206 $previous_page = Director::$menu_data->findPageById((int)$_POST["location"]); // (int) à cause de declare(strict_types=1); 215 $previous_page = Director::$menu_data->findPageById((int)$_POST["location"]); // (int) à cause de declare(strict_types=1);
207 $parent = $previous_page->getParent(); 216 $parent = $previous_page->getParent();
208 217
209 $page = new Page( 218 $page = new Page(
210 trim(htmlspecialchars($_POST["label_input"])), 219 trim(htmlspecialchars($_POST["label_input"])),
211 filter_var($_POST["url_input"], FILTER_VALIDATE_URL), 220 filter_var($_POST["url_input"], FILTER_VALIDATE_URL),
212 true, true, false, 221 true, true, false,
213 $previous_page->getPosition(), 222 $previous_page->getPosition(),
214 $parent); // peut et DOIT être null si on est au 1er niveau 223 $parent); // peut et DOIT être null si on est au 1er niveau
215 224
216 // on a donné à la nouvelle entrée la même position qu'à la précédente, 225 // on a donné à la nouvelle entrée la même position qu'à la précédente,
217 // addChild l'ajoute à la fin du tableau "children" puis on trie 226 // addChild l'ajoute à la fin du tableau "children" puis on trie
218 // exemple avec 2 comme position demandée: 1 2 3 4 2 devient 1 2 3 4 5 et la nouvelle entrée sera en 3è position 227 // exemple avec 2 comme position demandée: 1 2 3 4 2 devient 1 2 3 4 5 et la nouvelle entrée sera en 3è position
219 if($parent == null){ 228 if($parent == null){
220 $parent = Director::$menu_data; 229 $parent = Director::$menu_data;
221 } 230 }
222 $parent->addChild($page); // true pour réindexer les positions en BDD 231 $parent->addChild($page); // true pour réindexer les positions en BDD
223 $parent->reindexPositions(); 232 $parent->reindexPositions();
224 233
225 $entityManager->persist($page); 234 $entityManager->persist($page);
226 $entityManager->flush(); 235 $entityManager->flush();
227 header("Location: " . new URL(['page' => $_GET['from']])); 236 header("Location: " . new URL(['page' => $_GET['from']]));
228 die; 237 die;
229 }
230 // suppression d'une entrée de menu avec une URL
231 elseif(isset($_POST['delete']) && isset($_POST['x']) && isset($_POST['y'])){ // 2 params x et y sont là parce qu'on a cliqué sur une image
232 Director::$menu_data = new Menu($entityManager);
233 $page = Director::$menu_data->findPageById((int)$_POST["delete"]);
234 $parent = $page->getParent();
235 if($parent == null){
236 $parent = Director::$menu_data;
237 } 238 }
239 // suppression d'une entrée de menu avec une URL
240 elseif(isset($_POST['delete']) && isset($_POST['x']) && isset($_POST['y'])){ // 2 params x et y sont là parce qu'on a cliqué sur une image
241 Director::$menu_data = new Menu($entityManager);
242 $page = Director::$menu_data->findPageById((int)$_POST["delete"]);
243 $parent = $page->getParent();
244 if($parent == null){
245 $parent = Director::$menu_data;
246 }
238 247
239 $parent->removeChild($page); // suppression de $children avant de trier 248 $parent->removeChild($page); // suppression de $children avant de trier
240 $parent->reindexPositions(); 249 $parent->reindexPositions();
241 250
242 $entityManager->remove($page); // suppression en BDD 251 $entityManager->remove($page); // suppression en BDD
243 $entityManager->flush(); 252 $entityManager->flush();
244 header("Location: " . new URL(['page' => $_GET['from']])); 253 header("Location: " . new URL(['page' => $_GET['from']]));
245 die; 254 die;
246 } 255 }
247 elseif(isset($_GET['action']) && $_GET['action'] === 'modif_mdp' 256 elseif(isset($_GET['action']) && $_GET['action'] === 'modif_mdp'
248 && isset($_POST['login']) && isset($_POST['old_password']) && isset($_POST['new_password']) 257 && isset($_POST['login']) && isset($_POST['old_password']) && isset($_POST['new_password'])
249 && isset($_POST['modify_password_hidden']) && empty($_POST['modify_password_hidden'])) 258 && isset($_POST['modify_password_hidden']) && empty($_POST['modify_password_hidden']))
250 { 259 {
251 changePassword($entityManager); 260 changePassword($entityManager);
252 header("Location: " . new URL(['page' => $_GET['from']])); 261 header("Location: " . new URL(['page' => $_GET['from']]));
253 die; 262 die;
263 }
264 else{
265 header("Location: " . new URL(['error' => 'paramètres inconnus']));
266 die;
267 }
254 } 268 }
269
270 /* -- requêtes AJAX -- */
255 else{ 271 else{
256 header("Location: " . new URL(['error' => 'paramètres inconnus'])); 272 require '../src/controller/ajax_admin.php';
257 die;
258 } 273 }
259 }
260 274
261 /* -- requêtes AJAX -- */ 275 require '../src/controller/ajax_calendar_admin.php';
262 else{
263 require '../src/controller/ajax.php';
264 } 276 }
265
266 require '../src/controller/ajax_calendar_admin.php';
267} 277}
268 278elseif($_SERVER['REQUEST_METHOD'] === 'GET'){
269require '../src/controller/ajax_calendar_visitor.php'; 279 require '../src/controller/ajax_calendar_visitor.php'; // fullcalendar utilise un GET pour récupérer les données
280} \ No newline at end of file
diff --git a/src/model/entities/Email.php b/src/model/entities/Email.php
new file mode 100644
index 0000000..c6c2a29
--- /dev/null
+++ b/src/model/entities/Email.php
@@ -0,0 +1,41 @@
1<?php
2// src/model/entities/Email.php
3
4declare(strict_types=1);
5
6namespace App\Entity;
7
8use Doctrine\ORM\Mapping as ORM;
9
10#[ORM\Entity]
11#[ORM\Table(name: TABLE_PREFIX . "email")]
12class Email
13{
14 #[ORM\Id]
15 #[ORM\GeneratedValue]
16 #[ORM\Column(type: "integer")]
17 private int $id_log;
18
19 #[ORM\Column(type: "string", length: 320)]
20 private string $sender;
21
22 #[ORM\Column(type: "string", length: 320)]
23 private string $recipient;
24
25 // inutile, objet = 'Message envoyé par ' . $name . ' (' . $email . ') depuis le site web'
26 /*#[ORM\Column(type: "text")]
27 private string $subject;*/
28
29 #[ORM\Column(type: "text")]
30 private string $content;
31
32 #[ORM\Column(type: 'datetime', options: ['default' => 'CURRENT_TIMESTAMP'])]
33 private ?\DateTime $date_time ;
34
35 public function __construct(string $sender, string $recipient, string $content){
36 $this->sender = $sender;
37 $this->recipient = $recipient;
38 $this->content = $content;
39 $this->date_time = new \DateTime();
40 }
41}
diff --git a/src/model/entities/Log.php b/src/model/entities/Log.php
index 06a907e..39b4307 100644
--- a/src/model/entities/Log.php
+++ b/src/model/entities/Log.php
@@ -6,8 +6,6 @@ declare(strict_types=1);
6namespace App\Entity; 6namespace App\Entity;
7 7
8use Doctrine\ORM\Mapping as ORM; 8use Doctrine\ORM\Mapping as ORM;
9use Doctrine\Common\Collections\ArrayCollection;
10use Doctrine\Common\Collections\Collection;
11 9
12#[ORM\Entity] 10#[ORM\Entity]
13#[ORM\Table(name: TABLE_PREFIX . "log")] 11#[ORM\Table(name: TABLE_PREFIX . "log")]
diff --git a/src/view/FormBuilder.php b/src/view/FormBuilder.php
index 5f8545c..508763b 100644
--- a/src/view/FormBuilder.php
+++ b/src/view/FormBuilder.php
@@ -19,32 +19,31 @@ class FormBuilder extends AbstractBuilder
19 extract($node->getNodeData()->getData()); 19 extract($node->getNodeData()->getData());
20 } 20 }
21 21
22 $action_url = new URL(['page' => CURRENT_PAGE]);
23 $captcha = new Captcha; 22 $captcha = new Captcha;
24 $_SESSION['captcha'] = $captcha->getSolution(); 23 $_SESSION['captcha'] = $captcha->getSolution();
25 24
26 $recipient_found = false;
27 if(isset($email)){
28 $recipient_found = true;
29 }
30 else{
31 $email = '';
32 }
33
34 $admin_content = ''; 25 $admin_content = '';
35 if($_SESSION['admin']) 26 if($_SESSION['admin'])
36 { 27 {
37 $admin_content = '<script src="js/form.js"></script> 28 $admin_content = ''
38 <h3>Configuration du formulaire</h3> 29 //. '<h3>Configuration du formulaire</h3>' . "\n"
39 <div class="admin_form"> 30 . '<div class="admin_form">' . "\n"
40 <label for="recipient">E-mail de destination</label> 31 /*. '<p>
41 <input id="recipient" type="email" name="recipient" placeholder="mon-adresse@email.fr" value="' . $email . '"> 32 <label for="recipient">E-mail de destination</label>
42 <button onclick="changeRecipient(' . $node->getNodeData()->getId() . ')">Valider</button> 33 <input id="recipient" type="email" name="recipient" placeholder="mon-adresse@email.fr" value="' . $email . '">
43 </div>'; 34 <input type="hidden" id="recipient_hidden" value="">
35 <button onclick="changeRecipient(' . $node->getNodeData()->getId() . ')">Valider</button>
36 </p>
37 <p>
38 <label for="smtp">Serveur SMTP</label>
39 <input id="smtp" type="text" name="smtp" value="' . $smtp . '">
40 <input type="hidden" id="smtp_hidden" value="">
41 <button onclick="changeSmtp(' . $node->getNodeData()->getId() . ')">Valider</button>
42 </p>' . "\n"*/
43 . '<p><button onclick="sendTestEmail()">Envoi d\'un e-mail de test</button></p>' . "\n"
44 . '<p class="test_email_success full_width_column"></p>'
45 . '</div>' . "\n";
44 } 46 }
45
46 // vérifier qu'une adresse de destination est bien configurée
47 $no_recipient_warning = '<p class="no_recipient_warning ' . ($recipient_found ? 'hidden' : '') . '">Aucune adresse de destination n\'a été configurée, envoi d\'e-mail impossible!</p>';
48 47
49 ob_start(); 48 ob_start();
50 require $viewFile; 49 require $viewFile;
diff --git a/src/view/templates/form.php b/src/view/templates/form.php
index 0c44bf8..5f81f6f 100644
--- a/src/view/templates/form.php
+++ b/src/view/templates/form.php
@@ -2,31 +2,32 @@
2<section class="form" id="<?= $this->id_node ?>"> 2<section class="form" id="<?= $this->id_node ?>">
3 <?= $admin_content ?> 3 <?= $admin_content ?>
4 <h3><?= $title ?></h3> 4 <h3><?= $title ?></h3>
5 <?= $no_recipient_warning ?> 5 <div class="form_inputs">
6 <form method="post" action="<?= $action_url ?>"> 6 <label for="email_name">Votre nom</label>
7 <label for="email">Votre e-mail</label> 7 <input id="email_name" type="text" name="email_name" value="" required>
8 <input type="email" name="email" placeholder="mon-adresse@email.fr" value="" required> 8
9 <label for="email_address">Votre e-mail</label>
10 <input id="email_address" type="email" name="email_address" placeholder="mon-adresse@email.fr" value="" required>
9 11
10 <label for="subject">Objet</label> 12 <label for="email_message">Votre message</label>
11 <input type="text" name="subject" value="" required> 13 <textarea id="email_message" type="text" name="email_message" rows="4" required></textarea>
12
13 <label for="message">Votre message</label>
14 <textarea type="text" name="message" rows="4" required></textarea>
15 14
16 <div class="full_width_column"> 15 <div class="full_width_column">
17 <label for="captcha" >Montrez que vous n'êtes pas un robot</label> 16 <label for="captcha" >Montrez que vous n'êtes pas un robot</label>
18 </div> 17 </div>
19 18
20 <label for="captcha" >Combien font <?= $captcha->getA() ?> fois <?= $captcha->getB() ?>?</label> 19 <label for="email_captcha" >Combien font <?= $captcha->getA() ?> fois <?= $captcha->getB() ?>?</label>
21 <div> 20 <div>
22 <input type="text" name="captcha" size="1" required> 21 <input id="email_captcha" type="text" name="email_captcha" size="1" required>
23 </div> 22 </div>
24 23
25 <input type="hidden" name="form_id" value=""> 24 <input id="form_id_hidden" type="hidden" name="form_id_hidden" value="">
26 <input type="hidden" name="form_hidden"> 25 <input id="email_hidden" type="hidden" name="email_hidden">
27 26
28 <div class="full_width_column"> 27 <div class="full_width_column">
29 <input type="submit" value="Envoyez votre message"> 28 <input type="submit" value="Envoyez votre message" onclick="sendVisitorEmail()">
30 </div> 29 </div>
31 </form> 30
31 <p class="send_email_success full_width_column"></p>
32 </div>
32</section> \ No newline at end of file 33</section> \ No newline at end of file