72

It seems like I have not clearly communicated my problem. I need to send a file (using AJAX) and I need to get the upload progress of the file using the Nginx HttpUploadProgressModule. I need a good solution to this problem. I have tried with the jquery.uploadprogress plugin, but I am finding myself having to rewrite much of it to get it to work in all browsers and to send the file using AJAX.

All I need is the code to do this and it needs to work in all major browsers (Chrome, Safari, FireFox, and IE). It would be even better If I could get a solution that will handle multiple file uploads.

I am using the jquery.uploadprogress plugin to get the upload progress of a file from the NginxHttpUploadProgressModule. This is inside an iframe for a facebook application. It works in firefox, but it fails in chrome/safari.

When I open the console I get this.

Uncaught ReferenceError: progressFrame is not defined
jquery.uploadprogress.js:80

Any idea how I would fix that?

I would like to also send the file using AJAX when it is completed. How would I implement that?

EDIT:
I need this soon and it is important so I am going to put a 100 point bounty on this question. The first person to answer it will receive the 100 points.

EDIT 2:
Jake33 helped me solve the first problem. First person to leave a response with how to send the file with ajax too will receive the 100 points.

Conceited Code
  • 4,186
  • 3
  • 25
  • 32
  • 2
    I see that it uses browser sniffing to detect Safari (browser sniffing is usually frowned upon), so *progressFrame* is only used with Safari/Chrome (I don't know why). The part where the error is occurring seems to be where the script tries to reference *progressFrame* just by looking for its name in the global scope instead of using a function like `document.getElementsByName`. – jhartz Feb 01 '11 at 03:01
  • 1
    I'm not sure what you mean by "send it using AJAX when it is completed" -- Isn't the progress bar representing the progress of the submission? Doesn't that mean that it is already sent once it is complete? Do you mean that you want the original form submission to be driven by AJAX so it doesn't cause a page refresh after? – slifty Feb 03 '11 at 06:11
  • Yes. Yes, but it acts like a form submission. Thats exactly what I want. – Conceited Code Feb 03 '11 at 22:39
  • 1
    Do the answers below work for you? If not, can you comment on the answers. I'm slightly confused as a result of all of the edits and want to try to solve your problem. Thanks. BTW I included a link for JQuery's Multiple File upload plugin. – jmort253 Feb 07 '11 at 07:37
  • If the question how do you send data with an HTTP POST over XMLHttpRequest using jQuery, then there is [jQuery.post](http://api.jquery.com/jQuery.post/) – karlcow Feb 05 '11 at 13:22
  • http://customphpfunctions.blogspot.in/2014/12/multi-file-select-preview-without.html – Ima Dec 23 '14 at 11:08

2 Answers2

216

Uploading files is actually possible with AJAX these days. Yes, AJAX, not some crappy AJAX wannabes like swf or java.

This example might help you out: https://webblocks.nl/tests/ajax/file-drag-drop.html

(It also includes the drag/drop interface but that's easily ignored.)

Basically what it comes down to is this:

<input id="files" type="file" />

<script>
document.getElementById('files').addEventListener('change', function(e) {
    var file = this.files[0];
    var xhr = new XMLHttpRequest();
    (xhr.upload || xhr).addEventListener('progress', function(e) {
        var done = e.position || e.loaded
        var total = e.totalSize || e.total;
        console.log('xhr progress: ' + Math.round(done/total*100) + '%');
    });
    xhr.addEventListener('load', function(e) {
        console.log('xhr upload complete', e, this.responseText);
    });
    xhr.open('post', '/URL-HERE', true);
    xhr.send(file);
});
</script>

(demo: http://jsfiddle.net/rudiedirkx/jzxmro8r/)

So basically what it comes down to is this =)

xhr.send(file);

Where file is typeof Blob: http://www.w3.org/TR/FileAPI/

Another (better IMO) way is to use FormData. This allows you to 1) name a file, like in a form and 2) send other stuff (files too), like in a form.

var fd = new FormData;
fd.append('photo1', file);
fd.append('photo2', file2);
fd.append('other_data', 'foo bar');
xhr.send(fd);

FormData makes the server code cleaner and more backward compatible (since the request now has the exact same format as normal forms).

All of it is not experimental, but very modern. Chrome 8+ and Firefox 4+ know what to do, but I don't know about any others.

This is how I handled the request (1 image per request) in PHP:

if ( isset($_FILES['file']) ) {
    $filename = basename($_FILES['file']['name']);
    $error = true;

    // Only upload if on my home win dev machine
    if ( isset($_SERVER['WINDIR']) ) {
        $path = 'uploads/'.$filename;
        $error = !move_uploaded_file($_FILES['file']['tmp_name'], $path);
    }

    $rsp = array(
        'error' => $error, // Used in JS
        'filename' => $filename,
        'filepath' => '/tests/uploads/' . $filename, // Web accessible
    );
    echo json_encode($rsp);
    exit;
}
Rudie
  • 46,504
  • 37
  • 126
  • 167
  • 27
    This is a feature available only in XMLHttpRequest2, for a full compatibility list - have a look at http://caniuse.com/xhr2 – YS. Mar 23 '12 at 00:34
  • @Rudie Do you have the hotblocks.nl tutorial link? not just the demo Thanks in adv – vzhen Jan 28 '13 at 07:18
  • There's no tutorial. Never wrote it. Didn't even make the demo to be this public. – Rudie Jan 28 '13 at 17:43
  • @Rudie: IE10 seems to support this: http://caniuse.com/xhr2. IE10 is not that bad. Browser war has some advantages. FF9 seems to be the problematic one when it comes to file uploads: you cannot clear file input! – Timo Kähkönen Mar 24 '13 at 18:56
  • Yeah IE10 is much better AND with default automatic updating (but still configurable unfortunately). Let's hope they can keep up with the big boys. (This demo has been working in Chrome for 2+ years btw.) ([I actually noted this too some ago.](https://twitter.com/yodirkx/status/314786775442788352)) – Rudie Mar 24 '13 at 20:11
  • @Rudie Could you please post a simple code for server side handling of the data recieved? – Xpleria Jun 25 '13 at 18:45
  • 1
    @NeilMartin I've added PHP example code to the end of the answer. Obviously you'll want to do something else with it. – Rudie Jun 26 '13 at 10:40
  • This took a while to understand but it's sound. One note, if you don't want to upload immediately on form change but have an UPLOAD button you can do something like this (what I ended up doing...) document.getElementById('files').addEventListener('change', function(e) { file = this.files[0]; }, false); $('#mybutton').click(function() { /* ...proceed much as above using the file object from the change listener ... ...} – jsh Jul 31 '13 at 20:06
  • I had to use `xhr.upload.addEventListener('progress',...)` (with `.upload`) to have the progress indication working. – Florent2 Sep 09 '13 at 19:37
  • @Florent2 That's why there's a `xhr.upload.onprogress` in there. Weird that onprogress on `xhr` does something, but not actual progress. (Or at least that's my finding.) – Rudie Sep 09 '13 at 22:47
  • Thanks Rudie, sorry your code is fine actually, I had missed the `if ( xhr.upload ) {...` section. Indeed for me too `onprogress` on `xhr` without `.upload` is fired, but only when the upload finishes. – Florent2 Sep 10 '13 at 02:50
  • Ajax is the crappy wanna be who kicked every ones ass, fantastic post fellow – Heavy Gray Jan 29 '14 at 18:05
  • http://customphpfunctions.blogspot.in/2014/12/multi-file-select-preview-without.html – Ima Dec 23 '14 at 11:08
  • 1
    I'm not sure I understand how to make this work? I would be great if you could make a complete working example and demo online somewhere. Or maybe some guidance on how to make it work and what things are doing? – drooh Sep 21 '15 at 21:33
  • @drooh I've simplified the example and added a link to a very simple fiddle. What don't you understand? What doesn't work? – Rudie Sep 21 '15 at 23:27
  • thanks @Rudie for replying, I checked out the fiddle but when I go to select a file nothing happens? That is the part I don't understand? What is missing from this example to make it functional? Forgive me if it's obvious but I'm having trouble connecting the dots. – drooh Sep 22 '15 at 15:16
  • @drooh Check the console/JS log/devtools. When nothing happens, it's uploading and logging the progress. You can see what it does in the code. If you can't read that, this is probably too advanced. – Rudie Sep 22 '15 at 16:50
  • @Rudie thanks for that tip, now I can see something is happening. Is there a way for me to send you a private message? I have a form that works using ajax and I'm trying to add a file upload to it. I don't want to get to off topic on this post and add unnecessary comments. I certainly appreciate your help, Im putting in many hours on this and feel I am very close, just need an eye from an expert :) thanks man! – drooh Sep 22 '15 at 17:47
  • I can see `xhr progress: xx%` and `xhr upload complete` in Chrome (version 53) console, but at the server side `$_FILES`,`$_POST` and `$_GET` all is empty arrays. Dо i need to enable something in php to get this work? I'm using php 5.6 builtin server and first example with `xhr.send(file);` – Yaroslav Oct 15 '16 at 03:16
  • what is file size limit – Faizan Anwer Ali Rupani Aug 21 '17 at 10:24
18

Here are some options for using AJAX to upload files:

UPDATE: Here is a JQuery plug-in for Multiple File Uploading.

Community
  • 1
  • 1
jmort253
  • 32,054
  • 10
  • 92
  • 114
  • 2
    i used plUpload in several projects with success (multi file upload with progress, supports Flash/Html5/Silverlight etc) – Guillaume86 Feb 09 '11 at 12:02
  • 1
    AjaxFileUpload is a piece of crap. It's not compatible with any version of jquery newer than 1.5. Also the code is wicked ugly. – Adam Mar 27 '12 at 00:13
  • 1
    @Adam - Good to know. I guess a lot changes in a year. Our hair gets a little greyer and JavaScript libraries stop working with newer software versions... – jmort253 Mar 28 '12 at 00:29
  • 1
    To expand @Adam, AjaxFileUpload breaks on ie9+ – 0plus1 Feb 25 '13 at 00:26
  • All that complaining aside, it's still my favorite. One of these days I'll get around to rewriting the damn thing and putting it on github. – Adam Mar 08 '13 at 01:26
  • @jmort253 "Multiple File Uploading" link is not working. Please update or remove. – Nis Dec 04 '13 at 00:28
  • 1
    @RanaMuhammadUsman - Take another look now. I believe I found the location of the moved plugins. Hope this helps. – jmort253 Jun 23 '14 at 20:33