From dba24b8c18aed84a71c3169b2df5598d62deab06 Mon Sep 17 00:00:00 2001 From: polo Date: Sun, 17 Aug 2025 19:46:20 +0200 Subject: =?UTF-8?q?classe=20FormValidation=20et=20am=C3=A9lioration=20des?= =?UTF-8?q?=20envois=20d'e-mail?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- public/js/form.js | 24 ++- public/js/main.js | 2 +- src/EmailService.php | 67 ++++++++ src/FormValidation.php | 186 ++++++++++++++++++++ src/controller/ContactFormController.php | 40 ++++- src/controller/EmailController.php | 91 ---------- src/controller/UserController.php | 284 +++++++++---------------------- src/router.php | 2 +- src/view/UserEditBuilder.php | 8 +- src/view/templates/form.php | 8 +- src/view/templates/login.php | 1 + src/view/templates/user_create.php | 1 + src/view/templates/user_edit.php | 15 +- 13 files changed, 415 insertions(+), 314 deletions(-) create mode 100644 src/EmailService.php create mode 100644 src/FormValidation.php delete mode 100644 src/controller/EmailController.php diff --git a/public/js/form.js b/public/js/form.js index 5c5a164..cf138e6 100644 --- a/public/js/form.js +++ b/public/js/form.js @@ -26,6 +26,12 @@ function changeRecipient(id){ }); } +function checkCase(){ + if(document.getElementById('email_address').value.match('[A-Z]')){ + toastNotify("Votre e-mail comporte une lettre majuscule, il s'agit probablement d'une erreur."); + } +} + function sendTestEmail(id){ const admin_form = document.querySelector('.admin_form'); const test_email_success = document.querySelector('.test_email_success'); @@ -61,15 +67,21 @@ function sendTestEmail(id){ } function sendVisitorEmail(id){ - const send_email_success = document.querySelector('.send_email_success'); - send_email_success.innerHTML = 'Envoi en cours, veuillez patienter'; - send_email_success.style.backgroundColor = 'yellow'; - const email_name = document.getElementById('email_name').value; const email_address = document.getElementById('email_address').value; const email_message = document.getElementById('email_message').value; const email_captcha = document.getElementById('email_captcha').value; const email_hidden = document.getElementById('email_hidden').value; + const send_email_success = document.querySelector('.send_email_success'); + + if(email_name === '' || email_address === '' || email_message === '' || email_captcha === ''){ + toastNotify('Veuillez remplir tous les champs.'); + return; + } + else{ + send_email_success.innerHTML = 'Envoi en cours, veuillez patienter'; + send_email_success.style.backgroundColor = 'yellow'; + } fetch('index.php?action=send_email', { method: 'POST', @@ -90,7 +102,7 @@ function sendVisitorEmail(id){ let message; let color; if(data.success){ - message = 'Votre E-mail a été envoyé!'; + message = 'Votre e-mail a été envoyé!'; color = 'lawngreen'; } else{ @@ -98,8 +110,8 @@ function sendVisitorEmail(id){ color = "orangered" } send_email_success.innerHTML = message; - toastNotify(message); send_email_success.style.backgroundColor = color; + toastNotify(message); }) .catch(error => { console.error('Erreur:', error); diff --git a/public/js/main.js b/public/js/main.js index 2ffd33b..4be7843 100644 --- a/public/js/main.js +++ b/public/js/main.js @@ -33,7 +33,7 @@ function toastNotify(message) { var toast = document.getElementById('toast'); toast.textContent = message; toast.className = 'toast show'; - setTimeout(function(){ toast.className = toast.className.replace('show', ''); }, 3000); + setTimeout(function(){ toast.className = toast.className.replace('show', ''); }, 5000); } diff --git a/src/EmailService.php b/src/EmailService.php new file mode 100644 index 0000000..c1f74d1 --- /dev/null +++ b/src/EmailService.php @@ -0,0 +1,67 @@ + exceptions + $mail->CharSet = 'UTF-8'; + + try{ + // Paramètres du serveur + $mail->isSMTP(); + $mail->Host = Config::$smtp_host; + $mail->SMTPAuth = true; + $mail->Port = 25; + + if($mail->SMTPAuth){ + $mail->Username = Config::$smtp_username; // e-mail + $mail->Password = Config::$smtp_password; + $mail->SMTPSecure = Config::$smtp_secure; // tls (starttls) ou ssl (smtps) + if($mail->SMTPSecure === 'tls'){ + $mail->Port = 587; + } + elseif($mail->SMTPSecure === 'ssl'){ + $mail->Port = 465; + } + } + //var_dump($mail->smtpConnect());die; // test de connexion + + // Expéditeur et destinataire + $mail->setFrom(strtolower(Config::$email_from), Config::$email_from_name); // expéditeur + $mail->addAddress(strtolower($recipient), Config::$email_dest_name); // destinataire + + // Contenu + $mail->isHTML(true); + if($true_email){ + $mail->Subject = 'Message envoyé par: ' . $name . ' (' . $email . ') depuis le site web'; + } + else{ + $mail->Subject = "TEST d'un envoi d'e-mail depuis le site web"; + } + $mail->Body = $message; + $mail->AltBody = $message; + + $mail->send(); + + // copie en BDD + $db_email = new Email($email, Config::$email_dest, $message); + $entityManager->persist($db_email); + $entityManager->flush(); + + return true; + } + catch(Exception $e){ + return false; + //echo "Le message n'a pas pu être envoyé. Erreur : {$mail->ErrorInfo}"; + } + } +} \ No newline at end of file diff --git a/src/FormValidation.php b/src/FormValidation.php new file mode 100644 index 0000000..743cd13 --- /dev/null +++ b/src/FormValidation.php @@ -0,0 +1,186 @@ +data = $data; + $this->validation_strategy = $validation_strategy; + } + + public function validate(): bool + { + $this->errors = []; + + // pattern stratégie en une seule classe + switch($this->validation_strategy){ + case 'email': + $this->emailStrategy(); + break; + case 'create_user': + $this->createUserStrategy(); + break; + case 'connection': + $this->connectionStrategy(); + break; + case 'username_update': + $this->usernameUpdateStrategy(); + break; + case 'password_update': + $this->passwordUpdateStrategy(); + break; + default: + http_response_code(500); // c'est un peu comme jeter une exception + echo json_encode(['success' => false, 'error' => 'server_error']); + die; + } + + $this->validated = true; + return empty($this->errors); + } + + public function getErrors(): array + { + return $this->errors; + } + + public function getField(string $field): string + { + return $this->validated ? $this->data[$field] : ''; + } + + // méthodes de validation + private function captchaValidate(bool $clean_session = true): void + { + $captcha_solution = (isset($_SESSION['captcha']) && is_int($_SESSION['captcha'])) ? $_SESSION['captcha'] : 0; + $captcha_try = isset($this->data['captcha']) ? Captcha::controlInput($this->data['captcha']) : 0; + if($clean_session){ + unset($_SESSION['captcha']); + } + + if($captcha_try == 0){ + $error = 'error_non_valid_captcha'; + } + elseif($captcha_solution == 0){ // ne peut pas arriver, si? + $error = 'captcha_server_error'; + } + elseif($captcha_try !== $captcha_solution){ + $this->errors[] = 'bad_solution_captcha'; + } + } + + // erreurs à la création des mots de passe + static private function removeSpacesTabsCRLF(string $chaine): string + { + $cibles = [' ', "\t", "\n", "\r"]; // doubles quotes !! + return(str_replace($cibles, '', $chaine)); + } + + + // stratégies + private function emailStrategy(): void + { + $this->captchaValidate(false); + + if(!isset($this->data['name']) || empty($this->data['name']) + || !isset($this->data['email']) || empty($this->data['email']) + || !isset($this->data['message']) || empty($this->data['message']) + || !isset($this->data['hidden']) || !empty($this->data['hidden'])){ + $this->errors[] = 'missing_fields'; + } + + if(!filter_var(trim($this->data['email']), FILTER_VALIDATE_EMAIL)){ + $this->errors[] = 'bad_email_address'; + } + + $this->data['name'] = htmlspecialchars(trim($this->data['name'])); + $this->data['email'] = htmlspecialchars(trim($this->data['email'])); + $this->data['message'] = htmlspecialchars($this->data['message']); + } + private function createUserStrategy(): void + { + $this->captchaValidate(); + + // test mauvais paramètres + if(!isset($this->data['login']) || empty($this->data['login']) + || !isset($this->data['password']) || empty($this->data['password']) + || !isset($this->data['password_confirmation']) || empty($this->data['password_confirmation']) + || !isset($this->data['create_user_hidden']) || !empty($this->data['create_user_hidden'])) + { + $this->errors[] = 'bad_login_or_password'; + } + + if($this->data['password'] !== $this->data['password_confirmation']){ + $this->errors[] = 'different_passwords'; + } + + if($this->data['login'] !== self::removeSpacesTabsCRLF(htmlspecialchars($this->data['login'])) + || $this->data['password'] !== self::removeSpacesTabsCRLF(htmlspecialchars($this->data['password']))){ + $this->errors[] = 'forbidden_characters'; + } + } + private function connectionStrategy(): void + { + $this->captchaValidate(); + + if(!isset($this->data['login']) || empty($this->data['login']) + || !isset($this->data['password']) || empty($this->data['password']) + || !isset($this->data['connection_hidden']) || !empty($this->data['connection_hidden'])) + { + $this->errors[] = 'bad_login_or_password'; + } + } + private function usernameUpdateStrategy(): void + { + $this->captchaValidate(); + + if(!isset($this->data['login']) || empty($this->data['login']) + || !isset($this->data['password']) || empty($this->data['password']) + || !isset($this->data['new_login']) || empty($this->data['new_login']) + || !isset($this->data['modify_username_hidden']) || !empty($this->data['modify_username_hidden'])) + { + $this->errors[] = 'bad_login_or_password'; + } + + $new_login = self::removeSpacesTabsCRLF(htmlspecialchars($this->data['new_login'])); + if($new_login !== $this->data['new_login']){ + $this->errors[] = 'forbidden_characters'; + } + + if($this->data['login'] !== $_SESSION['user']){ + $this->errors[] = 'bad_login_or_password'; + } + if($this->data['login'] === $new_login){ + $this->errors[] = 'same_username_as_before'; + } + } + private function passwordUpdateStrategy(): void + { + $this->captchaValidate(); + + if(!isset($this->data['login']) || empty($this->data['login']) + || !isset($this->data['password']) || empty($this->data['password']) + || !isset($this->data['new_password']) || empty($this->data['new_password']) + || !isset($this->data['modify_password_hidden']) || !empty($this->data['modify_password_hidden'])) + { + $this->errors[] = 'bad_login_or_password'; + } + + $new_password = self::removeSpacesTabsCRLF(htmlspecialchars($this->data['new_password'])); + if($new_password !== $this->data['new_password']){ + $this->errors[] = 'forbidden_characters'; + } + + if($this->data['login'] !== $_SESSION['user']){ + $this->errors[] = 'bad_login_or_password'; + } + if($this->data['password'] === $new_password){ + $this->errors[] = 'same_password_as_before'; + } + } +} \ No newline at end of file diff --git a/src/controller/ContactFormController.php b/src/controller/ContactFormController.php index 9d62a77..dcea868 100644 --- a/src/controller/ContactFormController.php +++ b/src/controller/ContactFormController.php @@ -27,17 +27,53 @@ class ContactFormController } die; } + static public function sendVisitorEmail(EntityManager $entityManager, array $json): void + { + $form = new FormValidation($json, 'email'); + + $error = ''; + if($form->validate()){ + // destinataire = e-mail par défaut dans config.ini OU choisi par l'utilisateur + $form_data = $entityManager->find('App\Entity\NodeData', $json['id']); + if($form_data === null){ + http_response_code(500); + echo json_encode(['success' => false, 'error' => 'server_error']); + die; + } + $recipient = $form_data->getData()['email'] ?? Config::$email_dest; + + if(!EmailService::send($entityManager, $recipient, true, $form->getField('name'), $form->getField('email'), $form->getField('message'))){ + $error = 'email_not_sent'; + } + } + else{ + $error = $form->getErrors()[0]; // la 1ère erreur sera affichée + } + + if(empty($error)){ + echo json_encode(['success' => true]); + } + else{ + echo json_encode(['success' => false, 'error' => $error]); + } + die; + } static public function sendTestEmail(EntityManager $entityManager, array $json): void { // destinataire = e-mail par défaut dans config.ini OU choisi par l'utilisateur $form_data = $entityManager->find('App\Entity\NodeData', $json['id']); + if($form_data === null){ + http_response_code(500); + echo json_encode(['success' => false, 'error' => 'server_error']); + die; + } $recipient = $form_data->getData()['email'] ?? Config::$email_dest; - if(EmailController::send($recipient, false, 'nom du visiteur', 'adresse@du_visiteur.fr', "TEST d'un envoi d'e-mail depuis le site web")){ + if(EmailService::send($entityManager, $recipient, false, 'nom du visiteur', 'adresse@du_visiteur.fr', "TEST d'un envoi d'e-mail depuis le site web")){ echo json_encode(['success' => true]); } else{ - echo json_encode(['success' => false]); + echo json_encode(['success' => false, 'error' => 'email_not_sent']); } die; } diff --git a/src/controller/EmailController.php b/src/controller/EmailController.php deleted file mode 100644 index 1eea257..0000000 --- a/src/controller/EmailController.php +++ /dev/null @@ -1,91 +0,0 @@ - exceptions - $mail->CharSet = 'UTF-8'; - - try{ - // Paramètres du serveur - $mail->isSMTP(); - $mail->Host = Config::$smtp_host; - $mail->SMTPAuth = true; - $mail->Port = 25; - - if($mail->SMTPAuth){ - $mail->Username = Config::$smtp_username; // e-mail - $mail->Password = Config::$smtp_password; - $mail->SMTPSecure = Config::$smtp_secure; // tls (starttls) ou ssl (smtps) - if($mail->SMTPSecure === 'tls'){ - $mail->Port = 587; - } - elseif($mail->SMTPSecure === 'ssl'){ - $mail->Port = 465; - } - } - //var_dump($mail->smtpConnect());die; // test de connexion - - // Expéditeur et destinataire - $mail->setFrom(strtolower(Config::$email_from), Config::$email_from_name); // expéditeur - $mail->addAddress(strtolower($recipient), Config::$email_dest_name); // destinataire - - // Contenu - $mail->isHTML(true); - if($true_email){ - $mail->Subject = 'Message envoyé par: ' . $name . ' (' . $email . ') depuis le site web'; - - } - else{ - $mail->Subject = "TEST d'un envoi d'e-mail depuis le site web"; - } - $mail->Body = $message; - $mail->AltBody = $message; - - $mail->send(); - return true; - } - catch(Exception $e){ - return false; - //echo "Le message n'a pas pu être envoyé. Erreur : {$mail->ErrorInfo}"; - } - } - - static public function submit(array $json, EntityManager $entityManager): void - { - $captcha_solution = (isset($_SESSION['captcha']) && is_int($_SESSION['captcha'])) ? $_SESSION['captcha'] : 0; - $captcha_try = isset($json['captcha']) ? Captcha::controlInput($json['captcha']) : 0; - - // contrôles des entrées - $name = htmlspecialchars(trim($json['name'])); - $email = strtolower(htmlspecialchars(trim($json['email']))); - $message = htmlspecialchars(trim($json['message'])); - - // destinataire = e-mail par défaut dans config.ini OU choisi par l'utilisateur - $form_data = $entityManager->find('App\Entity\NodeData', $json['id']); - $recipient = $form_data->getData()['email'] ?? Config::$email_dest; - - if($captcha_try != 0 && $captcha_solution != 0 && ($captcha_try === $captcha_solution) - && filter_var($email, FILTER_VALIDATE_EMAIL) && isset($json['hidden']) && empty($json['hidden']) - && self::send($recipient, true, $name, $email, $message)) - { - $db_email = new Email($email, Config::$email_dest, $message); - $entityManager->persist($db_email); - $entityManager->flush(); - echo json_encode(['success' => true]); - } - else{ - echo json_encode(['success' => false]); - } - die; - } -} \ No newline at end of file diff --git a/src/controller/UserController.php b/src/controller/UserController.php index 50e8bf7..f0880bb 100644 --- a/src/controller/UserController.php +++ b/src/controller/UserController.php @@ -1,7 +1,15 @@ UserController devrait se limiter à gérer des requêtes et réponses (changement transparent pour le routeur) +il instancierait un classe correspondant au formulaire (prend POST et SESSION) et une classe "métier" UserService +=> UserService contiendrait des méthodes utilisant l'objet formulaire pour agir sur la BDD +=> les formulaires peuvent tenir dans une classe "UserUpdateForm" avec des stratégies ou plusieurs, les données y sont validées +=> il est aussi possible de découper UserController en contrôleurs par fonctionnalité: +Auth (connexion, deconnexion), User (infos, choix photo), Account (créer, supprimer compte), Avatar (upload photo...) +*/ declare(strict_types=1); @@ -11,6 +19,7 @@ use App\Entity\Log; class UserController { + // account static public function existUsers(EntityManager $entityManager): bool { // optimiser ça si possible, on veut juste savoir si la table est vide ou non @@ -28,71 +37,34 @@ class UserController } } + // account static public function createUser(EntityManager $entityManager) { - // test mauvais paramètres - if(!isset($_POST['login']) || empty($_POST['login']) - || !isset($_POST['password']) || empty($_POST['password']) - || !isset($_POST['password_confirmation']) || empty($_POST['password_confirmation']) - || !isset($_POST['create_user_hidden']) || !empty($_POST['create_user_hidden'])) - { - header('Location: ' . new URL); - die; - } - unset($_SESSION['user']); - $captcha_solution = (isset($_SESSION['captcha']) && is_int($_SESSION['captcha'])) ? $_SESSION['captcha'] : 0; - $captcha_try = isset($_POST['captcha']) ? Captcha::controlInput($_POST['captcha']) : 0; - unset($_SESSION['captcha']); + $form = new FormValidation($_POST, 'create_user'); + $url = new URL; $error = ''; - if($captcha_try == 0) - { - $error = 'error_non_valid_captcha'; - } - elseif($captcha_solution == 0) // ne peut pas arriver, si? - { - $error = 'captcha_server_error'; - } - elseif($captcha_try != $captcha_solution) // le test! - { - $error = 'bad_solution_captcha'; + if($form->validate()){ + $password = password_hash($_POST['password'], PASSWORD_DEFAULT); + $user = new App\Entity\User($_POST['login'], $password); + $entityManager->persist($user); + $entityManager->flush(); } - elseif($_POST['password'] !== $_POST['password_confirmation']) - { - $error = 'different_passwords'; + else{ + $error = $form->getErrors()[0]; // la 1ère erreur sera affichée } - else - { - $login = self::removeSpacesTabsCRLF(htmlspecialchars($_POST['login'])); - $password = self::removeSpacesTabsCRLF(htmlspecialchars($_POST['password'])); - - // self::removeSpacesTabsCRLF prévient la validation par erreur d'une chaine "vide" - - // conformité - if(!empty($password) && !empty($login) - && $password === $_POST['password'] && $login === $_POST['login']) - { - // enregistrement et redirection - $password = password_hash($password, PASSWORD_DEFAULT); - $user = new App\Entity\User($login, $password); - $entityManager->persist($user); - $entityManager->flush(); - - header('Location: ' . new URL); - die; - } - else{ - $error = 'forbidden_characters'; - } + + if(!empty($error)){ + $url->addParams(['error' => $error]); } - $url = empty($error) ? new URL : new URL(['error' => $error]); header('Location: ' . $url); die; } + // auth static public function connect(EntityManager $entityManager): void { if($_SESSION['admin']) // déjà connecté? @@ -100,74 +72,52 @@ class UserController header('Location: ' . new URL); die; } - $_SESSION['user'] = ''; $_SESSION['admin'] = false; - $captcha_solution = (isset($_SESSION['captcha']) && is_int($_SESSION['captcha'])) ? $_SESSION['captcha'] : 0; - $captcha_try = isset($_POST['captcha']) ? Captcha::controlInput($_POST['captcha']) : 0; - unset($_SESSION['captcha']); + $form = new FormValidation($_POST, 'connection'); $error = ''; - if($captcha_try == 0) - { - $error = 'error_non_valid_captcha'; - } - elseif($captcha_solution == 0) // pas censé se produire - { - $error = 'captcha_server_error'; - } - elseif($captcha_try != $captcha_solution) // le test! - { - $error = 'bad_solution_captcha'; - } - elseif(!isset($_POST['login']) || empty($_POST['login']) - || !isset($_POST['password']) || empty($_POST['password'])) - { - $error = 'bad_login_or_password'; - } - else // c'est OK - { - $login = trim($_POST['login']); - $password = trim($_POST['password']); - $user = self::getUser($login, $entityManager); - - // enregistrement et redirection - if(!empty($user) && $login === $user->getLogin() && password_verify($password, $user->getPassword())) + if($form->validate()){ + // à mettre dans une classe métier UserService, Authentication, AuthService? + $user = self::getUser($_POST['login'], $entityManager); + if(!empty($user) && $_POST['login'] === $user->getLogin() && password_verify($_POST['password'], $user->getPassword())) { $log = new Log(true); - $entityManager->persist($log); - $entityManager->flush(); // protection fixation de session, si l'attaquant crée un cookie de session, il est remplacé session_regenerate_id(true); - - $_SESSION['user'] = $login; + $_SESSION['user'] = $_POST['login']; $_SESSION['admin'] = true; $url = new URL(isset($_GET['from']) ? ['page' => $_GET['from']] : []); isset($_GET['id']) ? $url->addParams(['id' => $_GET['id']]) : ''; - header('Location: ' . $url); - die; } else { $log = new Log(false); - $entityManager->persist($log); - $entityManager->flush(); $error = 'bad_login_or_password'; } + $entityManager->persist($log); + $entityManager->flush(); + } + else{ + $error = $form->getErrors()[0]; // la 1ère erreur sera affichée + } + + if(!empty($error)){ + sleep(1); // défense basique à la force brute + $url = new URL(['page' => 'connexion']); + isset($_GET['from']) ? $url->addParams(['from' => $_GET['from']]) : null; + isset($_GET['id']) ? $url->addParams(['id' => $_GET['id']]) : null; + $url->addParams(['error' => $error]); } - // tous les cas sauf connexion réussie - sleep(1); // défense basique à la force brute - $url = new URL(isset($_GET['from']) ? ['page' => 'connexion', 'from' => $_GET['from']] : []); - isset($_GET['id']) ? $url->addParams(['id' => $_GET['id']]) : ''; - !empty($error) ? $url->addParams(['error' => $error]) : ''; header('Location: ' . $url); die; } + // auth static public function disconnect(): void { // nettoyage complet @@ -183,154 +133,87 @@ class UserController die; } + // user static public function updateUsername(EntityManager $entityManager): void { - if(!$_SESSION['admin']) // superflux, fait dans le routeur - { + if(!$_SESSION['admin']){ // superflux, fait dans le routeur self::disconnect(); } - $captcha_solution = (isset($_SESSION['captcha']) && is_int($_SESSION['captcha'])) ? $_SESSION['captcha'] : 0; - $captcha_try = isset($_POST['captcha']) ? Captcha::controlInput($_POST['captcha']) : 0; - unset($_SESSION['captcha']); - $url = new URL(['page' => 'user_edit']); isset($_GET['from']) ? $url->addParams(['from' => $_GET['from']]) : null; + $form = new FormValidation($_POST, 'username_update'); + $error = ''; - if(!isset($_POST['old_login']) || empty($_POST['old_login']) - || !isset($_POST['password']) || empty($_POST['password']) - || !isset($_POST['new_login']) || empty($_POST['new_login']) - || !isset($_POST['modify_username_hidden']) || !empty($_POST['modify_username_hidden'])) - { - $error = 'bad_login_or_password'; - } - elseif($captcha_try != $captcha_solution) // le test! - { - $error = 'bad_solution_captcha'; - } - else - { - // sécurisation de la saisie - $old_login = $_POST['old_login']; - $password = $_POST['password']; - $new_login = self::removeSpacesTabsCRLF(htmlspecialchars($_POST['new_login'])); - // removeSpacesTabsCRLF pour éviter d'enregistrer une chaîne vide + if($form->validate()){ + // à mettre dans une classe métier UserService? + $user = self::getUser($_POST['login'], $entityManager); + if(password_verify($_POST['password'], $user->getPassword())){ + $user->setLogin($_POST['new_login']); + $entityManager->flush(); + $_SESSION['user'] = $_POST['new_login']; - // tests de conformité - if($old_login !== $_POST['old_login'] || $password !== $_POST['password'] || $new_login !== $_POST['new_login']) - { - $error = 'forbidden_characters'; + $url->addParams(['success_username' => 'new_login']); + $error = ''; } - elseif($old_login !== $_SESSION['user']){ + else{ $error = 'bad_login_or_password'; } - elseif($old_login === $new_login){ - $error = 'same_username_as_before'; - } - else - { - $user = self::getUser($old_login, $entityManager); - - if(password_verify($password, $user->getPassword())) - { - $user->setLogin($new_login); - $entityManager->flush(); - $_SESSION['user'] = $new_login; - - $url->addParams(['success_login' => 'new_login']); - $error = ''; - } - else - { - $error = 'bad_login_or_password'; - } - } } - + else{ + $error = $form->getErrors()[0]; // la 1ère erreur sera affichée + } + if(!empty($error)){ sleep(1); - $url->addParams(['error_login' => $error]); + $url->addParams(['error_username' => $error]); } - header('Location: ' . $url); die; } + // user static public function updatePassword(EntityManager $entityManager): void { - if(!$_SESSION['admin']) // superflux, fait dans le routeur - { + if(!$_SESSION['admin']){ // superflux, fait dans le routeur self::disconnect(); } - $captcha_solution = (isset($_SESSION['captcha']) && is_int($_SESSION['captcha'])) ? $_SESSION['captcha'] : 0; - $captcha_try = isset($_POST['captcha']) ? Captcha::controlInput($_POST['captcha']) : 0; - unset($_SESSION['captcha']); - $url = new URL(['page' => 'user_edit']); isset($_GET['from']) ? $url->addParams(['from' => $_GET['from']]) : null; + $form = new FormValidation($_POST, 'password_update'); + $error = ''; - if(!isset($_POST['login']) || empty($_POST['login']) - || !isset($_POST['old_password']) || empty($_POST['old_password']) - || !isset($_POST['new_password']) || empty($_POST['new_password']) - || !isset($_POST['modify_password_hidden']) || !empty($_POST['modify_password_hidden'])) - { - $error = 'bad_login_or_password'; - } - elseif($captcha_try != $captcha_solution) // le test! - { - $error = 'bad_solution_captcha'; - } - else - { - // sécurisation de la saisie - $login = $_POST['login']; - $old_password = $_POST['old_password']; - $new_password = self::removeSpacesTabsCRLF(htmlspecialchars($_POST['new_password'])); - // removeSpacesTabsCRLF pour éviter d'enregistrer une chaîne vide + if($form->validate()){ + // à mettre dans une classe métier UserService? + $user = self::getUser($_POST['login'], $entityManager); + if(password_verify($_POST['password'], $user->getPassword())){ + $new_password = password_hash($_POST['new_password'], PASSWORD_DEFAULT); + $user->setPassword($new_password); + $entityManager->flush(); - // tests de conformité - if($login !== $_POST['login'] || $old_password !== $_POST['old_password'] || $new_password !== $_POST['new_password']) - { - $error = 'forbidden_characters'; + $url->addParams(['success_password' => 'new_password']); + $error = ''; } - elseif($login !== $_SESSION['user']){ + else{ $error = 'bad_login_or_password'; } - elseif($old_password === $new_password){ - $error = 'same_password_as_before'; - } - else - { - $user = self::getUser($login, $entityManager); - - if(password_verify($old_password, $user->getPassword())) - { - $new_password = password_hash($new_password, PASSWORD_DEFAULT); - $user->setPassword($new_password); - $entityManager->flush(); - - $url->addParams(['success_password' => 'new_password']); - $error = ''; - } - else - { - $error = 'bad_login_or_password'; - } - } } - + else{ + $error = $form->getErrors()[0]; // la 1ère erreur sera affichée + } + if(!empty($error)){ sleep(1); $url->addParams(['error_password' => $error]); } - header('Location: ' . $url); die; } + // dans une classe mère ou un trait après découpage de UserController? static private function getUser(string $login, EntityManager $entityManager): ?User { $users = $entityManager->getRepository('App\Entity\User')->findBy(['login' => $login]); @@ -351,6 +234,7 @@ class UserController return null; } + // dans une classe Form? // erreurs à la création des mots de passe static private function removeSpacesTabsCRLF(string $chaine): string { diff --git a/src/router.php b/src/router.php index 19fe1c1..238cac9 100644 --- a/src/router.php +++ b/src/router.php @@ -63,7 +63,7 @@ elseif($_SERVER['REQUEST_METHOD'] === 'POST'){ { // formulaire de contact if($_GET['action'] === 'send_email'){ - EmailController::submit($json, $entityManager); + ContactFormController::sendVisitorEmail($entityManager, $json); } } } diff --git a/src/view/UserEditBuilder.php b/src/view/UserEditBuilder.php index 63bbfad..3604e91 100644 --- a/src/view/UserEditBuilder.php +++ b/src/view/UserEditBuilder.php @@ -31,8 +31,8 @@ class UserEditBuilder extends AbstractBuilder 'same_password_as_before' => 'Nouveau mot de passe identique au précédent.' ]; - $error_username = isset($_GET['error_login']) ? $error_messages[$_GET['error_login']] : ''; - $success_username = (isset($_GET['success_login']) && $_GET['success_login']) ? 'Identifiant modifié avec succès.' : ''; + $error_username = isset($_GET['error_username']) ? $error_messages[$_GET['error_username']] : ''; + $success_username = (isset($_GET['success_username']) && $_GET['success_username']) ? 'Identifiant modifié avec succès.' : ''; $error_password = isset($_GET['error_password']) ? $error_messages[$_GET['error_password']] : ''; $success_password = (isset($_GET['success_password']) && $_GET['success_password']) ? 'Mot de passe modifié avec succès.' : ''; @@ -51,6 +51,10 @@ class UserEditBuilder extends AbstractBuilder isset($_GET['from']) ? $link_exit->addParams(['page' => $_GET['from'] ]) : ''; isset($_GET['id']) ? $link_exit->addParams(['id' => $_GET['id']]) : ''; + $link_logout = new URL(['action' => 'deconnection']); + isset($_GET['from']) ? $link_logout->addParams(['from' => $_GET['from'] ]) : ''; + isset($_GET['id']) ? $link_logout->addParams(['id' => $_GET['id']]) : ''; + ob_start(); require $viewFile; $this->html = ob_get_clean(); // nouveau contenu diff --git a/src/view/templates/form.php b/src/view/templates/form.php index bcde2f4..25446c1 100644 --- a/src/view/templates/form.php +++ b/src/view/templates/form.php @@ -4,13 +4,13 @@

