使用<input type =“ file”>时限制文件格式?


667

我想限制当用户单击<input type="file">HTML元素中的“浏览”按钮时可以从本机OS文件选择器选择的文件类型。我有一种感觉,这是不可能的,但我想知道是否有一个解决方案。我只想保留HTML和JavaScript;请不要使用Flash。


1
使用PHP可以轻松实现,但是我不知道您是否可以使用它,因此我不会发布代码。
拉托克斯

2
可以,但是我有使用JavaScript的解决方案-它消除了上传文件然后出现“错误文件” 的烦恼。错误。
Bojangles 2010年


需要注意的一件事是,尽管对于验证不是很有效,但是accept将在用户浏览可见文件时将可见文件限制为可接受的文件(至少在某些浏览器中……)。因此,这比验证功能更像是UI人体工程学功能。
Christophe Roussy 18/09/25

Answers:


1119

严格来说,答案是否定的。开发人员无法阻止用户上传任何类型或扩展名的文件。

但是,仍然可以使用的accept属性<input type = "file">在OS的文件选择对话框中提供过滤器。例如,

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

应该提供一种过滤掉.xls或.xlsx以外的文件的方法。尽管element 的MDN页面input总是说支持该功能,但令我惊讶的是,直到42版,此功能才在Firefox中对我不起作用。该功能在IE 10 +,Edge和Chrome中有效。

因此,为了支持IE 42+以上版本的Firefox和IE 10 +,Edge,Chrome和Opera,我认为最好使用逗号分隔的MIME类型列表:

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

[ Edge(EdgeHTML)行为:文件类型过滤器下拉列表显示此处提到的文件类型,但不是下拉列表中的默认类型。默认过滤器为All files (*)。]

您还可以在MIME类型中使用星号。例如:

<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 建议作者在accept属性中同时指定MIME类型和相应的扩展名。因此,最好的方法是:

<!-- 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相同:这里

参考: MIME类型列表

重要说明:使用accept属性仅提供一种在感兴趣的类型的文件中进行过滤的方法。浏览器仍然允许用户选择任何类型的文件。应该进行其他(客户端)检查(使用JavaScript,一种方法是this),并且绝对必须在服务器上使用文件扩展名及其二进制签名(ASP)使用MIME类型的组合来验证文件类型.NETPHPRubyJava)。您可能还需要参考这些 以获取文件类型及其魔幻数字,以执行更强大的服务器端验证。

这里有3个 良好的 读取上的文件上传和安全性。

编辑: 也许使用其二进制签名的文件类型验证也可以在客户端使用JavaScript(而不是仅通过查看扩展名)使用HTML5 File API进行,但是仍然必须在服务器上验证文件,因为恶意用户仍然可以通过发出自定义HTTP请求来上传文件。


2
@Sandesire我认为您不能限制HTML中的文件大小。正如您所建议的,可以使用JavaScript。
萨钦·约瑟夫

1
从我的个人经验来看,这似乎是一个很好的答案,仅mime类型无法在所有浏览器上正常工作。
Christophe Roussy 18/09/25

1
顺便说一句,accept在Edge中仍然无法使用:stackoverflow.com/questions/31875617/…。此处有更多详细信息:wpdev.uservoice.com/forums/257854-microsoft-edge-developer/…–
SharpC

1
我希望我们也可以选择排除文件exclude="exe"。_(ツ)_ /¯
Sagiv BG

1
为了进一步阐明Edge的行为(根据我的测试),它将根据您指定的内容添加不同的过滤器,但是a)它没有捆绑,因此它将每个扩展名列为单独的选项,并且b)它将始终添加一些in-如已经说明的那样建立扩展名,例如.html和c),它将始终预选(*)。在大多数情况下,这使事情变得一团糟且无用。我对uservoice链接进行了投票,希望他们早晚听。
阿里(Arie)

198

输入标签具有accept属性。但是,它无论如何都不可靠。浏览器很可能会将其视为“建议”,这意味着用户也将根据文件管理器进行预选择,仅显示所需的类型。他们仍然可以选择“所有文件”并上传所需的任何文件。

例如:

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

阅读HTML5规范中的更多内容

请记住,它仅用作用户查找正确文件的“帮助”。每个用户都可以将他/她想要的任何请求发送到您的服务器。您始终必须在服务器端验证所有内容。

因此,答案是:不,不能限制,但是您可以设置预选择,但不能依赖它。

替代地或附加地,您可以通过使用JavaScript检查文件名(输入字段的值)来执行类似的操作,但这是无稽之谈,因为它没有提供保护,也无法简化用户的选择。它只会潜在地诱使网站管理员认为他/她受到了保护,并打开了一个安全漏洞。对于具有其他文件扩展名(例如jpeg而不是jpg),大写或没有任何文件扩展名(在Linux系统中很常见)的用户来说,这可能会很麻烦。


3
有关更多信息,请参见 stackoverflow.com/questions/181214/...
马丁Meeser

1
尽管确实无法阻止用户最终选择任何类型的文件,但是如今,您可以利用HTML5 File API并处理选定的文件进行上传,然后再将其实际上传到服务器,包括检测它的类型,大小等等。试试看。它非常易于使用,但功能强大且有用。
TheCuBeMan'5

96

您可以使用该change事件来监视用户选择的内容,然后通知他们该文件不可接受。它不限制显示的文件的实际列表,但是除了支持不佳的accept属性外,它是客户端可以执行的最接近的操作。

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


11
@joe,这是一个示例...它可以扩展到您要允许的任何扩展名。
加布里埃莱·佩特里奥利

