上传文件前验证文件扩展名

114

我正在将图片上传到servlet。服务器端通过检查文件头中的魔数来验证上传的文件是否为图像。有没有办法在提交表单到servlet之前,在客户端验证文件扩展名?一旦我按下回车键,它就开始上传。

我在客户端使用JavaScript和jQuery。

更新:最终我采用了服务器端验证方案,读取字节并拒绝上传非图像文件。


2
你在之前的问题中,有没有使用Uploadify建议呢? - BalusC
不,它会在50-96之间停止。我尝试了很多次,使用了各种输入。当时我也很急需解决方案。所以,我尝试了简单的jquery.ProgressBar.js。它运行良好。###那么,我可以用uploadify进行验证吗? - user405398
我们不能简单地在输入标签中使用accept属性来确保用户选择指定格式的文件吗? - AnonSar
22个回答

132

可以仅检查文件扩展名,但是用户很容易将virus.exe重命名为virus.jpg并“通过”验证。

如果有用的话,这里是检查文件扩展名并在不符合有效扩展名之一时中止的代码:(选择无效文件并尝试提交以查看警报的操作)

var _validFileExtensions = [".jpg", ".jpeg", ".bmp", ".gif", ".png"];    
function Validate(oForm) {
    var arrInputs = oForm.getElementsByTagName("input");
    for (var i = 0; i < arrInputs.length; i++) {
        var oInput = arrInputs[i];
        if (oInput.type == "file") {
            var sFileName = oInput.value;
            if (sFileName.length > 0) {
                var blnValid = false;
                for (var j = 0; j < _validFileExtensions.length; j++) {
                    var sCurExtension = _validFileExtensions[j];
                    if (sFileName.substr(sFileName.length - sCurExtension.length, sCurExtension.length).toLowerCase() == sCurExtension.toLowerCase()) {
                        blnValid = true;
                        break;
                    }
                }
                
                if (!blnValid) {
                    alert("Sorry, " + sFileName + " is invalid, allowed extensions are: " + _validFileExtensions.join(", "));
                    return false;
                }
            }
        }
    }
  
    return true;
}
<form onsubmit="return Validate(this);">
  File: <input type="file" name="my file" /><br />
  <input type="submit" value="Submit" />
</form>

