¿Limitar el formato de archivo cuando se usa <input type = "file">?

667

Me gustaría restringir el tipo de archivo que se puede elegir del selector de archivos del sistema operativo nativo cuando el usuario hace clic en el botón Examinar en el <input type="file">elemento en HTML. Tengo la sensación de que es imposible, pero me gustaría saber si hay es una solución. Me gustaría mantener únicamente HTML y JavaScript; sin flash por favor.

Bojangles
fuente
1
Es fácilmente posible con PHP, pero no sé si puede usar eso, así que no publicaré el código.
Latox
2
Puedo, pero tengo una solución que funciona con JavaScript: elimina la molestia de cargar un archivo y luego obtener el "¡Archivo incorrecto!" error.
Bojangles
También vea la pregunta más reciente: stackoverflow.com/questions/181214/…
Christophe Roussy
Una cosa a tener en cuenta es que si bien no es bueno para la validación, aceptar limitará los archivos visibles a los aceptados mientras el usuario los navega (al menos en algunos navegadores ...). Por lo tanto, esta es más una función de ergonomía de la interfaz de usuario que una de validación.
Christophe Roussy

Respuestas:

1119

Estrictamente hablando, la respuesta es no . Un desarrollador no puede evitar que un usuario cargue archivos de ningún tipo o extensión.

Pero aún así, el atributo accept de <input type = "file">puede ayudar a proporcionar un filtro en el cuadro de diálogo de selección de archivos del sistema operativo. Por ejemplo,

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

debería proporcionar una forma de filtrar archivos que no sean .xls o .xlsx. Aunque la página MDN para inputelement siempre dijo que es compatible con esto, para mi sorpresa, esto no funcionó para mí en Firefox hasta la versión 42. Esto funciona en IE 10+, Edge y Chrome.

Entonces, para admitir Firefox anterior a 42 junto con IE 10+, Edge, Chrome y Opera, supongo que es mejor usar una lista de tipos MIME separados por comas:

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

Comportamiento [ Edge (EdgeHTML): el menú desplegable de filtro de tipo de archivo muestra los tipos de archivo mencionados aquí, pero no es el predeterminado en el menú desplegable. El filtro predeterminado es All files (*).]

También puede usar asteriscos en tipos MIME. Por ejemplo:

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

W3C recomienda a los autores que especifiquen los tipos MIME y las extensiones correspondientes en el acceptatributo. Entonces, el mejor enfoque es:

<!-- 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" /> 

JS Violín de lo mismo: aquí .

Referencia: Lista de tipos MIME

IMPORTANTE: el uso del acceptatributo solo proporciona una forma de filtrado en los archivos de tipos que son de interés. Los navegadores aún permiten a los usuarios elegir archivos de cualquier tipo. Se deben realizar verificaciones adicionales (del lado del cliente) (usando JavaScript, una forma sería esta ), y definitivamente los tipos de archivo DEBEN verificarse en el servidor , usando una combinación de tipo MIME usando la extensión del archivo y su firma binaria ( ASP .NET , PHP , Ruby , Java ). También puede consultar estas tablas para conocer los tipos de archivos y sus números mágicos., para realizar una verificación más sólida del lado del servidor.

Aquí hay tres buenas lecturas sobre la carga de archivos y la seguridad.

EDITAR: Quizás la verificación del tipo de archivo usando su firma binaria también se puede hacer en el lado del cliente usando JavaScript (en lugar de solo mirar la extensión) usando la API de archivos HTML5, pero aún así, el archivo debe ser verificado en el servidor, porque un usuario malintencionado aún podrá cargar archivos haciendo una solicitud HTTP personalizada.

Sachin Joseph
fuente
2
@Sandesire No creo que pueda restringir el tamaño de los archivos en HTML. Es posible usar JavaScript, como sugirió.
Sachin Joseph
1
Desde mi experiencia personal, esto parece una buena respuesta, el tipo mime solo no funcionará en todos los navegadores.
Christophe Roussy
1
Por cierto, accepttodavía no funciona en Edge: stackoverflow.com/questions/31875617/… . Más detalles aquí: wpdev.uservoice.com/forums/257854-microsoft-edge-developer/…
SharpC
1
Ojalá tuviéramos la opción de excluir archivos también, por ejemplo exclude="exe". ¯_ (ツ) _ / ¯
Sagiv bg
1
Para aclarar aún más el comportamiento de Edge (según mis pruebas), agregará diferentes filtros en función de lo que especifique, pero a) no está incluido, por lo que enumerará cada extensión como una opción separada yb) siempre agregará algunos elementos Construir extensiones como .html yc) como ya se indicó, siempre preseleccionará (*). Lo que lo hace un gran desastre e inútil en la mayoría de los casos. He votado por el enlace de la voz del usuario, esperemos que escuchen tarde o temprano.
Arie
198

