HTTP PUT, DELETE and I/O streams with PHP - php

Is there any way I can access data that was sent via HTTP PUT method other than $putdata = fopen("php://input", "r");?
I have never worked with PUT and DELETE methods and $putdata = fopen("php://input", "r"); seems a bit sketchy. Will it work everywhere is a specific server/php.ini configuration required?
I know that I can get the request method from $_SERVER['REQUEST_METHOD'];
But will the data be in $_REQUEST, if yes then what php://input is about?
And how do I access data that was sent via DELETE?

No, you will need to parse the request manually. $_REQUEST only contains data coming from GET and POST requests; for everything else you are on your own.
If your HTTP request has Content-Type: application/x-www-form-urlencoded, you can parse it back into a variables array very easily with parse_str like this:
parse_str(file_get_contents('php://input'), $vars);
print_r($vars);
You can use this content type with any HTTP method, there is no standard-imposed limitation.

Related

PHP How to Ready Body of File SENT to Script [duplicate]

I submit as POST to a php page the following:
{a:1}
This is the body of the request (a POST request).
In php, what do I have to do to extract that value?
var_dump($_POST);
is not the solution, not working.
To access the entity body of a POST or PUT request (or any other HTTP method):
$entityBody = file_get_contents('php://input');
Also, the STDIN constant is an already-open stream to php://input, so you can alternatively do:
$entityBody = stream_get_contents(STDIN);
From the PHP manual entry on I/O streamsdocs:
php://input is a read-only stream that allows you to read raw data
from the request body. In the case of POST requests, it is preferable
to use php://input instead of $HTTP_RAW_POST_DATA as it does not
depend on special php.ini directives. Moreover, for those cases where
$HTTP_RAW_POST_DATA is not populated by default, it is a potentially
less memory intensive alternative to activating
always_populate_raw_post_data. php://input is not available with
enctype="multipart/form-data".
Specifically you'll want to note that the php://input stream, regardless of how you access it in a web SAPI, is not seekable. This means that it can only be read once. If you're working in an environment where large HTTP entity bodies are routinely uploaded you may wish to maintain the input in its stream form (rather than buffering it like the first example above).
To maintain the stream resource something like this can be helpful:
<?php
function detectRequestBody() {
$rawInput = fopen('php://input', 'r');
$tempStream = fopen('php://temp', 'r+');
stream_copy_to_stream($rawInput, $tempStream);
rewind($tempStream);
return $tempStream;
}
php://temp allows you to manage memory consumption because it will transparently switch to filesystem storage after a certain amount of data is stored (2M by default). This size can be manipulated in the php.ini file or by appending /maxmemory:NN, where NN is the maximum amount of data to keep in memory before using a temporary file, in bytes.
Of course, unless you have a really good reason for seeking on the input stream, you shouldn't need this functionality in a web application. Reading the HTTP request entity body once is usually enough -- don't keep clients waiting all day while your app figures out what to do.
Note that php://input is not available for requests specifying a Content-Type: multipart/form-data header (enctype="multipart/form-data" in HTML forms). This results from PHP already having parsed the form data into the $_POST superglobal.
return value in array
$data = json_decode(file_get_contents('php://input'), true);
A possible reason for an empty $_POST is that the request is not POST, or not POST anymore... It may have started out as post, but encountered a 301 or 302 redirect somewhere, which is switched to GET!
Inspect $_SERVER['REQUEST_METHOD'] to check if this is the case.
See https://stackoverflow.com/a/19422232/109787 for a good discussion of why this should not happen but still does.
function getPost()
{
if(!empty($_POST))
{
// when using application/x-www-form-urlencoded or multipart/form-data as the HTTP Content-Type in the request
// NOTE: if this is the case and $_POST is empty, check the variables_order in php.ini! - it must contain the letter P
return $_POST;
}
// when using application/json as the HTTP Content-Type in the request
$post = json_decode(file_get_contents('php://input'), true);
if(json_last_error() == JSON_ERROR_NONE)
{
return $post;
}
return [];
}
print_r(getPost());
This is an exemple of how to create a php api with file_get_contents("php://input") and used in javascript using ajax with XMLHttpRequest.
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function () {
if (this.readyState == 4 && this.status == 200) {
console.log("done");
}
}
};
xhttp.open("POST", "http://127.0.0.1:8000/api.php", true);
xhttp.send(JSON.stringify({
username: $(this).val(),
email:email,
password:password
}));
$data = json_decode(file_get_contents("php://input"));
$username = $data->username;
$email = $data->email;
$password = $data->password;
Check the $HTTP_RAW_POST_DATA variable
If you have the pecl/http extension installed, you can also use this:
$request = new http\Env\Request();
$request->getBody();
If you have installed HTTP PECL extension, you can make use of the http_get_request_body() function to get body data as a string.
http_get_request_body() was explicitly made for getting the body of PUT and POST requests as per the documentation http://php.net/manual/fa/function.http-get-request-body.php

