type node extension check javascript html5 file-upload mime-types

javascript - extension - node js mime type



¿Cómo verificar el tipo MIME del archivo con javascript antes de subirlo? (7)

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 comprobar la extensión si no está disponible.

Otorga una alerta de error si no es una imagen

Si se trata de una imagen, carga una vista previa

** Aún debe hacer la validación del lado del servidor, esto es más conveniente para el usuario final que cualquier otra cosa. ¡Pero es útil!

<form id="myform"> <input type="file" id="myimage" onchange="readURL(this)" /> <img id="preview" src="#" alt="Image Preview" /> </form> <script> function readURL(input) { if (window.FileReader && window.Blob) { if (input.files && input.files[0]) { var reader = new FileReader(); reader.onload = function (e) { var img = new Image(); img.onload = function() { var preview = document.getElementById(''preview''); preview.src = e.target.result; }; img.onerror = function() { alert(''error''); input.value = ''''; }; img.src = e.target.result; } reader.readAsDataURL(input.files[0]); } } else { var ext = input.value.split(''.''); ext = ext[ext.length-1].toLowerCase(); var arrayExtensions = [''jpg'' , ''jpeg'', ''png'', ''bmp'', ''gif'']; if (arrayExtensions.lastIndexOf(ext) == -1) { alert(''error''); input.value = ''''; } else { var preview = document.getElementById(''preview''); preview.setAttribute(''alt'', ''Browser does not support preview.''); } } } </script>

He leído this y this preguntas que parecen sugerir que el tipo de archivo MIME podría verificarse utilizando javascript en el lado del cliente. Ahora, entiendo que la validación real todavía tiene que hacerse en el 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 archivo de prueba JPEG a .png y elijo el archivo para cargar. Antes de enviar el archivo, consulto el objeto de archivo utilizando una consola de JavaScript:

document.getElementsByTagName(''input'')[0].files[0];

Esto es lo que obtengo en Chrome 28.0:

Archivo {webkitRelativePath: "", lastModifiedDate: martes 16 de octubre de 2012 10:00:00 GMT + 0000 (UTC), nombre: "test.png", tipo: "image / png", tamaño: 500055 ...}

Muestra el tipo de image/png que parece indicar que la comprobación se realiza en función de la extensión de archivo en lugar del tipo MIME. Intenté Firefox 22.0 y me da el mismo resultado. Pero de acuerdo con las especificaciones W3C , MIME Sniffing debería implementarse.

¿Tengo razón al decir que no hay forma de verificar el tipo MIME con javascript en este momento? ¿O me estoy perdiendo algo?


Como Drake afirma que 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 restringe a solo JPG (para otros formatos, tendrás que cambiar el tipo de mimo y el número mágico ):

<form id="form-id"> <input type="file" id="input-id" accept="image/jpeg"/> </form> <script type="text/javascript"> $(function(){ $("#input-id").on(''change'', function(event) { var file = event.target.files[0]; if(file.size>=2*1024*1024) { alert("JPG images of maximum 2MB"); $("#form-id").get(0).reset(); //the tricky part is to "empty" the input file here I reset the form. return; } if(!file.type.match(''image/jp.*'')) { alert("only JPG images"); $("#form-id").get(0).reset(); //the tricky part is to "empty" the input file here I reset the form. return; } var fileReader = new FileReader(); fileReader.onload = function(e) { var int32View = new Uint8Array(e.target.result); //verify the magic number // for JPG is 0xFF 0xD8 0xFF 0xE0 (see https://en.wikipedia.org/wiki/List_of_file_signatures) if(int32View.length>4 && int32View[0]==0xFF && int32View[1]==0xD8 && int32View[2]==0xFF && int32View[3]==0xE0) { alert("ok!"); } else { alert("only valid JPG images"); $("#form-id").get(0).reset(); //the tricky part is to "empty" the input file here I reset the form. return; } }; fileReader.readAsArrayBuffer(file); }); }); </script>

Tenga en cuenta que esto fue probado en las últimas versiones de Firefox y Chrome, y en IExplore 10.

Para obtener una lista completa de los tipos de mimo, vea Wikipedia .

Para obtener una lista completa de números mágicos, vea Wikipedia .


Como se indica en otras respuestas, puede verificar el tipo de mimo al verificar la here del archivo en los primeros bytes del archivo.

Pero lo que otras respuestas están haciendo es cargar el archivo completo en la memoria para verificar la firma, lo cual es muy inútil y podría congelar fácilmente su navegador si selecciona un archivo grande por accidente o no.

/** * Load the mime type based on the signature of the first bytes of the file * @param {File} file A instance of File * @param {Function} callback Callback with the result * @author Victor N. wwww.victorborges.com * @date 2017-03-23 */ function loadMime(file, callback) { //List of known mimes var mimes = [ { mime: ''image/jpeg'', pattern: [0xFF, 0xD8, 0xFF], mask: [0xFF, 0xFF, 0xFF], }, { mime: ''image/png'', pattern: [0x89, 0x50, 0x4E, 0x47], mask: [0xFF, 0xFF, 0xFF, 0xFF], } // you can expand this list @see https://mimesniff.spec.whatwg.org/#matching-an-image-type-pattern ]; function check(bytes, mime) { for (var i = 0, l = mime.mask.length; i < l; ++i) { if ((bytes[i] & mime.mask[i]) - mime.pattern[i] !== 0) { return false; } } return true; } var blob = file.slice(0, 4); //read the first 4 bytes of the file var reader = new FileReader(); reader.onloadend = function(e) { if (e.target.readyState === FileReader.DONE) { var bytes = new Uint8Array(e.target.result); for (var i=0, l = mimes.length; i<l; ++i) { if (check(bytes, mimes[i])) return callback("Mime: " + mimes[i].mime + " <br> Browser:" + file.type); } return callback("Mime: unknown <br> Browser:" + file.type); } }; reader.readAsArrayBuffer(blob); } //when selecting a file on the input fileInput.onchange = function() { loadMime(fileInput.files[0], function(mime) { //print the output to the screen output.innerHTML = mime; }); };

<input type="file" id="fileInput"> <div id="output"></div>


Esto es lo que tienes que hacer

var fileVariable =document.getElementsById(''fileId'').files[0];

Si desea verificar los tipos de archivos de imagen, entonces

if(fileVariable.type.match(''image.*'')) { alert(''its an image''); }


La respuesta corta es no.

Como nota, los navegadores derivan el type de la extensión del archivo. La vista previa de Mac también parece ejecutarse fuera de la extensión. Estoy asumiendo que es porque es más rápido leer el nombre del archivo que figura en el puntero, en lugar de mirar hacia arriba y leer el archivo en el disco.

Hice una copia de un jpg renombrado con png.

Pude obtener de forma consistente 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 un String.indexOf (''jpeg'') comprobar el tipo de imagen.

Aquí hay un violín para explorar http://jsfiddle.net/bamboo/jkZ2v/1/

La línea ambigua me olvidé de comentar en el ejemplo

console.log( /^(.*)$/m.exec(window.atob( image.src.split('','')[1] )) );

  • Divide los datos img codificados en base64, dejando en la imagen
  • Base64 decodifica la imagen
  • Coincide solo con la primera línea de los datos de imagen

El código de violín utiliza decodificación base64 que no funcionará en IE9, encontré un buen ejemplo utilizando 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 buen lado del cliente para redimensionar el lienzo de la imagen antes de subirlo, lo que puede ser de interés https://joelvardy.com/writing/javascript-image-upload


Puede determinar fácilmente el tipo MIME del archivo con el FileReader de JavaScript 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 aún es posible. Le mostraré cómo y proporcionaré una demostración en funcionamiento en la parte inferior.

Verifique que su navegador sea compatible con File y Blob . Todos los principales deberían.

if (window.FileReader && window.Blob) { // All the File APIs are supported. } else { // File and Blob are not supported }

Paso 1:

Puede recuperar la información de File de un elemento <input> como este ( ref ):

<input type="file" id="your-files" multiple> <script> var control = document.getElementById("your-files"); control.addEventListener("change", function(event) { // When the control has changed, there are new files var files = control.files, for (var i = 0; i < files.length; i++) { console.log("Filename: " + files[i].name); console.log("Type: " + files[i].type); console.log("Size: " + files[i].size + " bytes"); } }, false); </script>

Aquí hay una versión de arrastrar y soltar del anterior ( ref ):

<div id="your-files"></div> <script> var target = document.getElementById("your-files"); target.addEventListener("dragover", function(event) { event.preventDefault(); }, false); target.addEventListener("drop", function(event) { // Cancel default actions event.preventDefault(); var files = event.dataTransfer.files, for (var i = 0; i < files.length; i++) { console.log("Filename: " + files[i].name); console.log("Type: " + files[i].type); console.log("Size: " + files[i].size + " bytes"); } }, false); </script>

Paso 2:

Ahora podemos inspeccionar los archivos y desenterrar los encabezados y tipos MIME.

✘ Método rápido

Puedes ingenuamente preguntarle a Blob por el tipo MIME de cualquier archivo que represente usando este patrón:

var blob = files[i]; // See step 1 above console.log(blob.type);

Para las imágenes, los tipos MIME regresan de la siguiente manera:

imagen / jpeg
imagen / png
...

Advertencia: el tipo MIME se detecta desde la extensión del archivo y puede engañarse o simularse. Se puede cambiar el nombre de un .jpg a .png y el tipo MIME se informará como image/png .

✓ Método adecuado de inspección del encabezado

Para obtener el tipo MIME genuino de un archivo del lado del cliente, podemos ir un paso más allá e inspeccionar los primeros bytes del archivo dado para compararlo 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. Es posible que se salga con la suya solo verificando los primeros dos bytes, pero prefiero verificar al menos 4 bytes para reducir los falsos positivos.

Ejemplos de firmas de archivos de JPEG (primeros 4 bytes):

FF D8 FF E0 (SOI + ADD0)
FF D8 FF E1 (SOI + ADD1)
FF D8 FF E2 (SOI + ADD2)

Aquí está el código esencial para recuperar el encabezado del archivo:

var blob = files[i]; // See step 1 above var fileReader = new FileReader(); fileReader.onloadend = function(e) { var arr = (new Uint8Array(e.target.result)).subarray(0, 4); var header = ""; for(var i = 0; i < arr.length; i++) { header += arr[i].toString(16); } console.log(header); // Check the file signature against known types }; fileReader.readAsArrayBuffer(blob);

A continuación, puede determinar el tipo MIME real como tal (más firmas de archivo here y here ):

switch (header) { case "89504e47": type = "image/png"; break; case "47494638": type = "image/gif"; break; case "ffd8ffe0": case "ffd8ffe1": case "ffd8ffe2": case "ffd8ffe3": case "ffd8ffe8": type = "image/jpeg"; break; default: type = "unknown"; // Or you can use the blob.type as fallback break; }

Acepte o rechace las cargas de archivos que desee en función de los tipos MIME esperados.

Manifestación

Aquí hay una demostración en funcionamiento para archivos locales y archivos remotos (tuve que omitir CORS solo para esta demostración). Abra el fragmento, ejecútelo y verá tres imágenes remotas de diferentes tipos. En la parte superior, puede seleccionar una imagen local o un 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

// Return the first few bytes of the file as a hex string function getBLOBFileHeader(url, blob, callback) { var fileReader = new FileReader(); fileReader.onloadend = function(e) { var arr = (new Uint8Array(e.target.result)).subarray(0, 4); var header = ""; for (var i = 0; i < arr.length; i++) { header += arr[i].toString(16); } callback(url, header); }; fileReader.readAsArrayBuffer(blob); } function getRemoteFileHeader(url, callback) { var xhr = new XMLHttpRequest(); // Bypass CORS for this demo - naughty, Drakes xhr.open(''GET'', ''//cors-anywhere.herokuapp.com/'' + url); xhr.responseType = "blob"; xhr.onload = function() { callback(url, xhr.response); }; xhr.onerror = function() { alert(''A network error occurred!''); }; xhr.send(); } function headerCallback(url, headerString) { printHeaderInfo(url, headerString); } function remoteCallback(url, blob) { printImage(blob); getBLOBFileHeader(url, blob, headerCallback); } function printImage(blob) { // Add this image to the document body for proof of GET success var fr = new FileReader(); fr.onloadend = function() { $("hr").after($("<img>").attr("src", fr.result)) .after($("<div>").text("Blob MIME type: " + blob.type)); }; fr.readAsDataURL(blob); } // Add more from http://en.wikipedia.org/wiki/List_of_file_signatures function mimeType(headerString) { switch (headerString) { case "89504e47": type = "image/png"; break; case "47494638": type = "image/gif"; break; case "ffd8ffe0": case "ffd8ffe1": case "ffd8ffe2": type = "image/jpeg"; break; default: type = "unknown"; break; } return type; } function printHeaderInfo(url, headerString) { $("hr").after($("<div>").text("Real MIME type: " + mimeType(headerString))) .after($("<div>").text("File header: 0x" + headerString)) .after($("<div>").text(url)); } /* Demo driver code */ var imageURLsArray = ["http://media2.giphy.com/media/8KrhxtEsrdhD2/giphy.gif", "http://upload.wikimedia.org/wikipedia/commons/e/e9/Felis_silvestris_silvestris_small_gradual_decrease_of_quality.png", "http://static.giantbomb.com/uploads/scale_small/0/316/520157-apple_logo_dec07.jpg"]; // Check for FileReader support if (window.FileReader && window.Blob) { // Load all the remote images from the urls array for (var i = 0; i < imageURLsArray.length; i++) { getRemoteFileHeader(imageURLsArray[i], remoteCallback); } /* Handle local files */ $("input").on(''change'', function(event) { var file = event.target.files[0]; if (file.size >= 2 * 1024 * 1024) { alert("File size must be at most 2MB"); return; } remoteCallback(escape(file.name), file); }); } else { // File and Blob are not supported $("hr").after( $("<div>").text("It seems your browser doesn''t support FileReader") ); } /* Drakes, 2015 */

img { max-height: 200px } div { height: 26px; font: Arial; font-size: 12pt } form { height: 40px; }

<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script> <form> <input type="file" /> <div>Choose an image to see its file signature.</div> </form> <hr/>


Si solo desea comprobar si el archivo cargado es una imagen, puede intentar cargarlo en la etiqueta <img> y verificar si hay algún error de devolución de llamada.

Ejemplo:

var input = document.getElementsByTagName(''input'')[0]; var reader = new FileReader(); reader.onload = function (e) { imageExists(e.target.result, function(exists){ if (exists) { // Do something with the image file.. } else { // different file format } }); }; reader.readAsDataURL(input.files[0]); function imageExists(url, callback) { var img = new Image(); img.onload = function() { callback(true); }; img.onerror = function() { callback(false); }; img.src = url; }