javascript - अपलोड करने से पहले जावास्क्रिप्ट के साथ फ़ाइल एमआईएमई प्रकार कैसे जांचें?




html5 file-upload (5)

अगर आप सिर्फ यह जांचना चाहते हैं कि अपलोड की गई फ़ाइल एक छवि है तो आप इसे किसी भी त्रुटि कॉलबैक के लिए <img> टैग को लोड करने का प्रयास कर सकते हैं।

उदाहरण:

var input = document.getElementsByTagName('input')[0];
var reader = new FileReader();

reader.onload = function (e) {
    imageExists(e.target.result, function(exists){
        if (exists) {

            // Do something with the image file.. 

        } else {

            // different file format

        }
    });
};

reader.readAsDataURL(input.files[0]);


function imageExists(url, callback) {
    var img = new Image();
    img.onload = function() { callback(true); };
    img.onerror = function() { callback(false); };
    img.src = url;
}

मैंने this और this प्रश्न पढ़ा है जो यह सुझाव देता है कि फ़ाइल माइम प्रकार को क्लाइंट साइड पर जावास्क्रिप्ट का उपयोग करके चेक किया जा सकता है। अब, मैं समझता हूं कि वास्तविक सत्यापन अभी भी सर्वर पक्ष पर किया जाना है। मैं सर्वर संसाधन की अनावश्यक बर्बादी से बचने के लिए क्लाइंट साइड जांच करना चाहता हूं।

यह जांचने के लिए कि क्या यह क्लाइंट साइड पर किया जा सकता है, मैंने एक JPEG परीक्षण फ़ाइल का विस्तार .png बदल दिया है और अपलोड के लिए फ़ाइल का चयन किया है। फ़ाइल भेजने से पहले, मैं जावास्क्रिप्ट कंसोल का उपयोग कर फ़ाइल ऑब्जेक्ट से पूछता हूं:

document.getElementsByTagName('input')[0].files[0];

क्रोम 28.0 पर मुझे यही मिलता है:

फ़ाइल {webkitRelativePath: "", lastModifiedDate: अक्टूबर 16 2012 10:00:00 GMT + 0000 (यूटीसी), नाम: "test.png", टाइप करें: "image / png", आकार: 500055 ...}

यह image/png को image/png दिखाता है जो इंगित करता है कि जांच एमआईएमई प्रकार के बजाय फ़ाइल एक्सटेंशन के आधार पर की जाती है। मैंने फ़ायरफ़ॉक्स 22.0 की कोशिश की और यह मुझे एक ही परिणाम देता है। लेकिन डब्ल्यू 3 सी स्पेक के अनुसार, एमआईएमई स्नीफिंग लागू किया जाना चाहिए।

क्या मुझे यह कहने का अधिकार है कि इस समय जावास्क्रिप्ट के साथ एमआईएमई प्रकार की जांच करने का कोई तरीका नहीं है? या क्या मैं कुछ न कुछ भूल रहा हूं?


आप किसी सर्वर पर अपलोड करने से पहले जावास्क्रिप्ट के FileReader साथ फ़ाइल MIME प्रकार आसानी से निर्धारित कर सकते हैं। मैं मानता हूं कि हमें क्लाइंट-साइड पर सर्वर-साइड जांच करना पसंद करना चाहिए, लेकिन क्लाइंट-साइड जांच अभी भी संभव है। मैं आपको दिखाऊंगा कि नीचे कैसे काम कर रहे डेमो प्रदान करते हैं।

जांचें कि आपका ब्राउज़र File और Blob दोनों का समर्थन करता है। सभी प्रमुखों को चाहिए।

if (window.FileReader && window.Blob) {
    // All the File APIs are supported.
} else {
    // File and Blob are not supported
}

चरण 1:

आप File <input> तत्व से इस तरह से पुनर्प्राप्त कर सकते हैं ( ref ):

