AJAX ve jQuery ile HTML5 dosya yüklemelerini kullanma


84

Kuşkusuz, Stack Overflow'da benzer sorular var, ancak hiçbiri gereksinimleri tam olarak karşılamıyor gibi görünüyor.

İşte yapmak istediğim şey:

  • Bir parçası tek bir dosya olan eksiksiz bir veri biçimi yükleyin
  • Codeigniter'in dosya yükleme kitaplığıyla çalışın

Buraya kadar her şey yolunda. Veriler, ihtiyaç duyduğum anda veritabanıma giriyor. Ancak formumu bir AJAX gönderisiyle de göndermek istiyorum:

  • Flash veya iframe çözümü değil, yerel HTML5 Dosya API'sini kullanma
  • Tercihen düşük seviyeli .ajax()jQuery yöntemiyle arayüz oluşturma

Alanın değeri saf javascript kullanarak değiştiğinde dosyayı otomatik olarak yükleyerek bunu nasıl yapacağımı hayal edebildiğimi düşünüyorum, ancak jQuery'ye göndermek için hepsini bir arada yapmayı tercih ederim. Tüm dosya nesnesini iletmem gerektiğinden sorgu dizeleri aracılığıyla yapmanın mümkün olmadığını düşünüyorum, ancak bu noktada ne yapacağım konusunda biraz kayboldum.

Bu başarılabilir mi?


Codeigniter kısmı hakkında hiçbir fikrim yok, ancak jQuery kısmı için bu eklentiye bir göz atın .
BalusC

Yanıtlar:


93

Çok zor değil. Öncelikle FileReader Arayüzüne bir göz atın .

Bu nedenle, form gönderildiğinde, gönderim sürecini yakalayın ve

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

Ardından, sunucu tarafında (yani 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);

Veya onun gibi bir şey. Yanılıyor (ve eğer ben, düzelt lütfen), ama böyle bir şey olarak dosya saklamak gerekir olabilir 1287916771myPicture.jpgde /uploads/(bir bir JSON değişkeni ile sunucu ve yanıt verdiğini continueSubmission()sunucuda fileName içeren fonksiyonu).

Kontrol edin fwrite()ve jQuery.post().

Yukarıdaki sayfada o nasıl kullanılacağını ayrıntıları readAsBinaryString(), readAsDataUrl()ve readAsArrayBuffer()(örneğin resimler, videolar, vb) diğer ihtiyaçları için.


Hey Clark, doğru anlıyor muyum? Bu, yüklenen dosyayı jQuery'nin düşük düzey .ajax işleyicisini atlayarak, dosya sisteminden FileReader yapıcısına yüklenir yüklenmez gönderir. Sonra formun geri kalanı normal olarak gönderilecek?
Joshua Cody

Pekala, daha önce anlayışımda yanılmışım. Şimdi bir görüntünün readAsDataUrl'sini alıyorum, onu .ajax'daki datastringime ekliyorum ve tüm bilgilerimi birlikte gönderiyorum. Önceki çözümüm, CodeIgniter'ın $ _FILES ['field'] 'dan veri alan varsayılan dosya girdi sınıfını içeriyordu, bu yüzden base64 görüntü verilerini ayrıştırmak için farklı bir çözüme geçmem gerekecek gibi görünüyor. Bu konudaki herhangi bir tavsiye memnuniyetle karşılanır, cevabınız burada olumlu oylanır ve uygulamayı bitirdiğimde doğru olarak işaretleyeceğim.
Joshua Cody

1
@Joshua Cody - Biraz daha detay vermek için cevabı güncelledim. Birçok aydır CodeIgniter'ı kullanmadığımı ve bunu kod tabanlarına nasıl entegre edeceğinizi size söyleyemeyeceğimi affetmelisiniz. Dosyayı göndermeden önce neden yüklemeniz gerektiğinden emin değilim, ancak bu en azından size bir ipucu vermelidir. (Sizin için daha iyiyse, resmi bir veritabanına da ekleyebilirsiniz).
clarkf

@Clarkf, göndermeden önce yüklememe gerek yok, önceki örneğinizi yanlış anladım :) SO aşağı inip w3 ve HTML5Rocks üzerinde biraz zaman geçirdikten sonra anlamaya başladım. Buna bir şans vereceğim ve buraya döneceğim.
Joshua Cody

Pekala, bütün sabah bununla uğraştım. PHP kötü biçimlendirilmiş dosyalar döndürüyor gibi görünüyor. Biri hemen, diğeri $ _POST'tan sonra sunucuya ve anında yankıya dönüştürülen iki görüntüyü görün . İki öğedeki fark bunu ortaya çıkarır , görünüşe göre PHP tüm "+" karakterleri çıkarır . Bir str_replace bunu anında geri dönüş için düzeltir, ancak kaydedilen dosya hala bozuk ve dosya sistemim aracılığıyla açılamaz. Ayrıca, devam edin ve bunu doğru olarak işaretleyin. Şimdiye kadarki yardımlarınız için çok teşekkürler.
Joshua Cody

6

JQuery ile (ve FormData API'siz) şunun gibi bir şey kullanabilirsiniz:

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 ile formunuzun tüm alanlarını FormData nesnesine eklemeniz ve $ .ajax yoluyla göndermeniz yeterlidir ({url: url, data: formData, processData: false, contentType: false, type: "POST"})


1
Bu çözüm, XMLHttpRequest.send () 'in içinden geçirilen verilere uyguladığı sınırlamayı ele almaz. Bir dize iletildiğinde (çok parçalı gibi) send () ikili verileri desteklemez. Buradaki çok parçanız bir utf-8 dizesi olarak ele alınacak ve utf-8 olmayan ikili verileri boğacak veya bozacaktır. Gerçekten FormData kaçınmak gerekiyorsa, XMLHttpRequest.sendAsBinary () (kullanmaya gerek polyfill mevcut Ne yazık ki bu araçlar ajax çağrısı için jQuery kullanarak çok daha zor olur..
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.