AJAX और jQuery के साथ HTML5 फ़ाइल अपलोड का उपयोग करना


84

बेशक, स्टैक ओवरफ्लो पर चारों ओर समान प्रश्न हैं, लेकिन ऐसा लगता है कि कोई भी मेरी आवश्यकताओं को पूरा नहीं करता है।

यहाँ मैं क्या करने के लिए देख रहा हूँ:

  • डेटा का एक पूरा फ़ॉर्म अपलोड करें, जिसमें से एक टुकड़ा एक फ़ाइल है
  • Codeigniter की फ़ाइल अपलोड लाइब्रेरी के साथ काम करें

यहाँ तक, सब ठीक है। डेटा मेरे डेटाबेस में हो जाता है जैसे ही मुझे इसकी आवश्यकता होती है। लेकिन मैं एक AJAX पोस्ट के माध्यम से अपना फॉर्म जमा करना चाहूंगा:

  • देशी एचटीएमएल 5 फ़ाइल एपीआई का उपयोग करना, फ्लैश या आईफ्रेम समाधान नहीं
  • अधिमानतः निम्न-स्तरीय .ajax()jQuery विधि के साथ इंटरफेस करना

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

क्या इसे हासिल किया जा सकता है?


मुझे Codeigniter भाग के बारे में कोई पता नहीं है, लेकिन jQuery के भाग के लिए, इस प्लगइन के लिए एक नज़र है ।
बालुस

3
संबं
धत लं क

जवाबों:


93

यह बहुत कठिन नहीं है। सबसे पहले, FileReader Interface पर एक नज़र डालें

इसलिए, जब फॉर्म जमा किया जाता है, तो जमा करने की प्रक्रिया को पकड़ें और

var file = document.getElementById('fileBox').files[0]; //Files[0] = 1st file
var reader = new FileReader();
reader.readAsText(file, 'UTF-8');
reader.onload = shipOff;
//reader.onloadstart = ...
//reader.onprogress = ... <-- Allows you to update a progress bar.
//reader.onabort = ...
//reader.onerror = ...
//reader.onloadend = ...


function shipOff(event) {
    var result = event.target.result;
    var fileName = document.getElementById('fileBox').files[0].name; //Should be 'picture.jpg'
    $.post('/myscript.php', { data: result, name: fileName }, continueSubmission);
}

फिर, सर्वर साइड (यानी myscript.php) पर:

$data = $_POST['data'];
$fileName = $_POST['name'];
$serverFile = time().$fileName;
$fp = fopen('/uploads/'.$serverFile,'w'); //Prepends timestamp to prevent overwriting
fwrite($fp, $data);
fclose($fp);
$returnData = array( "serverFile" => $serverFile );
echo json_encode($returnData);

या कुछ ऐसा है। मैं गलत हो सकता है (और अगर मैं कर रहा हूँ, कृपया, मुझे सही कर), लेकिन कुछ इस तरह के रूप में फ़ाइल की दुकान चाहिए 1287916771myPicture.jpgमें /uploads/अपने सर्वर, और एक JSON चर (एक के साथ प्रतिक्रिया पर continueSubmission()समारोह) सर्वर पर fileName हैं।

बाहर की जाँच करें fwrite()और jQuery.post()

उपरोक्त पृष्ठ पर यह विवरण है कि कैसे उपयोग करना है readAsBinaryString(), readAsDataUrl()और readAsArrayBuffer()आपकी अन्य आवश्यकताओं के लिए (जैसे चित्र, वीडियो, आदि)।


हे क्लार्क, क्या मैं सही ढंग से समझ रहा हूं? यह अपलोड की गई फ़ाइल को फाइल सिस्टम से FileReader कंस्ट्रक्टर में लोड होते ही भेज देगा, jQuery के निम्न-स्तर .ajax हैंडलर को दरकिनार कर देगा। फिर बाकी फॉर्म सामान्य के रूप में जमा करेंगे?
जोशुआ कोडी

सब ठीक है, इसलिए मैं पहले अपनी समझ में गलत था। अब मैं एक इमेज के readAsDataUrl को ले रहा हूं, इसे अपने डेटास्टोर में .ajax में जोड़ रहा हूं, और सभी जानकारी एक साथ सबमिट कर रहा हूं। मेरे पिछले समाधान में CodeIgniter की डिफ़ॉल्ट फ़ाइल इनपुट क्लास शामिल थी जिसने $ _FILES ['फ़ील्ड'] से डेटा हड़प लिया था, इसलिए ऐसा लगता है कि मुझे base64 छवि डेटा को पार्स करने के लिए एक अलग समाधान पर स्विच करने की आवश्यकता होगी। उस पर किसी भी सलाह का स्वागत किया गया है, यहाँ आपके उत्तर को बढ़ाते हुए, और एक बार जब मैंने कार्यान्वयन समाप्त कर लिया, तो मैं इसे सही के रूप में चिह्नित करूँगा।
जोशुआ कोडी

1
@ जोशुआ कोडी - मैंने थोड़ा और विस्तार देने के लिए उत्तर को अपडेट किया। आपको यह माफ़ करना होगा कि मैंने कई मॉन्स में कोडइंटराइटर का उपयोग नहीं किया है और आपको यह नहीं बता सकता कि इसे अपने कोडबेस में कैसे एकीकृत किया जाए। मुझे यकीन नहीं है कि आपको फ़ाइल सबमिट करने से पहले अपलोड करने की आवश्यकता है, लेकिन यह आपको कम से कम एक सुराग देना चाहिए। (आप छवि को डेटाबेस में सम्मिलित कर सकते हैं यदि यह आपके लिए बेहतर है)।
क्लार्क

