Jérôme Cutrona

Version statique de l'intranet de Jérôme Cutrona - Rejoindre la version dynamique 🔒

Les exemples et corrections sont potentiellement non fonctionnels.

B.U.T. Informatique - IUT de Reims - Université de Reims

Envoi de fichiers

Navigation

Objectifs de la séance

  • Utiliser phpMyAdmin pour créer et manipuler une table
  • Écrire une classe PHP simple
  • Effectuer une authentification classique
  • Utiliser les données de session pour mémoriser un objet PHP
  • Simuler un mode client/serveur connecté à l'aide des sessions
  • Limiter l'accès de certaines pages en modifiant le code de réponse HTTP avec « header() » et l'en-tête HTTP « Location »
  • Utiliser les sessions pour y stocker un objet PHP
  • Écrire une classe abstraite et la dériver
  • Effectuer une authentification sécurisée

Introduction

L'objectif est d'enrichir l'utilisateur du TP « Authentification et sessions » en gérant un avatar que l'utilisateur connecté pourra modifier. Cette mise à jour de l'avatar nécessite d'envoyer une image du navigateur du client connecté vers le serveur en mettant en œuvre un téléversement de fichier (classiquement appelé « upload de fichier »).

Les données supplémentaires associées à un utilisateur sont le contenu d'un fichier image. Il pourrait être intéressant de stocker le type d'image (GIF, JPEG, PNG voire WebP), la largeur et la hauteur ou la date de mise à jour de chaque image mais, pour des raisons de simplification du sujet de TP, seul le contenu du fichier sera stocké en base de données. D'un point de vue conception de base de données, nous choisirons d'ajouter un champ supplémentaire dans l'entité « user » plutôt qu'une entité « avatar » en relation avec l'entité « user », toujours pour des raisons de simplicité de réalisation du TP.

Versionnage du projet

Puisque vous enrichissez les fonctionnalités de l'utilisateur créé dans le TP précédent en lui donnant la possibilité de gérer son avatar, vous pouruivrez vos développements dans le même dépôt Git.

Modification de la table « user » avec phpMyAdmin

Vous devez modifier la table « user » pour y ajouter un champ « avatar » de type « BLOB » qui contiendra les mêmes données qu'un fichier PNG.

Travail à réaliser
  1. Connectez-vous sur phpMyAdmin
  2. Sélectionnez votre base de données « votre_login_authentication »
  3. Accédez à la structure de la table « user »
  4. Ajoutez un champ « avatar » avec les caractéristiques suivantes :
    • type « BLOB »
    • pouvant être « null »
    • valeur par défaut « null »
    • type de médias « image/png »
    • transformation d'affichage « Inline (image/png) »
    • transformation de saisie « Image upload »
    Information

    Les paramètres « type de médias », « transformation d'affichage » et « transformation de saisie » sont utilisés dans « phpMyAdmin » pour faciliter l'affichage et la saisie des données binaires. Visualisation d'un enregistrement de la table user avec l'image de l'avatar Visualisation d'un enregistrement de la table user avec l'image de l'avatar

  5. Insérez l'une des images suivantes issues de « https://robohash.org/ » pour votre/vos utilisateurs :
    un avatar issue de https://robohash.org/ un avatar issue de https://robohash.org/ un avatar issue de https://robohash.org/ un avatar issue de https://robohash.org/ un avatar issue de https://robohash.org/
    Remarque importante

    Un bug de phpMyAdmin fait que la case à cocher permettant d'indiquer la valeur « null » du champ « avatar » ne se décoche pas lorsque vous choisissez un fichier. Pensez à la décocher sinon l'avatar continuera à valoir « null ». Erreur demise à jour de l'avatar si la coche null n'est pas décochée

Visualisation du profil de l'utilisateur

L'utilisateur connecté doit pouvoir consulter son profil qui ne comporte pas encore son avatar. Pour cela, vous allez écrire le programme dédié « user.php ».