Existe el atributo de aceptación para la etiqueta de entrada. Sin embargo, no es confiable de ninguna manera. Lo más probable es que los navegadores lo traten como una "sugerencia", lo que significa que el usuario, dependiendo también del administrador de archivos, tendrá una preselección que solo muestra los tipos deseados. Todavía pueden elegir "todos los archivos" y cargar cualquier archivo que deseen.

Por ejemplo:

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

Lea más en la especificación HTML5

Tenga en cuenta que solo debe usarse como una "ayuda" para que el usuario encuentre los archivos correctos. Cada usuario puede enviar cualquier solicitud que desee a su servidor. Siempre tienes que validar todo el lado del servidor.

Entonces la respuesta es: no, no puede restringir , pero puede establecer una preselección pero no puede confiar en ella.

Alternativa o adicionalmente, puede hacer algo similar al verificar el nombre de archivo (valor del campo de entrada) con JavaScript, pero esto no tiene sentido porque no proporciona protección y tampoco facilita la selección para el usuario. Potencialmente solo engaña a un webmaster para que piense que está protegido y abre un agujero de seguridad. Puede ser una molestia para los usuarios que tienen extensiones de archivo alternativas (por ejemplo, jpeg en lugar de jpg), mayúsculas o ninguna extensión de archivo (como es común en los sistemas Linux).

El surrican
fuente
3
para obtener información adicional, consulte stackoverflow.com/questions/181214/…
Martin Meeser
1
Aunque es cierto que es imposible evitar que el usuario seleccione CUALQUIER tipo de archivo, en estos días puede aprovechar la API de archivos HTML5 y trabajar con el archivo seleccionado para cargarlo, antes de que realmente se cargue en el servidor, incluida la detección Su tipo, tamaño y más. Darle una oportunidad. Es muy fácil de usar, pero muy potente y útil.
TheCuBeMan
96

Puede usar el changeevento para monitorear lo que el usuario selecciona y notificarles en ese momento que el archivo no es aceptable. No limita la lista real de archivos que se muestran, pero es lo más cercano que puede hacer del lado del cliente, además del acceptatributo mal soportado .

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
fuente
11
@joe, es un ejemplo ... puede extenderse a cualquier extensión que desee permitir.
Gabriele Petrioli
si puedes. pero no lo hiciste! y maby alguien ya lo copió! ¿Y los archivos con el tipo MIME correcto pero sin extensión?
The Surrican
49
@ Joe ... bueno ... trato de proporcionar dirección y una lógica de sonido. Soluciones no completamente implementadas para cada caso. Confío en que los espectadores usen el sentido común al copiar / pegar código de la web;)
Gabriele Petrioli
77
¿Qué tal "Some.File.jpg"? Quizás esa línea regex necesita leer: var ext = this.value.match (/ \. ([^.] +) $ /) [1];
Jon Kloske
El problema con este enfoque es que algo aún podría ser técnicamente un JPEG, incluso si no termina con esa extensión. Extensiones! == tipos mime
Matt Fletcher
46

Sí, tiene usted razón. Es imposible con HTML. El usuario podrá elegir el archivo que desee.

Puede escribir un código JavaScript para evitar enviar un archivo en función de su extensión. Pero tenga en cuenta que esto de ninguna manera evitará que un usuario malintencionado envíe cualquier archivo que realmente desee.

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
fuente
3
hay un atributo html completamente válido para eso, por lo que es posible. simplemente no es respetado por los navegadores, pero ese es un problema de estandarización. así como cualquier cosa manejada del lado del cliente en marcado desprotegido no puede restringir nada. Java Script no es una solución.
The Surrican
2
Muy buen punto. Agregaré un segundo verificador de PHP por si acaso. No se puede tener mucho cuidado!
Bojangles
2
Bueno, no hace daño si estoy usando un script de validación PHP también, así que usaré ambos.
Bojangles
17
@ Joe: ¡deja de decir que mi respuesta apesta! :-) De todos modos, no es una solución perfecta. Como dije al principio: "es imposible" hacer lo que OP quiere. Pero puede tener algún grado de ayuda para el usuario si solo le permite elegir archivos con ciertas extensiones. La validación del tipo de archivo REAL debe hacerse del lado del servidor .
Pablo Santa Cruz
11
@JoeHopfgartner: Amigo, estás siendo demasiado duro con Pablo aquí. La validación del lado del cliente se realiza en toneladas de lugares y, aunque no es infalible (debe haber [b] siempre [/ b] incluida la validación del lado del servidor), puede ahorrar al usuario bastante tiempo (sin devolución de datos para una estúpida verificación de extensión, etc.). Si bien el script proporcionado por Pablo no es perfecto, solo pretende ser un ejemplo de cómo abordar este problema ... Tal vez debería enviar un correo electrónico a los técnicos de Microsoft y pedirles que eliminen la validación de Clientside de sus validadores ASP.NET desde todo es basura para ti ...
Nathan
18

