Limitar o formato do arquivo ao usar <input type = "file">?

667

Gostaria de restringir o tipo de arquivo que pode ser escolhido no seletor de arquivos do SO nativo quando o usuário clica no botão Procurar no <input type="file">elemento em HTML. Tenho a sensação de que é impossível, mas eu gostaria de saber se há é uma solução. Eu gostaria de manter apenas HTML e JavaScript; sem flash, por favor.

Bojangles
fonte
1
É facilmente possível com PHP, mas não sei se você pode usá-lo para não publicar o código.
Latox
2
Posso, mas tenho uma solução que trabalha com JavaScript - elimina o incômodo de carregar um arquivo e obter o "Arquivo errado!" erro.
Bojangles
Veja também a pergunta mais recente: stackoverflow.com/questions/181214/…
Christophe Roussy
Uma coisa a observar é que, embora não seja ótimo para validação, o accept limitará os arquivos visíveis aos aceitos enquanto o usuário os estiver navegando (pelo menos em alguns navegadores ...). Portanto, esse é mais um recurso de ergonomia da interface do usuário do que um de validação.
Christophe Roussy

Respostas:

1119

A rigor, a resposta é não . Um desenvolvedor não pode impedir que um usuário faça upload de arquivos de qualquer tipo ou extensão.

Ainda assim, o atributo de aceitação de <input type = "file">pode ajudar a fornecer um filtro na caixa de diálogo de seleção de arquivo do sistema operacional. Por exemplo,

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

deve fornecer uma maneira de filtrar arquivos que não sejam .xls ou .xlsx. Embora a página MDN para o inputelemento sempre tenha dito que suporta isso, para minha surpresa, isso não funcionou para mim no Firefox até a versão 42. Isso funciona no IE 10+, Edge e Chrome.

Portanto, para oferecer suporte ao Firefox com mais de 42 anos, juntamente com o IE 10+, Edge, Chrome e Opera, acho melhor usar a lista de tipos MIME separados por vírgula:

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

Comportamento [ Edge (EdgeHTML): o menu suspenso do filtro de tipo de arquivo mostra os tipos de arquivo mencionados aqui, mas não é o padrão no menu suspenso. O filtro padrão é All files (*).]

Você também pode usar asteriscos nos tipos MIME. Por exemplo:

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

O W3C recomenda que os autores especifiquem os tipos MIME e as extensões correspondentes no acceptatributo. Portanto, a melhor abordagem é:

<!-- 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 do mesmo: aqui .

Referência: lista de tipos MIME

IMPORTANTE: O uso do acceptatributo fornece apenas uma maneira de filtrar os arquivos dos tipos que são de interesse. Os navegadores ainda permitem que os usuários escolham arquivos de qualquer tipo. Verificações adicionais (do lado do cliente) devem ser feitas (usando JavaScript, uma maneira seria essa ), e definitivamente os tipos de arquivo DEVEM ser verificados no servidor , usando uma combinação de tipo MIME usando a extensão de arquivo e sua assinatura binária ( ASP .NET , PHP , Ruby , Java ). Você também pode consultar essas tabelas para tipos de arquivos e seus números mágicos, para executar uma verificação mais robusta do lado do servidor.

Aqui estão três boas leituras sobre upload de arquivos e segurança.

EDIT: Talvez a verificação do tipo de arquivo usando sua assinatura binária também possa ser feita no lado do cliente usando JavaScript (em vez de apenas olhar para a extensão) usando a API de arquivos HTML5, mas ainda assim, o arquivo deve ser verificado no servidor, porque um usuário mal-intencionado ainda poderá fazer o upload de arquivos fazendo uma solicitação HTTP personalizada.

Sachin Joseph
fonte
2
@ Sandesire Eu não acho que você pode restringir o tamanho dos arquivos em HTML. É possível usar JavaScript, como você sugeriu.
Sachin Joseph
1
Da minha experiência pessoal, isso parece uma boa resposta, apenas o tipo MIME não funciona em todos os navegadores.
Christophe Roussy
1
Aliás, acceptainda não funciona no Edge: stackoverflow.com/questions/31875617/… . Mais detalhes aqui: wpdev.uservoice.com/forums/257854-microsoft-edge-developer/…
SharpC
1
Eu gostaria que tivéssemos a opção de excluir arquivos também, por exemplo exclude="exe". ¯_ (ツ) _ / ¯
Sagiv bg
1
Para esclarecer ainda mais o comportamento do Edge (de acordo com meus testes), ele adicionará filtros diferentes com base no que você especificar, mas a) não está incluído, portanto listará cada extensão como uma opção separada eb) sempre adicionará algumas informações. criar extensões como .html e c), como já indicado, sempre pré-selecionará (*). O que torna uma grande bagunça e inútil na maioria dos casos. Votei no link uservoice, espero que eles ouçam mais cedo ou mais tarde.
Arie
198

