2010-10-23 21 views
77

Kuşkusuz, Yığın Taşması üzerinde etrafta benzer sorular var, ancak hiçbiri benim gereksinimlerimi karşılamıyor. İşte HTML5 dosya yüklemelerini AJAX ve jQuery ile kullanma

Yapmak arıyorum budur:

  • Yükle CodeIgniter'ın dosya yükleme kütüphanesi ile bir tek dosya
  • Eserim tek parça olan verilerin bütün bir formu

Buraya kadar her şey yolunda. Veri veritabanına ihtiyacım var gibi geliyor. Ama aynı zamanda bir AJAX posta yoluyla benim formu göndermek istiyorum:

  • yerel HTML5 Dosya API kullanarak, flaş veya
  • Tercihen düşük seviyeli .ajax() jQuery yöntemi ile arabirim bir iframe çözüm değildir

Sanırım, alanın değeri salt javascript kullanarak değiştiğinde dosyayı otomatik olarak yükleyerek bunu nasıl yapabileceğimi hayal edebiliyorum, ama jQuery'ye göndermek için hepsini bir yere düşürmeyi tercih ediyorum. Sanırım tüm dosya nesnesini geçmem gerekiyormuş gibi sorgu dizeleri ile yapmak mümkün değil, ama bu noktada ne yapacağımı biraz kaybettim.

bu gerçekleşebilir mi?

+0

Codeigniter bölümü hakkında hiçbir fikrim yok, jQuery kısmı için [bu eklenti] için bir göz atın. (http://code.google.com/p/jquery-html5-upload/). – BalusC

+3

ilgili: http://stackoverflow.com/questions/166221/how-can-i-upload-files-asynchronously-with-jquery –

cevap

85

Çok zor değil. İlk olarak, FileReader Interface'a bir göz atın. bunun gibi

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

Ya bir şey:

Yani, form gönderildiğinde, sunucu tarafında (yani myscript.php) üzerine, sonra gönderim işlemlerini 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); 
} 

yakalamak. Hatalı olabilirim (ve eğer lütfen, lütfen, beni düzeltin), ancak bu dosyayı /uploads/ sunucunuzda 1287916771myPicture.jpg gibi bir sunucuda depolamalı ve sunucudaki fileName değerini içeren bir JSON değişkeni ile (bir continueSubmission() işlevine) yanıt vermelidir. .

fwrite() ve jQuery.post()'a bakın.

Yukarıdaki sayfada, diğer gereksinimleriniz (ör. Resimler, videolar, vb.) Için readAsBinaryString(), readAsDataUrl() ve readAsArrayBuffer()'un nasıl kullanıldığı açıklanmaktadır.

jQuery (ve FormData API olmadan) böyle bir şey kullanabilirsiniz ile
+0

Hey Clark, doğru anlıyor muyum?Bu, yüklenen dosyayı dosya sisteminden FileReader yapıcısına yüklendikten sonra jQuery'nin düşük düzeyli .ajax işleyicisini atlayarak gönderir. Sonra formun geri kalanı normal olarak mı sunulacak? –

+0

Pekala, bu yüzden benim anlayışımda daha önce yanıldım. Şimdi bir görüntünün readAsDataUrl'sini alıyorum .Maxax'daki datastring'e ekliyorum ve tüm bilgilerimi birlikte gönderiyorum. Önceki çözümüm, CodeIgniter'ın $ _FILES ['alan'] 'dan veri alan varsayılan dosya giriş sınıfını içeriyordu, bu yüzden base64 görüntü verilerinin ayrıştırılması için farklı bir çözüme geçmem gerekiyor gibi görünüyor. Bu konuda herhangi bir tavsiye memnuniyetle karşılıyor, cevabınızı buraya çekiyorsunuz ve uygulamayı bitirdikten sonra doğru olarak işaretleyeceğim. –

+1

@Joshua Cody - Biraz daha detay vermek için cevabı güncelledim. CodeIgniter'i pek çok ay içinde kullanmadığımı ve bunu kod tabanına nasıl entegre edeceğinizi söyleyemediğimi bağışlamanız gerekecek. Gönderilmeden önce dosyayı neden yüklemeniz gerektiğinden emin değilim, ancak bu size en azından bir ipucu vermelidir. (Görüntüyü sizin için daha uygunsa, bir veritabanına da ekleyebilirsiniz). – clarkf

6

:

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

sadece FormData nesnesine formun tüm alanları ekleyebilir ve $ .ajax ile göndermek zorunda ({url: url, data: formData, processData: false, contentType: false, type: "POST"})

+0

Bu çözüm, XMLHttpRequest.send() öğesinin, üzerinden geçirilen verilere dayattığı sınırlamayı gidermez. Bir dize (multipartınız gibi) iletildiğinde,() ikili verileri desteklemez. Buradaki multipartınız utf-8 dizesi olarak ele alınacak ve utf-8 geçerli olmayan ikili verileri bozacak veya bozacaktır. FormData'dan gerçekten kaçınmanız gerekiyorsa, XMLHttpRequest.sendAsBinary() ([polyfill available] (https://developer.mozilla.org/en-US/docs/DOM/XMLHttpRequest#sendAsBinary()) yöntemini kullanmanız gerekir. Maalesef bu, ajax çağrısı için jQuery kullanımı çok daha zor hale gelir. –