Limiter le format de fichier lors de l'utilisation de <input type = "file">?

667

Je voudrais restreindre le type de fichier qui peut être choisi dans le sélecteur de fichiers OS natif lorsque l'utilisateur clique sur le bouton Parcourir dans l' <input type="file">élément en HTML. J'ai le sentiment qu'il est impossible, mais je voudrais savoir s'il est une solution. Je voudrais m'en tenir uniquement au HTML et au JavaScript; pas de Flash s'il vous plaît.

Bojangles
la source
1
C'est facilement possible avec PHP, mais je ne sais pas si vous pouvez l'utiliser, donc je ne publierai pas le code.
Latox
2
Je peux, mais j'ai une solution fonctionnant avec JavaScript - cela supprime la gêne de télécharger un fichier puis d' obtenir le "mauvais fichier!" Erreur.
Bojangles
Voir aussi la question la plus récente: stackoverflow.com/questions/181214/…
Christophe Roussy
Une chose à noter est que bien que ce ne soit pas idéal pour la validation, accept limitera les fichiers visibles aux fichiers acceptés pendant que l'utilisateur les parcourt (au moins dans certains navigateurs ...). Il s'agit donc davantage d'une fonctionnalité d'ergonomie de l'interface utilisateur que d'une fonctionnalité de validation.
Christophe Roussy

Réponses:

1119

À strictement parler, la réponse est non . Un développeur ne peut pas empêcher un utilisateur de télécharger des fichiers de n'importe quel type ou extension.

Mais tout de même, l' attribut accept de <input type = "file">peut aider à fournir un filtre dans la boîte de dialogue de sélection de fichier du système d'exploitation. Par exemple,

<!-- (IE 10+, Edge (EdgeHTML), Edge (Chromium), Chrome, Firefox 42+) -->
<input type="file" accept=".xls,.xlsx" />

devrait fournir un moyen de filtrer les fichiers autres que .xls ou .xlsx. Bien que le page MDN pour inputelement ait toujours dit qu'elle le supporte, à ma grande surprise, cela n'a pas fonctionné pour moi dans Firefox jusqu'à la version 42. Cela fonctionne dans IE 10+, Edge et Chrome.

Donc, pour prendre en charge Firefox plus de 42 ans avec IE 10+, Edge, Chrome et Opera, je suppose qu'il est préférable d'utiliser une liste de types MIME séparés par des virgules:

<!-- (IE 10+, Edge (EdgeHTML), Edge (Chromium), Chrome, Firefox) -->
<input type="file"
 accept="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,application/vnd.ms-excel" /> 

