Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AJAX File Upload with XMLHttpRequest

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];

like image 941
Danilo Valente Avatar asked May 06 '12 23:05

Danilo Valente


People also ask

How do I upload a file using XMLHttpRequest?

Create the form object for submissionCreate form data that would be submitted in the POST request to /upload. The formData will contain the file object which can be easily appended. Then an AJAX request can be created by using XMLHttpRequest() method.

Does AJAX use XMLHttpRequest?

XMLHttpRequest is used heavily in AJAX programming. Despite its name, XMLHttpRequest can be used to retrieve any type of data, not just XML. If your communication needs to involve receiving event data or message data from a server, consider using server-sent events through the EventSource interface.

Is AJAX and XMLHttpRequest same?

Ajax allows us to send and receive data from the webserver asynchronously without interfering with the current state or behavior of the web page or application. XHR is the XMLHttpRequest Object which interacts with the server.


3 Answers

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+

like image 148
Opty Avatar answered Oct 27 '22 13:10

Opty


Change the post_max_size directive in the ini file

like image 31
user1388342 Avatar answered Oct 27 '22 12:10

user1388342


The Ajax call will not limit the size. It is probably the max file size in the php ini file.

like image 20
epascarello Avatar answered Oct 27 '22 12:10

epascarello