it-swarm.com.de

Verwenden von HTML5-Datei-Uploads mit AJAX und jQuery

Zugegeben, es gibt ähnliche Fragen zu Stack Overflow, aber es scheint, als würde keine meinen Anforderungen gerecht.

Folgendes versuche ich zu tun:

  • Laden Sie eine ganze Form von Daten hoch, von denen ein Teil eine einzelne Datei ist
  • Arbeiten Sie mit der Datei-Upload-Bibliothek von Codeigniter

Bis hierher ist alles in Ordnung. Die Daten werden in meiner Datenbank gespeichert, sobald ich sie benötige. Ich möchte mein Formular aber auch über einen AJAX Post einreichen:

  • Verwenden Sie die native HTML5-Datei-API, kein Flash oder eine Iframe-Lösung
  • Schnittstelle vorzugsweise mit der Methode .ajax() jQuery auf niedriger Ebene

Ich denke, ich könnte mir vorstellen, wie man das macht, indem man die Datei automatisch hochlädt, wenn sich der Wert des Feldes mit reinem Javascript ändert, aber ich mache es lieber auf einen Schlag, um sie in jQuery einzureichen. Ich denke, es ist nicht möglich, über Abfragezeichenfolgen zu tun, da ich das gesamte Dateiobjekt übergeben muss, aber ich bin ein wenig verloren, was zu diesem Zeitpunkt zu tun ist.

Kann das erreicht werden?

82
Joshua Cody

Es ist nicht zu schwer. Schauen Sie sich zunächst FileReader Interface an.

Also, wenn das Formular gesendet wird, fangen Sie den Einreichungsprozess und

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

Dann auf der Serverseite (d. H. 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);

Oder so ähnlich. Ich kann mich irren (und bitte korrigieren Sie mich), aber dies sollte die Datei als 1287916771myPicture.jpg In /uploads/ Auf Ihrem Server speichern und mit einer JSON-Variablen (to) antworten eine continueSubmission() - Funktion, die den Dateinamen auf dem Server enthält.

Check out fwrite() und jQuery.post() .

Auf der obigen Seite erfahren Sie, wie Sie readAsBinaryString() , readAsDataUrl() und readAsArrayBuffer() verwenden = für Ihre anderen Bedürfnisse (z. B. Bilder, Videos usw.).

91
clarkf

Mit jQuery (und ohne FormData-API) können Sie Folgendes verwenden:

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

Mit der FormData-API müssen Sie nur alle Felder Ihres Formulars zum FormData-Objekt hinzufügen und es über $ .ajax senden ({url: url, data: formData, processData: false, contentType: false, type: "POST"})

6
Gheljenor