[ Comportement Edge (EdgeHTML): la liste déroulante du filtre de type de fichier affiche les types de fichiers mentionnés ici, mais ce n'est pas la valeur par défaut dans la liste déroulante. Le filtre par défaut est All files (*).]

Vous pouvez également utiliser des astérisques dans les types MIME. Par exemple:

<input type="file" accept="image/*" /> <!-- all image types --> 
<input type="file" accept="audio/*" /> <!-- all audio types --> 
<input type="file" accept="video/*" /> <!-- all video types --> 

Le W3C recommande aux auteurs de spécifier à la fois les types MIME et les extensions correspondantes dans l' acceptattribut. Donc, la meilleure approche est:

<!-- Right approach: Use both file extensions and corresponding MIME-types. -->
<!-- (IE 10+, Edge (EdgeHTML), Edge (Chromium), Chrome, Firefox) -->
<input type="file"
 accept=".xls,.xlsx, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,application/vnd.ms-excel" /> 

JSFiddle de la même: ici .

Référence: Liste des types MIME

IMPORTANT: L' utilisation de l' acceptattribut ne fournit qu'un moyen de filtrage dans les fichiers des types qui vous intéressent. Les navigateurs permettent toujours aux utilisateurs de choisir des fichiers de tout type. D' autres contrôles (côté client) doit être fait ( en utilisant JavaScript, une façon serait ce ), et certainement les types de fichiers doivent être vérifiés sur le serveur , en utilisant une combinaison de type MIME utilisant à la fois l'extension de fichier et sa signature binaire ( ASP .NET , PHP , Ruby , Java ). Vous pouvez également faire référence à ces tableaux pour les types de fichiers et leurs nombres magiques, pour effectuer une vérification côté serveur plus robuste.

Voici trois bonnes lectures sur les téléchargements de fichiers et la sécurité.

EDIT: Peut - être que la vérification du type de fichier à l'aide de sa signature binaire peut également être effectuée côté client à l'aide de JavaScript (plutôt que simplement en regardant l'extension) à l'aide de l'API de fichier HTML5, mais tout de même, le fichier doit être vérifié sur le serveur, car un utilisateur malveillant sera toujours en mesure de télécharger des fichiers en faisant une demande HTTP personnalisée.

Sachin Joseph
la source
2
@Sandesire Je ne pense pas que vous puissiez restreindre la taille des fichiers en HTML. C'est possible en utilisant JavaScript, comme vous l'avez suggéré.
Sachin Joseph
1
D'après mon expérience personnelle, cela semble être une bonne réponse, le type mime seul ne fonctionnera pas sur tous les navigateurs.
Christophe Roussy
1
Incidemment, acceptcela ne fonctionne toujours pas dans Edge: stackoverflow.com/questions/31875617/… . Plus de détails ici: wpdev.uservoice.com/forums/257854-microsoft-edge-developer/…
SharpC
1
J'aimerais que nous ayons le choix d'exclure également des fichiers, par exemple exclude="exe". ¯_ (ツ) _ / ¯
Sagiv bg
1
Pour clarifier davantage le comportement d'Edge (selon mes tests), il ajoutera différents filtres en fonction de ce que vous spécifiez, mais a) il n'est pas fourni, il répertoriera donc chaque extension en tant qu'option distincte et b) il ajoutera toujours des construire des extensions telles que .html et c) comme déjà indiqué, il présélectionnera toujours (*). Ce qui en fait un gros gâchis et inutile dans la plupart des cas. J'ai voté sur le lien uservoice, espérons qu'ils écouteront tôt ou tard.
Arie
198

Il existe l'attribut accept pour la balise d'entrée. Cependant, il n'est en aucun cas fiable. Les navigateurs la traitent très probablement comme une "suggestion", ce qui signifie que l'utilisateur aura, selon le gestionnaire de fichiers également, une présélection qui n'affiche que les types souhaités. Ils peuvent toujours choisir "tous les fichiers" et télécharger n'importe quel fichier de leur choix.

Par exemple:

<form>
    <input type="file" name="pic" id="pic" accept="image/gif, image/jpeg" />
</form>

En savoir plus dans le spécification HTML5

Gardez à l'esprit qu'il ne doit être utilisé que comme "aide" pour que l'utilisateur puisse trouver les bons fichiers. Chaque utilisateur peut envoyer toute demande qu'il souhaite à votre serveur. Vous devez toujours tout valider côté serveur.

La réponse est donc: non, vous ne pouvez pas restreindre , mais vous pouvez définir une présélection mais vous ne pouvez pas fier.

Alternativement ou en plus, vous pouvez faire quelque chose de similaire en vérifiant le nom de fichier (valeur du champ de saisie) avec JavaScript, mais cela n'a aucun sens car il n'offre aucune protection et ne facilite pas non plus la sélection pour l'utilisateur. Cela trompe potentiellement un webmaster en lui faisant croire qu'il est protégé et ouvre une faille de sécurité. Cela peut être pénible pour les utilisateurs qui ont des extensions de fichier alternatives (par exemple jpeg au lieu de jpg), en majuscules ou aucune extension de fichier (comme cela est courant sur les systèmes Linux).

Le Surrican
la source
3
pour plus d'informations, voir stackoverflow.com/questions/181214/…
Martin Meeser
1
Bien qu'il soit vrai qu'il est impossible d'empêcher l'utilisateur de sélectionner N'IMPORTE QUEL type de fichier, ces jours-ci, vous pouvez profiter de l'API de fichier HTML5 et travailler avec le fichier sélectionné pour le téléchargement, avant qu'il ne soit effectivement téléchargé sur le serveur, y compris la détection son type, sa taille et plus encore. Essaie. Il est très facile à utiliser, mais très puissant et utile.
TheCuBeMan
96

Vous pouvez utiliser l' changeévénement pour surveiller ce que l'utilisateur sélectionne et l'informer à ce stade que le fichier n'est pas acceptable. Il ne limite pas la liste réelle des fichiers affichés, mais c'est le plus proche que vous pouvez faire côté client, en plus de l' acceptattribut mal pris en charge .

var file = document.getElementById('someId');

file.onchange = function(e) {
  var ext = this.value.match(/\.([^\.]+)$/)[1];
  switch (ext) {
    case 'jpg':
    case 'bmp':
    case 'png':
    case 'tif':
      alert('Allowed');
      break;
    default:
      alert('Not allowed');
      this.value = '';
  }
};
<input type="file" id="someId" />

JSFiddle

Gabriele Petrioli
la source
11
@joe, c'est un exemple ... il peut s'étendre à toutes les extensions que vous souhaitez autoriser.
Gabriele Petrioli
Oui vous pouvez. mais vous N'AVEZ PAS FAIT! et quelqu'un maby l'a déjà copié! et qu'en est-il des fichiers avec le type MIME correct mais sans extension?
Le Surrican du
49
@Joe .. eh bien .. j'essaie de fournir une direction et une logique sonore. Solutions pas entièrement mises en œuvre pour chaque cas. Je fais confiance aux téléspectateurs pour faire preuve de bon sens lorsqu'ils copient / collent du code à partir du Web;)
Gabriele Petrioli
7
Que diriez-vous de "Some.File.jpg"? Peut-être que cette ligne d'expression régulière doit lire: var ext = this.value.match (/ \. ([^.] +) $ /) [1];
Jon Kloske
Le problème avec cette approche est que quelque chose pourrait toujours être techniquement un jpeg même s'il ne se termine pas avec cette extension. Extensions! == types de mime
Matt Fletcher
46

Oui, tu as raison. C'est impossible avec HTML. L'utilisateur pourra choisir le fichier qu'il souhaite.

Vous pouvez écrire un morceau de JavaScript code pour éviter de soumettre un fichier basé sur son extension. Mais gardez à l'esprit que cela n'empêchera en aucun cas un utilisateur malveillant de soumettre n'importe quel fichier qu'il souhaite vraiment.

Quelque chose comme:

function beforeSubmit()
{
    var fname = document.getElementById("ifile").value;
    // check if fname has the desired extension
    if (fname hasDesiredExtension) {
        return true;
    } else {
        return false;
    }
}

Code HTML:

<form method="post" onsubmit="return beforeSubmit();">
    <input type="file" id="ifile" name="ifile"/>
</form>
Pablo Santa Cruz
la source
3
il y a un attribut html entièrement valide pour cela donc c'est possible. il n'est tout simplement pas respecté par les navigateurs, mais c'est un problème de standardisation. ainsi que tout ce qui est géré côté client dans le balisage non protégé ne peut pas restreindre quoi que ce soit le script java n'est pas une solution.
Le Surrican du
2
Très bon point. J'ajouterai un deuxième vérificateur PHP au cas où. Ne peut pas être trop prudent!
Bojangles
2
Eh bien, cela ne fait pas de mal si j'utilise également un script de validation PHP, je vais donc utiliser les deux.
Bojangles
17
@Joe: arrête de dire que ma réponse craint! :-) Quoi qu'il en soit, ce n'est pas une solution parfaite. Comme je l'ai dit au début: "il est impossible" de faire ce que veut OP. Mais vous pouvez avoir un certain degré d'aide pour l'utilisateur si vous ne le laissez que choisir des fichiers avec certaines extensions. La validation du type de fichier REAL doit être effectuée côté serveur .
Pablo Santa Cruz
11
@JoeHopfgartner: Mec, tu es trop dur pour Pablo ici. la validation côté client se fait dans des tonnes d'endroits et bien qu'elle ne soit pas infaillible (il devrait toujours y avoir [b] [/ b] une validation côté serveur incluse), elle peut faire gagner beaucoup de temps à l'utilisateur (pas de publication pour une stupide vérification d'extension, etc.). Bien que le script donné par Pablo ne soit pas parfait, il est simplement destiné à être un exemple de la façon de résoudre ce problème ... Peut-être que vous devriez envoyer un e-mail aux techniciens de Microsoft et leur demander de supprimer la validation Clientside de leurs validateurs ASP.NET depuis ce sont des ordures pour vous ...
Nathan
18