请注意,该代码允许用户在不选择文件的情况下发送...如果需要,请删除 if (sFileName.length > 0) { 这行代码和其对应的闭合括号。该代码将验证表单中任何文件输入,而不管它的名称如何。

可以使用jQuery更少的行数实现这个功能,但我足够熟悉“原生”JavaScript,最终结果也是一样的。

如果您有多个文件或希望在更改文件时触发检查,而不仅仅是在表单提交时,请改用以下代码:

var _validFileExtensions = [".jpg", ".jpeg", ".bmp", ".gif", ".png"];    
function ValidateSingleInput(oInput) {
    if (oInput.type == "file") {
        var sFileName = oInput.value;
         if (sFileName.length > 0) {
            var blnValid = false;
            for (var j = 0; j < _validFileExtensions.length; j++) {
                var sCurExtension = _validFileExtensions[j];
                if (sFileName.substr(sFileName.length - sCurExtension.length, sCurExtension.length).toLowerCase() == sCurExtension.toLowerCase()) {
                    blnValid = true;
                    break;
                }
            }
             
            if (!blnValid) {
                alert("Sorry, " + sFileName + " is invalid, allowed extensions are: " + _validFileExtensions.join(", "));
                oInput.value = "";
                return false;
            }
        }
    }
    return true;
}
File 1: <input type="file" name="file1" onchange="ValidateSingleInput(this);" /><br />
File 2: <input type="file" name="file2" onchange="ValidateSingleInput(this);" /><br />
File 3: <input type="file" name="file3" onchange="ValidateSingleInput(this);" /><br />

如果文件扩展名无效,这将显示警报并重置输入。


我只想补充一下,使用"onSubmit"而不是"onChange"很麻烦 - 尤其是如果使用了"multiple"选项。每个文件应该在选择时进行检查,而不是在整个表单提交时。 - DevlshOne
@DevlshOne 很有趣的想法,我也会在帖子中提到。谢谢! - Shadow The Spring Wizard
非常感谢@Shadow Wizard提供的这段代码。它确实帮了我很多! - Anahit Ghazaryan
1
@garryman 失败了怎么办?这里的问题没有提到文件是必需的。如果在您的情况下,文件是必填字段,您可以将 var blnValid = false; 这一行移到 arrInputs 循环之前,然后在循环结束后检查变量 blnValid:如果为 true,则让表单提交,否则显示警告,指出文件是必需的。 - Shadow The Spring Wizard
请检查我下面的答案。 - Divyesh Jani
@DivyeshJani,为什么我要检查你的答案? - Shadow The Spring Wizard

81

对于这个简单的需求,没有一个现有的答案看起来足够简洁。要检查给定的文件输入字段是否具有一组扩展名,可以按如下方式完成:

function hasExtension(inputID, exts) {
    var fileName = document.getElementById(inputID).value;
    return (new RegExp('(' + exts.join('|').replace(/\./g, '\\.') + ')$')).test(fileName);
}

因此,使用示例可以是(其中upload是文件输入的id):

if (!hasExtension('upload', ['.jpg', '.gif', '.png'])) {
    // ... block upload
}

或者作为jQuery插件:

$.fn.hasExtension = function(exts) {
    return (new RegExp('(' + exts.join('|').replace(/\./g, '\\.') + ')$')).test($(this).val());
}

使用示例:

if (!$('#upload').hasExtension(['.jpg', '.png', '.gif'])) {
    // ... block upload
}

.replace(/\./g, '\\.') 是用来对正则表达式中的点进行转义,以便于基本扩展名可以不被匹配到任何字符。

这些函数没有错误检查,这样可以保持它们简短。假设您使用它们之前会确保输入存在并且扩展名数组是有效的!


11
好的。请注意,这些脚本是区分大小写的。为了解决这个问题,您需要给 RexExp 添加 "i" 修饰符,例如:return (new RegExp('(' + exts.join('|').replace(/\./g, '\\.') + ')$', "i")).test(fileName); - Tedd Hansen
2
有点难以阅读,但这意味着在正则表达式字符串的结尾()$')后添加 , "i"。这将为文件名扩展名中的任何大小写提供支持(.jpg、.JPG、.Jpg 等)。 - Tedd Hansen
谢谢,Tedd,最好是不区分大小写匹配。 - Orbling

44
$(function () {
    $('input[type=file]').change(function () {
        var val = $(this).val().toLowerCase(),
            regex = new RegExp("(.*?)\.(docx|doc|pdf|xml|bmp|ppt|xls)$");

        if (!(regex.test(val))) {
            $(this).val('');
            alert('Please select correct file format');
        }
    });
});

1
谢谢,非常简单和清晰。 - F.Lopez
如果您按下取消按钮,它将触发一个警报。 - PinoyStackOverflower
如果您有一个“file”对象,请使用file.name代替val():var val = $(file.name).toLowerCase(), ... - Avatar

22

我来到这里是因为我确信这里的答案都不够...诗意:

function checkextension() {
  var file = document.querySelector("#fUpload");
  if ( /\.(jpe?g|png|gif)$/i.test(file.files[0].name) === false ) { alert("not an image!"); }
}
<input type="file" id="fUpload" onchange="checkextension()"/>


谢谢,这个在 Angular 中稍作修改就可以用了,谢谢。 - skydev
1
对我来说效果很好,不过在测试之前应该修剪名称中的任何尾随空格。+1 - Yogi

14

你是否使用 input type="file" 来选择上传文件?如果是,为什么不使用 accept 属性呢?

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

1
这个!accept="image/*" 在大多数情况下绝对是最明智的选择。 - Alberto T.
很棒的提示!正是我需要的。 - oluwatyson
2
在浏览按钮上点击后,在弹出窗口中如果我们选择所有文件,它将显示所有文件,而不仅仅是图像。 - sangRam

10

检查文件是否已选中

       if (document.myform.elements["filefield"].value == "")
          {
             alert("You forgot to attach file!");
             document.myform.elements["filefield"].focus();
             return false;  
         }

检查文件扩展名

  var res_field = document.myform.elements["filefield"].value;   
  var extension = res_field.substr(res_field.lastIndexOf('.') + 1).toLowerCase();
  var allowedExtensions = ['doc', 'docx', 'txt', 'pdf', 'rtf'];
  if (res_field.length > 0)
     {
          if (allowedExtensions.indexOf(extension) === -1) 
             {
               alert('Invalid file Format. Only ' + allowedExtensions.join(', ') + ' are allowed.');
               return false;
             }
    }

8

我喜欢这个例子:

<asp:FileUpload ID="fpImages" runat="server" title="maximum file size 1 MB or less" onChange="return validateFileExtension(this)" />

<script language="javascript" type="text/javascript">
    function ValidateFileUpload(Source, args) {
        var fuData = document.getElementById('<%= fpImages.ClientID %>');
        var FileUploadPath = fuData.value;

        if (FileUploadPath == '') {
            // There is no file selected 
            args.IsValid = false;
        }
        else {
            var Extension = FileUploadPath.substring(FileUploadPath.lastIndexOf('.') + 1).toLowerCase();
            if (Extension == "gif" || Extension == "png" || Extension == "bmp" || Extension == "jpeg") {
                args.IsValid = true; // Valid file type
                FileUploadPath == '';
            }
            else {
                args.IsValid = false; // Not valid file type
            }
        }
    }
</script>

7
最好使用mimetype而不是检查扩展名来尝试。因为有时候文件可以在Linux或Unix系统上工作得很好,即使没有扩展名。
所以,您可以尝试像这样的内容:
["image/jpeg", "image/png", "image/gif"].indexOf(file.type) > -1

或者
["image/jpeg", "image/png", "image/gif"].includes(file.type)

6

如果你需要在输入框中测试远程url,可以尝试使用你感兴趣的类型进行简单的正则表达式匹配。

$input_field = $('.js-input-field-class');

if ( !(/\.(gif|jpg|jpeg|tiff|png)$/i).test( $input_field.val() )) {
  $('.error-message').text('This URL is not a valid image type. Please use a url with the known image types gif, jpg, jpeg, tiff or png.');
  return false;
}

这将捕获以 .gif、.jpg、.jpeg、.tiff 或 .png 结尾的所有内容。

需要注意的是,一些流行的网站(如 Twitter)会在其图像末尾添加一个大小属性。例如,下面的内容虽然是有效的图像类型,但仍将无法通过此测试:

https://pbs.twimg.com/media/BrTuXT5CUAAtkZM.jpg:large

由于这个原因,这不是一个完美的解决方案。但它会让你达到约90%的目标。

4

尝试这个(对我有效)

  
  function validate(){
  var file= form.file.value;
       var reg = /(.*?)\.(jpg|bmp|jpeg|png)$/;
       if(!file.match(reg))
       {
        alert("Invalid File");
        return false;
       }
       }
<form name="form">
<input type="file" name="file"/>
<input type="submit" onClick="return validate();"/>
</form>

     


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接