Eu li isso e estas perguntas que parecem sugerir que o tipo MIME do arquivo possa ser verificado usando javascript no lado do cliente. Agora, entendo que a validação real ainda precisa ser feita no servidor. Desejo executar uma verificação do lado do cliente para evitar desperdício desnecessário de recursos do servidor.
Para testar se isso pode ser feito no lado do cliente, alterei a extensão de um JPEG
arquivo de teste para .png
e escolhi o arquivo para upload. Antes de enviar o arquivo, consulte o objeto de arquivo usando um console javascript:
document.getElementsByTagName('input')[0].files[0];
É isso que recebo no Chrome 28.0:
Arquivo {webkitRelativePath: "", lastModifiedDate: terça-feira, 16 de outubro de 2012, 10:00:00 GMT + 0000 (UTC), nome: "test.png", tipo: "image / png", tamanho: 500055…}
Ele mostra o tipo image/png
que parece indicar que a verificação é feita com base na extensão do arquivo em vez do tipo MIME. Eu tentei o Firefox 22.0 e me dá o mesmo resultado. Mas, de acordo com as especificações do W3C , o MIME Sniffing deve ser implementado.
Estou certo em dizer que não há como verificar o tipo MIME com javascript no momento? Ou eu estou esquecendo de alguma coisa?
fonte
I want to perform a client side checking to avoid unnecessary wastage of server resource.
Não entendo por que você diz que a validação deve ser feita no servidor, mas diz que deseja reduzir os recursos do servidor. Regra de ouro: nunca confie na entrada do usuário . Qual é o objetivo de verificar o tipo MIME no lado do cliente, se você está apenas fazendo no lado do servidor. Certamente isso é um "desperdício desnecessário de recursos do cliente "?type
propriedade paraFile
objetos. O código fonte do webkit, por exemplo, revela essa verdade. É possível identificar com precisão os arquivos do lado do cliente, procurando "bytes mágicos" nos arquivos, entre outras coisas. Atualmente, estou trabalhando em uma biblioteca do MIT (no pouco tempo livre que tenho) que fará exatamente isso. Se você estiver interessado em meu progresso, dê uma olhada em github.com/rnicholus/determinater .image/jpeg
e não o modificou alterando a extensão?Respostas:
Você pode determinar facilmente o tipo MIME do arquivo com JavaScript
FileReader
antes de enviá-lo para um servidor. Concordo que devemos preferir a verificação do lado do servidor em vez do lado do cliente, mas a verificação do lado do cliente ainda é possível. Vou mostrar como e fornecer uma demonstração de trabalho na parte inferior.Verifique se o seu navegador suporta ambos
File
eBlob
. Todos os principais deveriam.Passo 1:
Você pode recuperar as
File
informações de um<input>
elemento como este ( ref ):Aqui está uma versão do tipo arrastar e soltar acima ( ref ):
Passo 2:
Agora podemos inspecionar os arquivos e exibir cabeçalhos e tipos MIME.
✘ método rápido
Você pode, ingenuamente, solicitar ao Blob o tipo MIME de qualquer arquivo que ele represente usando este padrão:
Para imagens, os tipos MIME retornam da seguinte forma:
Advertência: O tipo MIME é detectado na extensão do arquivo e pode ser enganado ou falsificado. Pode-se renomear a
.jpg
para a.png
e o tipo MIME será relatado comoimage/png
.✓ Método adequado de inspeção de cabeçalho
Para obter o tipo MIME genuíno de um arquivo do lado do cliente, podemos ir um pouco além e inspecionar os primeiros bytes do arquivo fornecido para comparar com os chamados números mágicos . Esteja avisado de que não é totalmente simples, porque, por exemplo, o JPEG possui alguns "números mágicos". Isso ocorre porque o formato evoluiu desde 1991. Você pode verificar apenas os dois primeiros bytes, mas prefiro verificar pelo menos 4 bytes para reduzir os falsos positivos.
Exemplo de assinaturas de arquivo JPEG (primeiros 4 bytes):
Aqui está o código essencial para recuperar o cabeçalho do arquivo:
Você pode determinar o tipo MIME real da seguinte maneira (mais assinaturas de arquivo aqui e aqui ):
Aceite ou rejeite os uploads de arquivos como desejar, com base nos tipos MIME esperados.
Demo
Aqui está uma demonstração de trabalho para arquivos locais e arquivos remotos (eu tive que ignorar o CORS apenas para esta demonstração). Abra o trecho, execute-o e você verá três imagens remotas de diferentes tipos exibidas. Na parte superior, você pode selecionar uma imagem ou arquivo de dados local e a assinatura do arquivo e / ou o tipo MIME serão exibidos.
Observe que, mesmo que uma imagem seja renomeada, seu verdadeiro tipo MIME pode ser determinado. Ver abaixo.
Captura de tela
Mostrar snippet de código
fonte
fileReader.readAsArrayBuffer(blob.slice(0,4))
? (2) Para copiar / colar assinaturas de arquivo, o cabeçalho não deve ser construído com zeros à esquerdafor(var i = 0; i < bytes.length; i++) { var byte = bytes[i]; fileSignature += (byte < 10 ? "0" : "") + byte.toString(16); }
?FF D8 FF E2
= CANNON EOS JPEG FILE,FF D8 FF E3
= SAMSUNG D500 JPEG FILE. A parte principal da assinatura JPEG é de apenas 2 bytes, mas para reduzir os falsos positivos, adicionei as assinaturas mais comuns de 4 bytes. Espero que ajude.fileReader.readAsArrayBuffer(blob.slice(0, 4))
Conforme indicado em outras respostas, você pode verificar o tipo de mímica, verificando a assinatura do arquivo nos primeiros bytes do arquivo.
Mas o que outras respostas estão fazendo é carregar o arquivo inteiro na memória para verificar a assinatura, o que é muito inútil e pode congelar facilmente o navegador se você selecionar um arquivo grande por acidente ou não.
fonte
readyState
que sempre estaráFileReader.DONE
no manipulador de eventos ( especificação W3C ), mesmo que tenha havido um erro - a verificação não deveria acontecer(!e.target.error)
?Para quem quer não implementar isso, o Sindresorhus criou um utilitário que funciona no navegador e possui os mapeamentos de cabeçalho para mimo para a maioria dos documentos que você deseja.
https://github.com/sindresorhus/file-type
Você pode combinar a sugestão do Vitim.us de apenas ler os primeiros X bytes para evitar carregar tudo na memória com o uso deste utilitário (exemplo em es6):
fonte
"file-type": "12.4.0"
funcionou e eu tive que usarimport * as fileType from "file-type";
Se você quiser apenas verificar se o arquivo enviado é uma imagem, tente carregá-lo na
<img>
tag e verifique se há retorno de chamada de erro.Exemplo:
fonte
Isto é o que você tem que fazer
Se você deseja verificar os tipos de arquivo de imagem,
fonte
Aqui está uma implementação do TypeScript que suporta webp. Isso é baseado na resposta JavaScript do Vitim.us.
fonte
Como Drake afirma, isso pode ser feito com o FileReader. No entanto, o que apresento aqui é uma versão funcional. Leve em consideração que o grande problema de fazer isso com JavaScript é redefinir o arquivo de entrada. Bem, isso se restringe apenas ao JPG (para outros formatos, você precisará alterar o tipo de mímica e o número mágico ):
Leve em consideração que isso foi testado nas versões mais recentes do Firefox e Chrome e no IExplore 10.
Para uma lista completa dos tipos de mímica, consulte Wikipedia .
Para uma lista completa dos números mágicos, consulte Wikipedia .
fonte
Aqui está uma extensão da resposta de Roberto14 que faz o seguinte:
Isso só permitirá imagens
Verifica se o FileReader está disponível e volta para a extensão, verificando se não está disponível.
Dá um alerta de erro, se não uma imagem
Se for uma imagem, ele carrega uma visualização
** Você ainda deve fazer a validação no lado do servidor; isso é mais uma conveniência para o usuário final do que qualquer outra coisa. Mas é útil!
fonte
Resposta curta é não.
Como você observa, os navegadores derivam
type
da extensão do arquivo. A pré-visualização do Mac também parece ficar sem a extensão. Estou assumindo que é porque é mais rápido ler o nome do arquivo contido no ponteiro, em vez de procurar e ler o arquivo no disco.Fiz uma cópia de um jpg renomeado com png.
Consegui obter consistentemente o seguinte de ambas as imagens no chrome (deve funcionar em navegadores modernos).
ÿØÿàJFIFÿþ;CREATOR: gd-jpeg v1.0 (using IJG JPEG v62), quality = 90
Que você pode hackear uma verificação String.indexOf ('jpeg') para o tipo de imagem.
Aqui está um violino para explorar http://jsfiddle.net/bamboo/jkZ2v/1/
A linha ambígua que eu esqueci de comentar no exemplo
console.log( /^(.*)$/m.exec(window.atob( image.src.split(',')[1] )) );
O código do violino usa a decodificação base64, que não funcionará no IE9, encontrei um bom exemplo usando o script VB que funciona no IE http://blog.nihilogic.dk/2008/08/imageinfo-reading-image-metadata-with.html
O código para carregar a imagem foi tirado de Joel Vardy, que está redimensionando a tela da imagem antes de fazer o upload, o que pode ser interessante https://joelvardy.com/writing/javascript-image-upload
fonte
JFIF
, o poçoAPP0
não precisa conter JFIF em EXIF-JPEG, para que também não ocorra).