0

I have a basic test project in Android Studio using Retrofit2 to interact with my Bluehost server. It should send a User object to the API on the server and the API returns the User's name as a string. Just a simple test, but the User never arrives at the API.
The log always prints MainActivity: simpleTest: onResponse: 200 empty

test.php located on the Bluehost server:

<?php
    if($_SERVER['REQUEST_METHOD']=='POST'){        
        require_once('connect.php');        
        
        $user_data = json_decode($_POST, true);
        
        if(empty($user_data)){
            mysqli_close($con);
            exit(json_encode('empty')); // Return string saying 'emtpy'
        }
        
        $return_string = $user_data['name'];
        echo json_encode($return_string);
        
        mysqli_close($con);
    } else {
        echo json_encode('error');
    }
?>


ApiInterface:
public interface ApiInterface {
    // getUsers works fine, and successfully returns the users from the MySQL db on the server.
    @GET( "retrofit/get_users.php")
    public Call<List<User>> getUsers();

    // The User should be sent to the test API as a JSON object
    // But it arrives empty
    @POST( "retrofit/test.php")
    public Call<String> test(@Body User user);
}


The User POJO:

public class User {
    Integer id; // Gson will convert Integer to null so that an auto id can be generated.
    String name;
    String password;

    public User(String name, String password) {
        this.name = name;
        this.password = password;
    }

    public int getId() {
        return id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

}


In MainActivity, clicking the button sends the new User and receives the response.

simpleTest = findViewById(R.id.simpleTest);
        simpleTest.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                User newUser = new User(name.getText().toString(), password.getText().toString());
                Call<String> call = api.test(newUser);
                call.enqueue(new Callback<String>() {
                    @Override
                    public void onResponse(Call<String> call, Response<String> response) {
                        Toast.makeText(MainActivity.this, response.code()+": "+response.body(), Toast.LENGTH_SHORT).show();
                        displayProgressBar(false);
                    }

                    @Override
                    public void onFailure(Call<String> call, Throwable t) {
                        Toast.makeText(MainActivity.this, t.getMessage(), Toast.LENGTH_SHORT).show();
                        displayProgressBar(false);
                    }
                });
            }
        });