How to get "php://input" data if I'm using Content-Type multipart/form-data

Is there an alternative?
I'm using Advanced Rest Client for testing an API I'm developing.
I send a JSON with POST.
In code, $_FILES is fine, but file_get_contents("php://input") is empty.
If I don't send any files, then I can use file_get_contents("php://input")
PHP version: 5.6.4
As GhostGambler states, php://input is not available with enctype="multipart/form-data".
You should not attach the JSON as a file to your request, you should add it as the request body to the post request, setting the Content-Type header (application/json). Then it will be available in php://input.
Ok, so I ended up giving a name to my JSON data, like 0=[{"q":"w"}] and then get it with $_POST['0']. And the files with $_FILES
Here's how it looks in Advanced REST Client:
Most likely accessing any of the POST/FILES superglobals consumes php://input.
In any case, if you send a JSON payload you cannot have a multipart-formdata payload too so $_FILES should be empty. If you need to handle both on the same page (bad idea IMO) make sure to check the content type header or some other information outside the request's body before accessing either $_FILES or php://input
php://input is a read-only stream that allows you to read raw data
from the request body. In the case of POST requests, it is preferable
to use php://input instead of $HTTP_RAW_POST_DATA as it does not
depend on special php.ini directives. Moreover, for those cases where
$HTTP_RAW_POST_DATA is not populated by default, it is a potentially
less memory intensive alternative to activating
always_populate_raw_post_data. php://input is not available with
enctype="multipart/form-data".
http://php.net/manual/de/wrappers.php.php
Since HTTP_RAW_POST_DATA is marked deprecated, I guess you are somewhat unlucky. I do not know alternatives.
Edit: Well, you could try php://stdin / STDIN, although I do not know if this works with PHP in a webserver ... maybe just try it out.

PHP post server - how does posttestserver.com work?

I am trying to build a post server similar to posttestserver.com and have been runnning into lots of trouble.
The following returns nothing -
do {
$data = file_get_contents('php://input');
} while (empty($data));
header('HTTP/1.0 200 OK');
header('Content-Type: text/html');
var_dump($data);
I have also had a look into the use of sockets but the client should be directed to a URL rather than an ip/port for the clients ease. I suspect that this is what i need to use but am not sure where to start.
For what its worth, the client expects an HTTP 2XX response code from its HTTP POST request, and the client will not attempt submitting the next HTTP POST request while a previous request is still in flight.
Any ideas?
It would seem that you cannot capture and view the POST data in the one browser window.
For what its worth, here is the code that worked in the end -
$data = file_get_contents('php://input');
//do something with the data such as write to file or database
Then you could use the data in another PHP script.

PHP accessing Incoming PUT Data

Is PUT similar to POST?
I'm getting some inbound requests (apache) with this:
[REQUEST_METHOD] => PUT
I've never worked with this request method before. So I have to ask if I'm supposed to process it differently.
The people sending me data are claiming to be sending xml. So my script has this:
<?php
if(isset($HTTP_RAW_POST_DATA)) {
mail("me#myemail.com","some title i want", print_r($HTTP_RAW_POST_DATA, true));
}else{
die("not post data");
}
?>
I'm stuck here now. If there's a PUT request, do I replace $HTTP_RAW_POST_DATA with something else?
According to the php docs, PUT data can be read using the php://input stream (which is preferred over $HTTP_RAW_POST_DATA).
$putdata = fopen("php://input", "r");
$str = stream_get_contents($putdata);
fclose($putdata);