是的,你可以。但是你不!maby已经有人复制了!以及具有正确的mime类型但没有扩展名的文件呢?
Surrican 2010年

49
@乔..好..我试图提供方向和合理的逻辑。没有针对每种情况的完全实施的解决方案。我相信观众在从网上复制/粘贴代码时会使用常识;)
Gabriele Petrioli 2010年

7
“ Some.File.jpg”怎么样?也许该正则表达式行需要读取:var ext = this.value.match(/ \。([^。] +)$ /)[1];
乔恩·克洛斯凯

这种方法的问题在于,即使它没有以该扩展名结尾,从技术上讲,它仍然可能是jpeg。扩展!== MIME类型
Matt Fletcher

46

是的,你是对的。使用HTML是不可能的。用户将能够选择他/她想要的任何文件。

您可以编写一段JavaScript代码来避免基于扩展名提交文件。但是请记住,这绝不会阻止恶意用户提交他/她真正想要的任何文件。

就像是:

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

HTML代码:

<form method="post" onsubmit="return beforeSubmit();">
    <input type="file" id="ifile" name="ifile"/>
</form>

3
有一个完全有效的html属性,因此有可能。它只是不被浏览器所尊重,但这就是一个标准化问题。以及在未受保护的标记中处理客户端的任何内容都不能限制Java脚本无法解决的任何问题。
Surrican 2010年

2
很好的一点。我将添加第二个PHP检查器,以防万一。不能太小心!
Bojangles 2010年

2
好吧,如果我也使用PHP验证脚本,那没有什么害处,因此我将同时使用它们。
Bojangles 2010年

17
@乔:别再说我的回答很烂!:-)无论如何,这不是一个完美的解决方案。正如我在开始时所说的:“不可能”做OP想要的事情。但是,如果只允许用户选择带有某些扩展名的文件,则可以为用户提供一定程度的帮助。REAL文件类型验证必须在服务器端完成。
巴勃罗·圣克鲁斯

11
@JoeHopfgartner:Dude,您对这里的Pablo太苛刻了。客户端验证是在很多地方进行的,尽管不是万无一失的(应该始终包括[b] [b]都是服务器端验证),但它可以节省用户很多时间(无需回发进行愚蠢的扩展检查等)。虽然Pablo给出的脚本并不完美,但是它仅是作为解决此问题的示例。也许您应该向Microsoft的技术人员发送电子邮件,并要求他们从其ASP.NET验证器中删除客户端验证,因为这对您来说都是垃圾……
内森

18

从技术上讲,您可以在元素上指定accept属性(在html5中为替代属性input,但未正确支持该属性


W3Schools浏览器支持失败!真是可惜。这也是一个安全问题-人们可以破解过去的客户端代码并上传他们想要的任何东西。
Bojangles 2010年

5
的确,最好不要将此用于安全性,但是它绝对有助于提高支持该功能的浏览器的可用性。仅向用户显示该站点允许的文件(不是他们可能在同一文件夹中拥有的所有其他垃圾文件),并且他们不必经过整个上载过程就可以得到错误提示,他们会立即知道。编码人员使用此代码。
西蒙·伊斯特

10

input标签与accept属性一起使用

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

单击此处以获取最新的浏览器兼容性表

现场演示在这里

要仅选择图像文件,可以使用此 accept="image/*"

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

现场演示在这里

仅会显示gif,jpg和png,Chrome 44版的屏幕截图 仅会显示gif,jpg和png,Chrome 44版的屏幕截图


谢谢!在Win10上的Chrome中,如果使用accept="image/*",则在文件选择器中显示“图像文件”而不是“自定义文件”,这对于最终用户来说很好。
泰迪

但是用户可以更改它并上传其他扩展文件
Prashant Prajapati

@PrashantPrajapati是的,这就是浏览器的制作方式,服务器中应进行相应的验证。浏览器功能只是为了获得更好的用户体验。
kiranvj

9

我知道这有点晚了。

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;
}

5

您实际上可以使用javascript做到这一点,但请记住js是客户端,因此,如果您要避免(如您所说的那样限制或限制)某些类型的文件,您实际上会在“警告用户”他们可以上传的文件类型。做服务器端。

如果您想开始使用服务器端验证,请看一下此基本教程。对于整个教程,请访问此页面

祝好运!


4

如前面的答案中所述,我们不能限制用户仅选择给定文件格式的文件。但是使用html中的file属性上的accept标签确实很方便。

至于验证,我们必须在服务器端进行。我们也可以在js的客户端执行此操作,但这不是万无一失的解决方案。我们必须在服务器端进行验证。

对于这些需求,我确实更喜欢struts2 Java Web应用程序开发框架。借助其内置的文件上传功能,将文件上传到基于struts2的Web应用程序简直是小菜一碟。只需提及我们希望在应用程序中接受的文件格式,其余所有内容都由框架本身的核心负责。您可以在struts官方站点上进行检查。


3

我可能建议如下:

  • 如果必须让用户默认选择任何图像文件,请使用accept =“ image / *”

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

  • 如果您想限制特定的图像类型,请使用accept =“ image / bmp,image / jpeg,image / png”

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

  • 如果您想限制为特定类型,请使用accept =“。bmp,.doc,.pdf”

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

  • 您不能限制用户将文件文件管理器更改为所有文件,因此请始终在脚本和服务器中验证文件类型


1
这就是我一直在寻找的东西:accept =“。bmp”在chrome上工作正常。
MichaelRom
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.