Es cierto que hay preguntas similares en Stack Overflow, pero parece que ninguna cumple con mis requisitos.
Esto es lo que estoy buscando hacer:
- Cargue un formulario completo de datos, uno de los cuales es un solo archivo
- Trabajar con la biblioteca de carga de archivos de Codeigniter
Hasta aquí todo está bien. Los datos entran en mi base de datos cuando los necesito. Pero también me gustaría enviar mi formulario a través de una publicación AJAX:
- Usando la API nativa de archivos HTML5, no flash ni una solución iframe
- Preferiblemente interactuando con el
.ajax()
método jQuery de bajo nivel
Creo que podría imaginarme cómo hacer esto cargando automáticamente el archivo cuando el valor del campo cambia usando javascript puro, pero prefiero hacerlo todo de una sola vez para enviarlo en jQuery. Estoy pensando que no es posible hacerlo a través de cadenas de consulta, ya que necesito pasar todo el objeto de archivo, pero estoy un poco perdido sobre qué hacer en este momento.
¿Se puede lograr esto?
javascript
jquery
ajax
html
file-upload
Joshua Cody
fuente
fuente
Respuestas:
No es muy dificil. En primer lugar, eche un vistazo a la interfaz FileReader .
Entonces, cuando se envíe el formulario, observe el proceso de envío y
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); }
Luego, en el lado del servidor (es decir, 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);
O algo parecido. Puedo estar equivocado (y si lo estoy, por favor, corríjame), pero esto debería almacenar el archivo como algo así
1287916771myPicture.jpg
en/uploads/
su servidor y responder con una variable JSON (a unacontinueSubmission()
función) que contiene el nombre de archivo en el servidor.Echa un vistazo
fwrite()
yjQuery.post()
.En la página anterior se detalla cómo usar
readAsBinaryString()
,readAsDataUrl()
yreadAsArrayBuffer()
para sus otras necesidades (por ejemplo, imágenes, videos, etc.).fuente
Con jQuery (y sin API FormData) puedes usar algo como esto:
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!"); }); });
Con la API de FormData solo tiene que agregar todos los campos de su formulario al objeto FormData y enviarlo a través de $ .ajax ({url: url, data: formData, processData: false, contentType: false, type: "POST"})
fuente