2

I'm trying to do a file upload using AJAX but I get a 403 server response... but when I do the same thing as a non-AJAX request, it works fine. Here is my HTML:

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Test</title>
<script type="text/javascript">

    function importFileAJAX() {
        fileData = $('#importfileAJAX').prop('files')[0];
        formData = new FormData();
        formData.append('file', fileData);
        $.ajax({
            method: "POST",
            url: "testimportfiles.php",
            data: formData,
            processData: false
        }).done(function(xml) {
            alert( $(xml).find('result').text());
        }).fail(function(jqXHR, errorText, exceptionText) {
            alert("Error: " + jqXHR.responseText);
        });
    }
    
</script>
</head>

<body>

    AJAX: <input id="importfileAJAX" type="file" />
    <button onclick="importFileAJAX();">Import Files</button>
    
    <hr />
    
    <form action="testimportfiles.php" method="post" enctype="multipart/form-data">
        Non-AJAX: <input type="file" name="file" id="file">
        <input type="submit" value="Import Files" name="submit">
    </form>

</body>

</html>

My php file (testimportfiles.php) is just this:

<?php

header('Content-Type: text/xml');
print("<?xml version=\"1.0\" encoding=\"UTF-8\"?><root>");
print("<result>0</result>");
print("</root>");

The second method works just fine, but the first method returns a 403 error from the server. Is this a configuration issue with my server, or am I just doing something wrong in my code?

Thanks!

EDIT: I'm leaving this question unanswered in case there's a better way, but I've solved my problem using AjaxFileUpload.js, which mimics an AJAX request by dynamically creating a form and targeting the response to a dynamically-created iFrame. The server response is then copied from the iFrame.

I'm still curious if a true AJAX transaction is possible (i.e., something that doesn't require a browser window or iFrame as a target for the server response), but this will work for me in my current project.

12
  • Have you looked at the requests in your browsers network tab to compare the ajax call to the other form call to look for any differences?
    – Taplar
    Commented Nov 16, 2017 at 20:08
  • I also notice your form has enctype set. The default contentType for an ajax call is application/x-www-form-urlencoded; charset=UTF-8
    – Taplar
    Commented Nov 16, 2017 at 20:11
  • @Toby are you authenticating on backend with cookies ? Commented Nov 16, 2017 at 20:27
  • @Taplar, I'm not seeing any clues in the Network tab; the non-AJAX attempt comes back as HTTP 200 with the type as "Document"; the AJAX attempt comes back as HTTP 403 with the type as "XHR." Everything else is the same.
    – TobyRush
    Commented Nov 16, 2017 at 20:48
  • 1
    It's clearly an authorization issue as response code 403 simply says The server understood the request but refuses to authorize it Commented Nov 16, 2017 at 21:01

3 Answers 3

1

When I try your code, I get the result 0 for both methods so it's definitely something server side (may or may not be permission issues)....but this is what I use to upload files. It can be tweaked how you want it but this is one way to do it. I will work to see if I can get a different method using your code.

<button type="button" onClick="return uploadFile();">Post Status</button>

function _(el) {
    return document.getElementById(el);
    // I honestly don't know if these 3 lines of code are 
    //necessary but idk what will happen if I delete them so....
}

function uploadFile() {
    var file = _("filetoupload_id").files[0];
    var formdata = new FormData();
    formdata.append("file12", file);
    var ajax = new XMLHttpRequest();
    ajax.open("POST", "path/to/upload.php");
    ajax.send(formdata);
}

UPDATE I tried the code below and it also worked on my server......

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Test</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
</head>

<body>
    AJAX: <input id="file1" type="file" />
    <button onclick="return importFileAJAX();">Import Files</button>
    <hr />
    <form action="tupload.php" method="post" enctype="multipart/form-data">
        Non-AJAX: <input type="file" name="file1" id="file1">
        <input type="submit" value="Import Files" name="submit">
    </form>
    <script type="text/javascript">
        function _(el) {
            return document.getElementById(el);
        }
        function importFileAJAX() {
            var file = _("file1").files[0];
            var formdata = new FormData();
            formdata.append("file1", file);
            $.ajax({
                method: "POST",
                url: "tupload.php",
                data: formdata,
                processData: false
            }).done(function(xml) {
                alert( $(xml).find('result').text());
            }).fail(function(jqXHR, errorText, exceptionText) {
                alert("Error: ");
            });
        }

    </script>
</body>
</html>
5
  • Thanks for checking this out. I tried your code on my server and I'm still getting a forbidden error, so it looks like you're right in that it's something specific to my server. I'll check with my ISP (who is running an Apache server through cPanel) to see about security settings. Thanks!
    – TobyRush
    Commented Nov 20, 2017 at 18:35
  • 1
    Are you trying to upload locally or on a server and if you're trying with a server who are you hosting with, if you don't mind my asking?
    – JeanPaul98
    Commented Nov 20, 2017 at 18:44
  • I'm trying to upload on a server. My account is with WestHost (westhost.com).
    – TobyRush
    Commented Nov 20, 2017 at 18:51
  • 1
    Do you have access to your error logs? And I would also recommend contacting WestHost to see what's going on.
    – JeanPaul98
    Commented Nov 20, 2017 at 19:10
  • Thanks. I had looked at error logs before with no luck (it was just showing the 403 response) and had the message to WestHost when @julekgwa commented and started me on the road to the solution: a missing contentType: false in my initial AJAX object. I notice you don't have one in yours, so it must be something specific to my server. Thanks for your help!
    – TobyRush
    Commented Nov 20, 2017 at 19:58
1

I think the problem is with your PHP file on the server, Using this function the code works on my side.

function importFileAJAX() {
    fileData = $('#importfileAJAX').prop('files')[0];
    formData = new FormData();
    formData.append('file', fileData);
    $.ajax({
        url: "testimportfiles.php",
        data: formData,
        type: 'POST',
        contentType: false,
        processData: false,
    }).done(function (xml) {
        console.log(xml);
       // alert( $(xml).find('result').text());
    }).fail(function (jqXHR, errorText, exceptionText) {
        alert("Error: " + jqXHR.responseText);
    });
}

Then in your testimportfiles.php

$file = $_FILES['file']['name'];
$tmp_file = $_FILES['file']['tmp_name'];

if (move_uploaded_file($tmp_file, "dir/to/upload/$file")) {
    echo "Success";
}else {
    echo "error";
}
1
  • Interestingly, I tried your code and it worked... and then I started backing up toward my code to see what fixed it and as it turns out my PHP file worked just fine. What I was missing was contentType: false in the initial ajax object.
    – TobyRush
    Commented Nov 20, 2017 at 19:51
0

Thanks to everyone, especially JealPaul98 and julekgwa for the answers that worked on their servers... using their code I was able to backtrack and discover that I needed contentType: false in my initial AJAX call. So my working importFileAJAX function became:

function importFileAJAX() {
  fileData = $('#importfileAJAX').prop('files')[0];
  formData = new FormData();
  formData.append('file', fileData);
  $.ajax({
    method: 'POST',
    url: "testimportfiles.php",
    data: formData,
    contentType: false,
    processData: false
  }).done(function(xml) {
    alert($(xml).find('result').text());
  }).fail(function(jqXHR, errorText, exceptionText) {
    alert("Error: " + jqXHR.responseText);
  });
}

Not the answer you're looking for? Browse other questions tagged or ask your own question.