Técnicamente, puede especificar el acceptatributo (alternativa en html5 ) en el inputelemento, pero no se admite correctamente.

zzzzBov
fuente
¡El soporte del navegador W3Schools falla! Es una pena realmente. También es un problema de seguridad: las personas pueden hackear el código del lado del cliente y subir lo que quieran.
Bojangles
55
Es cierto que es mejor no usar esto por seguridad, pero definitivamente ayuda a la usabilidad en los navegadores que lo admiten. A los usuarios se les muestran solo los archivos que el sitio permite (no todos los demás archivos basura que puedan tener en la misma carpeta) y no tienen que pasar por todo el proceso de carga para recibir un error, lo sabrán de inmediato. Los codificadores deberían usar esto.
Simon East
10

Usar inputetiqueta con acceptatributo

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

Haga clic aquí para obtener la última tabla de compatibilidad del navegador

Demostración en vivo aquí

Para seleccionar solo archivos de imagen, puede usar esto accept="image/*"

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

Demostración en vivo aquí

Solo se mostrarán gif, jpg y png, captura de pantalla de Chrome versión 44 Solo se mostrarán gif, jpg y png, captura de pantalla de Chrome versión 44

kiranvj
fuente
¡Gracias! En Chrome en Win10, si lo uso accept="image/*", dice "Archivos de imagen" en lugar de "Archivos personalizados" en el selector de archivos, lo cual es bueno para el usuario final.
Teddy
Pero el usuario puede cambiarlo y cargar el otro archivo de extensión
Prashant Prajapati
@PrashantPrajapati Sí, así es como se hacen los navegadores, debe haber una validación correspondiente en el servidor. La funcionalidad del navegador es solo para una mejor experiencia del usuario.
kiranvj
9

Sé que esto es un poco 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
fuente
5

En realidad, podría hacerlo con JavaScript, pero recuerde que js es del lado del cliente, por lo que en realidad estaría "advirtiendo a los usuarios" qué tipo de archivos pueden cargar, si desea EVITAR (restringir o limitar como usted dijo) cierto tipo de archivos que DEBE hazlo del lado del servidor.

Mire este tutorial básico si desea comenzar con la validación del lado del servidor. Para ver el tutorial completo, visite esta página .

¡Buena suerte!

Trufa
fuente
4

Como se mencionó en las respuestas anteriores, no podemos restringir al usuario a seleccionar archivos para formatos de archivo determinados. Pero es realmente útil usar la etiqueta de aceptación en el atributo de archivo en html.

En cuanto a la validación, tenemos que hacerlo en el lado del servidor. También podemos hacerlo en el lado del cliente en js, pero no es una solución infalible. Debemos validar en el lado del servidor.

Para estos requisitos, realmente prefiero el marco de desarrollo de aplicaciones web struts2 Java. Con su función integrada de carga de archivos, cargar archivos en aplicaciones web basadas en struts2 es pan comido. Solo mencione los formatos de archivo que nos gustaría aceptar en nuestra aplicación y todo lo demás se ocupa del núcleo del marco en sí. Puede consultarlo en el sitio oficial de Struts.

svg
fuente
3

Puedo sugerir lo siguiente:

  • Si tiene que hacer que el usuario seleccione cualquiera de los archivos de imagen por defecto, use accept = "image / *"

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

  • si desea restringir a tipos de imagen específicos, use accept = "image / bmp, image / jpeg, image / png"

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

  • si desea restringir a tipos específicos, use accept = ". bmp, .doc, .pdf"

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

  • No puede restringir al usuario para que cambie el archivador a todos los archivos, por lo tanto, siempre valide el tipo de archivo en el script y el servidor

Imran Javed
fuente
1
Esto era lo que estaba buscando: accept = ". Bmp" Funciona bien en Chrome.
MichaelRom