Should I use `php://input` and/or `$_POST`? - php

I'm building API with the following structure:
method POST
uri /words.
body {"word":"example"}.
This request should add word to database and if I testing it by httpie everything is ok.
$ http POST localhost:8000/words word="new word2"
HTTP/1.1 200 OK
Access-Control-Allow-Headers: application/json
Access-Control-Allow-Origin: http://localhost:8080
Connection: close
Content-Type: application/json
Host: localhost:8000
X-Powered-By: PHP/7.0.12-1+deb.sury.org~xenial+1
{
"test": {
"method": "POST",
"input": {
"word": "new word2"
},
"post": []
},
"words": {
"id": "581f2f118b0414307476f7b3",
"word": "new word2"
}
}
In test I placed variable obtained in php by:
$method = $_SERVER['REQUEST_METHOD'];
$input = json_decode(file_get_contents('php://input'),true);
$post = $_POST;
We can see that $_POST is empty. If I use javascript:
$(form).submit(function(e) {
var url = "http://localhost:8000/words";
var data = {"word" : form.elements["word"].value };
$.ajax({
type: "POST",
url: url,
data: data,
dataType: 'json',
success: function(data)
{
console.log(JSON.stringify(data));
}
});
e.preventDefault();
});
I obtain the following console log:
{
"test":{
"method":"POST",
"input":null,
"post":{
"word":"word from form"
}
},
"words":{
"id":"581f34b28b0414307476f7b6",
"word":null
}
}
Now input is empty. Word is null because I am processing $input["word"], from php://input. My questions:
Should I process $_POST, or check both variable?
How about best practices of using these methods?
Can I send php://input from browser or $_POST from command line toll like httpie?

Your manually constructed example and your JavaScript example are not equivalent.
In the first you are sending JSON encoded data with an application/json content-type.
In the second, you are passing a JavaScript object to jQuery and allowing it to follow it's default behaviour, which is to encod it using the application/x-www-form-urlencoded format and use that as the content type (just like submitting a regular HTML form would do).
PHP supports application/x-www-form-urlencoded data in POST requests, but not JSON.
Should I process $_POST, or check both variable?
If you are sending application/x-www-form-urlencoded data or another format supported by PHP, then use $_POST. Otherwise you need to get the raw data from php://input and parse it yourself.
Can I send php://input from browser
See POST data in JSON format
$_POST from command line toll like httpie?
See the httpie documentation:
http --form POST api.example.org/person/1 name='John Smith'

Related

Why we don't need dataType: "json" in AJAX call (conditionally)?

