Trzeba przyznać, że na Stack Overflow można znaleźć podobne pytania, ale wydaje się, że żadne z nich nie spełnia moich wymagań.
Oto, co chcę zrobić:
- Prześlij całą formę danych, z których jeden jest pojedynczym plikiem
- Pracuj z biblioteką przesyłania plików Codeigniter
Aż do tego miejsca wszystko jest w porządku. Dane trafiają do mojej bazy danych tak, jak tego potrzebuję. Ale chciałbym również przesłać mój formularz pocztą AJAX:
- Korzystanie z natywnego interfejsu API plików HTML5, a nie technologii Flash lub iframe
- Najlepiej współpracując z niskopoziomową
.ajax()
metodą jQuery
Myślę, że mógłbym sobie wyobrazić, jak to zrobić, automatycznie przesyłając plik, gdy wartość pola zmienia się za pomocą czystego javascript, ale wolałbym zrobić to wszystko za jednym zamachem i przesłać w jQuery. Myślę, że nie można tego zrobić za pomocą ciągów zapytań, ponieważ muszę przekazać cały obiekt pliku, ale jestem trochę zagubiony w tym, co mam zrobić w tym momencie.
Czy można to osiągnąć?
javascript
jquery
ajax
html
file-upload
Joshua Cody
źródło
źródło
Odpowiedzi:
To nie jest zbyt trudne. Po pierwsze, spójrz na interfejs FileReader .
Po przesłaniu formularza przechwyć proces przesyłania i
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); }
Następnie po stronie serwera (tj. 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);
Albo coś w tym stylu. Mogę się mylić (a jeśli się mylę, proszę, popraw mnie), ale powinno to zapisać plik jako coś podobnego
1287916771myPicture.jpg
do/uploads/
na twoim serwerze i odpowiedzieć za pomocą zmiennej JSON (docontinueSubmission()
funkcji) zawierającej nazwę pliku na serwerze.Sprawdź
fwrite()
ijQuery.post()
.Na powyższej stronie szczegółowo opisano, jak używać
readAsBinaryString()
,readAsDataUrl()
ireadAsArrayBuffer()
do innych potrzeb (np. Obrazów, filmów itp.).źródło
Z jQuery (i bez FormData API) możesz użyć czegoś takiego:
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!"); }); });
Dzięki FormData API wystarczy dodać wszystkie pola formularza do obiektu FormData i wysłać go przez $ .ajax ({url: url, data: formData, processData: false, contentType: false, type: "POST"})
źródło