AJAX File Upload with XMLHttpRequest

ajax, file, javascript, upload, xmlhttprequest

Solution

To avoid the post_max_size limitation problem... but also out of memory problems on both sides :

On the client side

use PUT instead of POST :

`xhr.open("put", "upload.php", true);`

add custom headers to specify original FileName and FileSize :

`xhr.setRequestHeader("X-File-Name", file.name);` `xhr.setRequestHeader("X-File-Size", file.size);`

use the File object directly in your XHR send method :

`xhr.send(file);`

Please note that the File object can be obtained directly via the “files” property of your input[type=file] DOM object

On the server side

read the custom headers via $_SERVER :

`$filename = $_SERVER['HTTP_X_FILE_NAME'];` `$filesize = $_SERVER['HTTP_X_FILE_SIZE'];`

read file data using php://input :

`$in = fopen('php://input','r');`

You'll then be able to send very big files (1GB or more) without any limitation!!!

This code works for FireFox 4+, Chrome 6+, IE10+

Problem

I know there are a lot of similar questions, but I still haven't found a solution for my problem. I'm trying to upload a file with XMLHttpRequest, so I developed the code below: ``` var sendFiles = function(url,onload,onerror,file,headers){ var xhr = XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject('Microsoft.XMLHttp'), upload = xhr.upload; API.addEvent(xhr,'readystatechange',function(){ if(xhr.readyState==4) if((xhr.status>=200 && xhr.status<300) || xhr.status==304){ this.response = this.response || this.responseText; onload.call(xhr); }else onerror.call(xhr); }); xhr.open('POST',url,true); for(var n=0;n<headers.length;n++) xhr.setRequestHeader(headers[n]); xhr.send(file); return xhr; }; ``` And the PHP-side script is: ``` <?php header('Content-type: text/html;charset=ISO-8859-1'); $status = 0; if(@copy($_FILES['file']['tmp_name'],'test\\' . $_FILES['file']['name'])) $status = 1; else $err = '0'; echo '{ "status": ' . $status . ' }'; ?>; ``` But the var $_FILES['file'] seems to be empty, which means that the file isn't being sent to the server. Then i decided to use the FormData Object, in the code below ``` var sendFiles = function(url,onload,onerror,file,headers){ var xhr = XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject('Microsoft.XMLHttp'), upload = xhr.upload, formData = new FormData(); formData.append('file',file); API.addEvent(xhr,'readystatechange',function(){ if(xhr.readyState==4) if((xhr.status>=200 && xhr.status<300) || xhr.status==304){ this.response = this.response || this.responseText; onload.call(xhr); }else onerror.call(xhr); }); xhr.open('POST',url,true); for(var n=0;n<headers.length;n++) xhr.setRequestHeader(headers[n]); xhr.send(formData); return xhr; }; ``` And it worked, but only with file sizes low to about 8mb. When I try sending a file that has more than 8mb of size, the var `$_FILES['file']` becomes empty again NOTE: the 'file' var corresponds to something like document.getElementsById('fileInput').files[0];

Original source