I'm creating a REST API in PHP. The service login is:
<?php
include_once 'libs/Database.php';
header("Content-Type: application/json; charset=UTF-8");
Database::getPDO();
$myObj = null;
if ( Database::check($_POST['username'], $_POST['password']) ) {
$myObj = array('message' => "Verified", 'success' => true);
} else {
$myObj = array('message' => "Unauthorized", 'username' => $_POST['username'], 'success' => false);
}
$myJSON = json_encode($myObj);
echo $myJSON;
?>
And as you may see, I'm accessing $_POST global variable.
Postman: sending a POST request with header x-www-form-urlenconded and specifying the keys and values, the server does capture such keys.
Ionic: sending a POST request using HttpClient will not work. (The server captures null for both keys, username and password).
This is the code of the provider:
login(user, pass, url) {
const httpOptions = {
headers: new HttpHeaders({
'Content-Type': 'application/x-www-form-urlencoded'
})
};
return this.http.post(url, "username="+user+"&"+"password="+pass, httpOptions);
}
I'm wondering how the body should be formatted, and according to this link should be like I have done (username=user&password=pass). By the way, all parameters are not null when the login function is called, hence, the problem is in the request.
For those of you interested, the answer of the server is:
{message: "Unauthorized", username: null, success: false}
Any help will be appreciated.
I'm copying my comment as an answer 'cause I want to post a photo.
Assuming you're using Angular's HttpClient, try to specify which type you're sending via POST: try to do something as this.http.post<string>(url, 'string', opts);.
I also suggest you to take a look at what you're sending as request via Chrome's Inspector (F12 on windows/linux, Cmd+Options+I on Mac), Network tab.
Obviously you must open it before sending request to be captured by DevTools. If you're debugging directly through the phone, on Windows/Linux you can use Remote Devices tab on Chrome's DevTools, or Safari on Mac.
An example using Chrome's DevTools:
Related
I have a javascript file that captures form input, makes an XMLHTTP POST request with the input, and handles errors. I am currently POSTing to a separate PHP file, as the request requires sensitive API data and needs encoding. From the PHP file, I then send a cURL request to post the form input to the remote URL.
I want to handle errors based on the cURL response, but the XHR errors are different and take precedent over the cURL errors. Are both these requests necessary, or should I only be making either a single XHR or cURL request?
Whether or not both requests are necessary depends on your use case. Since yours sounds as they are indeed necessary, there's absolutely nothing wrong with it.
How you handle server-side errors client-side is also entirely up to you. For example, let's assume this pretty basic XHR handler, which sends some JSON data off to some endpoint and evaluates the response:
var xhr = new XMLHttpRequest();
xhr.open('POST', '/endpoint.php');
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.onload = () => {
const status = xhr.status;
const response = JSON.parse(xhr.responseText);
if (status == 200) {
// Everything's fine
console.log(response.data);
} else {
// Some error occured
console.log(status, response.data);
}
};
xhr.send(JSON.stringify({}));
index.html
The above error handling strategy revolves around the HTTP status code received from the server, so we'll need to make sure they're send according to our needs:
/**
* In case an error occurred, send an error response.
*/
function error(string $message) {
// For properly returning a JSON response, see:
// https://stackoverflow.com/a/62834046/3323348
header("Content-type: application/json; charset=utf-8");
http_response_code(400); // HTTP status code - set to whatever code's appropriate
echo json_encode(['data' => $message]);
}
/**
* Send a response denoting a success.
*/
function success(array $data) {
// For properly returning a JSON response, see:
// https://stackoverflow.com/a/62834046/3323348
header("Content-type: application/json; charset=utf-8");
http_response_code(200);
echo json_encode(['data' => $data]);
}
// For proper error checking on JSON data, see:
// https://stackoverflow.com/a/37847337/3323348
$data = json_decode(file_get_contents('php://input'), true);
// Assume some processing happened. That result is either
// a success, or an error.
$success = mt_rand(0,1);
$success ? success($data) : error('An error occured.');
endpoint.php
Regarding cURL, you could easily change the last two lines to e.g.:
if(curl_errno($ch)) { // Assuming $ch is your cURL handle
error('Curl error: '.curl_error($ch));
}
else {
success($data);
}
Or you adapt the error function - if it would accept an array instead of a simple string, you'd be able to return more complex error data to your JavaScript client:
$curl_error = curl_errno($ch);
if ($curl_error) {
error([
'type' => 'cURL',
'no' => curl_errno($ch),
'message' => curl_error($ch)
]);
}
You don't have to stick with status codes for your error handling, though. You could send a JSON object back with one key denoting some successfully collected data, and one denoting an error if an error occurred. Or whatever suits your needs.
So I have a josn object which has an array of objects which I want to send to a react native app through https but the problem is that I get null in react native
The code of the php :
<?php
class Product {
// Properties
public $title;
public $price;
}
header('Content-Type: application/json');
$ProductList =array();
$aa=$a->{'shopping_results'};
foreach($aa as $y => $y_value) {
$product = new Product();
$product->{'title'} = $y_value ->{'title'};
$product->{'price'} = $y_value ->{'price'};
array_push($ProductList,$product);
}
echo $x=json_encode(array('listx' => $ProductList),JSON_UNESCAPED_UNICODE);// the JSON_UNESCAPED_UNICODE for the Arabic letters
?>
When I try to view the content of this json on the browser this is what I get
https://i.stack.imgur.com/gXT4X.png
The react native code
await fetch(URL, {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
}
// , body: JSON.stringify({ name: "tea" })
})
.then((response) => response.text()) //tried .json() got JSON Parse error: Unexpected EOF
.then((responseJson) => {
console.log(responseJson);//This prints blank
console.log("hi");
this.setState({ output: responseJson });//nothing shows
})
.catch((error) => {
console.error(error);
});
Note: I tried to receive a text from HTTPs request and it worked (The connection is fine)
You need to set HTTP headers, methods in your PHP code so as to accept requests from your react native app (basically I'm telling you to implement REST APIs). If already implemented, just make sure you are giving the correct endpoint in your react-native's fetch URL. And one more thing, when you are trying to retrieve data from the server make sure to set method: 'GET'.
If you're a beginner/ don't have prior knowledge about REST APIs, then here's a reference for you : https://www.positronx.io/create-simple-php-crud-rest-api-with-mysql-php-pdo/ I'm sure it'll give you some basic idea about your need.
i wrote a Simple PHP crud api and i'm getting HTTP_response_code(400) no matter what i do.
in the api a file named create.php is responsible for inserting new items in the database it checks if the data it receives from ajax isn't empty and then proceeds to creation if it's empty it sends an HTTP_response_code(400).
but, no matter what i do it always sends the HTTP_response_code(400) even though the data is not empty.
i thought the problem was coming from ajax first but after debugging i found out that ajax in facts gets the proper data from the form and sends it.
here is my create.php file
$db = $database->getConnection();
$consumable = new consumable($db);
//get json
$json = file_get_contents("php://input");
// get posted data
$data = json_decode($json);
// make sure data is not empty
if(
!empty($data->reference) &&
!empty($data->price) &&
!empty($data->description) &&
!empty($data->category_id) &&
!empty($data->quantity)
){
// set consumable property values
$consumable->reference = $data->reference;
$consumable->price = $data->price;
$consumable->description = $data->description;
$consumable->category_id = $data->category_id;
$consumable->quantity = $data->quantity;
$consumable->created = date('Y-m-d H:i:s');
// create the consumable
if($consumable->create()){
// set response code - 201 created
http_response_code(201);
// tell the user
echo json_encode(array("message" => "consumable was created."));
}
// if unable to create the consumable, tell the user
else{
// set response code - 503 service unavailable
http_response_code(503);
// tell the user
echo json_encode(array("message" => "Unable to create consumable."));
}
}
else{
// tell the user data is incomplete
// set response code - 400 bad request
//http_response_code(400);
// tell the user
echo json_encode(array("message" => "Unable to create consumable. Data is incomplete."));
echo json_encode($json);
}
and here is my ajax:
$(document).on('submit', '#create-consumable-form', function(){
alert("submit");
// get form data
var form=$(this).serializeObject();
var form_data=JSON.stringify(form);
console.log('a',form);
console.log(form_data);
// submit form data to api
$.ajax({
url: "http://localhost:3000/consumable/create.php",
type : "POST",
contentType : 'application/json',
data : form_data,
success : function(result) {
// consumable was created, go back to consumables list
showconsumables();
},
error: function(xhr, resp, text) {
// show error to console
console.log(xhr, resp, text);
}
});
return false;
});
after filling out the form and submitting instead of adding the entry to the database and sending a 201 OK it shows me the following error:
jquery.js:2 OPTIONS http://localhost:3000/consumable/create.php 400 (Bad Request)
send # jquery.js:2
ajax # jquery.js:2
(anonymous) # create-consumables.js:87
dispatch # jquery.js:2
v.handle # jquery.js:2
index.html:1 Access to XMLHttpRequest at 'http://localhost:3000/consumable/create.php' from origin 'http://localhost:5500' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: It does not have HTTP ok status.
and this is the result of my console.log
a {reference: "BT3000", price: "10", quantity: "5", description: "description", category_id: "3"}
create-consumables.js:85 {"reference":"BT3000","price":"10","quantity":"5","description":"description","category_id":"3"}
the weird thing is when i comment the HTTP_response_code(400) line in my create.php file it works perfectly does anyone have any idea of the cause of this behaviour?
Try to put header() in your create.php file:
header("Access-Control-Allow-Origin: *");
header("Content-Type: application/json; charset=UTF-8");
header("Access-Control-Allow-Methods: POST");
header("Access-Control-Max-Age: 3600");
header("Access-Control-Allow-Headers: Content-Type, Access-Control-Allow-Headers, Authorization, X-Requested-With");
json_decode returns null if it cannot decode it. It seems it does just that. Maybe you need to url_decode and/or stripslashes the contents before you can decode it. As Ahmed is saying, try to output the $data variable and the output of the json_decode and file_get_contents("php://input"); and you will see the mistake soon enough.
Also be aware that !empty(0) and !empty(false) returns true. So if your variable has a value which is 0 or false then it will return 400 in this case as well. This is not the issue in your example, but might become an issue later.
the problem was caused by the fact that the content-type in my headers was application/json and i was using postman for testing and i had left it to default content-type which is text
I've a php script who manage the connection of a user. When the connection is accepted by the script, a JSON web token is sent to the web service. The problem is, when I test my connection API with this web service, the script send me nothing without error. However, when i test it with postman, the script send me that token.
Here is my PHP script :
//Now create the TOKEN
$jwt = JWT::encode(
$data,
$secret_key,
$algorithme
);
$unencoded_array = ['jwt' => $jwt, 'admin' => $admin];
//echo "test";
echo json_encode($unencoded_array);
And here is my client call :
$rootScope.Connect = () => {
//Set params to request
var request = Global.url_api+'action=Connection&username='+$scope.username+
'&password='+$scope.pwd+
'&project='+$rootScope.project;
//Ask to the server if credentials is correct
$http.get(request)
.then((response) => {
console.log(response)
}
BUT, when i uncomment this
echo "test";
I receive my token with that string as you can see here :
Any idea ? if you need more information, please don't hesitate to ask.
This is the first time I'm making a post method request from Angular to CodeIgniter rest API.
postUsertask(Userid,TaskName)
{
let body ={
userid:Userid, taskname:TaskName
};
console.log(body);
return this.http.post("http://localhost/ci-abc/api/add_task",JSON.stringify(body) )
.map(res => res.json());
}
API method in codeigniter:
function add_task_post()
{
$obj=json_decode(file_get_contents('php://input'));
$taskname = $obj->taskname;
$userid = $obj->userid;
if (!$taskname || !$userid) {
$this->response("Enter taskname and userid to add", 400);
} else
$result = $this->todo_model->add_task($taskname, $userid);
if ($result === 0) {
$this->response("Task could not be added. Try again.", 404);
} else {
$this->response("success", 200);
}
}
Had to include to access the data
$obj=json_decode(file_get_contents('php://input'));
Because the $this->input->post and $_POST were empty and the data recieved from angular was an object so had to be accessed with -> notation. I am curious that this is not the right and ethical way to do this. Also when I didn't put JSON.stringify it gave me Cross Origin Request blocked error so that's why I put it. How should I make POST and PUT request in angular4 to rest API in CodeIgniter?
How do I get rid of CORS error which doesn't let me call the API method, if I can get rid of CORS error then I could also remove JSON.stringify which will send the data as it is and I believe the data should be accessed via input->post or $_POST.
EDIT 2:
These sort of errors while making POST PUT and DELETE API call.
Cross-Origin Request Blocked: The Same Origin Policy disallows reading
the remote resource at http://localhost/ci-abc/api/del_task?taskid=34.
(Reason: CORS preflight channel did not succeed)
EDIT (Perfect Solution):
Found out that the formdata object approach was deprecated so I just included a header in options and included in the API call http.post method which works fine and is much better solution.
constructor(public http:Http) {
let headers = new Headers();
headers.append('Content-Type', 'application/json');
let options = new RequestOptions({ headers: headers });}
createUser(userName)
{
let body = { username:userName};
return this.http.post("http://localhost/ci-abc/api/create_user",body,this.options)
.map(res => res.json());
}
Deprecated approach (Works but deprecated/not usual practice):
Took few hours but found the solution, I created body as a new formdata object, appended parameters to it as key and their values and it worked fine now I am retrieving through $this->input->post.
let body = new FormData;
body.append('userid', Userid);
body.append('taskname', TaskName);
console.log(body);
return this.http.post("http://localhost/ci-abc/api/add_task",body)
.map(res => res.json());
Using these headers in the constructor of my codeigniters API controller
header("Access-Control-Allow-Origin: *");
header('Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Access-Control-Allow-Origin');
header('Access-Control-Allow-Methods: POST, GET, OPTIONS, PUT, DELETE');
API method:
function add_task_post()
{
$userid = $this->input->post('userid');
$taskname = $this->input->post('taskname');
if (!$taskname || !$userid) {
$this->response("Enter taskname and userid to add", 400);
} else
$result = $this->todo_model->add_task($taskname, $userid);
if ($result === 0) {
$this->response("Task could not be added. Try again.", 404);
} else {
$this->response("success", 200);
}
}