From df3612ed7e6691530503f79483d2fdbc032d01b8 Mon Sep 17 00:00:00 2001 From: polo-pc-greta Date: Thu, 27 Mar 2025 10:13:03 +0100 Subject: mise en ligne github --- src/controller/Director.php | 101 ++++++++++++ src/controller/Security.php | 111 +++++++++++++ src/controller/URL.php | 88 ++++++++++ src/controller/ajax.php | 104 ++++++++++++ src/controller/installation.php | 144 ++++++++++++++++ src/controller/password.php | 357 ++++++++++++++++++++++++++++++++++++++++ src/controller/post.php | 17 ++ 7 files changed, 922 insertions(+) create mode 100644 src/controller/Director.php create mode 100644 src/controller/Security.php create mode 100644 src/controller/URL.php create mode 100644 src/controller/ajax.php create mode 100644 src/controller/installation.php create mode 100644 src/controller/password.php create mode 100644 src/controller/post.php (limited to 'src/controller') diff --git a/src/controller/Director.php b/src/controller/Director.php new file mode 100644 index 0000000..896cde1 --- /dev/null +++ b/src/controller/Director.php @@ -0,0 +1,101 @@ +entityManager = $entityManager; + self::$menu_data = new Menu($entityManager); // Menu est un modèle mais pas une entité + self::$page_path = new Path(); + $this->page = self::$page_path->getLast(); + $this->root_node = new Node; // instance mère "vide" ne possédant rien d'autre que des enfants + } + + public function makeRootNode(string $id = ''): void + { + // on récupère toutes les entrées + $dql = 'SELECT n FROM App\Entity\Node n WHERE n.page = :page OR n.page IS null'; + if($id == '') + { + $bulk_data = $this->entityManager + ->createQuery($dql) + ->setParameter('page', $this->page) + ->getResult(); + } + else // avec $_GET['id'] dans l'URL + { + $dql .= ' OR n.article_timestamp = :id'; + $bulk_data = $this->entityManager + ->createQuery($dql) + ->setParameter('page', $this->page) + ->setParameter('id', $id) + ->getResult(); + } + $this->feedObjects($bulk_data); + } + + public function makeArticleNode(string $id = ''): bool + { + $bulk_data = $this->entityManager + ->createQuery('SELECT n FROM App\Entity\Node n WHERE n.article_timestamp = :id') + ->setParameter('id', $id) + ->getResult(); + + if(count($bulk_data) === 0){ + return false; + } + + $this->root_node = $bulk_data[0]; + return true; + } + + public function feedObjects(array $bulk_data): void // $bulk_data = tableau de Node + { + // puis on les range + // (attention, risque de disfonctionnement si les noeuds de 1er niveau ne sont pas récupérés en 1er dans la BDD) + foreach($bulk_data as $node) + { + // premier niveau + if($node->getParent() == null) + { + $this->root_node->addChild($node); + + // spécifique page article + if($node->getName() === 'main' && $this->page->getEndOfPath() == 'article'){ + $main = $node; + } + } + // autres niveaux + else + { + $node->getParent()->addChild($node); + + // spécifique page article + if($node->getName() === 'new' && $this->page->getEndOfPath() == 'article'){ + $new = $node; + } + } + } + if(isset($new)){ + $main->setTempChild($new); + } + } + + public function getRootNode(): Node + { + return $this->root_node; + } +} diff --git a/src/controller/Security.php b/src/controller/Security.php new file mode 100644 index 0000000..ab59d07 --- /dev/null +++ b/src/controller/Security.php @@ -0,0 +1,111 @@ +1, // protection contre les élements et attributs dangereux + + // liste blanche d'éléments HTML + 'elements'=> 'h1, h2, h3, h4, h5, h6, p, s, em, span, strong, a, ul, ol, li, sup, sub, code, blockquote, div, pre, table, caption, colgroup, col, tbody, tr, th, td, figure, img, figcaption', + + // liste noire d'attributs HTML + 'deny_attribute'=> 'id, class' // on garde 'style' + ); + + // faire qu'un certain élément puisse n'avoir que certains attributs, regarder la doc + private static $specHtmLawed = ''; + + public static function secureString(string $chaine): string + { + return trim(htmLawed($chaine, self::$configHtmLawed, self::$specHtmLawed));; + } + + public static function secureFileName(string $chaine): string + { + // sécuriser un nom avec chemin avec basename? + //$chaine = basename($chaine); + + /* + - caractères interdits sous windows / \ : * ? " < > | + - mac autorise les / + - mac interdit : + - linux autorise tout sauf les / + - imagemagick ne supporte pas les : + + - 'espace' fonctionne + - / remplacé par firefox en : + - \ retire ce qui est devant le \ + - * fonctionne + - ? permet le téléchargement mais pas l'affichage + - " ne fonctionne pas, remplacé par %22, filtrer %22 + - < > fonctionnent + - | fonctionne + - = fonctionne, mais je filtre parce qu'on en trouve dans une URL + - ' ` fonctionnent + - % fonctionne + - (){}[] fonctionnent + - ^ fonctionne + - # ne fonctionne pas + - ~ fonctionne + - & fonctionne + - ^ pas encore testé + */ + + // => on remplace tout par des _ + // filtrer / et \ semble inutile + + $cibles = [' ', '/', '\\', ':', '*', '?', '<', '>', '|', '=', "'", '`', '"', '%22', '#']; + $chaine = str_replace($cibles, '_', $chaine); // nécéssite l'extension mbstring + $chaine = mb_strtolower($chaine); + return($chaine); + + // les problèmes avec \ persistent !! + // => javascript + // malheureusement document.getElementById('upload').files[0].name = chaine; ne marche pas! interdit! + // javascript ne doit pas pouvoir accéder au système de fichiers + // solutions: + // - au lieu de fournir une chaine (le chemin du fichier), donner un objet à files[0].name + // - créer une copie du fichier et l'envoyer à la place + // - envoyer le fichier en AJAX + // - envoyer le nom du fichier à part puis renommer en PHP + } +} + +// erreurs à la création des mots de passe +function removeSpacesTabsCRLF(string $chaine): string +{ + $cibles = [' ', "\t", "\n", "\r"]; // doubles quotes !! + return(str_replace($cibles, '', $chaine)); +} + +// lien sans http:// +function fixLinks($data) +{ + // 1/ + // si une adresse est de type "domaine.fr" sans le http:// devant, le comportement des navigateurs est de rechercher un fichier comme si mon adresse commençait par file:// + // tomber ainsi sur une page d'erreur est parfaitement déroutant + + // regex pour détecter les balises et ajouter http:// au début des liens si nécessaire + $pattern = '#(]+href=")((?!https?://)[^>]+>)#'; + //$data = preg_replace($pattern, '$1http://$2', $data); + + // 2/ + // cas où la regex fait mal son boulot: + // l'erreur 404 est gérée par le .htaccess + // et le visiteur est redirigé à la page "menu" + // (ça ne règle pas le problème mais c'est mieux) + + // 3/ + // quand l'éditeur est ouvert (avant de valider l'article), + // le lien qu'on vient de créer apparaît dans l'infobulle, + // cliquer dessus ouvre un onglet sur une erreur 404 + // solution partielle avec le .htaccess + // + // solution? fermer ce nouvel onglet avec echo ''; + // comment déclencher le JS? en faisant qu'une erreur 404 causée pour cette raison soit particulière? + + return($data); +} diff --git a/src/controller/URL.php b/src/controller/URL.php new file mode 100644 index 0000000..956d85d --- /dev/null +++ b/src/controller/URL.php @@ -0,0 +1,88 @@ +params = $gets; + if($anchor != ''){ + $this->setAnchor($anchor); + } + } + + //setters normaux + public function addParams(array $gets): void + { + // array_merge est préféré à l'opérateur d'union +, si une clé existe déjà la valeur est écrasée + $this->params = array_merge($this->params, $gets); + } + public function setAnchor(string $anchor = ''): void + { + if($anchor != ''){ + $this->anchor = '#' . ltrim($anchor, '#'); + } + else{ + $this->anchor = ''; + } + } + + private function makeParams(): string + { + $output = ''; + $first = true; + + foreach($this->params as $key => $value) { + if($first){ + $output .= '?'; + $first = false; + } + else{ + $output .= '&'; + } + $output .= $key . '=' . $value; + } + return $output; + } + + public function __toString(): string + { + return self::$protocol . self::$host . self::$port . self::$path . $this->makeParams() . $this->anchor; + } +} \ No newline at end of file diff --git a/src/controller/ajax.php b/src/controller/ajax.php new file mode 100644 index 0000000..130c4c6 --- /dev/null +++ b/src/controller/ajax.php @@ -0,0 +1,104 @@ +makeArticleNode($articleId)) // une entrée est trouvée + { + $node = $director->getRootNode(); + $node->getArticle()->setContent($content); + $entityManager->flush(); + + echo json_encode(['success' => true]); + } + else{ + echo json_encode(['success' => false, 'message' => 'Aucune entrée trouvée en BDD']); + } + } + else{ + echo json_encode(['success' => false, 'message' => 'Erreur de décodage JSON']); + } + die; + } + elseif($_GET['action'] === 'delete_article' && isset($json['id'])) + { + $articleId = $json['id']; + + $director = new Director($entityManager); + $director->makeArticleNode($articleId); + $node = $director->getRootNode(); + $entityManager->remove($node); + $entityManager->flush(); + + // test avec une nouvelle requête qui ne devrait rien trouver + if(!$director->makeArticleNode($articleId)) + { + echo json_encode(['success' => true]); + + // on pourrait afficher une notification "toast" + } + else{ + http_response_code(500); + echo json_encode(['success' => false, 'message' => 'Erreur lors de la suppression de l\'article.']); + } + die; + } +} + +// détection des requêtes d'upload d'image de tinymce +if(strpos($_SERVER['CONTENT_TYPE'], 'multipart/form-data') !== false && isset($_GET['action']) && $_GET['action'] === 'upload_image'){ + if (isset($_FILES['file'])) { + $file = $_FILES['file']; + $dest = 'images/'; + $dest_mini = 'images-mini/'; + + // Vérifier si les répertoires existent, sinon les créer + if(!is_dir($dest)) { + mkdir($dest, 0700, true); + } + if(!is_dir($dest_mini)) { + mkdir($dest_mini, 0700, true); + } + + $filePath = $dest . basename($file['name']); + + // créer une miniature de l'image + + if(move_uploaded_file($file['tmp_name'], $filePath)) { + $image_url = str_replace(basename($_SERVER['SCRIPT_NAME']), '', $_SERVER['SCRIPT_NAME']); + echo json_encode(['location' => $image_url . $filePath]); // renvoyer l'URL de l'image téléchargée + } + else{ + http_response_code(500); + echo json_encode(['message' => 'Erreur 500: Internal Server Error']); + } + } + else{ + http_response_code(400); + echo json_encode(['message' => 'Erreur 400: Bad Request']); + } + die; +} + +// détection des requêtes de type XHR, pas d'utilité pour l'instant +/*elseif(isset($_SERVER['HTTP_X_REQUESTED_WITH']) && $_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest'){ + echo "requête XHR reçue par le serveur"; + die; +}*/ + + diff --git a/src/controller/installation.php b/src/controller/installation.php new file mode 100644 index 0000000..a692618 --- /dev/null +++ b/src/controller/installation.php @@ -0,0 +1,144 @@ +'); + } + } + if(!extension_loaded('imagick') && !extension_loaded('gd')){ + echo("il manque une de ces extensions au choix: imagick (de préférence) ou gd
"); + } + + /* -- droits des fichiers et dossiers -- */ + $droits_dossiers = 0700; + $droits_fichiers = 0600; + + // accès interdit en HTTP + if(!file_exists('../config/.htaccess')){ + $contenu = <<< HTACCESS + + Order Allow,Deny + Deny from all + +HTACCESS; + + $fichier = fopen('../config/.htaccess', 'w'); + fputs($fichier, $contenu); + fclose($fichier); + chmod('../config/.htaccess', $droits_fichiers); + //echo("danger
pas de .htaccess dans config
prévenez le respondable du site"); + //die; + } + + // accès limité en local (600) pour config.ini + if(substr(sprintf('%o', fileperms('../config/config.ini')), -4) != 600){ + chmod('../config/config.ini', $droits_fichiers); + } + + // création de data et sous-dossiers + if(!file_exists('../data')){ + mkdir('../data/'); + chmod('../data/', $droits_dossiers); + } + if(!touch('../data')){ + echo("dossier data non autorisé en écriture"); + die; + } + $sous_dossiers = array('images', 'images-mini', 'videos'); + foreach ($sous_dossiers as $sous_dossier){ + if(!file_exists('../data/' . $sous_dossier)){ + mkdir('../data/' . $sous_dossier); + chmod('../data/' . $sous_dossier, $droits_dossiers); + } + if(!touch('../data/' . $sous_dossier)){ + echo("dossier data non autorisé en écriture"); + die; + } + } +} + +// création de la page d'accueil à la toute 1ère visite du site +// les informations ici ne sont pas demandées à l'utilisateur pour l'instant (on verra ça plus tard) +function makeStartPage(EntityManager $entityManager){ + /* -- table page -- */ + // paramètres: name_page, end_of_path, reachable, in_menu, parent + $accueil = new Page('Accueil', 'accueil', true, true, NULL); + $connection = new Page('Connexion', 'connexion', true, false, NULL); + $article = new Page('Article', 'article', true, false, NULL); + $edit_page = new Page("Modification d'une page", 'modif_page', true, false, NULL); + $new_page = new Page('Nouvelle page', 'nouvelle_page', true, false, NULL); + $edit_paths = new Page("Menu et chemins", 'menu_chemins', true, false, NULL); + + /* -- table node -- */ + // paramètres: name_node, article_timestamp, attributes, position, parent, page, article + $head_accueil = new Node('head', NULL, ['css_array' => ['body', 'head', 'nav', 'main', 'foot'], 'js_array' => ['main']], 1, NULL, $accueil, NULL); + $header = new Node('header', NULL, [], 2, NULL, NULL, NULL); + $nav = new Node('nav', NULL, [], 1, $header, NULL, NULL); + $main = new Node('main', NULL, [], 3, NULL, NULL, NULL); + $footer = new Node('footer', NULL, [], 4, NULL, NULL, NULL); + $breadcrumb = new Node('breadcrumb', NULL, [], 1, $footer, NULL, NULL); + $head_login = new Node('head', NULL, ["stop" => true, 'css_array' => ['body', 'head', 'nav', 'main'], 'js_array' => ['main']], 1, NULL, $connection, NULL); + $login = new Node('login', NULL, [], 1, $main, $connection, NULL); + $head_article = new Node('head', NULL, ['css_array' => ['body', 'head', 'nav', 'main', 'foot'], 'js_array' => ['main']], 1, NULL, $article, NULL); + + /* -- table image -- */ + // paramètres: file_name, file_path, file_path_mini, mime_type, alt + $favicon = new Image("favicon48x48.png", NULL, "assets/favicon48x48.png", "image/png", "favicon"); + $logo = new Image("logo-120x75.jpg", NULL, "assets/logo-120x75.jpg", "image/png", "head_logo"); + $facebook = new Image("facebook.svg", NULL, "assets/facebook.svg", "image/svg+xml", "facebook"); + $instagram = new Image("instagram.svg", NULL, "assets/instagram.svg", "image/svg+xml", "instagram"); + $fond_piscine = new Image("fond-piscine.jpg", "assets/fond-piscine.jpg", NULL, "images/jpg", "fond-piscine"); + + /* -- table node_data -- */ + // paramètres: data, node + $head_accueil_data = new NodeData(["description" => "Club, École de natation et Perfectionnement", "title" => "Les Nageurs Bigoudens"], $head_accueil, new ArrayCollection([$favicon])); + $header_data = new NodeData(["description" => "Club, École de natation et Perfectionnement", "title" => "Les Nageurs Bigoudens", "facebook_link" => "https://www.facebook.com/nageursbigoudens29120", "instagram_link" => "https://www.instagram.com/nageursbigoudens/"], $header, new ArrayCollection([$logo, $facebook, $instagram, $fond_piscine])); + $footer_data = new NodeData(["adresse" => "17, rue Raymonde Folgoas Guillou, 29120 Pont-l’Abbé", "contact_nom" => "Les Nageurs Bigoudens", "e_mail" => "nb.secretariat@orange.fr"], $footer); + $head_login_data = new NodeData(["description" => "Connexion", "title" => "Connexion"], $head_login, new ArrayCollection([$favicon])); + $head_article_data = new NodeData(["description" => "", "title" => ""], $head_article, new ArrayCollection([$favicon])); + + $entityManager->persist($accueil); + $entityManager->persist($connection); + $entityManager->persist($article); + $entityManager->persist($edit_page); + $entityManager->persist($new_page); + $entityManager->persist($edit_paths); + $entityManager->persist($head_accueil); + $entityManager->persist($header); + $entityManager->persist($nav); + $entityManager->persist($main); + $entityManager->persist($footer); + $entityManager->persist($breadcrumb); + $entityManager->persist($head_login); + $entityManager->persist($login); + $entityManager->persist($head_article); + $entityManager->persist($favicon); + $entityManager->persist($logo); + $entityManager->persist($facebook); + $entityManager->persist($instagram); + $entityManager->persist($fond_piscine); + $entityManager->persist($head_accueil_data); + $entityManager->persist($header_data); + $entityManager->persist($footer_data); + $entityManager->persist($head_login_data); + $entityManager->persist($head_article_data); + $entityManager->flush(); + + header('Location: ' . new URL); + die; +} \ No newline at end of file diff --git a/src/controller/password.php b/src/controller/password.php new file mode 100644 index 0000000..d5e66ff --- /dev/null +++ b/src/controller/password.php @@ -0,0 +1,357 @@ +getRepository(User::class)->findAll(); + + // cas particulier table vide + if(count($users) === 0) + { + $_GET = []; + $_SESSION['user'] = ''; + $_SESSION['admin'] = false; + + // création d'un utilisateur, puis rechargement de la page + createPassword($entityManager); + } +} + + +function createPassword(EntityManager $entityManager) +{ + // fonction exécutée à priori deux fois d'affilée: affichage puis traitement de la saisie + + // II - traitement + unset($_SESSION['user']); + + $captcha_solution = (isset($_SESSION['captcha']) && is_int($_SESSION['captcha'])) ? $_SESSION['captcha'] : 0; + $captcha = isset($_POST['captcha']) ? controlCaptchaInput($_POST['captcha']) : 0; + + $error = ''; + if(!isset($_POST['captcha'])) // page rechargée + { + //$error = ''; + } + elseif($captcha == 0) + { + $error = 'error_non_valid_captcha'; + } + elseif($captcha_solution == 0) + { + //$error = ''; + } + elseif($captcha != $captcha_solution) // le test! + { + $error = 'bad_solution_captcha'; + } + elseif(!isset($_POST['password']) || empty($_POST['password']) + || (!isset($_POST['login']) || empty($_POST['login']))) + { + $error = 'bad_login_or_password'; + } + else + { + // -> caractères HTML dangereux supprimés + $login = Security::secureString($_POST['login']); + $password = Security::secureString($_POST['password']); + + // -> prévenir la validation par erreur d'une chaine "vide" + $login = removeSpacesTabsCRLF($login); + $password = removeSpacesTabsCRLF($password); + + // conformité + if(isset($password) && isset($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); + exit(); + } + else + { + $error = 'bad_password'; + } + } + + // inséré dans $captchaHtml puis dans $formulaireNouveauMDP + $captcha = createCaptcha(); + // enregistrement de la réponse du captcha pour vérification + $_SESSION['captcha'] = $captcha[2]; // int + + + // I - affichage + $title = 'Bienvenue nageur bigouden'; + $subHeading = 'Veuillez choisir les codes que vous utiliserez pour gérer le site.'; + + // même vue que la fonction changerMotDePasse() + require('../src/view/password.php'); + + echo($header); + if($error != '') + { + sleep(1); + echo($error_messages[$error]); + } + echo($formulaireNouveauMDP); + echo($error_messages['forbidden_characters']); + echo($footer); + die; +} + + +function connect(LoginBuilder $builder, EntityManager $entityManager) +{ + // déjà connecté + if($_SESSION['admin']) + { + header('Location: ' . new URL); + die; + } + + // II - traitement + $_SESSION['user'] = ''; + $_SESSION['admin'] = false; + + $captcha_solution = (isset($_SESSION['captcha']) && is_int($_SESSION['captcha'])) ? $_SESSION['captcha'] : 0; + $captcha = isset($_POST['captcha']) ? controlCaptchaInput($_POST['captcha']) : 0; + + $error = ''; + if(!isset($_POST['captcha'])) // page rechargée + { + //$error = ''; + } + elseif($captcha == 0) + { + $error = 'error_non_valid_captcha'; + } + elseif($captcha_solution == 0) + { + //$error = ''; + } + elseif($captcha != $captcha_solution) // le test! + { + $error = 'bad_solution_captcha'; + } + elseif(!isset($_POST['login']) || empty($_POST['login']) + || !isset($_POST['password']) || empty($_POST['password'])) + { + $error = 'bad_password'; + } + else // c'est OK + { + $login = $_POST['login']; + $password = $_POST['password']; + $user = getUser($login, $entityManager); + + // enregistrement et redirection + if(password_verify($password, $user->getPassword())) + { + session_start(); + $_SESSION['user'] = $login; + $_SESSION['admin'] = true; + $link = new URL(isset($_GET['from']) ? ['page' => $_GET['from']] : []); + isset($_GET['id']) ? $link->addParams(['id' => $_GET['id']]) : ''; + header('Location: ' . $link); + die; + } + else + { + $error = 'bad_password'; + } + } + + // inséré dans $captchaHtml puis dans $formulaireNouveauMDP + $captcha = createCaptcha(); + // enregistrement de la réponse du captcha pour vérification + $_SESSION['captcha'] = $captcha[2]; // int + + // I - affichage + $title = "Connexion"; + $subHeading = "Veuillez saisir votre identifiant (e-mail) et votre mot de passe."; + + require('../src/view/password.php'); + + //$builder->addHTML($header); + if($error != '') + { + sleep(1); + $builder->addHTML($error_messages[$error]); + } + $builder->addHTML($formulaireConnexion); + //$builder->addHTML($warning_messages['message_cookie']); + $builder->addHTML($warning_messages['private_browsing']); + $builder->addHTML($footer); + + //die; +} + + +function changePassword(EntityManager $entityManager) +{ + // fonction exécutée à priori deux fois d'affilée: affichage puis traitement de la saisie + + // OUT !! + if(empty($_SESSION['user']) || !$_SESSION['admin']) + { + $_SESSION['user'] = ''; + $_SESSION['admin'] = false; + header('Location: index.php'); + die; + } + + // II - traitement + $error = ''; + $success = false; + if(empty($_POST)) // première fois ou page rechargée + { + // + } + elseif(!isset($_POST['login']) || empty($_POST['login']) + || !isset($_POST['old_password']) || empty($_POST['old_password']) + || !isset($_POST['new_password']) || empty($_POST['new_password'])) + { + $error = 'bad_login_or_password'; + } + else + { + // sécurisation de la saisie + $new_password = Security::secureString($_POST['new_password']); + $login = Security::secureString($_POST['login']); + $old_password = Security::secureString($_POST['old_password']); + + // éviter d'enregistrer une chaîne vide + $new_password = removeSpacesTabsCRLF($new_password); + + // tests de conformité + if($login != $_POST['login'] || $old_password != $_POST['old_password'] || $new_password != $_POST['new_password']) + { + $error = 'forbidden_characters'; + } + else + { + $user = getUser($login, $entityManager); + + if(password_verify($old_password, $user->getPassword())) + { + // enregistrement et redirection + $new_password = password_hash($new_password, PASSWORD_DEFAULT); + $user->setPassword($new_password); + $entityManager->flush(); + $success = true; + } + else + { + $error = 'bad_password'; + } + } + } + + + // I - affichage + $title = "Nouveau mot de passe"; + $subHeading = "Veuillez vous identifier à nouveau puis saisir votre nouveau mot de passe."; + + require('../src/view/password.php'); + + echo($header); + if($error != '') + { + sleep(1); // sécurité TRÈS insuffisante à la force brute + echo($error_messages[$error]); + } + elseif($success) + { + $success = false; + echo($alertJSNewPassword); + die; + } + echo($formulaireModifMDP); + echo($footer); + die; +} + + +function getUser(string $login, EntityManager $entityManager): User +{ + $users = $entityManager->getRepository('App\Entity\User')->findBy(['login' => $login]); + + // détection d'un abus + if(count($users) === 0) + { + $_SESSION['user'] = ''; + $_SESSION['admin'] = false; + + header('Location: index.php'); // page création d'un mot de passe à l'attérissage + die; + } + + foreach($users as $user) + { + if($user->getLogin() === $login) + { + return $user; + } + } + header('Location: ' . new URL); + die; +} + + +function disconnect(EntityManager $entityManager) +{ + // nettoyage complet + $_SESSION = []; // mémoire vive + session_destroy(); // fichier côté serveur + setcookie('PHPSESSID', '', time() - 4200, '/'); // cookie de session + $link = new URL(['page' => $_GET['page']]); + isset($_GET['id']) ? $link->addParams(['id' => $_GET['id']]) : ''; + header('Location: ' . $link); + die; +} + + +function createCaptcha(): array +{ + $a = rand(2, 9); + $b = rand(2, 9); + return array(toLettersFrench($a), toLettersFrench($b), $a * $b); +} + +function toLettersFrench(int $number): string +{ + return match($number) + { + 2 => 'deux', + 3 => 'trois', + 4 => 'quatre', + 5 => 'cinq', + 6 => 'six', + 7 => 'sept', + 8 => 'huit', + 9 => 'neuf', + default => '', // erreur + }; +} + +// on veut des chiffres +function controlCaptchaInput(string $captcha = '0'): int +{ + // $captcha est un POST donc une chaîne, '2.3' est acceptés + // (int) supprime les décimales + return (is_numeric($captcha) && $captcha == (int) $captcha) ? (int) $captcha : 0; +} \ No newline at end of file diff --git a/src/controller/post.php b/src/controller/post.php new file mode 100644 index 0000000..926a5ae --- /dev/null +++ b/src/controller/post.php @@ -0,0 +1,17 @@ +