<input type="file" id="your-files" multiple>
<script>
var control = document.getElementById("your-files");
control.addEventListener("change", function(event) {
    // When the control has changed, there are new files
    var files = control.files,
    for (var i = 0; i < files.length; i++) {
        console.log("Filename: " + files[i].name);
        console.log("Type: " + files[i].type);
        console.log("Size: " + files[i].size + " bytes");
    }
}, false);
</script>

उपर्युक्त ( ref ) का ड्रैग-एंड-ड्रॉप संस्करण यहां दिया गया है:

<div id="your-files"></div>
<script>
var target = document.getElementById("your-files");
target.addEventListener("dragover", function(event) {
    event.preventDefault();
}, false);

target.addEventListener("drop", function(event) {
    // Cancel default actions
    event.preventDefault();
    var files = event.dataTransfer.files,
    for (var i = 0; i < files.length; i++) {
        console.log("Filename: " + files[i].name);
        console.log("Type: " + files[i].type);
        console.log("Size: " + files[i].size + " bytes");
    }
}, false);
</script>

चरण 2:

अब हम फाइलों का निरीक्षण कर सकते हैं और हेडर और एमआईएमई प्रकारों को छेड़छाड़ कर सकते हैं।

✘ त्वरित विधि

आप इस पैटर्न का उपयोग करके प्रस्तुत की जाने वाली किसी भी फ़ाइल के एमआईएम प्रकार के लिए Blob पूछ सकते हैं:

var blob = files[i]; // See step 1 above
console.log(blob.type);

छवियों के लिए, एमआईएम प्रकार निम्न की तरह वापस आते हैं:

image / jpeg
छवि / png
...

चेतावनी: फ़ाइल एक्सटेंशन से एमआईएमई प्रकार का पता लगाया गया है और इसे मूर्ख या स्पूफ किया जा सकता है। कोई .jpg को .jpg का नाम बदल सकता है और MIME प्रकार को image/png रूप में रिपोर्ट किया जाएगा।

✓ उचित हेडर-निरीक्षण विधि

क्लाइंट-साइड फ़ाइल के बोनफाइड एमआईएम प्रकार को प्राप्त करने के लिए हम एक कदम आगे जा सकते हैं और दिए गए फ़ाइल के पहले कुछ बाइट्स को तथाकथित जादू संख्याओं के साथ तुलना करने के लिए देख सकते हैं। चेतावनी दीजिये कि यह पूरी तरह से सीधा नहीं है क्योंकि, उदाहरण के लिए, JPEG में कुछ "जादू संख्याएं" हैं। ऐसा इसलिए है क्योंकि प्रारूप 1 99 1 से विकसित हुआ है। आप केवल पहले दो बाइट्स को जांचने से दूर हो सकते हैं, लेकिन मैं झूठी सकारात्मक को कम करने के लिए कम से कम 4 बाइट्स जांचना पसंद करता हूं।

जेपीईजी (पहले 4 बाइट्स) के उदाहरण फ़ाइल हस्ताक्षर:

एफएफ डी 8 एफएफ ई 0 (एसओआई + एडीडी 0)
एफएफ डी 8 एफएफ ई 1 (एसओआई + एडीडी 1)
एफएफ डी 8 एफएफ ई 2 (एसओआई + एडीडी 2)

फ़ाइल हेडर पुनर्प्राप्त करने के लिए आवश्यक कोड यहां दिया गया है:

var blob = files[i]; // See step 1 above
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);
  }
  console.log(header);

  // Check the file signature against known types

};
fileReader.readAsArrayBuffer(blob);

इसके बाद आप वास्तविक एमआईएम प्रकार को इस प्रकार निर्धारित कर सकते हैं ( here और अधिक फ़ाइल हस्ताक्षर here और here ):

switch (header) {
    case "89504e47":
        type = "image/png";
        break;
    case "47494638":
        type = "image/gif";
        break;
    case "ffd8ffe0":
    case "ffd8ffe1":
    case "ffd8ffe2":
    case "ffd8ffe3":
    case "ffd8ffe8":
        type = "image/jpeg";
        break;
    default:
        type = "unknown"; // Or you can use the blob.type as fallback
        break;
}

