js获取上传文件类型的三种方式及伪文件类型辨别

js获取上传文件类型的三种方式及伪文件类型辨别

文件类型很多,我们常用的方式是通过后缀来辨识文件类型,那么如果文件真实类型与后缀不一致呢,我们怎么才能判别真实的文件类型,识别哪些伪造的文件。我们一个个来说:

一、通过后缀

先获取上传文件的文件名,然后根据文件名截取文件后缀,代码如下:

<!DOCTYPE html>
<html>

<head>

</head>

<body>
    <input type="file" id="fileInput">
    <div id="output"></div>
    <script type="text/javascript">

        
        fileInput.onchange = function() {
            var filename=fileInput.files[0].name;
            
             var suffixname =filename.substr(filename.lastIndexOf(".")).toLowerCase();
              output.innerHTML = suffixname;
            
        };
    </script>
</body>

</html>

二、通过file.type

通过file对象的type属性既可以获取上传文件的类型,类似于image/png这种格式的,代码如下:

<!DOCTYPE html>
<html>

<head>

</head>

<body>
    <input type="file" id="fileInput">
    <div id="output"></div>
    <script type="text/javascript">

        
        fileInput.onchange = function() {
            var filetype=fileInput.files[0].type;
              output.innerHTML = filetype;
          
            
            
        };
    </script>
</body>

</html>

以上两种办法获取上传文件的类型存在一个问题,如果我把别的类型的后缀更换了,那么以上两种办法获取的文件类型无法获取真实的文件类型,例如我把example.doc文件改成了example.png,那么上传后,上面两种方法获取文件类型分别是.png和image/png,但是其实这个文件是doc文档类型的,那么js如何获取文件的真实类型呢,下面我们说第三种,通过二进制读取文件头部字节的方式。

三、通过二进制获取mine type

我们可以通过读取文件的头4个字节结合pattern与mask进行文件签名匹配就可以获取到该文件的真实类型,代码如下:

<!DOCTYPE html>
<html>

<head>

</head>

<body>
    <input type="file" id="fileInput">
    <div id="output"></div>
    <script type="text/javascript">

function loadMime(file, callback) {
   
    //已知文件mine类型标识
    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],
        }
        // 更多扩展的mine标识请看这个 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); //读取文件的头部4个字节

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



fileInput.onchange = function() {
    loadMime(fileInput.files[0], function(mime) {

        output.innerHTML = mime;
    });
};
    </script>
</body>

</html>

每个类型的文件签名都不一样,如图:

js获取上传文件类型的三种方式及伪文件类型辨别

更多文件签名头部pattern与mask请查找这篇文章:https://mimesniff.spec.whatwg.org/#matching-an-image-type-pattern

还有一种也是直接通过读取文件签名来匹配的,他还能通过url读取远程图片的真实类型,代码如下:

<!DOCTYPE html>
<html>

<head>
    <style>
        img {
  max-height: 200px
}
div {
  height: 26px;
  font: Arial;
  font-size: 12pt
}
form {
  height: 40px;
}
    </style>
    <script type="text/javascript" src="//repo.bfw.wiki/bfwrepo/js/jquery-3.2.1.min.js"></script>
</head>

<body>

    <form>
        <input type="file" />
        <div>Choose an image to see its file signature.</div>
    </form>
    <hr/>
    <script type="text/javascript">
        // 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', "/asset/logo.png");
  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 = [""];

// 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 */
    </script>
</body>

</html>




{{collectdata}}

网友评论0