REST request data can't be read in 'put' method

13,131

Solution 1

The parse_str is used to parse a query string(in form arg1=xyz&arg2=abc) and not JSON. You need to use json_decode to parse JSON strings.

$data = json_decode(file_get_contents("php://input"), true);

Here is the code that works:

$method = strtolower($_SERVER['REQUEST_METHOD']);
$data = array();

switch ($method) {
    case 'get':
        $data = $_GET;
        break;
    case 'post':
        $data = $_POST;
        break;
    case 'put':
        $data = json_decode(file_get_contents("php://input"), true);
        break;
}

var_dump($data);

Curl command:

curl -i -X PUT -d '{"name":"a","data":"data1"}' http://my-server/my.php

Response:

array(2) {
  ["name"]=>
  string(1) "a"
  ["data"]=>
  string(5) "data1"
}

Solution 2

Could it be that there's something wrong with the web server?

Actually yes. After banging my head on this for a few hours, I found that the culprit for the missing data was this:

Note: Prior to PHP 5.6, a stream opened with php://input could only be read once

Another piece of code was accessing the php://input before my code, and on servers with php < 5.6, this caused the input to be lost.

Only on PUT requests that is.

Share:
13,131
Igor
Author by

Igor

Updated on June 27, 2022

Comments

  • Igor
    Igor almost 2 years

    I'm trying to develop a RESTful API with PHP without using frameworks. While processing the request, the client data cannot be read using this: parse_str(file_get_contents("php://input"), $put_vars);

    Here's the full code:

    public static function processRequest() {
    
        //get the verb
        $method = strtolower($_SERVER['REQUEST_METHOD']);
    
        $request = new Request();
    
        $data = array();
        $put_vars = array();
    
        switch ($method) {
            case 'get':
                $data = $_GET;
                break;
            case 'post':
                $data = $_POST;
                break;
            case 'put':
                parse_str(file_get_contents("php://input"), $put_vars);
                $data = $put_vars;
                echo $data;
                break;
        }
    
        $request->setMethod($method);
        $request->setRequestVars($data);
    
        if (isset($data['data'])) {
            $request->setData(json_decode($data));
            echo 'data exists';
        }
    
        return $request;
    }
    

    I'm using cURL to rest the API and when I type this command: curl -i -X PUT -d '{"name":"a","data":"data1"}' http://localhost/my-rest-api/api/ I only get this back:

    Array""

    Why isn't the proper data returned?

    EDIT

    I also tested another piece of code that is supposed to be an API and file_get_contents('php://input', true) still returns null. Could it be that there's something wrong with the web server?

    • Shimon Rachlenko
      Shimon Rachlenko over 10 years
      don't use echo $data for testing, use either var_dump($data) or print_r($data)
    • Shimon Rachlenko
      Shimon Rachlenko over 10 years
      I recreated your code on my server and was able to run it using your curl command and it produces required result.
  • Igor
    Igor over 10 years
    @ShimoRachlenko I Just edited the code and still get the same results
  • Shimon Rachlenko
    Shimon Rachlenko over 10 years
    Can you confirm that file_get_contents("php://input") give you the data you send? And another thing - how do you output the result?
  • Igor
    Igor over 10 years
    How can it be confirmed? So far the output is printed using 'echo', as shown above.
  • Shimon Rachlenko
    Shimon Rachlenko over 10 years
    Do echo file_get_contents("php://input"), and also do print_r($data) after you json_decode it.
  • Igor
    Igor over 10 years
    I also noticed that if I send data using 'POST', $_POST is empty.
  • Shimon Rachlenko
    Shimon Rachlenko over 10 years
    @Igor answer updated. The main point is to use var_dump instead of echo for debug.
  • Igor
    Igor over 10 years
    Can you add the cURL command and response also? I get 'null' using the same code
  • Mike Brant
    Mike Brant over 10 years
    @Igor If you are sending JSON data via POST, it will also not be parsed into $_POST. What you need to do is set you HTTP Content header for the request to be application/json, such that PHP will not try to parse the data as a query string, and then you need to json_decode the raw input data as suggested here. This applies to any cases where you are sending data via JSON.
  • Igor
    Igor over 10 years
    @MikeBrant Can I set the Content Header in cURL while making requests? I hope that's what you meant.
  • Igor
    Igor over 10 years
    @ShimonRachlenko Thanks for the edit, but I still get different response with your code. Here's what I get: <pre class='xdebug-var-dump' dir='ltr'><font color='#3465a4'>null</font></pre> Do you have any idea why?
  • Igor
    Igor over 10 years
    @MikeBrant Did you also try this code to see if it's working?
  • Mike Brant
    Mike Brant over 10 years
    @Igor How would I do that? I have no access to your code or servers. It seems that you are doing some sort of var_dump via xdebug based on the returned content. Looks like you need to do some debugging.
  • Igor
    Igor over 10 years
    @MikeBrant The code I use is the one from this answer. I created an index.php file with this code in it, placed it on a server, used cURL to test the PUT method and despite Shimon's claim, get_file_contents('php://input') returns null. I don't see what I'm doing wrong.
  • Vijay Kumar
    Vijay Kumar over 6 years
    This was very helpful. Thank you for sharing.