Tu souhaites permettre à tes utilisateurs d’ajouter une photo à leurs profils ou encore ajouter des images dans ton site directement depuis une partie admin ? Dans cet article, je vais te montrer comment uploader une image en PHP et l’ajouter dans ta base de données.
Tu peux retrouver le code source sur GitHub, en cliquant ici : https://github.com/ThomasEspritWeb/upload-image
Commençons par voir la structure HTML de base
La structure
<!DOCTYPE html> <html> <head> <meta charset='utf-8'> <meta name='viewport' content='width=device-width, initial-scale=1'> </head> <body> <form action="index.php" method="POST" enctype="multipart/form-data"> <label for="file">Fichier</label> <input type="file" name="file"> <button type="submit">Enregistrer</button> </form> </body> </html>
La structure HTML est assez simple, j’ai créé un simple formulaire avec un champs input de type « file » et j’ai rajouté un bouton pour pouvoir enregistrer
Lorsque l’on souhaite soumettre un formulaire avec un type file il faut rajouter l’attribut enctype= »multipart/form-data » dans la balise form.
Le formulaire utilisera la méthode POST pour envoyer les données. Elles seront envoyées sur cette même page (action=’index.php’) mais on pourrait les envoyer sur n’importe quelle autre page.
On obtient quelque chose comme ça :
On va rajouter nos premières lignes de PHP pour voir ce que l’on récupère comme données lorsque l’on valide le formulaire.
Par défaut, pour récupérer les données envoyées par un formulaire il faut utiliser la variable $_POST (car les données sont envoyées via la méthode POST). Dans le cas de la méthode GET, il faut utiliser la variable $_GET.
Mais lorsque l’on ajoute des inputs de type « file », les données sont stockées dans la variable $_FILES.
Pour tester, affichons ce que l’on obtient dans ces 2 variables.
<?php var_dump($_POST); var_dump($_FILES); ?> <!DOCTYPE html> <html> <head>
Après validation du formulaire on obtient ceci:
On voit que dans la variable $_POST, il n’y a rien, le tableau (« array ») est vide alors que dans la variable $_FILES, on bien une entrée « file » (qui correspond à l’attribut « name » de notre champs) avec toutes les informations du fichier (nom, type, un nom temporaire, un nombre d’erreurs, et sa taille).
On peut voir que PHP ajoute un nom temporaire (« tmp_name ») à notre fichier. Enfait, le fichier est stocké temporairement pour qu’on puisse le manipuler et faire des actions dessus. Il est automatiquement supprimé par la suite.
On va donc utiliser la variable $_FILES par la suite.
Les variables
Mettons toutes les informations dont on dispose dans des variables :
<?php $tmpName = $_FILES['file']['tmp_name']; $name = $_FILES['file']['name']; $size = $_FILES['file']['size']; $error = $_FILES['file']['error']; ?> <!DOCTYPE html> <html> <head>
Si on laisse comme ça et que l’on rafraîchit notre page, on vas avoir une erreur :
PHP nous indique qu’il ne reconnait pas un index (ici « file »). En effet, tant que le formulaire n’est pas envoyé, il n’y a rien dans la variable $_FILES. L’index « file » n’existe donc pas. Pour avoir plus d’informations sur cette erreur, tu peux lire l’article que j’ai écrit en cliquant ici.
Pour corriger cette erreur, il faut que l’on vérifie avant si l’index « file » existe.
if(isset($_FILES['file'])){ $tmpName = $_FILES['file']['tmp_name']; $name = $_FILES['file']['name']; $size = $_FILES['file']['size']; $error = $_FILES['file']['error']; }
Maintenant que l’on a stocké les valeurs qui nous intéresse on va pouvoir les manipuler.
Uploader l’image dans un dossier
On va directement rentrer dans le vif du sujet et uploader l’image dans un dossier.
Pour cela il faut créer un dossier à la racine de notre projet. Ce dossier contiendra l’ensemble des images uploadées.
J’ai donc créé un dossier « upload » à la racine de mon projet.
Pour envoyer l’image dans notre dossier, on va utiliser la fonction PHP « move_uploaded_file ». Cette fonction attend 2 paramètres : le chemin du fichier que l’on veut uploader et le chemin vers lequel on souhaite l’uploader.
Il faut donc que l’on ait quelque chose comme ça move_uploaded_file(« C:\Dev\wamp64\tmp\php84BB.tmp », « ./upload/image.jpg »)
Avec les variables que l’on a récupérées plus haut, on va faire ceci :
$tmpName = $_FILES['file']['tmp_name']; $name = $_FILES['file']['name']; $size = $_FILES['file']['size']; $error = $_FILES['file']['error']; move_uploaded_file($tmpName, './upload/'.$name);
Voilà, tu sais comment uploader une image en PHP !
Bon on va quand même essayer d’aller un peu plus loin, pour gérer les erreurs, les types de fichiers et même stocker le fichier en base de données.
Gérer les erreurs
Actuellement, on peut uploader n’importe quel type de fichier, il n’y a pas de restriction sur les images.
Pour cela on va faire une vérification sur l’extension du fichier. On va donc récupérer l’extension du fichier à partir de son nom.
$tmpName = $_FILES['file']['tmp_name']; $name = $_FILES['file']['name']; $size = $_FILES['file']['size']; $error = $_FILES['file']['error']; $tabExtension = explode('.', $name); $extension = strtolower(end($tabExtension));
La fonction explode permets de découper une chaîne de caractère en plusieurs morceaux à partir d’un délimiteur. Prenons l’exemple suivant : explode(« . » , « 10.25.65.20 ») permet de découper la chaîne de caractère à chaque fois qu’il y a un « . ». On obtient alors le tableau [« 10 », « 25 », « 65 », « 20 »].
On va faire de même avec le nom de notre fichier : explode(« . » , « image.jpg »). Ce qui nous donne un tableau avec 2 éléments, comme ceci [« image », « jpg »]. Il faut donc récupérer le dernier élément de ce tableau avec la fonction end().
Le fonction strtolower permets de mettre en minuscule tout une chaîne de caractère. Ce contrôle nous permet de ne pas avoir de problème de comparaison par la suite. Pas de soucis si quelqu’un mets un fichier avec une extension .Jpg, .JPG, .jpG, …
Vérification de l’extension
$tabExtension = explode('.', $name); $extension = strtolower(end($tabExtension)); //Tableau des extensions que l'on accepte $extensions = ['jpg', 'png', 'jpeg', 'gif']; if(in_array($extension, $extensions)){ move_uploaded_file($tmpName, './upload/'.$name); } else{ echo "Mauvaise extension"; }
On va donc créer un tableau des extensions que l’on accepte et s’assurer que l’extension du fichier envoyé se trouve bien dans ce tableau grâce à la fonction in_array.
Si ce n’est pas le cas, on affiche un message d’erreur.
Controller la taille du fichier
Un autre contrôle que l’on peut faire est de s’assurer que la taille du fichier uploadé n’est pas trop grande.
$extensions = ['jpg', 'png', 'jpeg', 'gif']; //Taille max que l'on accepte $maxSize = 400000; if(in_array($extension, $extensions) && $size <= $maxSize){ move_uploaded_file($tmpName, './upload/'.$name); } else{ echo "Mauvaise extension ou taille trop grande"; }
Nous avions précédemment récupéré la taille du fichier uploadé dans la variable « $size ». La taille est exprimée en bytes.
On va donc créer une variable « $maxSize » qui sera la taille maximale que l’on accepte.
On va ensuite rajouter une condition dans notre if pour s’assurer que la taille du fichier est inférieure à la taille limite ($maxSize). Sinon, on affiche l’erreur.
Vérifier s’il y a une erreur
La dernière vérification que l’on peut faire sur le fichier et de s’assurer qu’il n’y a pas d’erreur. Lorsque que tu upload un fichier, PHP ajoute une champs « error » au la variable $_FILES[‘file’]. C’est le champs que l’on a mis dans la variable $error = $_FILES[‘file’][‘error’];
Cette variable est un chiffre et chaque chiffre représente une erreur. Le chiffre 0 indique qu’il n’y a pas d’erreur. Pour voir l’ensemble des erreurs, tu peux consulter la documentation en cliquant ici.
On va donc s’assurer qu’il n’y a pas d’erreur.
if(in_array($extension, $extensions) && $size <= $maxSize && $error == 0){ move_uploaded_file($tmpName, './upload/'.$name); } else{ echo "Une erreur est survenue"; }
Dans notre « else », on met un message assez générique. Si tu veux afficher un message par erreur, il faudra faire plusieurs if (et esleif) avec chacun une condition et un message d’erreur différent.
Avoir un nom unique par fichier
Actuellement, si l’on insère plusieurs fois un fichier avec le même nom, il va écraser celui qui existe déjà avec le même nom. Ce qui peut être embêtant car des fichiers qui s’appelle « chat.png » ou « maison.png » sont assez commun.
On va donc changer le nom du fichier pour qu’il soit unique avant de l’uploader.
Pour cela on va utiliser la fonction PHP uniqid(). Elle attend 2 paramètres. Le premier est une chaîne de caractère qui servira de préfixe et le deuxième est un booléen (true / false) qui permets d’augmenter la taille de la chaîne générée pour plus de sécurité.
if(in_array($extension, $extensions) && $size <= $maxSize && $error == 0){ $uniqueName = uniqid('', true); //uniqid génère quelque chose comme ca : 5f586bf96dcd38.73540086 $file = $uniqueName.".".$extension; //$file = 5f586bf96dcd38.73540086.jpg move_uploaded_file($tmpName, './upload/'.$file); }
Dans un premier temps on génère un nom unique avec la fonction uniqid puis on lui concatène l’extension du fichier pour qu’il est un nom du style : « 5f586bf96dcd38.73540086.jpg ».
N’oublie pas de changer le nom du deuxième paramètre de la fonction move_uploaded_file ($name > $file)
Pour aller plus loin : sauvegarder l’image en base de données
Pour l’instant, on sait uploader une image dans un dossier, vérifier l’extension, gérer les erreurs et s’assurer qu’il ait un nom unique mais il serait pratique de pouvoir les stocker en base de données. L’avantage de les stocker en base de données c’est qu’on pourra les récupérer plus tard pour les afficher ou même avoir un fichier par utilisateur, etc. Les exemples sont nombreux.
La première chose à faire va être de créer une base de donnée.
Rends toi sur ton phpMyAdmin (http://localhost/phpmyadmin) ou en ligne de commande. Créé une base de donnée que tu appelleras « upload_file ».
Ensuite, exécute ce script SQL.
CREATE TABLE IF NOT EXISTS `file` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(255) NOT NULL, PRIMARY KEY (`id`) );
Ce script créé une table table « file » qui aura un id unique (primary key) et un champs « name » qui sera une chaine de caractère (varchar) dans lequel on stockera uniquement le nom de notre fichier.
Ensuite on va créer un fichier bdd.php qui nous servira à nous connecter à la base de données
//bdd.php <?php try{ $db = new PDO('mysql:host=localhost;dbname=upload_file', 'root', "TonMotDePasse"); }catch(PDOException $e){ die('Erreur connexion : '.$e->getMessage()); }
On va utiliser PDO pour gérer notre base de données. Lorsque l’on déclare un nouvel objet PDO (new PDO), il faut lui passer les informations de connexion.
Modifies ces informations en fonction de ta configuration (host, nom de la base, user, mot de passe).
Dans le fichier index.php, on va indiquer à PHP que l’on a besoin du fichier bdd.php
<?php require './bdd.php'; if(isset($_FILES['file'])){
Maintenant que l’on a notre connexion à la base de données, il ne nous reste plus qu’a insérer le nom du fichier dans notre base de données une fois qu’il est uploadé.
Insertion en base de données
$file = $uniqueName.".".$extension; //$file = 5f586bf96dcd38.73540086.jpg move_uploaded_file($tmpName, './upload/'.$file); $req = $db->prepare('INSERT INTO file (name) VALUES (?)'); $req->execute([$file]); echo "Image enregistrée";
Si tu te demandes d’où sort la variable $db, c’est la variable que l’on a déclarée dans notre fichier bdd.php. On peut l’utiliser du fait que l’on à intégré le fichier bdd.php dans notre index.php (require).
Comme tu peux le voir on utilise les « requêtes préparées » ($db->prepare). Dans ces requêtes, on ajoute des « ? » (point d’interrogation) lorsque l’on ajoute des paramètres dans la requête. Cela permets d’éviter les injections SQL.
On va ensuite exécuter notre requête en lui indiquant quelle(s) valeur(s) on souhaite mettre à la place du « ? ». Dans notre cas on va ajouter le nom de notre fichier ($file).
La fonction execute() attend 1 seul paramètre qui est un tableau. Dans ce tableau on doit lui passer autant de paramètre que l’on de « ? » dans la requête.
Si on a une requête du type « SELECT * FROM file WHERE id = ? OR id = ? OR id = ? », il faudra faire $db->execute([« 1″, »2″, »3 »]).
En base de données, on ne va pas enregistrer tout notre fichier mais uniquement son nom. Les fichiers sont uploadés dans le dossier « upload » et uniquement leurs noms sont enregistrés en base de données.
Ainsi, on va pouvoir afficher nos images.
Afficher les images de la base de données
Pour afficher nos images, on va aller récupérer les noms en base de données et faire une boucle dessus pour les afficher.
<body> <form action="index.php" method="POST" enctype="multipart/form-data"> <label for="file">Fichier</label> <input type="file" name="file"> <button type="submit">Enregistrer</button> </form> <h2>Mes images</h2> <?php $req = $db->query('SELECT name FROM file'); while($data = $req->fetch()){ var_dump($data); } ?> </body>
Pour récupérer le nom des fichiers en base de données, on vas exécuter une requête « SELECT » sur la table « file » avec $db->query(). Ici pas besoin de requête préparée car il n’y a aucun paramètre à passer.
On va ensuite boucler sur les résultats grâce à l’instruction « while » qui signifie : Tant qu’il y a des résultats, on continue. Le « fetch » est une méthode PDO qui permets d’accéder aux résultats de la requête.
Dans un premier temps, j’ai utilisé le « var_dump » pour te montrer les résultats que l’on obtient.
On récupère bien tous nos enregistrements avec le nom de la colonne (« name ») en clé de chaque tableau de résultat.
Pour afficher nos images :
<h2>Mes images</h2> <?php $req = $db->query('SELECT name FROM file'); while($data = $req->fetch()){ echo "<img src='./upload/".$data['name']."' width='300px' ><br>"; } ?>
On va donc faire un « echo » qui va afficher du HTML et notamment la balise <img> avec en source (« src »), le chemin de notre image. J’ai ajouté l’attribut width (largeur) pour qu’elle ne prenne pas trop de place. La balise <br> permet de faire un retour à la ligne.
Voici le résultat :
A chaque fois que tu vas rajouter une image, elle va :
- Avoir un nom unique
- Etre uploader dans le dossier « upload »
- Enregistrée en base de données
- Etre affichée sur la page
Tu sais désormais comment uploader une image en PHP et la stocker en base de données pour l’afficher.
Tu peux retrouver le code source sur GitHub, en cliquant ici : https://github.com/ThomasEspritWeb/upload-image
Si tu as aimé ce genre de tutoriel, tu peux me demander dans les commentaires quel tutoriel tu aimerais que je réalise.
J’ai aimé ce tuto qui est clair et précis… Thaks!!!
Dieu vous le bénisse abondamment
Merci !
Bravo pour ce super Tuto. Très clair et complet.
ça va mais chez moi le même code ne marche pas
Il doit y avoir un problème à un autre endroit. Si tu as une erreur d’affichée, regarde sur Google ce que c’est. Sinon, essaye de regarder dans les logs de ton serveur