/*! * GJframework * model/User.class.php * v1.1.0 (07/08/2019) * * Created by Guillaume Juncker on 24/08/2018. * Copyright © Guillaume Juncker. All rights reserved. */ /** * User * Classe de gestion des utilisateurs du site */ class User extends DB { private $min_password_len = 8, $max_password_try = 5; public $id = "", $first_name = "", $last_name = "", $email = "", $password = "", $accreditation = 0, $login_date = ""; const ACCREDITATION_NONE = 0, ACCREDITATION_GUEST = 1, ACCREDITATION_MEMBRE = 2, ACCREDITATION_MODERATOR = 3, ACCREDITATION_ADMINISTRATOR = 4, ACCREDITATION_DEVELOPER = 5, ACCREDITATION_GJ = 99; /*------------------------------------------------------------------------------------------------------------------------------*/ /** * __construct * Construit un objet User * [@param mixed $vars: un id, un email ou un tableau de clés => valeurs à rechercher] * @return User: un objet User */ public function __construct($vars = NULL) { if(!is_array($vars) AND !is_numeric($vars)) { $vars = array("email" => $vars);} parent::__construct($vars); } /*------------------------------------------------------------------------------------------------------------------------------*/ /** * initRequiredVars * Implémentation de la fonction parente * @return void */ protected function initRequiredVars() { $this->required_vars = array("first_name", "last_name", "email", "password"); } /** * initUniqueVars * Implémentation de la fonction parente * @return void */ protected function initUniqueVars() { $this->unique_vars = array("email"); } /** * initErrors * Surcharge de la fonction parente pour personnaliser les messages * @return void */ protected function initErrors() { parent::initErrors(); $this->Errors['I_SUCCESS']->message = "Votre compte a bien été créer, bienvenue"; $this->Errors['I_MISSING']->message = "Veuillez renseigner tous les champs obligatoires"; $this->Errors['I_EXISTS']->message = "Vous semblez être déjà inscrit avec cette adresse e-mail, vous pouvez vous connecter"; $this->Errors['I_PASSWORD_LEN'] = new CustomError("warning", "Par sécurité pour vos données personnelles, votre mot de passe doit comporter au minimum ".$this->min_password_len." caractères"); $this->Errors['I_ERROR']->message = "Une erreur s'est produite lors de la création de votre compte, veuillez réessayer"; $this->Errors['L_SUCCESS'] = new CustomError("success", "Bonjour ".$this->first_name); if((new Datime())->hour > 18) { $this->Errors['L_SUCCESS']->message = "Bonsoir ".$this->first_name;} $this->Errors['L_MISSING'] = new CustomError("warning", "Veuillez renseigner tous les champs obligatoires"); $this->Errors['L_FAILURE'] = new CustomError("danger", "Identifiant ou mot de passe invalide, ".($this->max_password_try - ($_SESSION['failures']))." tentative(s) restante(s)"); $this->Errors['U_SUCCESS']->message = "Vos informations personnelles ont bien été modifiées"; $this->Errors['U_MISSING']->message = "Veuillez renseigner tous les champs obligatoires"; $this->Errors['U_EXISTS']->message = "Cette adresse e-mail est déjà utilisée par un autre compte"; $this->Errors['U_ERROR']->message = "Une erreur s'est produite lors de la modification de vos informations personnelles, veuillez réessayer"; $this->Errors['UP_SUCCESS'] = new CustomError("success", "Votre mot de passe a bien été modifié"); $this->Errors['UP_INVALID'] = new CustomError("danger", "Le mot de passe actuel est invalide"); $this->Errors['UP_ERROR'] = new CustomError("danger", "Une erreur s'est produite lors de la modification de votre mot de passe, veuillez réessayer"); $this->Errors['FP_SUCCESS'] = new CustomError("success", "Un code de sécurité à six chiffres vous a été envoyé par e-mail, veuillez le renseigner ici pour choisir votre nouveau mot de passe"); $this->Errors['FP_INVALID'] = new CustomError("danger", "Identifiant invalide"); $this->Errors['SC_INVALID'] = new CustomError("danger", "Code de sécurité invalide ou périmé, ".($this->max_password_try - ($_SESSION['failures']))." tentative(s) restante(s)"); $this->Errors['FP_ERROR'] = new CustomError("danger", "Une erreur s'est produite lors de l'envoi du code de sécurité, veuillez réessayer"); $this->Errors['D_SUCCESS']->message = "Votre compte et toutes vos données personnelles ont bien été effacées"; $this->Errors['D_ERROR']->message = "Une erreur s'est produite lors de la suppression de votre compte, veuillez réessayer"; } /*------------------------------------------------------------------------------------------------------------------------------*/ /** * getByEmail * Version réservée à l'e-mail de la fonction getBy() * @param string $email: l'adresse e-mail à rechercher * @return mixed: l'Objet chargé s'il existe, FALSE sinon */ public function getByEmail(string $email) { return $this->getBy(array("email" => $email)); } /** * getAll * Surcharge de la fonction parente pour vérifier que l'utilisateur actif peut voir tous les utilisateurs * @return array: un tableau de tous les Objets */ public function getAll(string $req = "") { if($this->accreditation>= self::ACCREDITATION_ADMINISTRATOR) { if(!$req) { $req = "WHERE accreditation <= '".$this->accreditation."'";} return parent::getAll($req); } } /** * name * Met en forme le nom complet de l'utilisateur * [@param string $format: le format d'affichage du nom complet] * @return string: le nom de l'utilisateur formaté */ public function name($format = "first last") { if($this->id) { return preg_replace(array("#\bfirst\b#", "#\bf\b#", "#\blast\b#", "#\bl\b#"), array($this->first_name, $this->first_name[0], $this->last_name, $this->last_name[0]), $format); } return ""; } /** * accreditations * Liste l'ensemble des accréditations disponibles * @return array: le tableau des accréditations possibles */ public function accreditations() { return array(self::ACCREDITATION_NONE => "Aucune", self::ACCREDITATION_GUEST => "Invité", self::ACCREDITATION_MEMBRE => "Membre", self::ACCREDITATION_MODERATOR => "Modérateur", self::ACCREDITATION_ADMINISTRATOR => "Administrateur", self::ACCREDITATION_DEVELOPER => "Développeur", self::ACCREDITATION_GJ => "GJ"); } /** * accreditation * Met en forme l'accréditation de l'utilisateur * @return string: l'accréditation de l'utilisateur formaté */ public function accreditation() { return $this->accreditations()[$this->accreditation]; } /*------------------------------------------------------------------------------------------------------------------------------*/ /** * insert * Surcharge de la fonction parente pour ajouter un utilisateur après vérification et modifications de certaines données * @return CustomError: l'erreur déclenchée à l'exécution */ public function insert(array &$vars) { if(strlen($vars['password'])>= $this->min_password_len) { $vars['first_name'] = ucwords(strtolower($vars['first_name'])); $vars['last_name'] = ucwords(strtolower($vars['last_name'])); $vars['email'] = strtolower($vars['email']); $vars['password'] = password_hash($vars['password'], PASSWORD_DEFAULT); return parent::insert($vars); } else { return $this->Errors['I_PASSWORD_LEN'];} } /** * invite * Ajout d'un utilisateur par un autre utilisateur de niveau ADMINISTRATEUR ou plus * @param array $vars: un tableau de clés => valeurs à insérer * @return CustomError: l'erreur déclenchée à l'exécution */ public function invite(array $vars) { if($this->accreditation > $vars['accreditation']) { $password_clear = $vars['password']; if(($insertError = $this->insert($vars))->bool()) { $emailBody = "

Bonjour ".$vars['first_name'].",

Nous vous informons qu'un compte vous a été créer sur le site de base_url."\">".$GLOBALS['_SITE']->name.".

Vous pouvez vous y connecter dès maintenant avec les éléments suivants :

"; $GLOBALS['_SITE']->Email->send($vars['email'], "Bienvenue sur le site de ".$GLOBALS['_SITE']->name, $emailBody); } return $insertError; } else { return $GLOBALS['_SITE']->Errors['ACCESS'];} } /** * login * Vérifie et connecte l'utilisateur à son compte * @param string $password: le mot de passe entré à la connexion * @return CustomError: l'erreur déclenchée à l'exécution */ public function login(string $password) { if(password_verify($password, $this->password)) { $req = $this->pdo()->prepare("UPDATE ".$this->db_table." SET login_date = NOW() WHERE id = :id"); $req->execute(array("id" => $this->id)); $_SESSION['user_id'] = $this->id; unset($_SESSION['failures']); return $this->Errors['L_SUCCESS']; } else { $_SESSION['failures']++; return $this->Errors['L_FAILURE']; } } /** * auth * Permet la connexion au compte invité * @param array $vars: le tableau renvoyé par le formulaire d'authentification * @return CustomError: l'erreur déclenchée à l'exécution */ public function auth($vars) { if($GLOBALS['_SITE']->reCaptcha($_POST['g-recaptcha-response'])) { $_SESSION['auth'] = $vars['ref']; unset($_SESSION['failures']); return $this->Errors['L_SUCCESS']; } $_SESSION['failures']++; return $this->Errors['L_FAILURE']; } /** * update * Surcharge de la fonction parente pour modifier un utilisateur après modifications de certaines données * @return CustomError: l'erreur déclenchée à l'exécution */ public function update(array $vars) { if($this->id!= $GLOBALS['_USER']->id AND $GLOBALS['_USER']->accreditation<= $vars['accreditation']) { return $GLOBALS['_SITE']->Errors['ACCESS']; } $vars['first_name'] = ucwords(strtolower($vars['first_name'])); $vars['last_name'] = ucwords(strtolower($vars['last_name'])); $vars['email'] = strtolower($vars['email']); return parent::update($vars); } /** * setPassword * Modifie le mot de passe de l'utilisateur * @param string $password: le mot de passe actuel * @param string $new_password: le nouveau mot de passe * @return CustomError: l'erreur déclenchée à l'exécution */ public function setPassword(string $password, string $new_password) { if(password_verify($password, $this->password)) { if(strlen($new_password)>= $this->min_password_len) { $new_password = password_hash($new_password, PASSWORD_DEFAULT); $req = $this->pdo()->prepare("UPDATE ".$this->db_table." SET password = :password WHERE id = :id"); if($req->execute(array("id" => $this->id, "password" => $new_password))) { return $this->Errors['UP_SUCCESS']; } else { return $this->Errors['UP_ERROR'];} } else { return $this->Errors['I_PASSWORD_LEN'];} } else { return $this->Errors['UP_INVALID'];} } /** * forgotPassword * Envoi d'un code de sécurité par e-mail pour modifier un mot de passe oublié * @return CustomError: l'erreur déclenchée à l'exécution */ public function forgotPassword() { if($this->id) { $forgotpassword_securitykey = $GLOBALS['_SITE']->strRand(6, FALSE, TRUE, FALSE); setcookie("forgotpassword_securitykey", password_hash($forgotpassword_securitykey, PASSWORD_DEFAULT), time() + 60/*min*/ * 60/*sec*/, "/", NULL, FALSE, TRUE); $emailBody = "

Bonjour,

Vous avez oublié votre mot de passe … pas de panique.

Voici le code de sécurité nécessaire à la suite de la procédure : $forgotpassword_securitykey.

Si vous n'êtes pas l'auteur de cette demande ou si vous avez retrouvé votre mot de passe, vous pouvez simplement ignorer cet e-mail, votre mot de passe reste inchangé.

"; if($GLOBALS['_SITE']->Email->send($this->email, "Code de sécurité", $emailBody)) { $_SESSION['forgotpassword_login'] = $this->email; return $this->Errors['FP_SUCCESS']; } else { return $this->Errors['FP_ERROR'];} } else { return $this->Errors['FP_INVALID'];} } /** * forgotPasswordSecurity * Modification du mot de passe oublié après vérification du code de sécurité * @param int $code: le code de sécurité * @param string $new_password: le nouveau mot de passe * @return CustomError: l'erreur déclenchée à l'exécution */ public function forgotPasswordSecurity(int $code, string $new_password) { if(password_verify($code, $_COOKIE['forgotpassword_securitykey'])) { if(strlen($new_password)>= $this->min_password_len) { $new_password = password_hash($new_password, PASSWORD_DEFAULT); $req = $this->pdo()->prepare("UPDATE ".$this->db_table." SET password = :password WHERE id = :id"); if($req->execute(array("id" => $this->id, "password" => $new_password))) { setcookie("forgotpassword_securitykey", "", time() - 1, "/", NULL, FALSE, TRUE); unset($_SESSION['forgotpassword_login'], $_SESSION['failures']); return $this->Errors['UP_SUCCESS']; } else { return $this->Errors['UP_ERROR'];} } else { return $this->Errors['I_PASSWORD_LEN'];} } else { $_SESSION['failures']++; return $this->Errors['SC_INVALID']; } } /*------------------------------------------------------------------------------------------------------------------------------*/ public function __toString() { // if($this-id== $GLOBALS['_USER']->id) { return "vous";} return $this->name(); } }