He leído esto y estas preguntas que parecen sugerir que el tipo de archivo MIME podría verificarse usando javascript en el lado del cliente. Ahora, entiendo que la validación real todavía tiene que hacerse en el lado del servidor. Quiero realizar una verificación del lado del cliente para evitar el desperdicio innecesario de recursos del servidor.
Para probar si esto se puede hacer en el lado del cliente, cambié la extensión de un JPEG
archivo de prueba .png
y elegí el archivo para cargar. Antes de enviar el archivo, consulto el objeto del archivo usando una consola javascript:
document.getElementsByTagName('input')[0].files[0];
Esto es lo que obtengo en Chrome 28.0:
Archivo {webkitRelativePath: "", lastModifiedDate: Tue Oct 16 2012 10:00:00 GMT + 0000 (UTC), nombre: "test.png", tipo: "image / png", tamaño: 500055…}
Muestra el tipo de ser image/png
que parece indicar que la verificación se realiza en función de la extensión del archivo en lugar del tipo MIME. Probé Firefox 22.0 y me da el mismo resultado. Pero de acuerdo con las especificaciones del W3C , se debe implementar MIME Sniffing .
¿Tengo razón al decir que no hay forma de verificar el tipo MIME con javascript en este momento? ¿O me estoy perdiendo algo?
fuente
I want to perform a client side checking to avoid unnecessary wastage of server resource.
No entiendo por qué dice que la validación debe hacerse en el lado del servidor, pero luego dice que desea reducir los recursos del servidor. Regla de oro: nunca confíes en la entrada del usuario . ¿Cuál es el punto de verificar el tipo MIME en el lado del cliente si lo está haciendo en el lado del servidor? ¿Seguramente eso es un "desperdicio innecesario de recursos del cliente "?type
propiedad para losFile
objetos. El código fuente del webkit, por ejemplo, revela esta verdad. Es posible identificar con precisión los archivos del lado del cliente buscando "bytes mágicos" en los archivos, entre otras cosas. Actualmente estoy trabajando en una biblioteca MIT (en el poco tiempo libre que tengo) que hará exactamente eso. Si está interesado en mi progreso, eche un vistazo a github.com/rnicholus/determinater .image/jpeg
, y en realidad no lo modificó cambiando la extensión?Respuestas:
Puede determinar fácilmente el tipo de archivo MIME con JavaScript
FileReader
antes de cargarlo en un servidor. Estoy de acuerdo en que deberíamos preferir la verificación del lado del servidor sobre el lado del cliente, pero la verificación del lado del cliente todavía es posible. Le mostraré cómo y proporcionaré una demostración funcional en la parte inferior.Verifique que su navegador sea compatible con ambos
File
yBlob
. Todos los principales deberían.Paso 1:
Puede recuperar la
File
información de un<input>
elemento como este ( ref ):Aquí hay una versión de arrastrar y soltar de lo anterior ( ref ):
Paso 2:
Ahora podemos inspeccionar los archivos y extraer encabezados y tipos MIME.
✘ Método rápido
Puedes ingenuamente pedirle a Blob el tipo MIME de cualquier archivo que represente usando este patrón:
Para las imágenes, los tipos MIME regresan de la siguiente manera:
Advertencia: el tipo MIME se detecta desde la extensión del archivo y se puede engañar o suplantar. Se puede cambiar el nombre de a
.jpg
a a.png
y el tipo MIME se informará comoimage/png
.✓ Método de inspección de encabezado adecuado
Para obtener el tipo MIME de buena fe de un archivo del lado del cliente, podemos ir un paso más allá e inspeccionar los primeros bytes del archivo dado para compararlos con los llamados números mágicos . Tenga en cuenta que no es del todo sencillo porque, por ejemplo, JPEG tiene algunos "números mágicos". Esto se debe a que el formato ha evolucionado desde 1991. Puede salirse con la suya al verificar solo los dos primeros bytes, pero prefiero verificar al menos 4 bytes para reducir los falsos positivos.
Ejemplo de firmas de archivo de JPEG (primeros 4 bytes):
Aquí está el código esencial para recuperar el encabezado del archivo:
Luego puede determinar el tipo MIME real de esta manera (más firmas de archivos aquí y aquí ):
Acepte o rechace las cargas de archivos como desee según los tipos MIME esperados.
Manifestación
Aquí hay una demostración funcional para archivos locales y archivos remotos (tuve que omitir CORS solo para esta demostración). Abra el fragmento, ejecútelo, y debería ver tres imágenes remotas de diferentes tipos mostradas. En la parte superior, puede seleccionar una imagen local o archivo de datos, y se mostrará la firma del archivo y / o el tipo MIME.
Tenga en cuenta que incluso si se cambia el nombre de una imagen, se puede determinar su verdadero tipo MIME. Vea abajo.
Captura de pantalla
Mostrar fragmento de código
fuente
fileReader.readAsArrayBuffer(blob.slice(0,4))
? (2) Para copiar / pegar firmas de archivos, ¿no debería construirse el encabezado con ceros a la izquierdafor(var i = 0; i < bytes.length; i++) { var byte = bytes[i]; fileSignature += (byte < 10 ? "0" : "") + byte.toString(16); }
?FF D8 FF E2
= ARCHIVO JPEG CANOS EOS,FF D8 FF E3
= ARCHIVO JPEG SAMSUNG D500. La parte clave de la firma JPEG es de solo 2 bytes, pero para reducir los falsos positivos, agregué las firmas de 4 bytes más comunes. Espero que eso ayude.fileReader.readAsArrayBuffer(blob.slice(0, 4))
Como se indicó en otras respuestas, puede verificar el tipo mime al verificar la firma del archivo en los primeros bytes del archivo.
Pero lo que están haciendo otras respuestas es cargar todo el archivo en la memoria para verificar la firma, lo cual es muy derrochador y podría congelar fácilmente su navegador si selecciona un archivo grande por accidente o no.
fuente
readyState
que siempre estaráFileReader.DONE
en el controlador de eventos ( especificación W3C ) incluso si hubo un error, ¿no debería ser la verificación si(!e.target.error)
en su lugar?Para cualquiera que esté buscando no implementar esto ellos mismos, Sindresorhus ha creado una utilidad que funciona en el navegador y tiene las asignaciones de encabezado a mimo para la mayoría de los documentos que pueda desear.
https://github.com/sindresorhus/file-type
Puede combinar la sugerencia de Vitim.us de solo leer en los primeros X bytes para evitar cargar todo en la memoria con el uso de esta utilidad (ejemplo en es6):
fuente
"file-type": "12.4.0"
funcionó y tuve que usarimport * as fileType from "file-type";
Si solo desea verificar si el archivo cargado es una imagen, puede intentar cargarlo en la
<img>
etiqueta y verificar si hay alguna devolución de llamada de error.Ejemplo:
fuente
Esto es lo que tienes que hacer
Si desea verificar los tipos de archivos de imagen, entonces
fuente
Aquí hay una implementación de Typecript que admite webp. Esto se basa en la respuesta de JavaScript de Vitim.us.
fuente
Como dice Drake, esto podría hacerse con FileReader. Sin embargo, lo que presento aquí es una versión funcional. Tenga en cuenta que el gran problema al hacer esto con JavaScript es restablecer el archivo de entrada. Bueno, esto se limita solo a JPG (para otros formatos, tendrá que cambiar el tipo MIME y el número mágico ):
Tenga en cuenta que esto se probó en las últimas versiones de Firefox y Chrome, y en IExplore 10.
Para obtener una lista completa de los tipos de mimos, consulte Wikipedia .
Para obtener una lista completa del número mágico, consulte Wikipedia .
fuente
Aquí hay una extensión de la respuesta de Roberto14 que hace lo siguiente:
ESTO SOLO PERMITIRÁ IMÁGENES
Comprueba si FileReader está disponible y vuelve a la extensión comprobando si no está disponible.
Da una alerta de error si no es una imagen
Si es una imagen, carga una vista previa
** Aún debe hacer la validación del lado del servidor, esto es más una conveniencia para el usuario final que cualquier otra cosa. ¡Pero es útil!
fuente
La respuesta corta es no.
Como observa, los navegadores derivan
type
de la extensión del archivo. La vista previa de Mac también parece salir de la extensión. Supongo que es porque es más rápido leer el nombre del archivo contenido en el puntero, en lugar de buscar y leer el archivo en el disco.Hice una copia de un jpg renombrado con png.
Pude obtener constantemente lo siguiente de ambas imágenes en Chrome (debería funcionar en los navegadores modernos).
ÿØÿàJFIFÿþ;CREATOR: gd-jpeg v1.0 (using IJG JPEG v62), quality = 90
Que podría hackear una comprobación String.indexOf ('jpeg') para el tipo de imagen.
Aquí hay un violín para explorar http://jsfiddle.net/bamboo/jkZ2v/1/
La línea ambigua que olvidé comentar en el ejemplo
console.log( /^(.*)$/m.exec(window.atob( image.src.split(',')[1] )) );
El código de violín usa decodificación base64 que no funcionará en IE9, encontré un buen ejemplo usando el script VB que funciona en IE http://blog.nihilogic.dk/2008/08/imageinfo-reading-image-metadata-with.html
El código para cargar la imagen fue tomado de Joel Vardy, quien está haciendo un lienzo de imagen genial cambiando el tamaño del lado del cliente antes de cargarlo, lo que puede ser de interés https://joelvardy.com/writing/javascript-image-upload
fuente
JFIF
, buenoAPP0
, no tiene que contener JFIF en EXIF-JPEG, así que eso también está fuera).