Techniquement, vous pouvez spécifier l' acceptattribut (alternative en html5 ) sur l' inputélément, mais il n'est pas correctement pris en charge.

zzzzBov
la source
La prise en charge du navigateur W3Schools échoue! C'est vraiment dommage. C'est également un problème de sécurité - les gens peuvent pirater le code côté client et télécharger ce qu'ils veulent.
Bojangles
5
Certes, il est préférable de ne pas utiliser cela pour la sécurité, mais cela aide certainement la convivialité sur les navigateurs qui le prennent en charge. Les utilisateurs ne voient que les fichiers autorisés par le site (pas tous les autres fichiers indésirables qu'ils pourraient avoir dans le même dossier) et ils n'ont pas à passer par tout le processus de téléchargement pour recevoir une erreur, ils le sauront immédiatement. Les codeurs devraient l' utiliser.
Simon East
10

Utiliser une inputbalise avec un acceptattribut

<input type="file" name="my-image" id="image" accept="image/gif, image/jpeg, image/png" />

Cliquez ici pour le dernier tableau de compatibilité du navigateur

Démo en direct ici

Pour sélectionner uniquement les fichiers image, vous pouvez utiliser ceci accept="image/*"

<input type="file" name="my-image" id="image" accept="image/*" />

Démo en direct ici

Seuls gif, jpg et png seront affichés, capture d'écran de Chrome version 44 Seuls gif, jpg et png seront affichés, capture d'écran de Chrome version 44

kiranvj
la source
Merci! Dans Chrome sur Win10, si j'utilise accept="image/*", il dit "Fichiers image" au lieu de "Fichiers personnalisés" dans le sélecteur de fichiers, ce qui est agréable pour l'utilisateur final.
Teddy
Mais l'utilisateur peut le modifier et télécharger l'autre fichier d'extension
Prashant Prajapati
@PrashantPrajapati Oui, c'est ainsi que les navigateurs sont créés, il devrait y avoir une validation correspondante dans le serveur. La fonctionnalité du navigateur est juste pour une meilleure expérience utilisateur.
kiranvj
9

Je sais que c'est un peu tard.

function Validatebodypanelbumper(theForm)
{
   var regexp;
   var extension =     theForm.FileUpload.value.substr(theForm.FileUpload1.value.lastIndexOf('.'));
   if ((extension.toLowerCase() != ".gif") &&
       (extension.toLowerCase() != ".jpg") &&
       (extension != ""))
   {
      alert("The \"FileUpload\" field contains an unapproved filename.");
      theForm.FileUpload1.focus();
      return false;
   }
   return true;
}
bpross
la source
5

Vous pouvez réellement le faire avec javascript mais rappelez-vous que js est côté client, donc vous devriez en fait "avertir les utilisateurs" du type de fichiers qu'ils peuvent télécharger, si vous voulez ÉVITER (restreindre ou limiter comme vous l'avez dit) certains types de fichiers que vous DEVEZ faites-le côté serveur.

