En pratique
Dans l'exerice blog, nous allons autoriser l'upload d'une image par article.
Si vous le désirez, vous pouvez télécharger la version de départ sur GitHub >>
Veillez à modifier les valeurs dans les fichiers de configuration (config_perso.inc.php et config.inc.php )
Astuce
Pour télécharger les sources,
- cliquer sur le bouton vert `<> Code`
- cliquer sur `Download Zip`
![]()
Reprenons les étapes une à une :
2 - Ajouter des contraintes côté client
3 - Ajouter des vérifications côté serveur & traitement
4 - Modifier la table dans la BD
5 - Ajuster les droits sur le dossier uploads
Modifier le formulaire
Dans le fichier new.php :
- Ajouter l'input permettant le téléchargement de fichier dans le formulaire
- Préciser le type d'encodage
Soluce
Contraintes côté client
Les fichiers autorisés seront uniquement des images inférieures à 1Mo.
Dans le fichier new.php, ajoutez ces deux contraintes dans le formulaire.
Tip: Travailler avec des constantes et centraliser celles-ci dans un fichier
Soluce
Contraintes côté serveur & traitement
Nous allons réaliser différentes contraintes au niveau serveur et traiter le fichier uploadé.
Fonctions génériques
Warning: Dans un projet, il arrive fréquemment de devoir réaliser des uploads à partir de pages différentes. Afin d'éviter les redondances, il est préconisé d'implémenter des fonctions génériques ou une classe dédiée.
Dans le dossier php, créez un nouveau fichier nommé utils_upload.inc.php qui contiendra nos fonctions :
Gestion des erreurs de téléchargement
Rappelez-vous, lors de l'upload, le tableau $_FILES contient un clé nommée error Rappel >>
Créez une fonction qui reçoit la valeur de cette clé et qui retourne un message d'erreur adapté. Aidez-vous de ces infos >> .
Voici la signature de la fonction à utiliser :
<?php
/**
* Convertit un code d'erreur de téléchargement en message explicatif.
*
*
* @param int $codeErreur Code d'erreur du téléchargement.
* - UPLOAD_ERR_NO_FILE : Fichier manquant.
* - UPLOAD_ERR_INI_SIZE : Fichier dépassant la taille maximale autorisée par PHP.
* - UPLOAD_ERR_FORM_SIZE : Fichier dépassant la taille maximale autorisée par le formulaire.
* - UPLOAD_ERR_PARTIAL : Fichier transféré partiellement.
* - Autre : Erreur inconnue.
*
* @return string|null Message d'erreur si $codeErreur > 0, sinon null.
*/
function obtenirMessageErreurTelechargement(int $codeErreur): ?string{}
Astuce
Utiliser un switch ... case >> sur la valeur de l'erreur.
Validité fichier
Créez une fonction qui vérifie la validité d'un fichier uploadé.
Voici la signature de la fonction.
<?php
/**
* Vérifie la validité d'un fichier uploadé.
*
* @param array $fichier Données du fichier ($_FILES).
* @param array $extensionsAutorisees Extensions autorisées.
* @return bool|string True si le fichier est valide, sinon un message d'erreur.
*/
function verifierUpload(array $fichier, array $extensionsAutorisees): bool|string
{}
Cette fonction va réaliser les vérifications suivantes. En cas d'erreur, personnalisez le message envoyé.
- vérifier si un fichier a bien été envoyé (
if (empty($fichier['name'])) {) - vérifier le code d'erreur (utiliser la fonction
(obtenirMessageErreurTelechargement() )) -
vérifier que l'extension du fichier fait partie de celles attendues.
-
Récupérez l'extension du fichier en utilisant
pathinfo -
exemple :
$infosFichier = pathinfo($_FILES['name']);
$extension = strtolower($infosFichier['extension'] ?? '');
Explication
pathinfo: Analyse une chaîne représentant un chemin de fichier et retourne un tableau associatif contenant des informations telles que :`dirname` : Le chemin du répertoire. `basename` : Le nom complet du fichier (nom + extension). `extension` : L'extension du fichier. `filename` : Le nom du fichier sans l'extension.- vérifier que l'extension du fichier fait partie du tableau des extensions autorisées (reçu en paramètre de la fonction)
-
-
vérifier que la taille du fichier ne dépasse pas la taille autorisée. Rappelez-vous que la taille autorisée a été spécifiée via une constante nommée MAX_FILE_SIZE
Génération nom unique
Créez une fonction qui génére un nom unique, par exemple un identifiant basé sur le temps et le nom du fichier original. Attention, si le nom original comporte plus de 5 caractères, il sera tronqué. Le nom retourné conservera l'extension d'origine. Pour vous aider, utiliser la fonction pathinfo Référence officielle >>
Voici la signature de la fonction.
<?php
/**
* Génère un nom de fichier, en minuscules, unique en conservant l'extension d'origine.
* Le nom d'origine (sans espaces) est tronqué à 5 caractères.
* Retourne false si l'extension est absente.
*
* @param string $nom Nom original du fichier.
* @return string|false Nom de fichier unique ou false.
*/
function genererNomUnique(string $nomOriginal): string|false
{
}
Astuce
pathinfovous permet d'obtenir des infos sous forme d'un tableau associatif- vérifier la présence de l'extension (
empty) - remplacer les espaces blancs (
str_replace) - tronquer une chaine de caractères (
substr) - convertir en minuscules (
strtolower) - générer un code "unique" (
uniqid)
Déplacer le fichier
Créez une fonction qui va traiter déplacer le fichier.
Voici sa signature :
<?php
/**
* Renomme et déplace le fichier
*
* @param array $fichier Données du fichier ($_FILES).
* @return array{
* statut: bool, // true en cas de succès, false sinon.
* filename?: string, // Clé présente uniquement en cas de succès.
* erreur?: string // Clé présente uniquement en cas d'échec.
* } Tableau associatif contenant le résultat de l'opération.
*/
function deplacerFichier(array $fichier): array {}
Cette fonction va :
-
générer un nom unique (utiliser la fonction
genererNomUnique()) -
déplacer le fichier vers le dossier uploads (utiliser la fonction
move_uploaded_file())
Cette fonction deplacerFichier() sera appelée lors de la création ou modification d'un article. Si l'upload se déroule correctement, la requête sql devra enregistrer le nouveau nom de fichier dans la table. Il nous faut donc récupérer ce nom de fichier. Mais si le déplacement de fichier génére une erreur, nous devons récupérer cette erreur pour l'afficher. Comment distinguer si la string retournée est un message d'erreur ou le nom du fichier à stocker dans la table ?
Nous pourrions utiliser des références de variables (comme dans les classes), mais nous allons découvrir une autre technique. [Dans votre projet, vous utiliserez la technique de votre choix.]
Cette fonction va retourner un tableau associatif comprenant les clés suivantes :
-
statut: comporte vrai si l'upload est correctement réalise, faux si une erreur est détectée -
Si le statut est faux, la clé
erreurcomportera un message d'erreur -
Si le statut est vrai, la clé
nomFichierServeurcomportera le nom du fichier à stocker dans la table
Exemple :
<?php
$nomFichierServeur = genererNomUnique($fichier['name']);
if (!$nomFichierServeur) {
return ['statut' => false, 'erreur' => "Impossible de générer un nom de fichier"];
}
Modifier la table dans la BD
- Supprimez et recréez les tables + insert via ce lien>>
- Mettez à jour votre classe
Article(attribut image à ajouter, n'oubliez pas que l'attribut doit porter le même nom que la colonne de la table ) - Modifiez la méthode
insertArticle()(requête sql)
Warning: Ne modifiez toutes vos méthodes ensemble mais travaillez étape par étape.
Modifier les droits sur le dossier uploads
Via un client FTP, modifiez les droits sur le dossier uploads
Gestion de l'insert
Actuellement, dans le fichier new.php, nous vérifions les titre et contenu.
Ajoutons une vérification pour l'upload. Utilisez le tableau $_FILES. Si un fichier est présent, on appelle la fonction verifierUpload().
Si la vérification génére des erreurs, on crée une entrée dans le tableau des erreurs.
Soluce
<?php
// Traitement du fichier uploadé
if (isset($_FILES['photo_article']) && !empty($_FILES['photo_article']['name'])) {
$extensionsAutorisees = ['jpg','png','gif'];
$verifUpload = verifierUpload($_FILES['photo_article'], $extensionsAutorisees);
if ($verifUpload !== true) {
$erreurs[] = $verifUpload;
}
} else {
$erreurs[] = 'image obligatoire';
}
Warning
Testez votre code.
- Ajouter sans donnée
- Ajouter sans image
- Charger une image trop lourde
- Charger un fichier texte
- Charger une bonne image
Si les messages d'erreur/confirmation n'apparaissent pas, corrigez votre code avant d'aller plus loin !
Si aucune erreur n'est générée, on déplace le fichier à l'aide de la fonction deplacerFichier()
Si la fonction ne génère aucune erreur, on récupère le nom du fichier sinon on crée une entrée dans le tableau des erreurs.
Soluce
Si aucune erreur n'est détectée, on crée un objet Article. N'oubliez pas d'ajouter l'attribut $article->nom_img = $nomFichier;
Warning
Testez votre code. L'insert doit avoir lieu.
Si l'insert n'est pas réalisé dans la table, corrigez votre code avant d'aller plus loin !
Ajoutez le lien vers l'image dans la page article.php
Si vous obtenez une erreur de ce type: Warning: move_uploaded_file( /uploads/67d82a01355e0_img_2.jpg): Failed to open stream: No such file or directory in, vérifiez les droits sur le dossier d'uploads, vérifiez le chemin utilisé...
Gestion de la modification
Modifiez la requête dans la classe ArticleRepository
Lorsque nous cliquons sur le bouton Modifier, les données sont affichées dans le formulaire.
Nous allons afficher le nom du fichier dans le formulaire.
Ajoutez le nom du fichier dans le formulaire
Et n'oubliez pas d'assigner la valeur à la variable.
Testez votre code => cliquez sur un bouton modifier, supprimer la valeur du titre et valider. Que se passe-t-il ?
Soluce
La page est rechargée et un message d'erreur indique qu'il manque un titre et une image.
Pourquoi ?
Les données affichées dans le formulaire en cas d'erreur sont celles qui étaient présentes dans des champs du formulaire. Le nom du fichier n'est pas stocké dans un input et donc, n'est pas envoyé via la tableau $_POST. Afin de conserver le nom de l'image, nous allons le stocker dans un champ caché.
N'oubliez pas de stocker la valeur récupérée du formulaire en début de page.
Retestez votre code => modifier uniquement le titre. Que se passe-t-il ? Pourquoi ? Adaptez votre code.
Soluce
L'erreur 'Image obligatoire' apparait s'il n'y a pas de fichier uploadé ( if (isset($_FILES['photo_article']) && !empty($_FILES['photo_article']['name'])) {)
Mais en cas de modification, l'utilisateur n'est pas obligé d'uploader un nouveau fichier.
Nous allons donc ajouter une condition pour afficher le message d'erreur.