Search code examples
phpjqueryajaxslimslim-3

Empty PHP response object in AJAX but only on success


To receive my response object from my PHP server I have the code down below. First of all, it works. What does not work is that if my first PHP condition is met, the success function in my Ajax responds correctly but only without using the data object.

This is my AJAX function:

$.ajax({
    type: "PUT",
    url: "http://server/register",
    contentType: "application/json", 
    data: '{"username":"' + username + '", "password":"' + password + '"}',
    success: function(data) {             
        console.log(data)  // The output in my dev tools under Firefox is just a blank line, no error message or even "undefined".           
        console.log("Success") // Works!
        if(data.status == 200){ 
            console.log("Test 1") // Doesn't work. Although status code 200 is shown to me.
        }                       
    },
    error: function(data) {
        console.log(data)   // This works! I can see the content of the object. The correct status code (409) is shown to me.
        if(data.status == 409){
            console.log("Test 2") // Works
        }            
    }
}); 

This is my PHP function:

public function register($request, $response)
{              
    ...

    if(condition-1) {
        echo("Condition 1 works!"); // Works.
        return $response->withStatus(200);                    
    } elseif(condition-2) {
        echo("Condition 2 works!"); // Works too.
        return $response->withStatus(409);            
    }      
}         

I don't see why there is no data object. I'm using the Slim 3 Framework and could probably return a JSON object like this:

$content = ["foo" => 'bar', ...] ; //Any data you wish to return
return $response->withJson($content);

But so far my whole code works without using JSON objects. Even if I var_dump the $response object, I can see that on the server side it is there.

if(condition-1) {
    var_dump($response->withStatus(200)); // Works. I can see it.                
}

Solution

  • There's a lot wrong here, so I've done my best to point out what I see wrong, and hopefully with the changes I'm going to suggest you will have success.

    If you are trying to use data.status in your ajax success function, then it looks like you think you are returning json, but you aren't. Even if you are, you are corrupting it by echoing "Condition 1 works!".

    So think about it, if you have a json response like this:

    {'a':'1'}
    

    And you echo something out before it, your response is corrupted, and looks like this:

    Condition 1 works!{'a':'1'}
    

    Same corruption occurs if PHP throws an error your way, so be aware of that.

    You should also be declaring a dataType for your ajax request, so:

    $.ajax({
        type: "PUT",
        url: "http://server/register",
        contentType: "application/json", 
        data: JSON.stringify({
            "username": username, 
            "password": password
        }),
        dataType: 'json', // <-- THIS LINE IS IMPORTANT
        success: function(data, textStatus, jqXHR) {
            // ...
        },
        error: function(jqXHR, textStatus, errorThrown) {
            // ...
        }
    });
    

    Note: you were single quoting your data object, so you were doing it the hard way. Just use JSON.stringify on a JS object like I did!

    Since my code expects a json response, make sure to look at the other answer here, as it shows how to send back a proper json response with slim.

    Finally, in your ajax success function, data.status is not ever going to be available. Docs for jQuery show that there are three parameters, (data, textStatus, jqXHR) and data is specifically for the data, not the HTTP status code or any headers.

    I put together a full working example of a mini Slim app. It's fully tested and works (it's just not awesome, so don't laugh):

    <?php
    
    use \Psr\Http\Message\ServerRequestInterface as Request;
    use \Psr\Http\Message\ResponseInterface as Response;
    
    require 'vendor/autoload.php';
    
    $app = new \Slim\App;
    
    $app->get('/', function (Request $request, Response $response) {
        $response->getBody()->write('<!doctype html>
        <html>
            <head>
                <script
                  src="https://code.jquery.com/jquery-3.2.1.min.js"
                  integrity="sha256-hwg4gsxgFZhOsEEamdOYGBf13FyQuiTwlAQgxVSNgt4="
                  crossorigin="anonymous"></script>
                <script>
                    $(document).ready(function(){
                        $("p").on("click", function(){
                            var username = "kookoopapa";
                            var password = "gr3atp4ssWerd";
                            $.ajax({
                                type: "PUT",
                                url: "/register", 
                                data: JSON.stringify({
                                    "username": username, 
                                    "password": password
                                }),
                                contentType: "application/json", 
                                dataType: "json", // <-- THIS LINE IS IMPORTANT
                                success: function(data, textStatus, jqXHR) {
                                    alert( data.a );
                                    alert( data.b );
                                },
                                error: function(jqXHR, textStatus, errorThrown) {
                                    // ...
                                }
                            });
                        });
                    });
                </script>
            </head>
            <body>
                <p>Click</p>
            </body>
        </html>');
        return $response;
    });
    
    $app->put('/register', function (Request $request, Response $response) {
        $php_input = file_get_contents('php://input');
        $vars = json_decode( $php_input, TRUE );
        $content = [
            'a' => $vars['username'],
            'b' => $vars['password']
        ];
        return $response->withStatus(200)->withJson($content);
    });
    
    $app->run();