Regardez ce tut de base si vous souhaitez commencer avec la validation côté serveur. Pour l'ensemble du tutoriel, visitez cette page .

Bonne chance!

Trufa
la source
4

Comme mentionné dans les réponses précédentes, nous ne pouvons pas restreindre l'utilisateur à sélectionner des fichiers uniquement pour des formats de fichiers donnés. Mais c'est vraiment pratique d'utiliser la balise accept sur l'attribut file en html.

Quant à la validation, nous devons le faire côté serveur. Nous pouvons également le faire côté client en js mais ce n'est pas une solution infaillible. Nous devons valider côté serveur.

Pour ces exigences, je préfère vraiment le cadre de développement d'applications Web Java struts2. Avec sa fonction de téléchargement de fichiers intégrée, le téléchargement de fichiers vers des applications Web basées sur struts2 est un jeu d'enfant. Il suffit de mentionner les formats de fichiers que nous aimerions accepter dans notre application et tout le reste est pris en charge par le cœur du framework lui-même. Vous pouvez le vérifier sur le site officiel de struts.

svg
la source
3

Je peux suggérer ce qui suit:

  • Si vous devez obliger l'utilisateur à sélectionner l'un des fichiers image par défaut, utilisez accept = "image / *"

    <input type="file" accept="image/*" />

  • si vous souhaitez vous limiter à des types d'images spécifiques, utilisez accept = "image / bmp, image / jpeg, image / png"

    <input type="file" accept="image/bmp, image/jpeg, image/png" />

  • si vous souhaitez vous limiter à des types spécifiques, utilisez accept = ". bmp, .doc, .pdf"

    <input type="file" accept=".bmp, .doc, .pdf" />

  • Vous ne pouvez pas restreindre l'utilisateur à changer le fichier Filer à tous les fichiers, donc toujours valider le type de fichier dans le script et le serveur

Imran Javed
la source
1
C'est ce que je cherchais: accept = ". Bmp" Fonctionne très bien sur le chrome.
MichaelRom