Travail à réaliser
  1. Créez le programme « user.php » dans le répertoire « public » en prenant « auth.php » comme base
  2. Affichez le profil de l'utilisateur connecté
  3. Vérifiez le fonctionnement de l'ensemble lorsque l'utilisateur est connecté
  4. Faites en sorte que l'utilisateur soit invité à se connecter lorsqu'il ne l'est pas
    • Remplacez la capture des « AuthenticationException » par la capture des « NotLoggedInEception »
    • Effectuez une redirection vers « form.php » dans ce cas
  5. Dans « authenticated.php », ajoutez un lien vers « user.php » ayant le prénom de l'utilisateur comme texte support

Gestion des données de l'avatar : classe « Entity\UserAvatar »

La gestion d'une image contenue en base de données implique d'adapter la conception. En effet, les données représentatives de l'image sont de grande taille par rapport aux autres descripteurs de l'utilisateur : les champs « id », « lastName », « firstName », « login » et « phone » représentent au maximum 259 octets (« sha512pass » n'est jamais sélectionné pour des raisons de sécurité) alors que le type « BLOB » du champ « avatar » peut stocker jusqu'à 65535 octets, soit un rapport de l'ordre de 1 pour 250. De plus, les données « classiques » de l'utilisateur ne sont presque jamais utilisées en même temps que les données « image » de l'avatar puisque l'image est généralement extraite par un programme PHP spécifique désigné dans l'attribut « src » d'une balise « <img /> ».

Les précédentes constatations vont vous amener à écrire une classe « UserAvatar » dédiée à la gestion de l'avatar de l'utilisateur. Diagramme de la classe UserAvatar

Travail à réaliser
  1. Créez à l'emplacement approprié dans la sous-arborescence de « src » la classe « Entity\UserAvatar » dont les attributs privés correspondent aux champs « id » et « avatar » de la table « user » MySQL
    Remarque importante

    L'attribut « id » est de type entier.

    L'attribut « avatar », reflet du champ base de données « avatar » pouvant être « null », doit également pouvoir être « null »

  2. Utilisez votre IDE/éditeur de texte pour générer automatiquement les accesseurs
  3. Écrivez la méthode de classe « findById(int $userId): self » qui recherche dans la base de données l'utilisateur dont l'identifiant est passé en paramètre et retourne une instance de « UserAvatar » ou lève une exception de type « EntityNotFoundException » si aucun enregistrement n'a été trouvé.
    Remarque importante

    Ne sélectionnez que les champs utiles dans votre requête SQL.

    Les données récupérées depuis la base de données par le biais de « PDOStatement » seront structurées sous forme d'instances de « UserAvatar ». Vous utiliserez donc la méthode « fetchObject() ».

    Utilisez « UneClasse::class » pour désigner le nom pleinement qualifié de la classe « UnEspaceDeNom\UnSousEspaceDeNom\UneClasse » lorsqu'elle est importée avec « use ».

  4. Vous n'écrirez aucun modificateur car ils sont inutiles pour le moment.

Production de la réponse HTTP contenant les données de l'image

Comme vous venez de le voir, les données de l'image stockées dans la base de données sont accessibles à travers la classe « UserAvatar ». Afin de proposer l'avatar dans une page Web, il convient d'écrire un programme qui portera ces données de type image dans une réponse HTTP et informera le navigateur de la nature de la charge utile, ici de type image PNG.

Puisque l'avatar dépend d'un utilisateur, le programme devra recevoir un paramètre HTTP de type « GET » « userId » désignant l'identifiant de l'utilisateur dont on souhaite obtenir l'avatar. Le contrôle de ce paramètre sera nécessaire et vous proposerez par défaut l'image suivante dans tous les cas où l'image de l'avatar de l'utilisateur ne peut pas être fournie. Avatar par défaut

Travail à réaliser
  1. Enregistrez l'avatar par défaut dans un sous-répertoire « img » de « public »
  2. Créez le programme « avatar.php » dans le répertoire « public »
  3. Tentez de (« try ») :
    • Récupérer le paramètre de requête HTTP de type « GET » « userId »
    • Utiliser la valeur récupérée du paramètre « userId » dans la méthode « findById() » de la classe « UserAvatar »
    • Récupérer le contenu de l'avatar
  4. Si un problème se produit (« catch »), le contenu de l'avatar sera celui de l'avatar par défaut (utilisez la fonction « file_get_contents() » pour lire le contenu du fichier)
  5. Dans tous les cas, la réponse HTTP produite contient des données de type image et informe le navigateur du client de la nature de la charge utile, ici « image/png »
  6. Testez votre programme dans ses diverses configurations de fonctionnement, avec ou sans paramètre, valide ou pas

Affichage de l'avatar dans le profil de l'utilisateur

Vous disposez à présent du profil de l'utilisateur fourni par la classe « UserProfile » et de l'image de l'avatar de l'utilisateur fournie par le programme « avatar.php » qui utilise la classe « UserAvatar ». Il est temps de réunir les deux pour proposer un profil utilisateur montrant l'image de son avatar : Capture d'écran du profil de l'utilisateur avec son avatar

Vous réaliserez cette tâche dans la classe « UserProfileWithAvatar » : Diagramme de la classe UserProfileWithAvatar

Travail à réaliser
  1. Créez la classe « Html\UserProfileWithAvatar » héritant de « Html\UserProfile »
  2. Écrivez le code de la méthode « toHtml() » de « UserProfileWithAvatar » qui produit le code HTML du profil de l'utilisateur en utilisant la méthode « toHtml() » de « UserProfile » ainsi que le programme « avatar.php » dans une balise « <img /> »
  3. Modifiez le programme « user.php » pour qu'il utilise « UserProfileWithAvatar » en lieu et place de « UserProfile »
  4. Effectuez quelques ajustements de structure et/ou de style pour obtenir un affichage agréable

Modification de l'avatar par l'utilisateur connecté

L'objectif final est de proposer à l'utilisateur connecté de modifier son avatar à l'aide d'un formulaire d'envoi de fichier. Pour y parvenir, vous aurez besoin de modifier l'avatar à travers la classe « UserAvatar » et évidemment de mettre en œuvre un formulaire d'envoi de fichier ainsi que son traitement dans la classe « UserProfileWithAvatar ».

Modification des données de l'avatar

La classe « UserAvatar » nécessite des fonctionnalités de modification de la propriété « avatar » ainsi que de mise à jour de la base de données : Diagramme de la classe UserAvatar.v2

Information

Le diagramme UML de la classe « UserAvatar » présente la précédente version des propriétés et méthodes en gris clair et les nouveaux éléments en blanc.

Travail à réaliser
  1. Définissez la méthode « setAvatar() » à l'aide du générateur de code de PhpStorm
    Information

    N'oubliez pas de cocher l'option « Fluent setters » lors de la génération de code pour permettre le chaînage de méthodes.

  2. Écrivez la méthode « save() » qui met à jour le champ « avatar » de l'enregistrement de l'utilisateur concerné de la base de données
    Information

    Cette méthode peut également être conforme au chaînage de méthodes.

Formulaire d'envoi de fichier

Puisque la classe « UserProfileWithAvatar » gère le profil de l'utilisateur connecté, elle peut se charger de produite le formulaire de modification de l'avatar. Ainsi, vous allez faire évoluer le comportement de la méthode « toHtml() » pour obtenir un visuel similaire à la capture suivante : Capture d'écran du profil de l'utilisateur avec son avatar et le formulaire pour le modifier

Les détails de la structure HTML sous-jacente seront donnés dans le travail à réaliser ci-après.

La mise en place d'un formulaire HTML nécessite de connaître la ressource cible des données envoyées vers le serveur, c'est-à-dire la valeur de l'attribut « action » de la balise « <form> ». Cet élément nécessaire à la méthode « toHtml() » pourrait lui être passé en paramètre. Cependant, dans le lien d'héritage entre « UserProfile » et « UserProfileWithAvatar », « UserProfileWithAvatar » doit se conformer au prototype de la méthode « toHtml() » de son parent « UserProfile » et ne peut pas le modifier. Aussi, la valeur de l'attribut « action » du formulaire doit être injecté dans l'instance de « UserProfileWithAvatar » au moment de sa création et être mémorisé dans une propriété d'instance : Diagramme de la classe UserProfileWithAvatar v2

Information

Le diagramme UML de la classe « UserProfileWithAvatar » présente la précédente version des propriétés et méthodes en gris clair et les nouveaux éléments en blanc.

Travail à réaliser
  1. Ajoutez à la classe « UserProfileWithAvatar » la propriété « formAction » et la constante « AVATAR_INPUT_NAME »
  2. Ajoutez le constructeur et écrivez son code
  3. Modifiez la méthode « toHtml() » pour qu'elle produise le formulaire d'envoi du fichier dont le champ de saisie de type « file » sera nommé grâce à la constante de la classe
    Remarque importante

    Pensez à utiliser la nouvelle constante de classe.

  4. Limitez le type de fichier à PNG en utilisant l'attribut « accept » de la balise « input »
  5. Modifiez l'appel au constructeur de « UserProfileWithAvatar » dans « user.php » pour que la cible du formulaire soit le programme lui-même (voir la clé « 'PHP_SELF' » du tableau « $_SERVER »)
  6. Utilisez le formulaire nouvellement créé pour envoyer le contenu d'une image et observez que la charge utile (corps de la requête) HTTP comporte bien le contenu du fichier : Visualisation de la charge utile d'une requête POST multipart/form-data
    Remarque importante

    Pour de raisons invoquées de performance, vous ne pouvez pas voir le contenu de la charge utile (corps de la requête) sur Chrome si les données envoyées en « POST » sont structurées en « multipart/form-data ». Utilisez Firefox pour cette tâche.

Traitement des données reçues du formulaire d'envoi de fichier

Le formulaire d'envoi d'un fichier produit par la classe « UserProfileWithAvatar » et la modification de l'avatar dans la classe « UserAvatar » sont prêts. Il reste donc à recevoir le contenu du fichier sur le serveur, le vérifier et le traiter pour mettre à jour la base de données. La responsabilité en incombe à la classe « UserProfileWithAvatar » qui proposera une nouvelle méthode « updateAvatar() ». Diagramme de la classe UserProfileWithAvatar v3

Information

Le diagramme UML de la classe « UserProfileWithAvatar » présente la précédente version des propriétés et méthodes en gris clair et les nouveaux éléments en blanc.

Travail à réaliser
  1. Ajoutez à votre classe « UserProfileWithAvatar » la méthode « updateAvatar() »
  2. Dans un premier temps, utilisez simplement le « Dumper » pour consulter le contenu de « $_FILES »
  3. Ajoutez un appel à la méthode « updateAvatar() » dans le programme « user.php », juste à la suite de la construction de l'instance de « UserProfileWithAvatar »
  4. Soumettez un nouveau fichier et constatez le contenu de « $_FILES »
  5. Effectuez chacun des contrôles suivants dans la méthode « updateAvatar() »
    Remarque importante

    Pensez à utiliser la nouvelle constante de classe.

  6. Dans le cas favorable des tests
    • Cherchez le « UserAvatar » correspondant à l'utilisateur connecté
    • Modifiez l'avatar avec le contenu du fichier temporaire
    • Sauvegardez les nouvelles valeurs de l'instance de « UserAvatar » en base de données
    • Effacez le fichier temporaire
    • Retournez « true »
  7. Dans les cas défavorables, retournez « false »

Sujet complémentaire

Si vous avez traité l'ensemble des questions du sujet, vous pouvez poursuivre avec le sujet complémentaire.