1. Introduction

Avec la prise de conscience de la crise climatique à laquelle nous devons faire face, nous avons droit à beaucoup de technologies et innovations pour assurer un mode de vie durable. Cependant, un autre type de commerce explose lui aussi, celui de la ‘’fast fashion’’ (référence 1) ou des habits peu chers et souvent, fabriqués en grande quantité en Chine ou en Bangladesh. Ce mode de vente n’est pas compatible avec les enjeux climatiques, car il ne satisfait aucun des piliers de la durabilité en vendant souvent des habits de piètre qualité.

Mon projet a pour but d’offrir un site de service de vente utilisateur-utilisateur disponible uniquement en Suisse (car existant déjà à l'étranger avec Vinted par exemple) afin d’y encourager la vente de seconde main, minimiser le gaspillage et procurer une méthode durable à tous les fans de mode.

Sur ce site, il sera possible de mettre en vente des habits et de fixer le prix à notre guise. Idéalement, un système de messagerie permettrait de poser des questions sur l’article et d’éventuellement négocier le prix. Un compte devra être créé pour acheter et vendre. Il faudra alors enregistrer les données de chaque utilisateur et les produits que ceux-ci mettent en vente. Un outil de recherche doit aussi exister pour faciliter les recherches et satisfaire les utilisateurs. Néanmoins le site ne sera pas très ‘’beau’’, car CSS est compliqué à maîtriser (référence 2) et je ne pourrai qu’explorer la surface de ce qu’il peut proposer. De plus, la sécurité sera plus que discutable étant donné que rien ne garantira la protection des données et des mots de passe des utilisateurs.

2. Matériel et méthodes

2.1 Matériel

  • Ordinateur avec connexion internet
  • Accès aux bases de données MySQL
  • Serveur web

2.2 Méthode

2.2.1 Structure

Le site est organisé de manière à ce que l'utilisateur ne puisse pas interagir avec les articles sans être connecté. Pour cela, on doit structurer le site avec un système de connexion comme montré sur la figure 1. Une fois connecté l'utilisateur peut vendre et acheter des articles.Mind Map.jpg, avr. 2022
Figure 1: Structure du site (créé avec le site Miro.com)

2.2.2 Création de compte et connexion

Dans un premier temps, pour avoir accès à tous les comptes sur le site, il faut avoir une base de données et on doit pouvoir interagir avec. Pour cela, on utilise "MySQL". J'ai choisi d'utiliser la méthode orienté-objet plutôt que la méthode procédurale, car elle me paraissait plus simple à comprendre et plus claire à lire (référence 3).

<?php

    include("../../../etc/mysql.inc.php");

    $servername = "***********";
    $user = "***********";
    $password = "***********";
    $dbname = "*****_julieniffland";

    $conn = new mysqli($servername, $user, $password, $dbname);

?>

Voici le code nécessaire pour créer une connexion à mes tables dans la base de données MySQL. La variable "$conn" sera utilisée pour créer cette connexion à tout moment du code lorsque nous faisons une requête SQL.

La création d'un nouveau compte implique en fait qu'on ajoute une ligne à la table users_list de la base de données MySQL. La méthode que j'ai employée consiste à remplir un formulaire html à l'aide des balises <form> et <input>. Avec l'outil "post" de PHP, les données entrées dans le formulaire sont récupérables et on va pouvoir les insérer dans les bases de données.

        // Check availability
        $av_username = "SELECT username FROM users_list WHERE
                                     username = '$username'";
        $result_av_username = $conn->query($av_username);

        // Add
        if (($pwd == $pwdbis) and ($result_av_username->num_rows == 0)) {
            $sql = "INSERT INTO users_list (username, email, pwd)
                    VALUES ('$username', '$email', '$pwd')";
            $erreur = TRUE;
            if ($conn->query($sql) == TRUE) {
                print ("Compte enregistre<br><br><a href='../connected'> \\
                    se diriger vers la boutique</a>");
            }
        } elseif (($pwd != $pwdbis) and ($result_av_username->num_rows == 0)) {
            print ("Les deux mots de passe ne sont pas identiques.");
        } elseif (($pwd == $pwdbis) and ($result_av_username->num_rows > 0)) {
            print ("Ce nom d'utilisateur n'est pas disponible.");
        } elseif (($pwd != $pwdbis) and ($result_av_username->num_rows > 0)) {
            print ("Ce nom d'utilisateur n'est pas disponible \\
                        et les deux mots de passe ne sont pas identiques.");
        }

Ici, on vérifie d'abord que le nom d'utilisateur est disponible et que le mot de passe et la confirmation du mot de passe concordent. Si c'est le cas on ajoute les données dans la table users_list (figure 2), sinon on affiche un message d'erreur et un lien pour se rediriger vers le formulaire de création de compte.

exemple_sql.jpg, mai 2022 Figure 2: extrait de la table users_list issue de la base de données MySQL

Pour que l'on puisse se connecter sans refaire un compte à chaque fois que l'on arrive sur le site j'ai créé un onglet se connecter sur lequel on doit simplement écrire son nom d'utilisateur et son mot de passe. Grâce à la même méthode "post" que pour la création de compte, on récupère les données du formulaire pour les comparer avec les données de la table users_list.

       // Check data with db

        $sql_user = "SELECT username FROM users_list WHERE
                     username = '$username'";

        $sql_pwd = "SELECT pwd FROM users_list WHERE
                        username = '$username'";

        $result_sql_user = $conn->query($sql_user);
        $result_sql_pwd = $conn->query($sql_pwd);

        if ($result_sql_user->num_rows == 1) {
            while ($row = $result_sql_pwd->fetch_assoc()) {
                $pwdbis = $row['pwd'] ;
            }
        }


        if ($pwd == $pwdbis) {
            $erreur = TRUE;
        } else {
            print ("Nom d'utilisateur ou mot de passe incorrect");
        }

        ?><br>

        <?php

        if ($erreur == FALSE) {
            print ("<br><a href='index.html'>corriger </a>");
        }

        ?>

        <?php

        if ($erreur == TRUE) {
            print ("connexion reussie <br><br> <a href='../connected'> \\
                 se diriger vers la boutique </a>");
        }
        ?>

On va dans un premier temps chercher si le nom d'utilisateur existe. Si c'est le cas on va récupérer le mot de passe de la ligne de l'utilisateur dans la base de donnée à l'aide de la fonction "fetch_assoc()", de la variable "$row" et d'une boucle "while". C'est la façon la plus simple que j'ai trouvée pour récupérer les données des tables (référence 4). On va comparer la valeur sortant de la base de donnée et celle entrée dans le formulaire du site. Si les deux correspondent on va accorder l'accès, sinon un message d'erreur s'affichera.

2.2.3 Etat connecté

Une fois la connexion créée, on se retrouve dans la partie principale du site. On crée une session où l'utilisateur interagira avec la base de données avec son nom en utilisant la variable "$_SESSION". Il pourra alors naviguer sur les pages du site en restant connecté sur le site.

<?php
// start session
session_start();
$username = $_SESSION["username"];
?>

Ce code se trouvera en haut de chacune des pages lorsque nous sommes connectés au site.

<?php
//stop session
session_unset();
?>

Celui-ci se trouve en haut de la page d'accueil du site, celle sur laquelle nous nous retrouvons lorsque nous cliquons sur "déconnexion". Ce code va stopper la session et effacer la variable "$_SESSION" crée au préalable.

2.2.4 Publication d'article

Pour publier des articles, j'ai choisi d'opter pour un formulaire à remplir dont les données insérées à l'aide d'inputs de types "radio", "text", "file" et "number" vont servir à ajouter une nouvelle ligne à la table produts (figure 3) dans ma base de données. Chaque ligne correspond à un article et chaque article possède un id qui sera utile lors des achats.

exemple2_sql.jpg, mai 2022 Figure 3: extrait de la table products de ma base de donnée

Ce formulaire fonctionne avec la méthode "post", comme les formulaires pour créer un compte et se connecter. C'est donc de la même manière qu'on ajoutera les données à la table products. Avec une simple requête SQL, mais ici on aura pas besoin de vérifier si les articles ne sont pas en double, car cela n'a pas d'importance.

Pour avoir des images sur le site, la solution m'étant venue à l'esprit était de créer un dossier sur le site, de télécharger les fichiers jpg ou jpeg ayant été postés par l'utilisateur dans le formulaire et de les placer dans le dossier picture.

        <?php

        $target_dir = "../picture";
        $target_file = $target_dir . basename($_FILES["newfile"]["name"]);
        $imageFileType = strtolower(pathinfo($target_file, PATHINFO_EXTENSION));

        ?>

Ce code doit permettre de récupérer le fichier inséré dans le formulaire de la page précédente pour le placer dans picture (référence 5). La base de données ne stocke pas l'image mais seulement le nom de cette image ainsi que son extension.

2.2.5 Visualisation des articles en ligne

Sur le site on peut visualiser les articles à deux endroits différents. On peut voir les articles mis en vente par nous mêmes sur la page vente du site et on peut voir tous les articles en vente sur la page achat. Pour chaque article, je crée un tableau html dans lequel j'insère les données de la table products que je récupère avec la méthode utilisant la boucle while citée plus haut. Cette méthode va pouvoir récupérer toutes les données dans la table satisfaisant la condition imposée lors de la requête SQL. Dans le cas de la page d'achat on récupère toutes les lignes et dans le cas de la page de vente on récupère seulement les lignes où le contenu de la colonne username correspond au nom de l'utilisateur sur la page.

Code de la page de vente:

        <div class="products">
            <h2> Articles en vente sur votre compte: </h2>
            <p>
            <?php
                if ($num_products > 0) {
                    while ($row = $result_userproducts->fetch_assoc()) {
                        print "<table>";

                        print "<tr><td><img src='../picture/" . \\
                                    $row['picture'] . "'/></td></tr>";
                        print "<tr><td>" . $row['type_clothing'] . "</td></tr>";
                        print "<tr><td>" . $row['color1'] . "</td></tr>";
                        print "<tr><td>" . $row['color2'] . "</td></tr>";
                        print "<tr><td>" . $row['gender'] . "</td></tr>";
                        print "<tr><td>Prix: " . $row['price'] . ".-</td></tr>";
                        print "<tr><td>Publie par " . $row['username'] . "</td></tr>";
                        print "<tr><td>" . $row['description'] . "</td></tr><br/>";

                        print "</table>";
                    }
                } else {
                    print ("aucun article en vente pour le moment");
                }

                $conn->close();

            ?></p>
        </div>

Code de la page d'achat:

        <div class="products_to_buy">
            <h2> Articles en vente: </h2>
            <p>
            <?php
                if ($num_products > 0) {
                    while ($row = $result_products->fetch_assoc()) {
                        print "<table>";

                        print "<tr><td>ID de l'article: " . $row['id'] . "</td></tr>";
                        print "<tr><td><img src='../picture/" . \\
                                    $row['picture'] . "'/></td></tr>";
                        print "<tr><td>" . $row['type_clothing'] . "</td></tr>";
                        print "<tr><td>" . $row['color1'] . "</td></tr>";
                        print "<tr><td>" . $row['color2'] . "</td></tr>";
                        print "<tr><td>" . $row['gender'] . "</td></tr>";
                        print "<tr><td>Prix: " . $row['price'] . ".-</td></tr>";
                        print "<tr><td>Publie par " . $row['username'] . "</td></tr>";
                        print "<tr><td>" . $row['description'] . "</td></tr><br/>";

                        print "</table>";
                    }
                } else {
                    print "aucun article en vente pour le moment";
                }
            ?></p>
        </div>

Pour afficher l'image on crée un chemin relatif avec comme dernière partie une variable $row'picture' qui complète ce chemin. Pour savoir si il y a des lignes satisfaisant la condition de la requête SQL, j'utilise la fonction "num_rows" qui va retourner le nombre de la ligne trouvée lors de la requête. Le code va vérifier si il y a au moins une ligne récupérée. Si c'est le cas, il affiche l'article à l'écran et sinon il affiche qu'il n'y a pas d'article en vente.

2.2.6 Recherche d'article et achat

Avant toute chose, les achats ne sont pas de réels transactions, mais des achats fictifs, car les transactions ne font pas partie de ce projet. Pour acheter des articles, j'ai créé un formulaire avec un input de type number où l'on peut rentrer l'id de l'objet que l'on désire. Lorsqu'on appuie sur "acheter" on arrive sur une page qui va vérifier si l'article existe ou non. Si oui, on va demander une confirmation d'achat, sinon on va simplement nous rediriger vers la boutique et nous dire qu'aucun article ne correspond à l'id choisi. En confirmant la commande, on va simplement supprimer la ligne correspondante à l'id saisi de la table products a l'aide d'une requête SQL.

<?php

    $sql = "DELETE FROM products WHERE id='$id'";

    if ($conn->query($sql) == TRUE) {
        print ("<div class='content_home'><p>L'article n'est plus \\
            dans la boutique. Felicitations !</p></div>");
    } else {
        print("erreur");
    }

    $conn->close();

?>


Pour rechercher un article, j'ai opté sur un système de filtre plutôt qu'un outil de recherche à proprement parler. Il est ainsi possible de filtrer les articles en fonction de ce que nous recherchons. J'ai choisi d'utiliser ici aussi un formulaire avec des inputs de type "radio". Comme pour les autres formulaires la méthode "post" est utilisée. Ensuite, on va faire des requêtes SQL avec les données reçues pour finalement afficher tous les articles satisfaisant les conditions données.

<?php

    if (($color1 and $color2) == "none") {
        $sql = "SELECT * FROM products WHERE (type_clothing = '$clothing' \\
                     AND gender = '$gender')";
    } else {
        $sql = "SELECT * FROM products
                WHERE (type_clothing = '$clothing' AND color1 = '$color1' \\
                     AND color2 = '$color2' AND gender = '$gender')";
    }

    $result_products = $conn->query($sql);
    $num_products = $result_products->num_rows;

?>

Ici, on regarde si l'utilisateur a spécifié des couleurs, car en ne faisant pas de différence on aurait eu des problèmes avec les données dans la table SQL étant donné que la colonne "color1" ne peut pas avoir de valeur "none". Or, si on ne cherche pas de couleur en particulier la requête SQL est plus simple. C'est pour cela qu'on vérifie si la couleur importe ou non. Cette technique évite aussi d'avoir une condition par case cochée dans le formulaire. Par exemple, si on recherchait en fonction de la couleur 1 seulement on devrait faire une requête différente de si on recherchait en fonction du type d'article et du genre. Avec ce raisonnement j'aurais dû écrire 24 conditions différentes avec des "if".

Enfin, on va récupérer le résultat de la requête SQL pour afficher tous les articles correspondants.

<div class="products_to_buy">
    <h2> Articles en vente: </h2>
    <p>
    <?php
        if ($num_products > 0) {
            while ($row = $result_products->fetch_assoc()) {
                print "<table>";

                print "<tr><td>ID de l'article: " . $row['id'] . "</td></tr>";
                print "<tr><td><img src='../picture/" . $row['picture'] . "'/></td></tr>";
                print "<tr><td>" . $row['type_clothing'] . "</td></tr>";
                print "<tr><td>" . $row['color1'] . "</td></tr>";
                print "<tr><td>" . $row['color2'] . "</td></tr>";
                print "<tr><td>" . $row['gender'] . "</td></tr>";
                print "<tr><td>Prix: " . $row['price'] . ".-</td></tr>";
                print "<tr><td>Publie par " . $row['username'] . "</td></tr>";
                print "<tr><td>" . $row['description'] . "</td></tr><br/>";

                print "</table>";
            }
        } else {
           print "aucun article ne correspond a votre recherche";
        }
    ?></p>
</div>

Avec la variable "$num_products" on regarde si il y a au moins une ligne récupérée. Si c'est le cas on affiche le nombre de ligne avec la boucle "while", sinon on affiche qu'aucun article n'est trouvé.

2.2.7 Visuel du site et CSS

Pour donner une apparence plus agréable à mon site, j'ai choisi de lier chaque page html du site à un fichier "CSS". Ce fichier va servir à modifier différents aspects des différentes parties de la page html. Pour séparer les parties de la page comme le "header" et la barre de navigation, j'utilise des balises "div" (comme on le voit dans les extraits de code visibles plus haut). On va pouvoir attribuer des classes à ces divs et les modifier via CSS. Par exemple, pour la barre de navigation, chaque page possède une div "navbar" et dans le fichier CSS on décrit comment la barre de navigation doit être. Je me suis inspiré d'un exemple déja existant pour cette barre de navigation et pour comprendre CSS plus généralement (référence 6).

.navbar {
    overflow: hidden;
    background-color: #333;
}

.navbar a {
    float: left;
    display: block;
    text-align: center;
    padding: 14px 16px;
    text-decoration: none;
    color: white;
    font-family: Verdana, sans-serif;
}

.navbar a:hover {
    background-color: #ddd;
    color: black;
}

Ces lignes servent donc à manipuler la forme de cette barre, mais aussi des balises à l'intérieur de la div, comme avec les balises <a>.

Pour chaque partie des pages on va procéder de la même manière. Pour les boutons, les formulaires, les textes, les titres l'en-tête et les inputs des lignes de code similaires à celle ci-dessus vont se retrouver dans le fichier CSS.

3. Résultats

Le site permet la création de compte (figure 5) et la connexion à son compte. On peut y gérer nos habits en vente et en proposer de nouveaux (figure 6) ainsi qu'acheter d'autres habits et effectuer des recherches (figure 7). Le site fonctionne et permet l'interaction avec les autres utilisateurs. Les photos des habits n'apparaissent pas sur le site comme je l'aurai voulu (figure 6 et 7).

homepic.jpg, mai 2022 Figure 4: Page d'accueil

signinpic.jpg, mai 2022 Figure 5: Page de création de compte

sellpic.jpg, mai 2022 Figure 6: Page de vente d'habits de l'utilisateur

buypic.jpg, mai 2022 Figure 7: Page d'achats et de filtrage des articles

4. Discussion

Dans l'ensemble, le site fonctionne tout à fait bien, mais il y a quelques points clairement améliorables à mes yeux.

Premièrement, la sécurité laisse à désirer. Par exemple, les mots de passe de tous les utilisateurs se trouvent sur ma table users_list et ne sont aucunement crypté. Je peux même les modifier à ma guise. Le risque de fuite de mot de passe est grand étant donné que la seule sécurité sont les points à la place des caractères qu'html affiche dans une balise de type "password". De plus, si on se déconnecte du site et qu'on revient simplement une page en arrière, nous revoila connecté. Ces failles sont facilement remarquables, mais nécessite une bien meilleure connaissance d'html et de PHP. On peut aussi accéder à n'importe quelle page du site juste en tapant l'URL, même pour les pages censées être réservées aux utilisateurs connectés.

Deuxièmement, l'affichage des habits était logiquement un des points les plus importants du projet. Or, les images que je mettais dans le site ne se téléchargeait pas à cause d'un bug que je n'ai pas réussi à résoudre. C'est un problème assez handicapant, surtout pour un site proposant des ventes d'habits et cela marque pour moi le plus gros point faible de mon travail.

Ensuite, le travail effectué sur CSS est plutôt minimaliste quant aux temps à disposition pour la réalisation de ce projet. Néanmoins, l'esthétique de mon site est simple et agréable à regarder. CSS est compliqué à maîtriser et j'aurai pu, selon moi, améliorer grandement la mise en page et le dynamisme si j'avais de meilleure connaissance en ce langage.

En addition à cela, j'avais pour projet un système de messagerie pour proposer aux utilisateurs de négocier les prix. Je n'ai finalement pas eu le temps de mettre au point cet aspect, car le temps que cela m'aurait pris m'aurait empêché de terminer mon projet. J'ai alors choisi de laisser cela de côté afin d'avoir un travail "fini".

Malgré cela, je suis satisfait de mon travail, car j'ai pu m'habituer à ces nouveaux langages que sont html, PHP et CSS qui représentaient la plus grande difficulté pour moi. Un des autres obstacles que j'ai dû surmonter était de bien structurer mon site, car en ayant aucune expérience dans ce domaine il y avait un risque que le site soit simplement désorganisé et désagréable à utiliser. Selon moi, j'ai bien réussi la structure de mon site qui est simple et facile à comprendre.

5. Conclusion

Ce projet est une réussite pour moi en considérant le résultat final. Même si certaines fonctionnalités ne fonctionnent pas, l'idée initiale est respectée et la plupart des objectifs que je m'étais fixé aussi. La plateforme propose bien de placer des habits en vente et de commander d'autres habits, le site reste inutilisable pour l'instant pour le grand public, car les images sont clairement essentiels pour un site de vente d'habits et la sécurité des données des utilisateurs n'est pas assez bonne pour proposer ce genre de services.

On pourrait aller bien plus loin en prenant comme base mon projet selon moi. Pour compléter ce travail, l'idéal serait d'ajouter un système de paiement, de messagerie et de panier pour commander plusieurs articles d'un coup. Tous ces ajouts permettraient la mise en ligne de ce site et l'utilisation par le grand public.

En travaillant sur ce projet, j'ai appris que j'appréciais le codage en html et PHP, mais le CSS ne m'intéresse pas plus que ça. Je ne me vois donc pas réaliser d'autres projet web.

Références

1. https://www.treehugger.com/fast-fashion-environmental-ethical-issues4869800#:~:text=Besides%20the%20sheer%20bulk%20of,flights%20and%20maritime%20shipping%20combined

2. https://www.tentononline.com/is-css-easy-to-learn/#:~:text=CSS%20is%20easy%20to%20learn%20and%20get%20started%20with.,quite%20a%20bit%20of%20time

3. https://www.w3schools.com/php/php_mysql_connect.asp

4. https://www.php.net/manual/fr/mysqli-result.fetch-assoc.php

5. https://www.w3schools.com/php/php_file_upload.asp

6. https://www.w3schools.com/css/css_navbar_horizontal.asp