@ क्लार्क, मुझे सबमिट करने से पहले अपलोड करने की आवश्यकता नहीं है, मैं आपके पिछले उदाहरण को गलत समझ रहा था :) एसओ के नीचे जाने के बाद और मैंने w3 और HTML5Rocks पर कुछ समय बिताया , मुझे समझ में आने लगा। मैं इसे एक शॉट दूंगा और यहां वापस आऊंगा।
जोशुआ कोडी

सब ठीक है, यह सब सुबह के साथ खिलवाड़ कर रहा है। PHP बुरी तरह से स्वरूपित फ़ाइलों को लौटाने लगती है। दो चित्र देखें , एक तुरंत प्रदान किया गया और दूसरा $ _POST के बाद सर्वर और तत्काल प्रतिध्वनि के लिए। दो तत्वों पर एक अंतर यह प्रकट करता है , कि जाहिरा तौर पर PHP सभी "+" वर्णों को अलग कर रहा है। एक str_replace तत्काल वापसी के लिए इसे ठीक करता है, लेकिन जो फ़ाइल सहेजी गई है वह अभी भी भ्रष्ट है और मेरी फाइल सिस्टम के माध्यम से नहीं खोला जा सकता है। इसके अलावा, आगे जा रहे हैं और इसे सही के रूप में चिह्नित कर रहे हैं। अब तक आपकी मदद के लिए बहुत बहुत धन्यवाद।
जोशुआ कोडी

6

JQuery के साथ (और FormData API के बिना) आप कुछ इस तरह का उपयोग कर सकते हैं:

function readFile(file){
   var loader = new FileReader();
   var def = $.Deferred(), promise = def.promise();

   //--- provide classic deferred interface
   loader.onload = function (e) { def.resolve(e.target.result); };
   loader.onprogress = loader.onloadstart = function (e) { def.notify(e); };
   loader.onerror = loader.onabort = function (e) { def.reject(e); };
   promise.abort = function () { return loader.abort.apply(loader, arguments); };

   loader.readAsBinaryString(file);

   return promise;
}

function upload(url, data){
    var def = $.Deferred(), promise = def.promise();
    var mul = buildMultipart(data);
    var req = $.ajax({
        url: url,
        data: mul.data,
        processData: false,
        type: "post",
        async: true,
        contentType: "multipart/form-data; boundary="+mul.bound,
        xhr: function() {
            var xhr = jQuery.ajaxSettings.xhr();
            if (xhr.upload) {

                xhr.upload.addEventListener('progress', function(event) {
                    var percent = 0;
                    var position = event.loaded || event.position; /*event.position is deprecated*/
                    var total = event.total;
                    if (event.lengthComputable) {
                        percent = Math.ceil(position / total * 100);
                        def.notify(percent);
                    }                    
                }, false);
            }
            return xhr;
        }
    });
    req.done(function(){ def.resolve.apply(def, arguments); })
       .fail(function(){ def.reject.apply(def, arguments); });

    promise.abort = function(){ return req.abort.apply(req, arguments); }

    return promise;
}

var buildMultipart = function(data){
    var key, crunks = [], bound = false;
    while (!bound) {
        bound = $.md5 ? $.md5(new Date().valueOf()) : (new Date().valueOf());
        for (key in data) if (~data[key].indexOf(bound)) { bound = false; continue; }
    }

    for (var key = 0, l = data.length; key < l; key++){
        if (typeof(data[key].value) !== "string") {
            crunks.push("--"+bound+"\r\n"+
                "Content-Disposition: form-data; name=\""+data[key].name+"\"; filename=\""+data[key].value[1]+"\"\r\n"+
                "Content-Type: application/octet-stream\r\n"+
                "Content-Transfer-Encoding: binary\r\n\r\n"+
                data[key].value[0]);
        }else{
            crunks.push("--"+bound+"\r\n"+
                "Content-Disposition: form-data; name=\""+data[key].name+"\"\r\n\r\n"+
                data[key].value);
        }
    }

    return {
        bound: bound,
        data: crunks.join("\r\n")+"\r\n--"+bound+"--"
    };
};

//----------
//---------- On submit form:
var form = $("form");
var $file = form.find("#file");
readFile($file[0].files[0]).done(function(fileData){
   var formData = form.find(":input:not('#file')").serializeArray();
   formData.file = [fileData, $file[0].files[0].name];
   upload(form.attr("action"), formData).done(function(){ alert("successfully uploaded!"); });
});

FormData API के साथ आपको बस अपने फॉर्म के सभी क्षेत्रों को FormData ऑब्जेक्ट में जोड़ना होगा और इसे $ .ajax ({url: url, data: formData, processData: false, contentType: false, type: POST "}) के माध्यम से भेजना होगा।


1
यह समाधान उस सीमा को संबोधित नहीं करता है जो XMLHttpRequest.send () इसके माध्यम से फ़नल किए गए डेटा पर लगाता है। जब एक स्ट्रिंग (जैसे आपका मल्टीपार्ट) पास किया गया, तो बाइनरी डेटा का समर्थन नहीं करता। यहां आपके मल्टीपार्ट को utf-8 स्ट्रिंग के रूप में माना जाएगा, और यह द्विआधारी डेटा को दूषित या चोक कर देगा जो मान्य utf-8 नहीं है। यदि आपको वास्तव में फ़ॉर्मडैट से बचने की आवश्यकता है, तो आपको XMLHttpRequest.sendAsBinary () उपलब्ध पॉलीफ़िल का उपयोग करने की आवश्यकता है । दुर्भाग्य से इसका मतलब है कि ajax कॉल के लिए jQuery का उपयोग करना अधिक कठिन हो जाता है।
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.