diff options
| author | polo <ordipolo@gmx.fr> | 2026-10-23 00:47:32 +0200 |
|---|---|---|
| committer | polo <ordipolo@gmx.fr> | 2026-10-23 00:47:32 +0200 |
| commit | f27cca08ff786ceff1870147f6d6bad14d71117f (patch) | |
| tree | d36597a72025313d6faf4ed228755fa267ebe2f6 /src/Controller/UserController.php | |
| parent | c7309f900ef05bd5cb313110ec159b761af394ec (diff) | |
| download | cms-f27cca08ff786ceff1870147f6d6bad14d71117f.tar.gz cms-f27cca08ff786ceff1870147f6d6bad14d71117f.tar.bz2 cms-f27cca08ff786ceff1870147f6d6bad14d71117f.zip | |
dossiers avec majuscule, namespace pour toutes les classes, autoload psr-4, UserDataService::createZip déplacé dans Backup
Diffstat (limited to 'src/Controller/UserController.php')
| -rw-r--r-- | src/Controller/UserController.php | 237 |
1 files changed, 237 insertions, 0 deletions
diff --git a/src/Controller/UserController.php b/src/Controller/UserController.php new file mode 100644 index 0000000..812a2da --- /dev/null +++ b/src/Controller/UserController.php | |||
| @@ -0,0 +1,237 @@ | |||
| 1 | <?php | ||
| 2 | // src/Controller/UserController.php | ||
| 3 | // | ||
| 4 | /* actuellement un fourre-tout de méthodes en rapport avec les utilisateurs | ||
| 5 | pour l'améliorer on pourrait appliquer le principe de reponsabilité unique | ||
| 6 | => UserController devrait se limiter à gérer des requêtes et réponses (changement transparent pour le routeur) | ||
| 7 | il instancierait un classe correspondant au formulaire (prend POST et SESSION) et une classe "métier" UserService | ||
| 8 | => UserService contiendrait des méthodes utilisant l'objet formulaire pour agir sur la BDD | ||
| 9 | => les formulaires peuvent tenir dans une classe "UserUpdateForm" avec des stratégies ou plusieurs, les données y sont validées | ||
| 10 | => il est aussi possible de découper UserController en contrôleurs par fonctionnalité: | ||
| 11 | Auth (connexion, deconnexion), User (infos, choix photo), Account (créer, supprimer compte), Avatar (upload photo...) | ||
| 12 | */ | ||
| 13 | |||
| 14 | declare(strict_types=1); | ||
| 15 | |||
| 16 | namespace App\Controller; | ||
| 17 | |||
| 18 | use Symfony\Component\HttpFoundation\RedirectResponse; | ||
| 19 | use Doctrine\ORM\EntityManager; | ||
| 20 | use App\Entity\User; | ||
| 21 | use App\Entity\Log; | ||
| 22 | use App\Service\FormValidation; | ||
| 23 | use App\Service\ValidationStrategy; | ||
| 24 | use App\Service\URL; | ||
| 25 | use App\Service\Backup; | ||
| 26 | use App\Service\EmailService; | ||
| 27 | |||
| 28 | class UserController | ||
| 29 | { | ||
| 30 | // account | ||
| 31 | static public function createAdminUser(EntityManager $entityManager): RedirectResponse | ||
| 32 | { | ||
| 33 | unset($_SESSION['user']); | ||
| 34 | |||
| 35 | $form = new FormValidation($_POST, ValidationStrategy::CreateUser); | ||
| 36 | |||
| 37 | $url = new URL; | ||
| 38 | $error = ''; | ||
| 39 | if($form->validate()){ | ||
| 40 | $password = password_hash($_POST['password'], PASSWORD_DEFAULT); | ||
| 41 | $user = new User($_POST['login'], 'admin', $password); | ||
| 42 | $entityManager->persist($user); | ||
| 43 | $entityManager->flush(); | ||
| 44 | } | ||
| 45 | else{ | ||
| 46 | $error = $form->getError(); | ||
| 47 | } | ||
| 48 | |||
| 49 | if(!empty($error)){ | ||
| 50 | $url->addParams(['error' => $error]); | ||
| 51 | } | ||
| 52 | |||
| 53 | return new RedirectResponse((string)$url); | ||
| 54 | } | ||
| 55 | |||
| 56 | // account | ||
| 57 | //static public function createUser(EntityManager $entityManager){} | ||
| 58 | |||
| 59 | // auth | ||
| 60 | static public function connect(EntityManager $entityManager): RedirectResponse | ||
| 61 | { | ||
| 62 | $url = new URL; | ||
| 63 | if(IS_ADMIN){ // déjà connecté? | ||
| 64 | return new RedirectResponse((string)$url); | ||
| 65 | } | ||
| 66 | unset($_SESSION['user']); | ||
| 67 | |||
| 68 | $form = new FormValidation($_POST, ValidationStrategy::Connection); | ||
| 69 | |||
| 70 | $error = ''; | ||
| 71 | if($form->validate()){ | ||
| 72 | // à mettre dans une classe métier UserService, Authentication, AuthService? | ||
| 73 | $user = self::getUserByName($_POST['login'], $entityManager); | ||
| 74 | if(!empty($user) && $_POST['login'] === $user->getLogin() && password_verify($_POST['password'], $user->getPassword())){ | ||
| 75 | $log = new Log(true); | ||
| 76 | |||
| 77 | // protection fixation de session, si l'attaquant crée un cookie de session, il est remplacé | ||
| 78 | session_regenerate_id(true); | ||
| 79 | $_SESSION['user']['id'] = $user->getId(); | ||
| 80 | $_SESSION['user']['username'] = $user->getLogin(); | ||
| 81 | $_SESSION['user']['role'] = $user->getRole(); | ||
| 82 | |||
| 83 | EmailService::cleanEmails($entityManager); | ||
| 84 | |||
| 85 | try{ | ||
| 86 | if(file_exists('../var/backups')){ | ||
| 87 | Backup::mySQLdump($entityManager, 'auto'); // créer un nouveau backup, sauf si les dossiers nécessaires sont encore à créer | ||
| 88 | } | ||
| 89 | } | ||
| 90 | catch(\RuntimeException $e){ | ||
| 91 | echo '<script>window.error_message = "' . $e->getMessage() . '";</script>'; | ||
| 92 | } | ||
| 93 | |||
| 94 | $url->addParams(isset($_GET['from']) ? ['page' => $_GET['from']] : []); | ||
| 95 | isset($_GET['id']) ? $url->addParams(['id' => $_GET['id']]) : ''; | ||
| 96 | } | ||
| 97 | else | ||
| 98 | { | ||
| 99 | $log = new Log(false); | ||
| 100 | $error = 'bad_login_or_password'; | ||
| 101 | } | ||
| 102 | $entityManager->persist($log); | ||
| 103 | $entityManager->flush(); | ||
| 104 | } | ||
| 105 | else{ | ||
| 106 | $error = $form->getError(); | ||
| 107 | } | ||
| 108 | |||
| 109 | if(!empty($error)){ | ||
| 110 | sleep(1); // défense basique à la force brute | ||
| 111 | $url->addParams(['page' => 'connection']); | ||
| 112 | isset($_GET['from']) ? $url->addParams(['from' => $_GET['from']]) : null; | ||
| 113 | isset($_GET['id']) ? $url->addParams(['id' => $_GET['id']]) : null; | ||
| 114 | $url->addParams(['error' => $error]); | ||
| 115 | } | ||
| 116 | |||
| 117 | return new RedirectResponse((string)$url); | ||
| 118 | } | ||
| 119 | |||
| 120 | // auth | ||
| 121 | static public function disconnect(): RedirectResponse | ||
| 122 | { | ||
| 123 | // nettoyage complet | ||
| 124 | unset($_SESSION['user']); // mémoire vive | ||
| 125 | session_destroy(); // fichier côté serveur | ||
| 126 | setcookie('PHPSESSID', '', time() - 86400, '/'); // cookie de session | ||
| 127 | |||
| 128 | // retour même page | ||
| 129 | $url = new URL; | ||
| 130 | isset($_GET['from']) ? $url->addParams(['page' => $_GET['from']]) : ''; | ||
| 131 | isset($_GET['id']) ? $url->addParams(['id' => $_GET['id']]) : ''; | ||
| 132 | return new RedirectResponse((string)$url); | ||
| 133 | } | ||
| 134 | |||
| 135 | // user | ||
| 136 | static public function updateUsername(EntityManager $entityManager): RedirectResponse | ||
| 137 | { | ||
| 138 | if(!IS_ADMIN){ // superflux, fait dans le routeur | ||
| 139 | return self::disconnect(); | ||
| 140 | } | ||
| 141 | |||
| 142 | $url = new URL(['page' => 'user_edit']); | ||
| 143 | isset($_GET['from']) ? $url->addParams(['from' => $_GET['from']]) : null; | ||
| 144 | |||
| 145 | $form = new FormValidation($_POST, ValidationStrategy::UsernameUpdate); | ||
| 146 | |||
| 147 | $error = ''; | ||
| 148 | if($form->validate()){ | ||
| 149 | // à mettre dans une classe métier UserService? | ||
| 150 | $user = self::getUserByName($_POST['login'], $entityManager); | ||
| 151 | if(password_verify($_POST['password'], $user->getPassword())){ | ||
| 152 | $user->setLogin($_POST['new_login']); | ||
| 153 | $entityManager->flush(); | ||
| 154 | $_SESSION['user']['username'] = $_POST['new_login']; | ||
| 155 | |||
| 156 | $url->addParams(['success_username' => 'new_login']); | ||
| 157 | $error = ''; | ||
| 158 | } | ||
| 159 | else{ | ||
| 160 | $error = 'bad_login_or_password'; | ||
| 161 | } | ||
| 162 | } | ||
| 163 | else{ | ||
| 164 | $error = $form->getError(); | ||
| 165 | } | ||
| 166 | |||
| 167 | if(!empty($error)){ | ||
| 168 | sleep(1); | ||
| 169 | $url->addParams(['error_username' => $error]); | ||
| 170 | } | ||
| 171 | return new RedirectResponse((string)$url); | ||
| 172 | } | ||
| 173 | |||
| 174 | // user | ||
| 175 | static public function updatePassword(EntityManager $entityManager): RedirectResponse | ||
| 176 | { | ||
| 177 | if(!IS_ADMIN){ // superflux, fait dans le routeur | ||
| 178 | return self::disconnect(); | ||
| 179 | } | ||
| 180 | |||
| 181 | $url = new URL(['page' => 'user_edit']); | ||
| 182 | isset($_GET['from']) ? $url->addParams(['from' => $_GET['from']]) : null; | ||
| 183 | |||
| 184 | $form = new FormValidation($_POST, ValidationStrategy::PasswordUpdate); | ||
| 185 | |||
| 186 | $error = ''; | ||
| 187 | if($form->validate()){ | ||
| 188 | // à mettre dans une classe métier UserService? | ||
| 189 | $user = self::getUserByName($_POST['login'], $entityManager); | ||
| 190 | if(password_verify($_POST['password'], $user->getPassword())){ | ||
| 191 | $new_password = password_hash($_POST['new_password'], PASSWORD_DEFAULT); | ||
| 192 | $user->setPassword($new_password); | ||
| 193 | $entityManager->flush(); | ||
| 194 | |||
| 195 | $url->addParams(['success_password' => 'new_password']); | ||
| 196 | $error = ''; | ||
| 197 | } | ||
| 198 | else{ | ||
| 199 | $error = 'bad_login_or_password'; | ||
| 200 | } | ||
| 201 | } | ||
| 202 | else{ | ||
| 203 | $error = $form->getError(); | ||
| 204 | } | ||
| 205 | |||
| 206 | if(!empty($error)){ | ||
| 207 | sleep(1); | ||
| 208 | $url->addParams(['error_password' => $error]); | ||
| 209 | } | ||
| 210 | return new RedirectResponse((string)$url); | ||
| 211 | } | ||
| 212 | |||
| 213 | // dans une classe mère ou un trait après découpage de UserController? | ||
| 214 | static private function getUserByName(string $login, EntityManager $entityManager): ?User | ||
| 215 | { | ||
| 216 | $users = $entityManager->getRepository(User::class)->findBy(['login' => $login]); | ||
| 217 | foreach($users as $user){ | ||
| 218 | if($user->getLogin() === $login){ | ||
| 219 | return $user; | ||
| 220 | } | ||
| 221 | } | ||
| 222 | return null; | ||
| 223 | } | ||
| 224 | |||
| 225 | static public function getUserById(int $id, EntityManager $entityManager): ?User | ||
| 226 | { | ||
| 227 | return $entityManager->find(User::class, $id); | ||
| 228 | } | ||
| 229 | |||
| 230 | // dans une classe Form? | ||
| 231 | // erreurs à la création des mots de passe | ||
| 232 | static private function removeSpacesTabsCRLF(string $chaine): string | ||
| 233 | { | ||
| 234 | $cibles = [' ', "\t", "\n", "\r"]; // doubles quotes !! | ||
| 235 | return(str_replace($cibles, '', $chaine)); | ||
| 236 | } | ||
| 237 | } \ No newline at end of file | ||