- + - + - +
@@ -18,7 +18,7 @@
- +
diff --git a/src/view/templates/login.php b/src/view/templates/login.php index 766c114..c40b3a7 100644 --- a/src/view/templates/login.php +++ b/src/view/templates/login.php @@ -9,6 +9,7 @@

+

Montrez que vous n'êtes pas un robot.
diff --git a/src/view/templates/user_create.php b/src/view/templates/user_create.php index dd17547..68e115c 100644 --- a/src/view/templates/user_create.php +++ b/src/view/templates/user_create.php @@ -5,6 +5,7 @@ $error_messages = [ 'error_non_valid_captcha' => 'Erreur au test anti-robot, veuillez saisir un nombre entier.', 'captcha_server_error' => 'captcha_server_error', 'bad_solution_captcha' => 'Erreur au test anti-robot, veuillez réessayer.', + 'bad_login_or_password' => 'Mauvais identifiant ou mot de passe, veuillez réessayer.', 'different_passwords' => 'Les deux mots de passe saisis sont différents', 'forbidden_characters' => 'Caractères interdits: espaces, tabulations, sauts CR/LF.' ]; diff --git a/src/view/templates/user_edit.php b/src/view/templates/user_edit.php index b4b35ed..77cd9f2 100644 --- a/src/view/templates/user_edit.php +++ b/src/view/templates/user_edit.php @@ -14,8 +14,8 @@

-

-

+

+

@@ -37,8 +37,8 @@

-

-

+

+

@@ -54,9 +54,10 @@
\ No newline at end of file -- cgit v1.2.3