Existe o atributo de aceitação para a tag de entrada. No entanto, não é confiável de forma alguma. Os navegadores provavelmente o tratam como uma "sugestão", o que significa que o usuário, dependendo do gerenciador de arquivos, também terá uma pré-seleção que exibe apenas os tipos desejados. Eles ainda podem escolher "todos os arquivos" e enviar o arquivo que quiserem.

Por exemplo:

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

Leia mais na especificação HTML5

Lembre-se de que ele deve ser usado apenas como uma "ajuda" para o usuário encontrar os arquivos corretos. Todo usuário pode enviar qualquer solicitação que desejar para o seu servidor. Você sempre tem que validar tudo do lado do servidor.

Portanto, a resposta é: não, você não pode restringir , mas pode definir uma pré-seleção, mas não pode confiar nela.

Alternativamente ou adicionalmente, você pode fazer algo semelhante, verificando o nome do arquivo (valor do campo de entrada) com JavaScript, mas isso não faz sentido porque não oferece proteção e também não facilita a seleção para o usuário. Isso apenas potencialmente induz um webmaster a pensar que ele está protegido e abre uma brecha na segurança. Pode ser um problema para usuários que possuem extensões de arquivo alternativas (por exemplo, jpeg em vez de jpg), maiúsculas ou nenhuma extensão de arquivo (como é comum nos sistemas Linux).

O Surricano
fonte
3
Para obter informações adicionais, consulte stackoverflow.com/questions/181214/...
Martin Meeser
1
Embora seja verdade que é impossível impedir que o usuário selecione QUALQUER tipo de arquivo, nos dias de hoje, você pode aproveitar a API de arquivos HTML5 e trabalhar com o arquivo selecionado para upload, antes de realmente ser carregado no servidor, incluindo a detecção seu tipo, tamanho e muito mais. De uma chance. É muito fácil de usar, mas muito poderoso e útil.
TheCuBeMan
96

Você pode usar o changeevento para monitorar o que o usuário seleciona e notificá-lo nesse ponto de que o arquivo não é aceitável. Ele não limita a lista real de arquivos exibidos, mas é o mais próximo possível do lado do cliente, além do acceptatributo com suporte insuficiente .

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
fonte
11
@ joe, é um exemplo ... pode se estender a qualquer extensão que você deseja permitir.
Gabriele Petrioli
Sim você pode. mas você NÃO! e talvez alguém já tenha copiado! e arquivos com o tipo mime correto, mas sem extensão?
The Surrican
49
@ Joe .. bem .. eu tento fornecer direção e uma lógica de som. Soluções não totalmente implementadas para todos os casos. Confio os telespectadores a usar o bom senso quando copiar / colar o código a partir da web;)
Gabriele Petrioli
7
Que tal "Some.File.jpg"? Talvez essa linha de regex precise ler: var ext = this.value.match (/ \. ([^.] +) $ /) [1];
Jon Kloske
O problema dessa abordagem é que algo ainda pode ser tecnicamente um jpeg, mesmo que não termine com essa extensão. Extensões! == tipos mime #
Matt Fletcher
46

Sim você está certo. É impossível com HTML. O usuário poderá escolher o arquivo que desejar.

Você pode escrever um código JavaScript para evitar o envio de um arquivo com base em sua extensão. Mas lembre-se de que isso não impedirá que um usuário mal-intencionado envie qualquer arquivo que ele / ela realmente deseja.

Algo como:

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

Código HTML:

<form method="post" onsubmit="return beforeSubmit();">
    <input type="file" id="ifile" name="ifile"/>
</form>
Pablo Santa Cruz
fonte
3
existe um atributo html totalmente válido para isso, portanto é possível. simplesmente não é respeitado pelos navegadores, mas isso é um problema de padronização. assim como qualquer coisa manipulada do lado do cliente na marcação desprotegida não pode restringir nada, o script java não é solução.
The Surrican
2
Muito bom ponto. Vou adicionar um segundo verificador PHP por precaução. Não pode ser muito cuidadoso!
Bojangles
2
Bem, não faz mal se eu estiver usando um script de validação PHP também, então usarei os dois.
Bojangles
17
@ Joe: pare de dizer que minha resposta é péssima! :-) De qualquer forma, não é uma solução perfeita. Como eu disse no começo: "é impossível" fazer o que o OP quer. Mas você pode ter algum grau de ajuda para o usuário se você permitir que ele escolha apenas arquivos com determinadas extensões. A validação do tipo de arquivo REAL deve ser feita no servidor .
Pablo Santa Cruz
11
@JoeHopfgartner: Cara, você está sendo muito duro com Pablo aqui. A validação no lado do cliente é feita em vários locais e, embora não seja infalível (sempre deve haver uma validação no servidor), ele pode economizar bastante tempo ao usuário (sem postback para uma verificação estúpida de extensão, etc.). Embora o script fornecido por Pablo não seja perfeito, ele serve apenas como exemplo de como resolver esse problema ... Talvez você deva enviar um e-mail para os técnicos da Microsoft e solicitar que eles removam a validação Clientside de seus validadores ASP.NET desde é tudo lixo claro para você ...
Nathan
18