फ़ाइल अपलोड को स्वीकार या अस्वीकार करें जैसा कि आप अपेक्षित एमआईएम प्रकारों के आधार पर पसंद करते हैं।

डेमो

यहां स्थानीय फाइलों और रिमोट फाइलों के लिए एक कामकाजी डेमो है (मुझे सिर्फ इस डेमो के लिए सीओआरएस को बाईपास करना पड़ा)। स्निपेट खोलें, इसे चलाएं, और आपको प्रदर्शित विभिन्न प्रकार की तीन दूरस्थ छवियां देखना चाहिए। शीर्ष पर आप एक स्थानीय छवि या डेटा फ़ाइल का चयन कर सकते हैं, और फ़ाइल हस्ताक्षर और / या एमआईएम प्रकार प्रदर्शित किया जाएगा।

ध्यान दें कि भले ही किसी छवि का नाम बदला गया हो, फिर भी इसका सही एमआईएम प्रकार निर्धारित किया जा सकता है। निचे देखो।

स्क्रीनशॉट

// 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', '//cors-anywhere.herokuapp.com/' + url);
  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 = ["http://media2.giphy.com/media/8KrhxtEsrdhD2/giphy.gif", "http://upload.wikimedia.org/wikipedia/commons/e/e9/Felis_silvestris_silvestris_small_gradual_decrease_of_quality.png", "http://static.giantbomb.com/uploads/scale_small/0/316/520157-apple_logo_dec07.jpg"];

