É certo que existem questões semelhantes no Stack Overflow, mas parece que nenhuma atende aos meus requisitos.
Aqui está o que procuro fazer:
- Faça upload de toda uma forma de dados, uma das quais é um único arquivo
- Trabalhe com a biblioteca de upload de arquivos da Codeigniter
Até aqui está tudo bem. Os dados são armazenados em meu banco de dados conforme preciso. Mas também gostaria de enviar meu formulário por meio de uma postagem AJAX:
- Usando a API de arquivo HTML5 nativa, não flash ou uma solução iframe
- Interface preferível com o
.ajax()
método jQuery de baixo nível
Acho que poderia imaginar como fazer isso enviando automaticamente o arquivo quando o valor do campo muda usando puro javascript, mas prefiro fazer tudo de uma só vez para enviar em jQuery. Estou pensando que não é possível fazer por meio de strings de consulta, pois preciso passar o objeto de arquivo inteiro, mas estou um pouco perdido sobre o que fazer neste momento.
Isso pode ser alcançado?
javascript
jquery
ajax
html
file-upload
Joshua Cody
fonte
fonte
Respostas:
Não é muito difícil. Em primeiro lugar, dê uma olhada na Interface do FileReader .
Então, quando o formulário for enviado, pegue o processo de envio e
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); }
Então, no lado do servidor (ou seja, 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);
Ou algo parecido. Posso estar enganado (e se estiver, por favor, corrija-me), mas isso deve armazenar o arquivo como algo como
1287916771myPicture.jpg
in/uploads/
em seu servidor e responder com uma variável JSON (para umacontinueSubmission()
função) contendo o fileName no servidor.Confira
fwrite()
ejQuery.post()
.Na página acima, ele detalha como usar
readAsBinaryString()
,readAsDataUrl()
ereadAsArrayBuffer()
para suas outras necessidades (por exemplo, imagens, vídeos, etc.).fonte
Com jQuery (e sem API FormData) você pode usar algo assim:
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!"); }); });
Com a API FormData você só precisa adicionar todos os campos do seu formulário ao objeto FormData e enviá-lo via $ .ajax ({url: url, data: formData, processData: false, contentType: false, type: "POST"})
fonte