Tecnicamente, você pode especificar o acceptatributo (alternativo em html5 ) no inputelemento, mas ele não é suportado corretamente.

zzzzBov
fonte
O suporte ao navegador W3Schools falha! É realmente uma pena. Também é uma preocupação de segurança - as pessoas podem invadir o código do lado do cliente e enviar o que quiserem.
Bojangles
5
É verdade que é melhor não usá-lo por segurança, mas definitivamente ajuda a usabilidade em navegadores que o suportam. Os usuários recebem apenas os arquivos permitidos pelo site (nem todos os outros itens indesejados que podem ter na mesma pasta) e não precisam passar por todo o processo de upload para receber um erro, eles saberão imediatamente. Os codificadores devem usar isso.
Simon East
10

Usar inputtag com acceptatributo

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

Clique aqui para obter a tabela de compatibilidade do navegador mais recente

Demonstração ao vivo aqui

Para selecionar apenas arquivos de imagem, você pode usar este accept="image/*"

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

Demonstração ao vivo aqui

Somente gif, jpg e png serão mostrados, captura de tela da versão 44 do Chrome Somente gif, jpg e png serão mostrados, captura de tela da versão 44 do Chrome

kiranvj
fonte
Obrigado! No Chrome no Win10, se eu usar accept="image/*", ele diz "Arquivos de imagem" em vez de "Arquivos personalizados" no seletor de arquivos, o que é bom para o usuário final.
Teddy
Mas o usuário pode alterá-lo e fazer o upload do outro arquivo de extensão
Prashant Prajapati
@PrashantPrajapati Sim, é assim que os navegadores são criados, deve haver uma validação correspondente no servidor.A funcionalidade do navegador é apenas para uma melhor experiência do usuário.
precisa saber é o seguinte
9

Eu sei que isso é um pouco tarde.

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
fonte
5

Na verdade, você poderia fazê-lo com javascript, mas lembre-se de que js é do lado do cliente; portanto, você estaria "alertando os usuários" sobre o tipo de arquivo que eles podem enviar, se você quiser EVITAR (restringir ou limitar o que disse) certos tipos de arquivos que DEVE faça do lado do servidor.

Veja este tutorial básico se você deseja iniciar a validação no servidor. Para todo o tutorial, visite esta página .

Boa sorte!

Trufa
fonte
4

Conforme mencionado nas respostas anteriores, não podemos restringir o usuário a selecionar arquivos apenas para determinados formatos de arquivo. Mas é realmente útil usar a tag de aceitação no atributo de arquivo em html.

Quanto à validação, temos que fazê-lo no lado do servidor. Também podemos fazer isso no lado do cliente em js, mas não é uma solução infalível. Precisamos validar no lado do servidor.

Para esses requisitos, eu realmente prefiro a estrutura de desenvolvimento de aplicativos Web struts2 Java. Com seu recurso de upload de arquivos embutido, o upload de arquivos para aplicativos da Web baseados no struts2 é muito fácil. Apenas mencione os formatos de arquivo que gostaríamos de aceitar em nosso aplicativo e todo o resto é tratado pelo próprio núcleo da estrutura. Você pode conferir no site oficial do struts.

svg
fonte
3

Eu posso sugerir o seguinte:

  • Se você precisar fazer com que o usuário selecione qualquer arquivo de imagem por padrão, use accept = "image / *"

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

  • se você deseja restringir a tipos de imagem específicos, use accept = "image / bmp, image / jpeg, image / png"

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

  • se você deseja restringir a tipos específicos, use accept = ". bmp, .doc, .pdf"

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

  • Você não pode restringir o usuário a alterar o arquivador de arquivos para todos os arquivos; portanto, sempre valide o tipo de arquivo no script e no servidor

Imran Javed
fonte
1
Era isso que eu estava procurando: accept = ". Bmp" Funciona bem no chrome.
MichaelRom 13/03