1

I'm trying to implement a HTML5 ajax file upload with the help of HTML5's File API. It is based on Afzaal Ahmad Zeeshan's answer to this question.

My main aim would be to be able to let users upload .xls and .xlsx spreadsheet for later use.

HTML

<form class="form-uploadXLS" method="post" action="php/uploadXLS.php" enctype="multipart/form-data">
    <div class="form-group">
        <div class="col-md-12">
            <input type="file" name="xls" class="xls" />
        </div>
    </div>
    <input type="button" value="Upload" class="btn-uploadXLS" />
</form>
<progress></progress>

And here are the jQuery event handlers, just like in the above mentioned answer:

File input onChange event:

$('.xls').on('change', function () {
    var file = this.files[0];
    var fileName = file.name;
    var fileType = file.type;
    var fileSize = file.size;

    console.log("file name: " + fileName + ", type: " + fileType + ", size: " + fileSize);
});

This works correctly, the file's name, type and size gets logged to the server.

Upload button's onClick event:

$('.btn-uploadXLS').on('click', function (event) {
    event.preventDefault();
    console.log("Upload button clicked");
    var formData = new FormData($('.form-uploadXLS')[0]);

    $.ajax({
        url: 'php/uploadXLS.php', //Server script to process data
        type: 'POST',
        xhr: function () { // Custom XMLHttpRequest
            var myXhr = $.ajaxSettings.xhr();
            if (myXhr.upload) { // Check if upload property exists
                myXhr.upload.addEventListener('progress', progressHandlingFunction, false); // For handling the progress of the upload
            }
            return myXhr;
        },
        //Ajax events
        beforeSend: function (stuff) {
            console.log("BeforeSend");
            console.log(stuff);
        },
        success: function (data) {
            console.log("Success!");
            console.log(data);
        },
        error: function (error) {
            console.log("Error!");
            console.log(error);
        },
        // Form data
        data: formData,
        //Options to tell jQuery not to process data or worry about content-type.
        cache: false,
        contentType: false,
        processData: false
    });
});

On server side, I'm using this PHP code to check if the file has been sent to the server

if(!empty($_FILES['xls'])) {
    echo '<pre>',print_r($_FILES,1),'</pre>';
}
else {
    die('no $_FILES variable');
}

And here's the result of print_r:

Array
(
[xls] => Array
(
[name] =>
[type] =>
[tmp_name] =>
[error] => 4
[size] => 0
)

)

According to the documentation, error code 4 means: UPLOAD_ERR_NO_FILE Value: 4; No file was uploaded.

What am I doing wrong?

Edit:

If I disable the click event listener and submit the form as normal, the file gets uploaded without problems.

I've noticed, that the formData variable doesn't have any value. This is the value of formData after it's been set: FormData { append=append()}

Community
  • 1
  • 1
PeterInvincible
  • 2,230
  • 5
  • 34
  • 62
  • Yes using ajax u can not directly send the files. check this link you need to get the file data in a separate var and then append http://stackoverflow.com/questions/20097081/php-ajax-file-upload-error – Abhik Chakraborty Mar 06 '14 at 21:00
  • 1
    @AbhikChakraborty he is already doing it properly. There's nothing wrong with how he is sending the files via ajax. – Kevin B Mar 06 '14 at 21:03
  • Have you tried different files? different browsers? Have you tried disabling the button click handling and instead having it submit the form to see if it works without ajax (for debugging)? – Kevin B Mar 06 '14 at 21:04
  • This could be due to a setting in php.ini or your server limiting the upload file size. Try with a very small file and see if it works. – Bradley Trager Mar 06 '14 at 21:12
  • @KevinB files and browsers do not matter, I've checked it in Firefox, Chrome and IE10 using .xls, .jpg and .doc files, same result with all of them. However disablin the click handling and submitting the form as normal works, print_r outputs file information as it should. – PeterInvincible Mar 06 '14 at 21:12
  • @BradleyTrager that isn't it either, I've checked it multiple times, besides without ajax the upload works as it should. – PeterInvincible Mar 06 '14 at 21:13
  • Check the permissions on /tmp - nevermind... if you can upload it with POST, then permissions are probably fine. – dcarrith Mar 06 '14 at 21:14
  • @dcarrith I'm developing locally on OSX with MAMP server. I've set the permissions of /tmp to read&write to everyone, still no change – PeterInvincible Mar 06 '14 at 21:20
  • 1
    The only thing i see you doing differently than many other examples is you're passing the entire form to FormData rather than just adding the file to it. However, looking at documentation, the form should be enough. – Kevin B Mar 06 '14 at 21:21
  • You could try using something like the jQuery-File-Upload plugin to see if you get a different result: https://github.com/blueimp/jQuery-File-Upload – dcarrith Mar 06 '14 at 21:23
  • @KevinB I've added some edits to the question. FormData actually does not seem to have any value. How should I "only add the file to it"? – PeterInvincible Mar 06 '14 at 21:25
  • The answer to the question linked in the first comment has a great example. – Kevin B Mar 06 '14 at 21:27
  • 1
    Try changing the input name to name="xls[]" - eh... nevermind, that's only for when you're allowing the selection of multiple files for upload. – dcarrith Mar 06 '14 at 21:28
  • I've found the solution. It was indeed the formData variable. I've modified it to this: var formData = new FormData($('.form-uploadXLS')[1]); and now it works. I have no idea why is that though. – PeterInvincible Mar 06 '14 at 21:29

2 Answers2

0

For some reason the problem was with the formData variable, previously defined as such:

var formData = new FormData($('.form-uploadXLS')[0]);

I've changed the index to 1 like this..

var formData = new FormData($('.form-uploadXLS')[1]);

.. and for some reason it works now.

PeterInvincible
  • 2,230
  • 5
  • 34
  • 62
-1

Instead of:

if(!empty($_FILES['xls'])) {

try this:

if(!empty($_FILES['xls']['name'])) {

type = $_FILES['xls']['type']) tmp = $_FILES['xls']['tmp_name'])

SuperDJ
  • 7,488
  • 11
  • 40
  • 74
  • Well since the $_FILES['xls'] in fact doesn't have a file (as you can guess by error code 4), using this technique leads to die('no $_FILES variable'); – PeterInvincible Mar 06 '14 at 21:06