Aller au contenu

Upload

Différentes étapes sont nécessaires pour réaliser un upload de fichier.

Comprenons d'abord ces différentes étapes et dans un second temps, appliquons-les dans le projet.

1 - Modifier le formulaire

2 - Ajouter des contraintes côté client

3 - Ajouter des vérifications côté serveur

4 - Traiter le fichier

5 - Ajuster les droits sur le répertoire d'uploads

Modifier le formulaire

L'envoi de fichier via un formulaire nécessite de modifier l'encodage des données en "multipart/form-data" qui ne transforme pas les caractères non-alphanumériques en entités HTML; particulièrement utile pour ne pas altérer les données binaires d'un fichier.

Le champ de type "file" permet à l'utilisateur de cliquer sur un bouton pour parcourir son arborescence de dossiers et sélectionner un fichier à téléverser.

  • Ajouter l'input permettant le téléchargement de fichier dans le formulaire

  • Préciser le type d'encodage

<?php 
<form action="#" method="post"  enctype="multipart/form-data">
    <input type="file" name="fichierUpload" >
</form>

Côté client: contraintes

Afin d'éviter le téléchargement inutile de fichiers non autorisés, des contraintes sur la taille et le type de fichier peuvent être spécifiées.

Limiter la taille de fichier autorisée

<?php 
<input type="hidden" name="MAX_FILE_SIZE" value="en octet!" >  

💡 Tip: 1 048 576 d'octets vaut 1 Mo.

⚠ Warning: Ce champ doit être placé avant le champ "file".

Limiter les types de fichiers autorisés

<?php 
<input type="file" accept="image/*, .pdf, .docx"  >  