I noticed that we don't need to include dataType: "json" in our AJAX call if the server file is already in .json format, e.g.
index.html
$.ajax({
url: "ajax/test.json",
data: "id="+id,
cache: false,
type: "POST",
success: function(response){
// Some more stuff here...
}
});
test.json
{
"fname" : "Aileen",
"lname" : "Brown",
"email" : "ab#gmail.com",
"phone" : "1234567890",
"country" : "USA"
}
But if we have to fetch above content from a PHP file through MySQL database
index.html
$.ajax({
url: "ajax/test.php",
data: "id="+id,
cache: false,
type: "POST",
dataType: "json",
success: function(response){
// Some more stuff here...
}
});
test.php
<?php
$data = array(
"fname" => "Aileen",
"lname" => "Brown",
"email" => "ab#gmail.com",
"phone" => "1234567890",
"country" => "USA"
);
// Convert PHP array into JSON object
echo json_encode($data);
?>
The response from this server PHP file via AJAX call in web browser console is collected in the same JSON format as my test.json file has.
{"fname":"Aileen","lname":"Brown","email":"ab#gmail.comk","phone":"1234567890","country":"USA"}
Can anyone please explain me properly why using dataType: "json" is mandatory when the data has to be fetched from a PHP file rather than a JSON file if the format of data coming from server is identical?
In short, this is because of a bug in your PHP code.
Any HTTP request or response with a body has a matching Content-Type in the headers to describe what type of data it is.
By default, jQuery will parse the response it gets according to the Content-Type header it came with. dataType causes it to ignore that header (and also set an Accept header on the request).
Most web servers these days are configured by default so that a file with a .json file extension gets a Content-Type: application/json header.
Any PHP program will output, again by default, a Content-Type: text/html header unless overridden using the header function.
Since your PHP doesn't include header("Content-Type: application/json") it tells the web browser that it is sending HTML and jQuery tries to parse the JSON as if it were HTML.
This is because the Content-Type sent in the header for a .json file is already application/json whereas a "normal" PHP file has text/html.
jQuery AJAX uses "Intelligent Guess" to determine the data type from the MIME type of the file if no dataType is set:
The type of data that you're expecting back from the server. If none is specified, jQuery will try to infer it based on the MIME type of the response (an XML MIME type will yield XML, in 1.4 JSON will yield a JavaScript object, in 1.4 script will execute the script, and anything else will be returned as a string).
(see https://api.jquery.com/jQuery.ajax/)
You can easily watch this behavior in your Developer Console (here I used Firefox's built-in version):

Can't find variables with $http.post AngularJS

I'm having some trouble using $http.post() with angularJS.
When I use the "post" method with a form, I can find the data in my php file using $_POST, and it works fine.
But when I do, for example:
$http.post(myUrl, {data: "test data"})
.success(function(){
console.log("ok");
});
How can I get the data and use it in my php file?
Thanks
By default, Angular $http will use the header Content-type: application/json and send the request body as JSON. You can get this in PHP using:
json_decode(file_get_contents("php://input"));
More information about php://input
If you don't want this and you want to use $_POST you will have to send the data as x-www-form-urlencoded which requires changing the header and sending the data as an x-www-form-urlencoded string. For example:
$http({
url: myUrl,
data: "data=" + encodeURIComponent("test data"),
method: "POST",
headers: {"Content-type": "application/x-www-form-urlencoded"}
});
If you want these settings to be global, you can configure them with $httpProvider.defaults

Ajax call with contentType: 'application/json' not working

I have an ajax call, that sends form data to a php function. Since I read a lot that using contentType: 'application/json' is best practice I wanted to give it a try as well. But unfortunately my script doesn't return anything when I use it. If I remove it, the script does what it is supposed to do.
Do you have any idea what the reason might be and why? Thank you!
$('#Form').submit(function(e) {
e.preventDefault();
var content = $(this).serialize() + "&ajax=1";
$.ajax('app/class/controller/contactForm.php', {
type: "POST",
//contentType: 'application/json',
dataType: 'json',
data: content,
success: function(result) {
console.log(result);
}
});
})
and my PHP:
if(isset($_POST['ajax']) && $_POST['ajax'] === '1') {
echo json_encode(validateForm($_POST));
}
When using contentType: 'application/json' you will not be able to rely on $_POST being populated. $_POST is only populated for form-encoded content types.
As such, you need to read your data from PHP raw input like this:
$input = file_get_contents('php://input');
$object = json_decode($input);
Of course if you want to send application/json you should actually send JSON, which you are not doing. You either need to build the object serialization to JSON directly, or you need to do something like this - Convert form data to JavaScript object with jQuery - to serialize the object from the form.
Honestly in your case, since you are dealing with form data, I don't quite think the use case for using application/json is there.
The best practice you refer to is about the server script setting the Content-Type for JSON to "application/json":
Header('Content-Type: application/json; charset=UTF8');
This is because otherwise a default Content-Type will be sent, often a catch-all text/html, and this could lead to an incomprehension with the client.
If you do not specify yourself a Content-Type in the jQuery request, jQuery will determine the most appropriate one. The problem here is that you were sending a POST form, for which the default Content-Type set by jQuery is application/x-www-form-urlencoded, which tells PHP to decode the data as POST fields and populate $_POST. Your script would have then recovered its parameters from $_POST (or maybe $_REQUEST).
By changing it to application/json, $_POST will no longer be populated, the receiving script operation won't receive the parameters where it was expecting to, and the operation breaks.
So you either need to:
not specify the Content-Type yourself (better, IMHO)
set a Content-Type of application/x-www-form-urlencoded; charset=UTF-8
set a Content-Type of application/json; charset=UTF-8 and modify the script to parse the POST stream and decode the JSON data; see this answer.
The third option requires proper handling of php://input.
The PHP script should be setting the Content-Type header.
if(isset($_POST['ajax']) && $_POST['ajax'] === '1') {
header('Content-Type: application/json');
echo json_encode(validateForm($_POST));
}

Json request to another domain

Im trying to make a request from one server to another with json and php.
my html page:
$.ajax({
type: "POST",
url: "https://api.domain.com/gateway/partners/create_account.ajax.php",
dataType: 'jsonp',
crossDomain: true,
data: { "name" : "Test name"},
success: function(data)
{
console.log(data.responseText);
}
});
My php looks like this:
$name = $_GET['name'];
$data = array("Hello", $name);
echo json_encode($data);
I want to receive on my console: Hello Test name
What did I do wrong?
You are:
Telling jQuery to process the response as JSONP
Writing PHP that will output JSON (not JSONP) … presumably with a text/html content-type.
Trying to make a POST request instead of a GET request. JSONP only supports GET.
Trying to treat the data returned by the request as if it were an XHR object.
The minimal example of a JSONP response would be:
<?php
header("Content-Type: application/javascript");
$name = $_GET['name'];
$data = array("Hello", $name);
echo $_GET['callback'];
echo "(";
echo json_encode($data);
echo ");";
Then you need to alter the JS so that type: "POST" becomes type: "GET" and console.log(data.responseText); becomes console.log(data);
Alternatively, you could use another technique to bypass the same origin policy and still use POST.
The jsonp is a old practice and a insecure one because any one can call to your script. To is very default tor retrieving errors when a jsonp call fails.
You can implement CORS headers in your request, and then you can use just a simple XHR call.
Addeding the header:
Access-Control-Allow-Origin: *
Will fix your issue, but is better use the exact domain instead of the wildcard.

Receive POST request in PHP from OpenLayers JavaScript

I have problems in receiving POST request in PHP. I'm using JavaScript to send data to a PHP page with POST request. The JavaScript is from OpenLayers.js, and the part that sends the request looks like this:
var postrequest = OpenLayers.Request.POST({
url: "http://localhost/index.php",
data: "success",
headers: {
"Content-Type": "application/x-www-form-urlencoded"
}
});
In PHP, I'm using this code to see, what I'm getting:
<?php
print_r($_POST);
?>
This is what happens:
index.php receives POST request.
FireBug also informs that POST Parameters contain Success, the one that was sent.
print_r($_POST); in index.php just gives this: array() and doesn't change after the POST request from JavaScript.
So the data is sent and received, but my PHP code doesn't somehow understand it, or I'm not using the right PHP function.
Any suggestions, where to look, and what to try?
I think the "data" property needs to be an object containing key/value pairs.
eg:
var postrequest = OpenLayers.Request.POST({
url: "http://localhost/index.php",
data: {
userName: "myUsername",
password: "myPassword"
},
headers: {
"Content-Type": "application/x-www-form-urlencoded"
}
});
If this works when you print_r($_POST) you should see
array("userName" => "myUsername", "password" => "myPassword")
I guess you need include XMLHttpRequest.js library, you can download it from this link
https://github.com/ilinsky/xmlhttprequest

Categories