Html File Input on Chrome for Android missing extension and mime type

2.8k views Asked by At

In html/js, when you select a file on Chrome (43) for Android (5.1.1), the resulting files name is missing the extension and the file type is an empty string. Wondering if there is way to get the missing information? And if not, is there a reasonable way to do clientside side validation on file types?

Please see the example fiddle below and note that I get extension and mime type on windows desktop browsers and ios safari.

http://jsfiddle.net/Lfg3xhy4/

$(function(){
    $("#fileInput").on("change", function(e){
        $("#name").html(e.target.files[0].name);
        $("#type").html(e.target.files[0].type);
    });
});

Update I noticed when using the android Documents browser, the Audio tab (which I was using to select files) does not seem to supply file extension and mime type. If I navigate to files using any other tab, everything seems ok.

2

There are 2 answers

0
Kenneth Ito On BEST ANSWER

Via the android Documents file browser, some of the tabs do not provide file extension and type. The Audio tab (which displays audio metadata) and some of the connected storage accounts for example.

As such, another way to do file type validation is to use "file signatures" http://www.filesignatures.net/index.php?page=all

Essentially you take a look at a portion of the binary file. Simplified example below.

var audioFile;  //Set from elsewhere
if (FileReader) {
    var reader = new FileReader();
    reader.addEventListener("load", function(e) {
        var mp3FileSignature = [255, 251, 48];
        var id3FileSignature = [73, 68, 51];
        //There are actually quite a few more scenarios to handle for mp3's in particular
        //Most file types are simpler

        var arrayBuffer = e.target.result;

        if (arrayBuffer && arrayBuffer.byteLength >= 3) {
            var slice = arrayBuffer.slice(0, 3);
            var view = new Uint8Array(slice);
            if ((mp3FileSignature[0] != view[0] || mp3FileSignature[1] != view[1] || mp3FileSignature[2] != view[2])  
                && (id3FileSignature[0] != view[0] || id3FileSignature[1] != view[1] || id3FileSignature[2] != view[2])) {

                //Not an mp3
            }
        }

    })
    reader.readAsArrayBuffer(audioFile);
}
4
ѺȐeallү On

Here is some code that does similar to yours except you can select multiple files. #name == f.name and #type == f.type. I tested mine on android and its working on...

Android 4.1.2 | Chrome 42.0.2311.111 | JS V8 4.2.77.15

HTML

<input type="file" id="files" name="files[]" multiple />
    <output id="list"></output>

JS

<script>
  function handleFileSelect(evt) {
    var files = evt.target.files; // FileList object

    // files is a FileList of File objects. List some properties.
    var output = [];
    for (var i = 0, f; f = files[i]; i++) {
      output.push('<li><strong>', escape(f.name), '</strong> (', f.type || 'n/a', ') - ',
                  f.size, ' bytes, last modified: ',
                  f.lastModifiedDate ? f.lastModifiedDate.toLocaleDateString() : 'n/a',
                  '</li>');
    }
    document.getElementById('list').innerHTML = '<ul>' + output.join('') + '</ul>';
  }

  document.getElementById('files').addEventListener('change', handleFileSelect, false);
</script>

Result

  • List item Untitled%20Diagram.xml (text/xml) - 1224 bytes, last modified: 2/24/2015