file_get_contents('php://input') always returns an empty string
Asked Answered
R

16

34

I'm building a PHP RESTful API, following this tutorial. The following function, which should return the data sent with the request when the 'put' method is used, returns null every time:

file_get_contents('php://input').

I've even downloaded and tested the full code example in the tutorial and it still returns null.

I'm using cURL and the following command in order to test the 'put' method:

curl -i -X PUT -d '{"address":"Sunset Boulevard"}' http://localhost/clients/ryan.

I've wasted days on this and still haven't gotten it to read the json data. What am I doing wrong?

Ragi answered 2/10, 2013 at 21:17 Comment(2)
You aren't by any chance reading from php://input more than once? See the Note here - php.net/manual/…Augustusaugy
@Augustusaugy Nope, I tried reading just once.Ragi
B
50

As noted elsewhere on the web, php://input content does not get through if request is redirected. Maybe your web server has a redirect from an URL starting with www to an URL without www, or from URLs using HTTP to URLs using HTTPS. Check your web server logs to verify this, and act accordingly to avoid the redirection when making calls to the web service.

Bauxite answered 17/1, 2019 at 16:25 Comment(7)
I didn't believe this could be my problem, but testing from curl confirmed there was indeed a 301 from example.com/test to example.com/test/ (added a trailing slash) :facepalm:Exsert
Yesssah, you saved my day. Been searching all over the internet and found this. Mine was redirecting from http:// to https:// through htaccess. Thanks a bunch.Skaw
You're a life saver. I created an index.php file inside a folder called "extraction", and supplied the URL in Postman as http://my-project/extraction. Changing index.php to extract.php, and the URL to http://my-project/extraction/extract.php solved it for me. I deduce that a HTTP redirect occurs to any index.php file in a folder when only the folder name is provided in the application URLDonnadonnamarie
Star for you. Thanks so muchRosaline
You are really a life saver!! Thanks GiulioInevitable
In my case it's another problem and i solve it by decod/encode 2 times, it's ridiculous but it works... $inputs = json_decode(file_get_contents("php://input"), true); $inputs = json_decode(json_encode($inputs));Ensiform
My silly web server redirect /api/path to /api/path/ wowJespersen
S
13

Make sure there are no redirects.

