5

My javascript function only uploads text files correctly. Can anybody help me figure out how to make it also accept images etc. ?

function fileUpload(files) {
  if (!files.length) {  
   fileList.innerHTML = "<p>No files selected!</p>";  
  } else {    
var list = document.createElement("ul");

for (var i = 0; i < files.length; i++) {

  //Set vars
  var file = files[i],
  fileName = file.name,
  fileSize = file.size,  
  fileData = file.getAsBinary(),  
  boundary = "xxxxxxxxx",  
  uri = "receive.php",

  //Create file info HTML output
  li = document.createElement("li");  
  list.appendChild(li);
  var info = document.createElement("span");  
  info.innerHTML = file.name + ": " + file.size + " bytes";  
  li.appendChild(info);

  //Start sending file
  var xhr = new XMLHttpRequest();
  xhr.open("POST", uri, true);  
  xhr.setRequestHeader("Content-Type", "multipart/form-data, boundary="+boundary); // simulate a file MIME POST request.

  xhr.onreadystatechange = function() {  
    if (xhr.readyState == 4) {  
      if ((xhr.status >= 200 && xhr.status <= 200) || xhr.status == 304) {  

        if (xhr.responseText != "") {  
          alert(xhr.responseText); // display response.  
        }  
      }  
    }  
  } 

  var body = "--" + boundary + "\r\n";  
  body += "Content-Disposition: form-data; name='upload'; filename='" + fileName + "'\r\n";  
  body += "Content-Type: application/octet-stream\r\n\r\n";  
  body += fileData + "\r\n";  
  body += "--" + boundary + "--";  

  xhr.send(body);  

}  
fileList.appendChild(list);
return true;
  }
}

Update: I found the following function online at http://code.google.com/p/html5uploader/ but I can't figure out how to apply it to my current function. Is xhr.sendAsBinary the only thing that changed?

