【问题标题】:Limit file format when using <input type="file">?使用 <input type="file"> 时限制文件格式?
【发布时间】:2011-05-18 18:07:18
【问题描述】:

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

【问题讨论】:

  • 用 PHP 很容易实现,但我不知道你是否可以使用,所以我不会发布代码。
  • 我可以,但我有一个使用 JavaScript 的解决方案 - 它消除了上传文件然后得到“错误文件!”的烦恼错误。
  • 另见最近的问题:stackoverflow.com/questions/181214/…
  • 需要注意的一点是,虽然它不是很好的验证,但当用户浏览它们时,accept 会将可见文件限制为已接受的文件(至少在某些浏览器中......)。因此,这更像是一种 UI 人机工程学功能,而不是验证功能。

标签: html file types


【解决方案1】:

您可以使用“接受”属性作为文件选择框中的过滤器。 使用“接受”可帮助您根据输入文件的“后缀”或“MIME 类型”过滤输入文件

1.根据后缀过滤: 这里的“accept”属性只允许选择扩展名为 .jpeg 的文件。

<input type="file" accept=".jpeg" />

2.根据“文件类型”过滤 这里的“accept”属性只允许你选择一个“image/jpeg”类型的文件。

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

重要提示:我们可以更改或删除文件的扩展名,而无需更改 meme 类型。例如,可以有一个没有扩展名的文件,但这个文件的类型可以是“image/jpeg”。所以这个文件不能通过 accept=".jpeg" 过滤器。但它可以通过accept="image/jpeg"。

3.我们可以使用*来选择各种文件类型。例如下面的代码允许选择各种图像。例如 "image/png" 或 "image/jpeg" 或 ... 。所有这些都是允许的。

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

4.我们可以在 select 属性中使用 cama ( , ) 作为“或运算符”。例如,要允许所有类型的图像或 pdf 文件,我们可以使用以下代码:

<input type="file" accept="image/* , application/pdf" />