beebopbogo
  • 29
  • 4
  • `$user_data = json_decode($_POST, true);` - that makes no sense; json_decode wants a string as first parameter, but $_POST is an array. – CBroe Apr 01 '22 at 07:11
  • Does this answer your question? [Receive JSON POST with PHP](https://stackoverflow.com/questions/18866571/receive-json-post-with-php) – CBroe Apr 01 '22 at 07:12
  • CBroe: Your comment could be helpful. Maybe that's the issue. $_POST is an array, not a string. So let me rephrase the question: – beebopbogo Apr 03 '22 at 05:28
  • Retrofit sends data to the API via `public Call test(@Body User user);` So how would I parse the $_POST data to PHP variables for inserting into the MySQL database? You say `$user_data = json_decode($_POST, true);` doesn't work. So how could I save the $_POST data to PHP variables? `$username = $_POST[0]->'username'`? – beebopbogo Apr 03 '22 at 05:34
  • _"even though the database contains 2 entries"_ - what has that got to do with anything, when you are currently returning the data that was _posted_ to your script? – CBroe Apr 04 '22 at 06:23

1 Answers1

1

Got it.

PHP file (test.php) located on my Bluehost server. The MySQL database is also found on the Bluehost server. This PHP api receives a user object, prints the data and sends a String message back to Java.

<?php
    if($_SERVER['REQUEST_METHOD']=='POST'){
        
        // Connect to the database
        //require_once('connect.php');
        define('USER', "myname"); // db user
        define('PASS', "mypass"); // db password
        define('DB', "db_name"); // database name
        define('HOST', "localhost"); // db server
        $con=mysqli_connect(HOST, USER, PASS, DB) or die(mysqli_connect_error());
        
        
        // Listen to all output. We'll save it to a log when complete.
        ob_start();
        
        echo "Printing \$_POST:\n";
        echo $_POST."\n\n";
        
        // $_POST is an empty array
        echo "Printing var_dump(\$_POST):\n";
        var_dump($_POST);
        echo "\n";
        
        // grab the data from the request body as a string
        $json_string_in = file_get_contents('php://input');
        echo "Printing \$json_string_in\n";
        echo $json_string_in."\n\n\n\n";
        
        
        
        
        /////////////// ARRAY ///////////////////
        echo "JSON ARRAY:\n\n";
        
        // Decode the string into an array
        $json_array = json_decode($json_string_in, true);
        echo "Printing var_dump(\$json_array)\n";
        var_dump($json_array);
        echo "\n";
        
        // We can grab items from the array
        echo "Printing \$json_array['name']\n";
        echo $json_array['name'];
        echo "\n\n";
    
        // Encode the array into a string
        $json_string_out = json_encode($json_array);
        echo "Printing encoded \$json_string_out\n";
        echo $json_string_out; 
        echo "\n\n\n\n";
        
        
        
        
        
        
        
        
        
        /////////////// OBJECT ///////////////////
        echo "JSON OBJECT:\n\n";
        
        // Decode the string into an object
        $json_object = json_decode($json_string_in);
        echo "Printing var_dump(\$json_object)\n";
        var_dump($json_object);
        echo "\n";
        
        // We can grab items from the object
        echo "Printing \$json_object->name\n";
        echo $json_object->name;
        echo "\n\n";
    
        // Encode the object into a string
        $json_string_out = json_encode($json_object);
        echo "Printing encoded \$json_string_out\n";
        echo $json_string_out;   // {"name":"SuzieQ","password":"heyo"}
        echo "\n\n";
        
        
        
        
        
        
        
        
        // Print the output buffer to a log file. Great for debugging.
        $path = $_SERVER["DOCUMENT_ROOT"]."/api/retrofit-test/"; 
        file_put_contents($path . 'log.txt', ob_get_contents());
        ob_end_flush();


        // send a return message back to Java

        // If we want to return the same object we received:
        // If using retrofit, we have to edit the java code to catch a matching object. Change:
        //  Call<String> call = api.insertUser(user); to
        //  Call<User>   call = api.insertUser(user);
        //$json_string_out = json_encode($json_object);
        //echo $json_string_out;

        // But for now, we'll just send back a String
        echo json_encode('success');
        mysqli_close($con);
    } else {
        echo json_encode('error');
    }
?>



Here's the Java code found in MainActivity when a user presses the Test button: (Learning how to connect to the server was a fairly easy Google search, so I'll omit it here. Just Google Retrofit and GsonConverter.)

simpleTest = (Button)findViewById(R.id.simpleTest);
        simpleTest.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                User newUser = new User(name.getText().toString(), password.getText().toString());
                Call<String> call = api.test(newUser); // String can be changed here to <User> if you want the php code to send back a User object
                call.enqueue(new Callback<String>() {
                    @Override
                    public void onResponse(Call<String> call, Response<String> response) {
                        Log.d(TAG, "MainActivity: simpleTest: onResponse: " + response.code() + " " + response.body());
                        Toast.makeText(MainActivity.this, response.code()+": "+response.body(), Toast.LENGTH_SHORT).show();
                        displayProgressBar(false);
                    }

                    @Override
                    public void onFailure(Call<String> call, Throwable t) {
                        Toast.makeText(MainActivity.this, t.getMessage(), Toast.LENGTH_SHORT).show();
                        displayProgressBar(false);
                    }
                });
            }
        });


And here's the output:

Printing $_POST:
Array

Printing var_dump($_POST):
array(0) {
}

Printing $json_string_in
{"name":"SuzieQ","password":"heyo12"}



JSON ARRAY:

Printing var_dump($json_array)
array(2) {
  ["name"]=>
  string(6) "SuzieQ"
  ["password"]=>
  string(6) "heyo12"
}

Printing $json_array['name']
SuzieQ

Printing encoded $json_string_out
{"name":"SuzieQ","password":"heyo12"}



JSON OBJECT:

Printing var_dump($json_object)
object(stdClass)#2 (2) {
  ["name"]=>
  string(6) "SuzieQ"
  ["password"]=>
  string(6) "heyo12"
}

Printing $json_object->name
SuzieQ

Printing encoded $json_string_out
{"name":"SuzieQ","password":"heyo12"}
beebopbogo
  • 29
  • 4