file_get_contents(php://input) doesn't pass the body content through redirects.

One quick way to check for redirects is to check the url with curl. On the command line: curl -IL http://example.com/api

Scapegrace answered 5/8, 2019 at 20:7 Comment(3)
This really helped. A 301 redirect could be changed to a 308 (if redirects are necessary and if the requirements permit). See the documentation on MDN developer.mozilla.org/en-US/docs/Web/HTTP/Status/301 "It is therefore recommended to use the 301 code only as a response for GET or HEAD methods and to use the 308 Permanent Redirect for POST methods instead, as the method change is explicitly prohibited with this status."Ferrate
My http requests were being redirected to https hence dropping the form content. Thanks for the hintAryl
@WilburOmae does this mean that a 308 redirect passes body content? If so I think the answer should be updated to specify which redirect types don't pass body content.Scapegrace
E
10

First off, i was able to run this code and it worked fine:

--Terminal---------
//I ran this curl request against my own php file:
curl -i -X PUT -d '{"address":"Sunset Boulevard"}' http://localhost/test.php


--PHP--------------
//get the data
$json = file_get_contents("php://input");

//convert the string of data to an array
$data = json_decode($json, true);

//output the array in the response of the curl request
print_r($data);

If that doesn't work, check the console for errors and your php settings:

  1. the curl url you used, make sure that url is actually working and not returning errors.
  2. open up another terminal / console window and run tail -f /path/to/the/php/log/file so you can actually see the output of these php calls.
  3. often people get this error: file_get_contents(file://input): failed to open stream: no suitable wrapper could be found which can indicate either a typo of the "file://input" string or the fact that allow_url_fopen is disabled in php (see #5 if unsure)
  4. make sure your code is correct, and by that I mean make sure you're not typing in incorrect arguments and things... stuff that doesn't necessarily get underlined in netbeans.
  5. remember, file_get_contents only works when allow_url_fopen is set to true in your PHP settings. thats something that is set in php.ini, but you can also change settings at run time by writing something along the lines of the following code before the other code:

    ini_set("allow_url_fopen", true);
    
Ephemerid answered 2/10, 2013 at 23:15 Comment(8)
I took your code and ran it and this is all I get: C:\Users\Igor\Desktop\curl>curl -i -X PUT -d '{"address":"Sunset"}' http://local host/server.php HTTP/1.1 200 OK Date: Thu, 03 Oct 2013 07:53:54 GMT Server: Apache/2.2.21 (Win64) PHP/5.3.8 X-Powered-By: PHP/5.3.8 Content-Length: 0 Content-Type: text/html Still nothing. allow_url_fopen is on too.Ragi
try running curl without -i flag and add the -v flag to see what's going on. i practically never run *amp stacks on windows, so there may be something funky going on there. also, try just outputting an arbitrary string in that response just to make sure you can see output at all. Also, did you look in your php_log to see if there were any errors occurring?Ephemerid
I replaced the -i flag with -v and still got the same result. I also added print_r('error') to see if it would show and it did, but $data was still empty. The log file is empty too. Maybe I should reinstall wamp???Ragi
I even installed XAMP and WAMP on another machine and ran this code and I got the empty string. Using the -v flag showed me that all bytes have been sent. I don't get it.Ragi
you still haven't answered the question about viewing your php error logsEphemerid
teamviewer? like the shared desktop application?Ephemerid
no thank you. i wish you well on your endeavors. make sure you tail your logs while you work. thats the best advice i can give you.Ephemerid
I have the same problem. Could you tell me if you found a solution!Copartner
S
6

I had got this error too, my solution is to change the data format to raw.

I get it from php doc where it says

php://input is not available with enctype="multipart/form-data".

Shortterm answered 14/12, 2017 at 6:28 Comment(0)
Y
6

for me this problem started, suddenly.
i had installed ssl certificate.
when i checked the response code it showed me 301, then i realized and changed
http://
to
https://
and got all the request back with file_get_contents('php://input').

in your example curl call:
put s after http as shown below:
curl -i -X PUT -d '{"address":"Sunset Boulevard"}' https://localhost/clients/ryan

Yazzie answered 25/9, 2019 at 15:14 Comment(0)
B
5

I wrote a headerfile with this code:

if($_SERVER["REQUEST_METHOD"] == "POST" && $_SERVER["CONTENT_TYPE"] == "application/json")
{
  $data = file_get_contents("php://input", false, stream_context_get_default(), 0, $_SERVER["CONTENT_LENGTH"]);
  global $_POST_JSON;
  $_POST_JSON = json_decode($_REQUEST["JSON_RAW"],true);

  // merge JSON-Content to $_REQUEST 
  if(is_array($_POST_JSON)) $_REQUEST   = $_POST_JSON+$_REQUEST;
}

It checks for the correct content-type and it reads only as much post input, like specified in Content-Length header. When receiving a valid JSON it created an global Array $_POST_JSON.

So you can work with your JSON-Content the similiar like you do it with url-encoded POST values.

Example:

 echo $_POST_JSON["address"];
 // or
 echo $_REQUEST["address"];
Ballentine answered 9/7, 2015 at 15:40 Comment(1)
the function example with all parameters was useful for me: $data = file_get_contents("php://input", false, stream_context_get_default(), 0, $_SERVER["CONTENT_LENGTH"]);Justinejustinian
O
3

FWIW I was using Postman to send the values. On the Body tab I should have used the "Raw" tab to send the json {"ID":1234,"Type":"Blah"} but I was foolishly using the form-data tab to put in the Key/Value which made the php://input result in NULL. Once I switched to using the raw tab with the JSON then all worked as expected.

Ochs answered 2/2, 2021 at 23:47 Comment(0)
O
2

I had the same problem. Eventually, I found that the problem was that in the client side I didn't stringify the json object (previously I used nodejs server and it was OK). Once I did that, I received the data in $_POST (not as json), as regular parameters.

Orientate answered 24/5, 2019 at 7:54 Comment(0)
B
2

Edit as you wish

function getPostObject() {
    $str = file_get_contents('php://input');
    $std = json_decode($str);
    if ($std === null) {
        $std = new stdClass();
        $array = explode('&', $str);
        foreach ($array as $parm) {
            $parts = explode('=', $parm);
            if(sizeof($parts) != 2){
                continue;
            }
            $key = $parts[0];
            $value = $parts[1];
            if ($key === NULL) {
                continue;
            }
            if (is_string($key)) {
                $key = urldecode($key);
            } else {
                continue;
            }
            if (is_bool($value)) {
                $value = boolval($value);
            } else if (is_numeric($value)) {
                $value += 0;
            } else if (is_string($value)) {
                if (empty($value)) {
                    $value = null;
                } else {
                    $lower = strtolower($value);
                    if ($lower === 'true') {
                        $value = true;
                    } else if ($lower === 'false') {
                        $value = false;
                    } else if ($lower === 'null') {
                        $value = null;
                    } else {
                        $value = urldecode($value);
                    }
                }
            } else if (is_array($value)) {
                // value is an array
            } else if (is_object($value)) {
                // value is an object
            }
            $std->$key = $value;
        }
        // length of post array
        //$std->length = sizeof($array);
    }
    return $std;
}
Barefaced answered 28/6, 2019 at 5:34 Comment(2)
when you want call $post->p1, json_decode(file_get_contents('php://input')) return empty or null when parameters like p1=1&p2=blabla$p3=false. E.g: JQUERY $.post(url, $('form').serialize()); Because it expect a JSON typesBarefaced
You should really take on "Return Early Principles" most else and else if can be avoided and indentation can be flattened significantly, only in rare scenarios should you ever need else or else if - change your approach :)Interference
S
1

The correct function call is:

file_get_contents("php://input");

You should be getting an error message saying that php:input doesn't exist...

In any case, PUT is intended for uploading files to the server, assuming the server supports it. Usually you'd use POST with a Content-Type header appropriate to the content.

Satiated answered 2/10, 2013 at 21:19 Comment(10)
I'm sorry I am using file_get_contents('php://input'), I've edited the question.Ragi
sorry again it's late and I'm tiredRagi
Looking at the notes in the manual, it looks like PUT requests aren't really ideal for this. Try POST instead.Satiated
Just did. It returned null once again.Ragi
But... null is not a valid return value for file_get_contents. It can return a string, or false. Never null. Are you sure you don't have a typo somewhere? Like maybe the variable name you use to store the string?Satiated
Actually the full code is this: $data = json_decode(file_get_contents("php://input", true));, so that's why it returns null. But after that I'm doing print_r(file_get_contents("php://input")); and that return an empty string.Ragi
Okay, with that new information... hmm... What content-type header is being sent to the server?Satiated
It should be application/json. I just tried adding -H "Content-Type:application/json" to the command and it still returns empty.Ragi
@Ragi Wait, why are you passing true as the 2nd arg to file_get_contents? You really don't want to use the include path for the PHP input streamAugustusaugy
@Augustusaugy I even tried running the code without it, still get nothing.Ragi
C
1

On Windows the combination of 'single "double" quotes' does not seem to work. Use escape for quotes in your json data (as below) & it should work

curl -X PUT -d "{\"address\":\"Sunset Boulevard\"}" http://localhost/clients/ryan
Cavalla answered 12/2, 2015 at 3:29 Comment(0)
H
1

I see the problem,

You need to add filename.php in the end of the request url or need to rewrite the server rules in .htaccess file to get around this.

curl -i -X PUT -d '{"address":"Sunset Boulevard"}' http://localhost/clients/ryan/{filename.php}

replace {filename.php} with appropriate file name. :)

Hexastyle answered 20/12, 2018 at 12:42 Comment(0)
C
0
{
  "action":"get_events_by_category",
  "category_id":2
}

Your row string data must be a Double quote "" not use single ''

Carboxylate answered 28/8, 2020 at 18:12 Comment(0)
M
0
{"id": 1, "username":"surecoder", "password":"surecoder"}

Your key and value strings data must be a Double quote "" not use single ''

Mishear answered 3/10, 2022 at 7:57 Comment(0)
F
0

Check your CSRF permissions. This one got me - I was hoping for Webhooks to be posted to the server but had forgotten to turn off CSRF requirements so the server (rightly) wasn't able to post to my page. Simple issue but check that you can post content to your page if there are no redirects in place.

Forfeiture answered 17/4, 2023 at 13:23 Comment(0)
N
0

I had the same issue, because I was using the default document, instead of specifying the php file.

/dynarax/php/index.php

vs

/dynarax/php/

Neace answered 2/8, 2023 at 19:19 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.