How to get body of a POST in php?

I submit as POST to a php page the following:
{a:1}
This is the body of the request (a POST request).
In php, what do I have to do to extract that value?
var_dump($_POST);
is not the solution, not working.
To access the entity body of a POST or PUT request (or any other HTTP method):
$entityBody = file_get_contents('php://input');
Also, the STDIN constant is an already-open stream to php://input, so you can alternatively do:
$entityBody = stream_get_contents(STDIN);
From the PHP manual entry on I/O streamsdocs:
php://input is a read-only stream that allows you to read raw data
from the request body. In the case of POST requests, it is preferable
to use php://input instead of $HTTP_RAW_POST_DATA as it does not
depend on special php.ini directives. Moreover, for those cases where
$HTTP_RAW_POST_DATA is not populated by default, it is a potentially
less memory intensive alternative to activating
always_populate_raw_post_data. php://input is not available with
enctype="multipart/form-data".
Specifically you'll want to note that the php://input stream, regardless of how you access it in a web SAPI, is not seekable. This means that it can only be read once. If you're working in an environment where large HTTP entity bodies are routinely uploaded you may wish to maintain the input in its stream form (rather than buffering it like the first example above).
To maintain the stream resource something like this can be helpful:
<?php
function detectRequestBody() {
$rawInput = fopen('php://input', 'r');
$tempStream = fopen('php://temp', 'r+');
stream_copy_to_stream($rawInput, $tempStream);
rewind($tempStream);
return $tempStream;
}
php://temp allows you to manage memory consumption because it will transparently switch to filesystem storage after a certain amount of data is stored (2M by default). This size can be manipulated in the php.ini file or by appending /maxmemory:NN, where NN is the maximum amount of data to keep in memory before using a temporary file, in bytes.
Of course, unless you have a really good reason for seeking on the input stream, you shouldn't need this functionality in a web application. Reading the HTTP request entity body once is usually enough -- don't keep clients waiting all day while your app figures out what to do.
Note that php://input is not available for requests specifying a Content-Type: multipart/form-data header (enctype="multipart/form-data" in HTML forms). This results from PHP already having parsed the form data into the $_POST superglobal.
return value in array
$data = json_decode(file_get_contents('php://input'), true);
A possible reason for an empty $_POST is that the request is not POST, or not POST anymore... It may have started out as post, but encountered a 301 or 302 redirect somewhere, which is switched to GET!
Inspect $_SERVER['REQUEST_METHOD'] to check if this is the case.
See https://stackoverflow.com/a/19422232/109787 for a good discussion of why this should not happen but still does.
function getPost()
{
if(!empty($_POST))
{
// when using application/x-www-form-urlencoded or multipart/form-data as the HTTP Content-Type in the request
// NOTE: if this is the case and $_POST is empty, check the variables_order in php.ini! - it must contain the letter P
return $_POST;
}
// when using application/json as the HTTP Content-Type in the request
$post = json_decode(file_get_contents('php://input'), true);
if(json_last_error() == JSON_ERROR_NONE)
{
return $post;
}
return [];
}
print_r(getPost());
This is an exemple of how to create a php api with file_get_contents("php://input") and used in javascript using ajax with XMLHttpRequest.
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function () {
if (this.readyState == 4 && this.status == 200) {
console.log("done");
}
}
};
xhttp.open("POST", "http://127.0.0.1:8000/api.php", true);
xhttp.send(JSON.stringify({
username: $(this).val(),
email:email,
password:password
}));
$data = json_decode(file_get_contents("php://input"));
$username = $data->username;
$email = $data->email;
$password = $data->password;
Check the $HTTP_RAW_POST_DATA variable
If you have the pecl/http extension installed, you can also use this:
$request = new http\Env\Request();
$request->getBody();
If you have installed HTTP PECL extension, you can make use of the http_get_request_body() function to get body data as a string.
http_get_request_body() was explicitly made for getting the body of PUT and POST requests as per the documentation http://php.net/manual/fa/function.http-get-request-body.php

Categories