// 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 */
img {
  max-height: 200px
}
div {
  height: 26px;
  font: Arial;
  font-size: 12pt
}
form {
  height: 40px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<form>
  <input type="file" />
  <div>Choose an image to see its file signature.</div>
</form>
<hr/>


जैसा कि ड्रेक कहता है कि यह फाइल रीडर के साथ किया जा सकता है। हालांकि, जो मैं यहां प्रस्तुत करता हूं वह एक कार्यात्मक संस्करण है। ध्यान रखें कि जावास्क्रिप्ट के साथ ऐसा करने में बड़ी समस्या इनपुट फ़ाइल को रीसेट करना है। खैर, यह केवल जेपीजी तक सीमित है (अन्य प्रारूपों के लिए आपको माइम प्रकार और जादू संख्या बदलनी होगी):

<form id="form-id">
  <input type="file" id="input-id" accept="image/jpeg"/>
</form>

<script type="text/javascript">
    $(function(){
        $("#input-id").on('change', function(event) {
            var file = event.target.files[0];
            if(file.size>=2*1024*1024) {
                alert("JPG images of maximum 2MB");
                $("#form-id").get(0).reset(); //the tricky part is to "empty" the input file here I reset the form.
                return;
            }

            if(!file.type.match('image/jp.*')) {
                alert("only JPG images");
                $("#form-id").get(0).reset(); //the tricky part is to "empty" the input file here I reset the form.
                return;
            }

            var fileReader = new FileReader();
            fileReader.onload = function(e) {
                var int32View = new Uint8Array(e.target.result);
                //verify the magic number
                // for JPG is 0xFF 0xD8 0xFF 0xE0 (see https://en.wikipedia.org/wiki/List_of_file_signatures)
                if(int32View.length>4 && int32View[0]==0xFF && int32View[1]==0xD8 && int32View[2]==0xFF && int32View[3]==0xE0) {
                    alert("ok!");
                } else {
                    alert("only valid JPG images");
                    $("#form-id").get(0).reset(); //the tricky part is to "empty" the input file here I reset the form.
                    return;
                }
            };
            fileReader.readAsArrayBuffer(file);
        });
    });
</script>

ध्यान रखें कि यह फ़ायरफ़ॉक्स और क्रोम के नवीनतम संस्करणों और आईईक्सप्लोर 10 पर परीक्षण किया गया था।

माइम प्रकारों की पूरी सूची के लिए विकिपीडिया देखें

जादू संख्या की पूरी सूची के लिए विकिपीडिया देखें


यहां रॉबर्टो 14 के उत्तर का विस्तार है जो निम्न कार्य करता है:

यह केवल छवियों को अनुमति देगा

चेक करता है कि क्या FileReader उपलब्ध है और यदि यह उपलब्ध नहीं है तो एक्सटेंशन जांच पर वापस आ जाता है।

अगर कोई छवि नहीं है तो त्रुटि चेतावनी देता है

अगर यह एक छवि है तो यह एक पूर्वावलोकन लोड करता है

** आपको अभी भी सर्वर साइड सत्यापन करना चाहिए, यह किसी अन्य चीज़ की तुलना में अंतिम उपयोगकर्ता की सुविधा है। लेकिन यह आसान है!

<form id="myform">
    <input type="file" id="myimage" onchange="readURL(this)" />
    <img id="preview" src="#" alt="Image Preview" />
</form>

<script>
function readURL(input) {
    if (window.FileReader && window.Blob) {
        if (input.files && input.files[0]) {
            var reader = new FileReader();
            reader.onload = function (e) {
                var img = new Image();
                img.onload = function() {
                    var preview = document.getElementById('preview');
                    preview.src = e.target.result;
                    };
                img.onerror = function() { 
                    alert('error');
                    input.value = '';
                    };
                img.src = e.target.result;
                }
            reader.readAsDataURL(input.files[0]);
            }
        }
    else {
        var ext = input.value.split('.');
        ext = ext[ext.length-1].toLowerCase();      
        var arrayExtensions = ['jpg' , 'jpeg', 'png', 'bmp', 'gif'];
        if (arrayExtensions.lastIndexOf(ext) == -1) {
            alert('error');
            input.value = '';
            }
        else {
            var preview = document.getElementById('preview');
            preview.setAttribute('alt', 'Browser does not support preview.');
            }
        }
    }
</script>

संक्षिप्त उत्तर नहीं है।

जैसा कि आप नोट करते हैं कि ब्राउजर फ़ाइल एक्सटेंशन से type प्राप्त करते हैं। मैक पूर्वावलोकन भी एक्सटेंशन को चलाने के लिए प्रतीत होता है। मैं इसे मान रहा हूं क्योंकि यह डिस्क पर फ़ाइल को देखने और पढ़ने के बजाय पॉइंटर में फ़ाइल नाम को तेज़ी से पढ़ रहा है।

मैंने पीएनजी के साथ नामित एक जेपीजी की प्रति बना दी।

मैं लगातार क्रोम में दोनों छवियों से निम्नलिखित प्राप्त करने में सक्षम था (आधुनिक ब्राउज़रों में काम करना चाहिए)।

ÿØÿàJFIFÿþ;CREATOR: gd-jpeg v1.0 (using IJG JPEG v62), quality = 90

जो आप String.indexOf ('jpeg') को छवि प्रकार के लिए चेक आउट कर सकते हैं।

Http://jsfiddle.net/bamboo/jkZ2v/1/ का पता लगाने के लिए यहां एक http://jsfiddle.net/bamboo/jkZ2v/1/

उदाहरण में टिप्पणी करने के लिए मैं भूल गया महत्वाकांक्षी रेखा

console.log( /^(.*)$/m.exec(window.atob( image.src.split(',')[1] )) );

  • छवि पर छोड़कर, बेस 64 एन्कोडेड आईएमजी डेटा विभाजित करता है
  • बेस 64 छवि को डीकोड करता है
  • छवि डेटा की केवल पहली पंक्ति से मेल खाता है

बेवकूफ कोड बेस 64 डीकोड का उपयोग करता है जो आईई 9 में काम नहीं करेगा, मुझे आईबी में काम करता है जो वीबी स्क्रिप्ट का उपयोग करके एक अच्छा उदाहरण मिला है http://blog.nihilogic.dk/2008/08/imageinfo-reading-image-metadata-with.html

छवि लोड करने के लिए कोड जोएल वर्डी से लिया गया था, जो कुछ शानदार छवि कैनवास क्लाइंट पक्ष को आकार देने से पहले कर रहा है जो अपलोड करने से पहले https://joelvardy.com/writing/javascript-image-upload






mime-types