【讨论】:

    【解决方案2】:

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

    但是,&lt;input type = "file"&gt;accept 属性仍然可以帮助在操作系统的文件选择对话框中提供过滤器。例如,

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

    应该提供一种过滤除 .xls 或 .xlsx 以外的文件的方法。尽管 input 元素的 MDN 页面总是说它支持这一点,但令我惊讶的是,这在 Firefox 42 之前对我不起作用。这适用于 IE 10+、Edge 和 Chrome。

    所以,为了支持 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 recommends 作者在 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:here

    参考: List of MIME-types

    重要提示: 使用 accept 属性仅提供一种过滤类型为兴趣。浏览器仍然允许用户选择任何类型的文件。应该进行额外的(客户端)检查(使用 JavaScript,一种方法是 this),并且绝对文件类型必须在服务器上验证,使用使用文件扩展名及其二进制签名(ASP.NETPHPRubyJava)的 MIME 类型的组合。您可能还想参考thesetables 了解文件类型及其magic numbers,以执行更强大的服务器端验证。

    以下是关于文件上传和安全性的threegoodreads

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

    【讨论】:

    • @Sandesire 我认为您不能限制 HTML 中的文件大小。正如您所建议的,可以使用 JavaScript。
    • 从我个人的经验来看,这似乎是一个很好的答案,单独的 mime 类型并不适用于所有浏览器。
    • 顺便说一句 accept 在 Edge 中仍然不起作用:stackoverflow.com/questions/31875617/…。更多细节在这里:wpdev.uservoice.com/forums/257854-microsoft-edge-developer/…
    • 我希望我们也可以选择排除文件,例如exclude="exe"。 ¯_(ツ)_/¯
    • 为了进一步阐明 Edge 行为(根据我的测试),它将根据您指定的内容添加不同的过滤器,但是 a) 它没有捆绑,因此它将每个扩展程序列为单独的选项和 b ) 它总是会添加一些内置扩展,例如 .html 和 c),如前所述,它总是会预先选择 (*)。在大多数情况下,这使它变得一团糟而且毫无用处。我对 uservoice 链接进行了投票,希望他们迟早会听到。
    【解决方案3】:

    在之前使用 accept 属性的答案的基础上,您可以使用 File API 完成此操作。如果您使用FileReader 进行一些本地解析或数据处理,这也可以让您访问文件内容。

    首先创建一个输入元素,在这里您可以将文件类型应用于接受属性,但对于示例,它将允许您选择所有文件类型。

    <input type="file" name="upload" accept="*" multiple>
    

    接下来我们需要监听输入元素上的'change'事件。

    var upload = document.querySelector('input[type="file"]');
    upload.addEventListener('change', function() {});
    

    在函数内部,您将能够访问输入的文件对象。

    var files = this.files
    

    我们不能只遍历对象,因为它不是一个数组,但是我们可以使用 item() 函数从列表中访问我们的 File 对象。

    for (var i = 0; i < files.length; i++) {
        var file = files.item(i);
    }
    

    现在我们有了 File 对象,我们可以访问它的名称和类型属性并在此处进行文件检查。在这种情况下,我正在检查它是否是 .txt 文件,如果不是,则打印一条消息。您可以根据文件类型的正则表达式模式检查名称或根据其 MIME 类型检查类型。

    if (!file.name.match(/.txt$/i) || file.type != 'text/plain') {
        console.log(file.name + ' is not a .txt file.');
    }
    

    var upload = document.querySelector('input[type="file"]');
    upload.addEventListener('change', function() {
        var files = this.files;
        for (var i = 0; i < files.length; i++) {
            var file = files.item(i);
            if (!file.name.match(/.txt$/i) || file.type != 'text/plain') {
                console.log(file.name + ' is not a .txt file.');
            }
        }
    });
    &lt;input type="file" name="upload" accept="*" multiple&gt;

    现代浏览器很好地支持文件 API。通过将此与接受属性相结合,您可以轻松过滤本地用户可以在上传中选择的内容并提供有用的反馈。如果您要上传文件,您仍应在后端检查并验证文件类型。

    【讨论】:

      【解决方案4】:

      我建议如下:

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

        &lt;input type="file" accept="image/*" /&gt;

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

        &lt;input type="file" accept="image/bmp, image/jpeg, image/png" /&gt;

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

        &lt;input type="file" accept=".bmp, .doc, .pdf" /&gt;

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

      【讨论】:

      • 这就是我要找的:accept=".bmp" 在 chrome 上运行良好。
      【解决方案5】:

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

      例如:

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

      HTML5 spec了解更多信息

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

      所以答案是:不能限制,但你可以设置一个预选但你不能 em> 依赖它。

      另外或另外,您可以通过使用 JavaScript 检查文件名(输入字段的值)来做类似的事情,但这是无稽之谈,因为它没有提供任何保护,也不会简化用户的选择。它只会潜在地诱使网站管理员认为他/她受到保护并打开安全漏洞。对于具有其他文件扩展名(例如 jpeg 而不是 jpg)、大写字母或没有任何文件扩展名(在 Linux 系统上很常见)的用户来说,这可能会让人头疼。

      【讨论】:

      • 虽然确实不可能阻止用户最终选择任何类型的文件,但如今,您可以利用 HTML5 File API 并使用所选文件进行上传,然后再上传实际上传到服务器,包括检测其类型、大小等。试一试。它非常易于使用,但功能强大且有用。
      【解决方案6】:

      您可以使用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 = '';
        }
      };
      &lt;input type="file" id="someId" /&gt;

      JSFiddle

      【讨论】:

      • @joe,这是一个例子......它可以扩展到您想要允许的任何扩展。
      • 是的,你可以。但你没有!也许有人已经复制了它!那些具有正确 mime 类型但没有扩展名的文件呢?
      • @Joe .. 好吧.. 我尝试提供方向和合理的逻辑。未针对每种情况完全实施解决方案。我相信观众在从网络复制/粘贴代码时会使用常识;)
      • “Some.File.jpg”怎么样?也许该正则表达式行需要阅读: var ext = this.value.match(/\.([^.]+)$/)[1];
      • 这种方法的问题是,即使它没有以该扩展名结尾,从技术上讲,某些东西仍然可能是 jpeg。扩展 !== mime 类型
      【解决方案7】:

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

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

      对于这些需求我真的更喜欢struts2 Java web 应用程序开发框架。凭借其内置的文件上传功能,将文件上传到基于 struts2 的 Web 应用程序是小菜一碟。只需提及我们希望在我们的应用程序中接受的文件格式,其余的都由框架本身的核心处理。可以在struts官网查看。

      【讨论】:

        【解决方案8】:

        使用带有accept 属性的input 标记

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

        点击here for the latest browser compatibility table

        现场演示here

        要只选择图片文件,可以使用accept="image/*"

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

        现场演示here

        仅显示 gif、jpg 和 png,屏幕抓取来自 Chrome 版本 44

        【讨论】:

        • 谢谢!在 Win10 上的 Chrome 中,如果我使用 accept="image/*",它会在文件选择器中显示“图像文件”而不是“自定义文件”,这对最终用户来说很好。
        • 但用户可以更改它并上传其他扩展文件
        • @PrashantPrajapati 是的,浏览器就是这样制作的,服务器中应该有相应的验证。浏览器功能只是为了更好的用户体验。
        【解决方案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;
        }
        

        【讨论】:

          【解决方案10】:

          从技术上讲,您可以在 input 元素上指定 accept attributehtml5 中的替代),但它没有得到适当的支持。

          【讨论】:

          • W3Schools 浏览器支持失败!真的很可惜。这也是一个安全问题 - 人们可以破解客户端代码并上传他们想要的任何内容。
          • 没错,为了安全起见,最好不要使用它,但它肯定有助于支持它的浏览器的可用性。用户只会看到网站允许的文件(而不是他们可能在同一文件夹中的所有其他垃圾),并且他们不必经历整个上传过程就会收到错误,他们会立即知道。编码人员应该使用这个。
          【解决方案11】:

          您实际上可以使用 javascript 来执行此操作,但请记住 js 是客户端,因此如果您想避免(如您所说的限制或限制)某些类型的文件,您实际上会“警告用户”他们可以上传什么类型的文件您必须在服务器端执行文件。

          如果您想开始使用服务器端验证,请查看this basic tut。整个教程请访问this page

          祝你好运!

          【讨论】:

            【解决方案12】:

            是的,你是对的。 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>
            

            【讨论】:

            • 有一个完全有效的 html 属性,所以它是可能的。它只是不受浏览器的尊重,但这是一个标准化问题。以及在不受保护的标记中处理客户端的任何东西都不能限制任何东西 java 脚本不是解决方案。
            • 非常好。以防万一,我将添加第二个 PHP 检查器。不能太小心!
            • 好吧,如果我也使用 PHP 验证脚本也没关系,所以我会同时使用。
            • @Joe:别再说我的回答很烂了! :-) 无论如何,这不是一个完美的解决方案。正如我在开头所说的那样:“不可能”做 OP 想要的。但是,如果您只让他/她选择具有特定扩展名的文件,您可以为用户提供某种 程度的帮助。 REAL 文件类型验证必须在服务器端完成。
            • @JoeHopfgartner :伙计,你在这里对 Pablo 过于苛刻了。客户端验证在很多地方完成,虽然不是万无一失的(应该 [b]always[/b] 包括服务器端验证),但它可以为用户节省相当多的时间(对于愚蠢的扩展检查等没有回发)。虽然 Pablo 给出的脚本并不完美,但它只是作为如何解决这个问题的一个例子......也许你应该给微软的技术人员发电子邮件,要求他们从他们的 ASP.NET 验证器中删除客户端验证,因为这对你来说都是垃圾......
            猜你喜欢
            • 2011-06-05
            • 1970-01-01
            • 2011-08-17
            • 1970-01-01
            • 2011-08-13
            • 2017-02-24
            • 2016-05-25
            相关资源
            最近更新 更多