diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml
index db60a95..e745855 100644
--- a/.github/workflows/deploy.yml
+++ b/.github/workflows/deploy.yml
@@ -15,22 +15,23 @@ jobs:
with:
host: boulayoune.com
username: yass
- key: ${{ secrets.SSH_KEY }}
+ key: |
+ ${{ secrets.SSH_KEY }}
port: 22
+ debug: true
script: |
- set -e
echo "➡️ Connexion réussie !"
cd /var/www/projet_php
echo "➡️ Mise à jour du code..."
- # On enlève le SUDO ici pour que Git utilise la clé de l'utilisateur yass
git fetch origin main
git reset --hard origin/main
echo "➡️ Correction des permissions et nettoyage..."
- # On garde le SUDO ici car ces commandes touchent au système
sudo chown -R yass:www-data /var/www/projet_php
sudo chmod -R 775 /var/www/projet_php/templates_c
sudo rm -rf /var/www/projet_php/templates_c/*
+ sudo chmod -R 775 /var/www/projet_php/uploads/projects
+ sudo chmod -R 775 /var/www/projet_php/uploads/profiles
- echo "✅ Déploiement terminé ! (Shin-en no Egotisu)"
\ No newline at end of file
+ echo "✅ Déploiement terminé ! (Shin-en no Egotisu)"
diff --git a/controllers/project_controller.php b/controllers/project_controller.php
index 9b62f84..ae44662 100644
--- a/controllers/project_controller.php
+++ b/controllers/project_controller.php
@@ -116,20 +116,21 @@
* Fonction d'affichage de la page projet
* @author Christel adapter par Guillaume
*/
- public function addedit_project() {
+ 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;
+ $objProject = new Project;
+ $objProjectModel = new ProjectModel;
+ $objCategoryModel = new CategoryModel;
- // dans la cas de modif
+ // Dans la cas de modif
if (isset($_GET['id'])){
- $arrProject = $objProjectModel->findOne($_GET['id']);
+ $arrProject = $objProjectModel->findOne($_GET['id']);
$objProject->hydrate($arrProject); // BDD
+ $this->_arrData['arrImages'] = $objProjectModel->getImagesByProjectId($objProject->getId());
}
// Tester le formulaire
@@ -147,26 +148,23 @@
if ($objProject->getContent() == ""){
$arrError['content'] = "Le contenu est obligatoire";
- }
+ }
- // Vérification de l'image
- $arrTypeAllowed = array('image/jpeg', 'image/png', 'image/webp');
+ // 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{
- // Vérification des codes d'erreur
switch ($_FILES['thumbnail']['error']){
case 0 :
- // Renommage de l'image
- $strImageName = uniqid().".webp";
-
- // Récupère le nom de l'image avant changement
- $strOldImg = $objProject->getThumbnail();
- // Mise à jour du nom de l'image dans l'objet
+ $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;
@@ -181,113 +179,213 @@
break;
}
}
-
}else{
- // Est-ce que le fichier existe ?
if (is_null($objProject->getThumbnail())){
$arrError['thumbnail'] = "L'image est obligatoire";
}
}
- // SI pas d'erreur : on traite l'image depuis la bdd
- if (count($arrError) == 0){
+ // SI pas d'erreur : on traite l'image principale
+ if (count($arrError) == 0){
- $boolImageOk = true;
-
- // Redimensionnement de l'image
- if (isset($strImageName)){
- $strDest = $_ENV['IMG_PATH'].$strImageName;
- $strSource = $_FILES['thumbnail']['tmp_name'];
- list($intWidth, $intHeight) = getimagesize($strSource);
-
- $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);
- }
+ $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);
- // Condition en fonction de l'extension de l'image
- $objDest = imagecreatetruecolor($intDestWidth, $intDestHeight);
- switch ($_FILES['thumbnail']['type']) {
- case 'image/jpeg' :
+ // 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' :
+ break;
+ case 'image/png' :
$objSource = imagecreatefrompng($strSource);
- break;
- case 'image/webp' :
+ break;
+ case 'image/webp' :
$objSource = imagecreatefromwebp($strSource);
- break;
- }
-
- imagecopyresampled($objDest, $objSource, 0, 0, $intCropX, $intCropY, $intDestWidth, $intDestHeight, $intCropWidth, $intCropHeight);
-
- // Sauvegarde du fichier
- $boolImageOk = imagewebp($objDest, $strDest);
- imagedestroy($objDest);
- imagedestroy($objSource);
- }
+ 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);
- }
+ // 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;
- if ($boolOk){
- // Suppression de l'ancienne image
- if(isset($strOldImg) && !empty($strOldImg) && isset($strImageName)){
- $strOldFile = $_ENV['IMG_PATH'].$strOldImg;
- if (file_exists($strOldFile)) unlink($strOldFile);
- }
+ // 1. On compte combien d'images le projet possède déjà en BDD
+ $currentImages = $objProjectModel->getImagesByProjectId($objProject->getId());
+ $totalExisting = count($currentImages);
- $_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";
- }
- }
+ // 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;
+ $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["arrProject"] = $arrProject;
+
+ $this->_arrData["objProject"] = $objProject;
+ $this->_arrData["arrImages"] = $arrImages;
+
$this->_display("project_display");
+
} else {
header("Location: index.php?ctrl=project&action=home");
exit;
@@ -298,6 +396,9 @@
}
}
+ /**
+ * Fonction de partage de projet
+ */
public function shareProject(){
if (count($_POST) > 0)
{
@@ -364,6 +465,10 @@
exit;
}
+ /**
+ * Fonction de modération de projet = accepté
+ * @author Guillaume
+ */
public function accept(){
//Récupéré l'id dans l'url
@@ -377,7 +482,11 @@
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
@@ -391,7 +500,11 @@
header("Location: index.php");
exit;
}
-
+
+ /**
+ * Fonction de suppression de projet
+ * @author Guillaume
+ */
public function delete(){
//Récupéré l'id dans l'url
@@ -406,6 +519,99 @@
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
*/
@@ -413,8 +619,7 @@
// Afficher
$this->_display("mentions");
}
-
-
+
/**
* Page à propos
*/
diff --git a/controllers/templates_c/299f75d7692a19207f23bf5795a2721f507c3fc6_0.file_home.tpl.php b/controllers/templates_c/299f75d7692a19207f23bf5795a2721f507c3fc6_0.file_home.tpl.php
new file mode 100644
index 0000000..208dcfd
--- /dev/null
+++ b/controllers/templates_c/299f75d7692a19207f23bf5795a2721f507c3fc6_0.file_home.tpl.php
@@ -0,0 +1,69 @@
+getCompiled()->isFresh($_smarty_tpl, array (
+ 'version' => '5.7.0',
+ 'unifunc' => 'content_6985a47abcda40_19846426',
+ 'has_nocache_code' => false,
+ 'file_dependency' =>
+ array (
+ '299f75d7692a19207f23bf5795a2721f507c3fc6' =>
+ array (
+ 0 => 'views/home.tpl',
+ 1 => 1770365364,
+ 2 => 'file',
+ ),
+ ),
+ 'includes' =>
+ array (
+ 'file:views/_partial/preview.tpl' => 1,
+ ),
+))) {
+function content_6985a47abcda40_19846426 (\Smarty\Template $_smarty_tpl) {
+$_smarty_current_dir = 'C:\\wamp64\\www\\projetphp\\views';
+$_smarty_tpl->getInheritance()->init($_smarty_tpl, false);
+?>
+
+getInheritance()->instanceBlock($_smarty_tpl, 'Block_3150142016985a47abb6c29_00747518', "content");
+?>
+
+
+
+
+
Folliow
+
Là où les talents rencontrent leur avenir
+
Une plateforme de portfolio adapté à vos besoins et aux besoins des entreprises.
+ Créer un portfolio réellement pertinent aux exigences du marché et rentrez
+ directement en contact avec les entreprises.