// Upload image files
upload = function(file) {

    // Firefox 3.6, Chrome 6, WebKit
    if(window.FileReader) { 

        // Once the process of reading file
        this.loadEnd = function() {
            bin = reader.result;                
            xhr = new XMLHttpRequest();
            xhr.open('POST', targetPHP+'?up=true', true);
            var boundary = 'xxxxxxxxx';
            var body = '--' + boundary + "\r\n";  
            body += "Content-Disposition: form-data; name='upload'; filename='" + file.name + "'\r\n";  
            body += "Content-Type: application/octet-stream\r\n\r\n";  
            body += bin + "\r\n";  
            body += '--' + boundary + '--';      
            xhr.setRequestHeader('content-type', 'multipart/form-data; boundary=' + boundary);
            // Firefox 3.6 provides a feature sendAsBinary ()
            if(xhr.sendAsBinary != null) {
                xhr.sendAsBinary(body); 
*snip*
Daniel Trebbien
  • 38,421
  • 18
  • 121
  • 193
natli
  • 3,782
  • 11
  • 51
  • 82
  • How do you retrieve the files. I mean the file parameter must be provided somewhere. How do you do that? I need a bit explanation on this topic of file upload via ajax. Any help will be greatly appreciated. – azam Jan 26 '13 at 16:13
  • @user1698985 I'm not sure what you mean, do you mean retrieve it on the PHP side? In that case you can find it in the POST data. – natli Jan 26 '13 at 19:10
  • retrieving it on the server side is another discussion. I just want to find the way the file is selected on client loaded into the forms data and sent via ajax. In Html5 it is easy. but I don't understand how it is in previous versions of html. I tried to peek into the ajaxform plugin but difficult to understand it as to how its is retrieving the file data and sending via ajax. I want to understand the whole procedure, From selection of file to handling in jquery and submitting it to the server. – azam Jan 26 '13 at 19:38
  • In your post you are sending the file parameter to the function.. Where do you get and how do you get the value into file parameter? – azam Jan 26 '13 at 20:14
  • I really don't understand what you mean.. it's a parameter. You provide it when calling the function and then you can use it within the function, but I'm guessing that's not what you mean. Within the function, the file data is loaded and added to the POST body after which it is sent to the script.. what exactly is it you don't understand about that? – natli Jan 26 '13 at 20:19
  • Think like I don't know anything about the file uploading. And I want to understand how the html and http do this. When we place the input element and set the type attibute to file and select the file into it, how do we get the binary data then? When the form is posted like full post back the file is retrieved on server with httppostedfile class. When I send the file via ajax the page is not posted but the data goes to server. So How do I get to that binary data of file being attached. In your code the file attribute must be coming from somewhere so where is that place.Tell me like l am new. – azam Jan 26 '13 at 20:36
  • My code is part of the page that requests te upload, not the one that receives the data. So the file attribute isn't 'coming from somewhere.' It's called from the HTML form or javascript code that uses the function. Like here: http://stackoverflow.com/questions/1947263/using-an-html-button-to-call-a-javascript-function – natli Jan 26 '13 at 21:13
  • Can I get the code of how you are retrieving the file. For me the confusion is how to get the data of the file to be uploaded. When the file is selected from the local drive and when the page is posted back then it is easy to retrieve is on the server. However, when I wan to send it with the ajax request I don't understand how the file data is sent, because the page does not posts back, so how the server gets the binary data of the file. When I send the request with ajax only the file name is supposed to be transmitted and no data of the file and if it is sent then how it is? – azam Jan 29 '13 at 05:27
  • In the javascript there is code such as `body += file.getAsBinary() + "\r\n";` - this is the code that puts the content of the file into the data that is sent to the script. And then there is something like `body += "Content-Disposition: form-data; name='upload'; filename='" + file.fileName + "'\r\n";` to add additional post data. Then all of that is sent with (`xhr.sendAsBinary(body);`) after which the script receives that data with something like `$currentname = $_FILES['upload']['name'];` and `$_FILES['upload']['tmp_name']` – natli Jan 29 '13 at 13:14
  • I have asked my question here please check it if you can help http://stackoverflow.com/questions/14588052/low-level-information-needed-for-the-uploading-of-the-files-via-http-and-html – azam Jan 29 '13 at 16:57

1 Answers1

2

There is a W3C example of sending a GIF image using multipart/form-data at http://www.w3.org/TR/html401/interact/forms.html#h-17.13.4.2:

Content-Type: multipart/form-data; boundary=AaB03x

--AaB03x
Content-Disposition: form-data; name="submit-name"

Larry
--AaB03x
Content-Disposition: form-data; name="files"
Content-Type: multipart/mixed; boundary=BbC04y

--BbC04y
Content-Disposition: file; filename="file1.txt"
Content-Type: text/plain

... contents of file1.txt ...
--BbC04y
Content-Disposition: file; filename="file2.gif"
Content-Type: image/gif
Content-Transfer-Encoding: binary

...contents of file2.gif...
--BbC04y--
--AaB03x--

Notice the extra line Content-Transfer-Encoding: binary. Try adding that.

EDIT: Try base64-encoding the file data using the Base64 jQuery plugin:

  var body = "--" + boundary + "\r\n";
  body += "Content-Disposition: form-data; name='upload'; filename='" + fileName + "'\r\n";
  body += "Content-Type: application/octet-stream\r\n";
  body += "Content-Transfer-Encoding: base64\r\n\r\n";
  body += $.base64Encode(fileData) + "\r\n";
  body += "--" + boundary + "--";
Daniel Trebbien
  • 38,421
  • 18
  • 121
  • 193
  • Unfortunately that didn't change a thing. Text files still ge uploaded correctly but images don't. The images end up on the server corrupted and are about twice their normal filesize. I did however find a function online that does what I want but as I'm new to javascript I don't know how to implement it into my own function. (See updated question) Due to my inexperience I also don't understand your question, why would it have to be body.length ? – natli Sep 23 '11 at 13:30
  • @natli: [As Firefox is apparently the only browser that supports `sendAsBinary()` natively](http://stackoverflow.com/q/4236153/196844), it looks like they use FF's built-in `sendAsBinary()` method, but on Chrome and Safari, they implement a work-around (just a guess, though). In any case, perhaps the binary should be encoded with base64 first. Then set `Content-Transfer-Encoding: base64`. As far as `Content-Length`, this is one of the headers that cannot be set with the `setRequestHeader()` method (http://www.w3.org/TR/XMLHttpRequest/#the-setrequestheader-method). So, don't worry about it. – Daniel Trebbien Sep 23 '11 at 13:49
  • Ah, by the looks of it base64 is only required on Chrome 7 and Safari doesn't even support FileReader at all (yet). The script works now on Firefox, but the javascript to select files doesn't work in any browser except firefox so I can't even get to testing base64 on Chrome. But I guess I'll open up another question for that, thanks alot :D – natli Sep 23 '11 at 15:20