Les extensions (.pdf, .docx, ...) et/ou les types (image/, audio/, video/*, type média) de fichiers vont filtrer les fichiers, lors du parcours de l'arborescence des dossiers, pour ne garder que ceux qui respectent les extensions acceptées par le champ "file".

Attention: comme toujours, les contraintes côté client sont utiles mais non suffisantes car le client peut aisément passer outre grâce aux outils du navigateur ou par programmation!

Côté serveur: réception des fichiers

Analyser le code suivant : Code upload >>

Vous pouvez soit le tester sur votre espace Panoramix ou le tester via cette url >>

Uploader un fichier de votre choix et observez le contenu du tableau $_POST et du tableau $_FILES.

Exemple :


Contenu du tableau POST

array(3) {
  ["nom"]=>
  string(7) "Leblanc"
  ["MAX_FILE_SIZE"]=>
  string(7) "1000000"
  ["Go_!"]=>
  string(7) "Envoyer"
}

Contenu du tableau FILES

array(1) {
  ["fichierUpload"]=>
  array(5) {
    ["name"]=>
    string(21) "271394-P5Y4BA-207.jpg"
    ["type"]=>
    string(10) "image/jpeg"
    ["tmp_name"]=>
    string(14) "/tmp/phpQJayGZ"
    ["error"]=>
    int(0)
    ["size"]=>
    int(418508)
  }
}

Que pouvez-vous en déduire ?

En plus des tableaux associatifs $_POST, $_GET et $_REQUEST, un tableau associatif $_FILES contient l'ensemble des fichiers téléversés avec les données du formulaire.

Référence officielle >>

Les clés du tableau $_FILES sont les valeurs des attributs name des champs de type file

Pour chaque fichier, la valeur associée est un tableau contenant le nom du fichier, son type, le nom du fichier temporaire, le code d'erreur éventuel et la taille du fichier exprimée en octets.

Reprenons l'exemple précédent.

Clés basées sur les attributs name

Chaque champ de type="file" crée une entrée dans $_FILES. La clé est la valeur de la value

Structure du tableau associé

La structure du tableau est :

  • name : Nom original du fichier (ex. "271394-P5Y4BA-207.jpg").

  • type : Type MIME du fichier (ex. "image/jpeg") – à valider car cette valeur peut être manipulée.

  • tmp_name : Chemin vers le fichier temporaire sur le serveur (ex. "/tmp/phpQJayGZ").

  • error : Code d'erreur de l'upload (0 signifie aucun problème).

  • size : Taille du fichier en octets (ex. 418508 octets).

Lors de la soumission du formulaire, chaque fichier est d'abord téléversé sur le serveur dans un répertoire dédié aux fichiers temporaires. Après validation, il pourra être déplacé (ou non) vers un répertoire choisi grâce à l'instruction move_uploaded_file().

Côté serveur : contraintes

Le fichier de configuration de PHP sur le serveur permet de limiter la taille maximale d'un fichier téléversé ainsi que le nombre de fichiers simultanés téléversés sur le serveur.

Une fois les fichiers reçus, il faut vérifier si une erreur est survenue lors de la réception des fichiers ou si les contraintes spécifiques de tailles et d'extensions sont respectées.

Configuration de php.ini

Les principaux paramètres liés au téléversement de fichiers sur le serveur sont:

Exemple de paramètres
<?php 
file_uploads = On //autorisation de téléversement
upload_max_filesize : 5M //taille maximale d'un fichier téléversé
max_file_uploads : 20 ////nombre maximum de fichiers téléversés simultanément
upload_tmp_dir= 'temp' //répertoire des fichiers temporaires 

Pour déterminer en PHP, le répertoire des fichiers temporaires, utilisez la fonction sys_get_temp_dir()

<?php 
echo sys_get_temp_dir();   // => "/tmp"

Vérifications

Les vérifications à effectuer pour chaque fichier reçu sont, dans l'ordre:

  • Vérifier le code d'erreur :

    Référence officielle >>

    Erreur si $_FILES['mon_fichier']['error'] > 0,

    $_FILES['mon_fichier']['error'] == UPLOAD_ERR_NO_FILE : Aucun fichier n’a été spécifié.

    $_FILES['mon_fichier']['error'] == UPLOAD_ERR_INI_SIZE : Le fichier dépasse la taille maximale définie dans php.ini (upload_max_filesize).

    $_FILES['mon_fichier']['error'] == UPLOAD_ERR_FORM_SIZE : Le fichier dépasse la taille maximale imposée par l’input MAX_FILE_SIZE.

    $_FILES['mon_fichier']['error'] == UPLOAD_ERR_PARTIAL : Le fichier a été partiellement téléchargé.

  • Vérifier la taille du fichier : $_FILES['mon_fichier']['size'] > $maximum

Comparaison de $_FILES['mon_fichier']['size'] avec une valeur maximale prédéfinie pour éviter des transferts trop volumineux. Permet une validation personnalisée, indépendamment du champ MAX_FILE_SIZE.

  • Vérifier les dimensions de l'image (si image): getimagesize($_FILES['mon_fichier']['tmp_name']) Référence officielle >>`

Utilisation de getimagesize($_FILES['mon_fichier']['tmp_name']) pour obtenir les dimensions et s’assurer que l’image respecte les contraintes attendues.

Extraction de l’extension via pathinfo($_FILES['mon_fichier']['name'])['extension'] et comparaison avec une liste d’extensions acceptées.

  • Vérifier existence du fichier: file_exists($filename)

Utilisation de file_exists($filename) pour s’assurer qu’un fichier du même nom n’est pas déjà présent, évitant ainsi des conflits ou écrasements.

⚠ Warning: Cette étape dépend du traitement que vous désirez appliquer. De manière générale, il est préférable de renommer le fichier suivant des conventions choisies.

💡 Tip: La fonction uniqid peut générer un identifiant basé sur l'heure actuelle avec une précision à la microseconde, préfixé par le préfixe donné et ajoutant éventuellement une valeur générée aléatoirement. Référence officielle >>

Côté serveur: traitement des fichiers

Les fichiers reçus sont conservés temporairement et sont supprimés dès la fin du script sauf si ils sont copiés.

Il est possible de copier un fichier temporaire sur lui-même pour le conserver, mais cette pratique est déconseillée puisqu'elle entraîne un mélange entre les fichiers temporaires et les fichiers à conserver.

Le déplacement pour conservation s'effectue grâce à la fonction :

<?php 
move_uploaded_file($_FILES['mon_fichier']['tmp_name'], $destination);

Cette fonction ne crée pas le répertoire s'il n'existe pas; par contre si le fichier existe déjà, il est écrasé. Référence officielle >>

⚠ Warning: La configuration des droits d'accès sur les répertoires est importante, surtout lorsque l'application permet le téléversement de fichiers.

Droits sur répertoire

La spécification des droits sur les dossiers et fichiers

Les opérations sur fichiers/dossiers sont limités selon les droits suivants:

  • Lire: le fichier peut être consulté; le contenu du répertoire peut être vu
  • Écrire: le fichier peut être édité/renommé/supprimé; un nouveau fichier peut être créé dans le répertoire, le répertoire peut être renommé/supprimé
  • Exécuter: le fichier, si c'est l'exécutable d'un programme, peut être lancé; le dossier peut être ouvert pour accéder à son contenu

valeurDroit

Ces droits sont à spécifier pour :

  1. Le propriétaire: par défaut, le créateur du dossier/fichier,

  2. Le groupe: le groupe d'utilisateurs dont fait partie le propriétaire,

  3. Les autres: tous les autres utilisateurs

droits

Expérience : Droits sur fichiers/dossiers

Créez le répertoire "/public_html/test_droits" sur le serveur Panoramix. Avec FileZilla, faites un clic-droit sur ce répertoire et modifiez les droits en "754". Copiez dans ce répertoire un fichier "index.html" avec le contenu suivant:

<?php 
<!DOCTYPE html>
<html lang="fr">
    <head>
        <meta charset="utf-8">
        <title>Test de droits</title>
    </head>
    <body>
        <h1>Bravo !</h1>
        <p>Vous avez le droit de voir ce fichier !</p>
    </body>
</html>

Question

Ouvrez votre navigateur et tentez d'accéder à ce contenu. Que constatez-vous et pourquoi ?

Soluce

Vous n'avez pas le droit de voir ce fichier car le répertoire "/test_droits" n'accorde pas l'exécution (l'ouverture) du dossier au public. Modifiez via FileZilla les droits en "755" et tentez à nouveau de voir la page.

Bonnes pratiques pour vos sites

Sur un serveur, il vaut mieux limiter les droits d'accès aux dossiers/fichiers comme suit (droits d'accès à définir via FileZilla):

  • dossiers: 755 par défaut,
  • fichiers: 644 par défaut,
  • dossiers avec que du code PHP ou des images: 555 (protection contre l'écriture),
  • fichiers PHP, images, html, js: 444,
  • fichiers logs: 755 si script exécuté par propriétaire, 775 voire 777 en fonction de la configuration du serveur,
  • dossiers pour téléversement via formulaire: 777.

Même sur Panoramix, soyez vigilants!!