getTokenUser($hash_a_verifier); if ($row) { // 3. Jeton trouvé ! On récupère les infos de l'utilisateur $user = $objUserModel->findUserById($row['token_user_id']); if ($user) { // 4. On recrée la session comme lors d'un login normal $_SESSION['user'] = $user; } } } $intCategory = 0; if (!empty($_GET['filter_cat'])) { $intCategory = (int) $_GET['filter_cat']; } $boolOld = false; if (!empty($_GET['filter_old']) && $_GET['filter_old'] == 'true') { $boolOld = true; } $objProjectModel = new ProjectModel; $arrProject = $objProjectModel->findAll(0,'',0,0,'','','',$intCategory,$boolOld); $arrProjectToDisplay = array(); foreach($arrProject as $arrDetProject){ $objProject = new Project; $objProject->hydrate($arrDetProject); $arrProjectToDisplay[] = $objProject; } $this->_arrData['arrProjectToDisplay'] = $arrProjectToDisplay; $this->_display("home"); } /** * Fonction d'affichage de la barre de recherche */ public function search(){ //Récupérer les informations du formulaire $strKeywords = $_POST['keywords']??''; $intAuthor = $_POST['author']??0; $intPeriod = $_POST['period']??0; $strDate = $_POST['date']??''; $strStartDate = $_POST['startdate']??''; $strEndDate = $_POST['enddate']??''; $intCategory = $_POST['category']??0; // Récupération des projets $objProjectModel = new ProjectModel; $arrProject = $objProjectModel->findAll(intAuthor:$intAuthor, intPeriod:$intPeriod, strDate:$strDate, strKeywords:$strKeywords, strStartDate:$strStartDate, strEndDate:$strEndDate, intCategory:$intCategory); $arrProjectToDisplay = array(); foreach($arrProject as $arrDetProject){ $objProject = new Project; $objProject->hydrate($arrDetProject); $arrProjectToDisplay[] = $objProject; } // Récupération des utilisateurs $objUserModel = new UserModel; $arrUser = $objUserModel->findAllUsers(); // Récupération des catégories $objCategoryModel = new CategoryModel; $arrCategory = $objCategoryModel->findAllCategory(); $this->_arrData['arrProjectToDisplay'] = $arrProjectToDisplay; $this->_arrData['arrCategory'] = $arrCategory; $this->_arrData['arrProject'] = $arrProject; $this->_arrData['arrUser'] = $arrUser; $this->_display("search"); } /** * Fonction d'affichage de la page projet * @author Christel adapter par Guillaume */ public function addedit_project(){ if (!isset($_SESSION['user'])){ // Pas d'utilisateur connecté header("Location:index.php?ctrl=error&action=error_403"); exit; } $objProject = new Project; $objProjectModel = new ProjectModel; $objCategoryModel = new CategoryModel; // Dans la cas de modif if (isset($_GET['id'])){ $arrProject = $objProjectModel->findOne($_GET['id']); $objProject->hydrate($arrProject); // BDD $this->_arrData['arrImages'] = $objProjectModel->getImagesByProjectId($objProject->getId()); } // Tester le formulaire $arrError = []; if (count($_POST) > 0) { $objProject->hydrate($_POST); // Formulaire if ($objProject->getTitle() == ""){ $arrError['title'] = "Le titre est obligatoire"; } if ($objProject->getDescription() == ""){ $arrError['description'] = "La description est obligatoire"; } if ($objProject->getContent() == ""){ $arrError['content'] = "Le contenu est obligatoire"; } // Vérification de l'image (Thumbnail) $arrTypeAllowed = array('image/jpeg', 'image/png', 'image/webp'); if ($_FILES['thumbnail']['error'] != 4){ if (!in_array($_FILES['thumbnail']['type'], $arrTypeAllowed)){ $arrError['thumbnail'] = "Le type de fichier n'est pas autorisé"; }else{ switch ($_FILES['thumbnail']['error']){ case 0 : $strImageName = uniqid().".webp"; $strOldImg = $objProject->getThumbnail(); $objProject->setThumbnail($strImageName); break; case 1 : $arrError['thumbnail'] = "Le fichier est trop volumineux"; break; case 2 : $arrError['thumbnail'] = "Le fichier est trop volumineux"; break; case 3 : $arrError['thumbnail'] = "Le fichier a été partiellement téléchargé"; break; case 6 : $arrError['thumbnail'] = "Le répertoire temporaire est manquant"; break; default : $arrError['thumbnail'] = "Erreur sur l'image"; break; } } }else{ if (is_null($objProject->getThumbnail())){ $arrError['thumbnail'] = "L'image est obligatoire"; } } // SI pas d'erreur : on traite l'image principale if (count($arrError) == 0){ $boolImageOk = true; // On peux changer ces dimensions si on veux que la miniature soit plus grande/petite if (isset($strImageName)){ $strDest = $_ENV['IMG_PROJECT_PATH'].$strImageName; $strSource = $_FILES['thumbnail']['tmp_name']; list($intWidth, $intHeight) = getimagesize($strSource); // Redimensionnement de la Thumbnail $intDestWidth = 200; $intDestHeight = 250; $fltDestRatio = $intDestWidth / $intDestHeight; $fltSourceRatio = $intWidth / $intHeight; if ($fltSourceRatio > $fltDestRatio) { $intCropHeight = $intHeight; $intCropWidth = (int)round($intHeight * $fltDestRatio); $intCropX = (int)(($intWidth - $intCropWidth) / 2); $intCropY = 0; } else { $intCropWidth = $intWidth; $intCropHeight = (int)round($intWidth / $fltDestRatio); $intCropX = 0; $intCropY = (int)(($intHeight - $intCropHeight) / 2); } $objDest = imagecreatetruecolor($intDestWidth, $intDestHeight); switch ($_FILES['thumbnail']['type']) { case 'image/jpeg' : $objSource = imagecreatefromjpeg($strSource); break; case 'image/png' : $objSource = imagecreatefrompng($strSource); break; case 'image/webp' : $objSource = imagecreatefromwebp($strSource); break; } imagecopyresampled($objDest, $objSource, 0, 0, $intCropX, $intCropY, $intDestWidth, $intDestHeight, $intCropWidth, $intCropHeight); $boolImageOk = imagewebp($objDest, $strDest); //Suppression des doublons pour la mémoire vive imagedestroy($objDest); imagedestroy($objSource); } // SI image ok, on balance tout dans la bdd if ($boolImageOk){ if (!isset($_GET['id'])){ $objProject->setUser_id($_SESSION['user']['user_id']); $boolOk = $objProjectModel->insert($objProject); } else { $boolOk = $objProjectModel->updateProject($objProject); } // Gestion des 20 Images après l'envoie de la Thumbnail en BDD if ($boolOk){ //Si pas d'erreur if (isset($_FILES['imageProject']) && $_FILES['imageProject']['error'][0] != 4) { $files = $_FILES['imageProject']; $maxPhotos = 20; // 1. On compte combien d'images le projet possède déjà en BDD $currentImages = $objProjectModel->getImagesByProjectId($objProject->getId()); $totalExisting = count($currentImages); // 2. On calcule combien de photos on peut encore ajouter $remainingSlots = $maxPhotos - $totalExisting; // Si on a déjà atteint ou dépassé la limite, on ne traite même pas les fichiers if ($remainingSlots <= 0) { $_SESSION['error'] = "Limite de $maxPhotos photos atteinte. Supprimez-en pour en ajouter de nouvelles."; } else { $uploadedCount = 0; foreach ($files['name'] as $key => $name) { // 3. On utilise le quota restant comme condition d'arrêt if ($uploadedCount >= $remainingSlots) break; if ($files['error'][$key] === 0 && in_array($files['type'][$key], $arrTypeAllowed)) { $galleryName = uniqid() . "_gallery.webp"; $strDestGallery = $_ENV['IMG_PROJECT_PATH'].$galleryName; $strSourceGallery = $files['tmp_name'][$key]; // Reprise de la logique de redimensionnement list($intW, $intH) = getimagesize($strSourceGallery); // On peux changer ces dimensions si on veux que la galerie soit plus grande/petite $intDestW = 150; $intDestH = 150; $fltDestR = $intDestW / $intDestH; $fltSourceR = $intW / $intH; if ($fltSourceR > $fltDestR) { $intCropH = $intH; $intCropW = (int)round($intH * $fltDestR); $intCropX = (int)(($intW - $intCropW) / 2); $intCropY = 0; } else { $intCropW = $intW; $intCropH = (int)round($intW / $fltDestR); $intCropX = 0; $intCropY = (int)(($intH - $intCropH) / 2); } $objDestGallery = imagecreatetruecolor($intDestW, $intDestH); // Création de la source selon le type de chaque image de la boucle switch ($files['type'][$key]) { case 'image/jpeg' : $objSourceGallery = imagecreatefromjpeg($strSourceGallery); break; case 'image/png' : $objSourceGallery = imagecreatefrompng($strSourceGallery); break; case 'image/webp' : $objSourceGallery = imagecreatefromwebp($strSourceGallery); break; } if ($objSourceGallery) { imagecopyresampled($objDestGallery, $objSourceGallery, 0, 0, $intCropX, $intCropY, $intDestW, $intDestH, $intCropW, $intCropH); if (imagewebp($objDestGallery, $strDestGallery)) { // Insertion en BDD $objProjectModel->addImageInProject($galleryName, $objProject->getId()); $uploadedCount++; } imagedestroy($objDestGallery); imagedestroy($objSourceGallery); } } } if ($uploadedCount > 0) { $_SESSION['success'] = "$uploadedCount image(s) ajoutée(s) à la galerie !"; } } } // Suppression de l'ancienne miniature if(isset($strOldImg) && !empty($strOldImg) && isset($strImageName)){ $strOldFile = $_ENV['IMG_PROJECT_PATH'].$strOldImg; if (file_exists($strOldFile)) unlink($strOldFile); } $_SESSION['success'] = (!isset($_GET['id'])) ? "Le projet a bien été créé" : "Le projet a bien été modifié"; header("Location:index.php"); exit; } else { $arrError[] = "Erreur lors de l'enregistrement en base de données"; } } else { $arrError['thumbnail'] = "Erreur dans le traitement de l'image"; } } } // Données pour la vue $this->_arrData['arrCategory'] = $objCategoryModel->findAllCategory(); $this->_arrData['objProject'] = $objProject; $this->_arrData['arrError'] = $arrError; // Si on est en modifications de projet, on récupère les images pour les afficher dans le formulaire if ($objProject->getId()) { // On récupère les images via le modèle et on les stocke dans le tableau de données $this->_arrData['arrImages'] = $objProjectModel->getImagesByProjectId($objProject->getId()); } else { // Sinon on initialise un tableau vide pour éviter que Smarty ne râle $this->_arrData['arrImages'] = []; } $this->_display('addedit_project'); } /** * Fonction d'affichage de projet */ public function display() { $intId = $_GET['id'] ?? null; if ($intId) { $objProjectModel = new ProjectModel(); $arrProject = $objProjectModel->findOne((int)$intId); // CORRECTION ICI : on utilise $intId (pas $id) $arrImages = $objProjectModel->getImagesByProjectId((int)$intId); if ($arrProject) { $objProject = new Project(); $objProject->hydrate($arrProject); $this->_arrData["objProject"] = $objProject; $this->_arrData["arrImages"] = $arrImages; $this->_display("project_display"); } else { header("Location: index.php?ctrl=project&action=home"); exit; } } else { header("Location: index.php?ctrl=project&action=home"); exit; } } /** * Fonction de partage de projet */ public function shareProject(){ if (count($_POST) > 0) { $projectId = (int)($_POST['project_id'] ?? 0); $toEmail = trim($_POST['to_email'] ?? ''); $objProjectModel = new ProjectModel(); $arrProject = $objProjectModel->findOne($projectId); if (!$arrProject) { header("Location: index.php?ctrl=project&action=home"); exit; } $objProject = new Project(); $objProject->hydrate($arrProject); $objMail = new PHPMailer(); $objMail->IsSMTP(); $objMail->Mailer = "smtp"; $objMail->CharSet = PHPMailer::CHARSET_UTF8; $objMail->SMTPDebug = 0; $objMail->SMTPAuth = true; $objMail->SMTPSecure = "tls"; $objMail->Port = 587; $objMail->Host = 'smtp-relay.brevo.com'; $objMail->Username = 'a2a67e001@smtp-brevo.com'; $objMail->Password = 'xsmtpsib-f2af87e12d3db6f1b99802a92c1acda32d45fc32a8446eeed7e49ec91c4ec7ef-AX8Y7YkRWYSmKHwS'; // Désactive la vérification du certificat SSL // Cela permet d'éviter les erreurs liées au certificat, mais réduit la sécurité de la connexion. $objMail->SMTPOptions = [ 'ssl' => [ 'verify_peer' => false, ], ]; $objMail->IsHTML(true); $objMail->setFrom('projet.folliow@hotmail.com', 'Folliow'); $objMail->addAddress($toEmail); $objMail->Subject = "Projet : " . $objProject->getTitle(); $url = "https://php.boulayoune.com/index.php?ctrl=project&action=display&id=" . $projectId; $this->_arrData['projectTitle'] = $objProject->getTitle(); $this->_arrData['projectDescription'] = $objProject->getDescription(); $this->_arrData['projectUrl'] = $url; $objMail->Body = $this->_display("mail_message", false); if ($objMail->Send()) { header("Location: index.php?ctrl=project&action=display&id=".$projectId."&mail=ok"); } else { header("Location: index.php?ctrl=project&action=display&id=".$projectId."&mail=fail"); } exit; } header("Location: index.php?ctrl=project&action=home"); exit; } /** * Fonction de modération de projet = accepté * @author Guillaume */ public function accept(){ //Récupéré l'id dans l'url $intId = $_GET['id']; //Je créer un nouveau model pour exec la commande SQL $objProjectModel = new ProjectModel; $objProjectModel->accept($intId); //Redirection vers la page header("Location: index.php"); exit; } /** * Fonction de modération de projet = refusé * @author Guillaume */ public function refuse(){ //Récupéré l'id dans l'url $intId = $_GET['id']; //Je créer un nouveau model pour exec la commande SQL $objProjectModel = new ProjectModel; $objProjectModel->refuse($intId); //Redirection vers la page header("Location: index.php"); exit; } /** * Fonction de suppression de projet * @author Guillaume */ public function delete(){ //Récupéré l'id dans l'url $intId = $_GET['id']; //Je créer un nouveau model pour exec la commande SQL $objProjectModel = new ProjectModel; $objProjectModel->delete($intId); //Redirection vers la page header("Location: index.php"); exit; } /** * Fonction de changement de statut (Approuvé, Refusé, En attente) * @author Guillaume */ public function change_image_status() { if (isset($_GET['id_img']) && isset($_GET['status'])) { $idImg = (int)$_GET['id_img']; $status = $_GET['status']; // "en_attente" passage à "approuvé" $objProjectModel = new ProjectModel(); // On passe le statut texte directement à ta méthode de modèle if ($objProjectModel->updateImageStatus($idImg, $status)) { $_SESSION['success'] = "Le statut de l'image est désormais : " . ucfirst($status); } } // La redirection : Si on sait d'où on vient, on y retourne, sinon index $urlRedirect = isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : "index.php"; header("Location: " . $urlRedirect); exit; } /** * Fonction de validation de l'image de projet * @author Guillaume */ public function delete_image() { // Vérifier l'id de l'image $idImg = $_GET['id_img']; $objProjectModel = new ProjectModel(); // Récupérer le nom du fichier pour le supprimer physiquement $image = $objProjectModel->findImage($idImg); if ($image) { $filePath = $_ENV['IMG_PROJECT_PATH'] . $image['image_name']; if (file_exists($filePath)) unlink($filePath); $objProjectModel->deleteImage($idImg); $_SESSION['success'] = "Image supprimée !"; } // La redirection : Si on sait d'où on vient, on y retourne, sinon index $url = (isset($_SERVER['HTTP_REFERER'])) ? $_SERVER['HTTP_REFERER'] : "index.php"; header("Location: " . $url); exit; } /** * Fonction d'ajout des 20 images max du projet * @author Guillaume * @param string $fileName = le nom de l'image, int $projectId = L'Id du projet que l'on veut afficher, string $alt = qui affichera pars défaut "Image de projet" * @return bool Est-ce que la requête s'est bien passée */ public function addImageInProject(string $fileName, int $projectId, string $alt = "Image de projet"): bool { $strRq = "INSERT INTO image ( image_name, image_alt, image_status, image_project ) VALUES (:name, :alt, :status, :project)"; $rqPrep = $this->_db->prepare($strRq); $rqPrep->bindValue(":name", $fileName, PDO::PARAM_STR); $rqPrep->bindValue(":alt", $alt, PDO::PARAM_STR); $rqPrep->bindValue(":status", "en_attente", PDO::PARAM_STR); // Valeur string en brute $rqPrep->bindValue(":project", $projectId, PDO::PARAM_INT); return $rqPrep->execute(); } /** * Fonction d'affichage des 20 images max du projet * @author Guillaume * @param array $ProjectId L'Id du projet que l'on veut afficher * @return bool Est-ce que la requête s'est bien passée */ public function getImagesByProjectId(int $projectId): array { $strRq = "SELECT image_id, image_name, image_alt, image_status FROM image WHERE image_project = :id"; $rqPrep = $this->_db->prepare($strRq); $rqPrep->bindValue(":id", $projectId, PDO::PARAM_INT); $rqPrep->execute(); return $rqPrep->fetchAll(PDO::FETCH_ASSOC); } /** * Page mentions légales */ public function mentions(){ // Afficher $this->_display("mentions"); } /** * Page à propos */ public function about(){ // Afficher $this->_display("about"); } }