Adding http response code in php breaks axios - javascript

After adding http response code in the login file axios is returning these errors even if the login email and password are correct and the catch block isn't executed I get these errors. If I remove the http_response_code(400) it will work and return the user or the message with 200 ok but I don't want that.
How do i fix it? thanks in advance.
Access to XMLHttpRequest at 'http://localhost/classroom-api/api/user/login.php' from origin 'http://localhost:3000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: It does not have HTTP ok status.
POST http://localhost/classroom-api/api/user/login.php net::ERR_FAILED
login.php
<?php
// Headers
header('Access-Control-Allow-Origin: *');
header('Content-Type: application/json');
header('Access-Control-Allow-Methods: POST');
header('Access-Control-Allow-Headers: Access-Control-Allow-Headers,Content-Type,Access-Control-Allow-Methods, Authorization, X-Requested-With');
require_once '../../vendor/autoload.php';
use Firebase\JWT\JWT;
require_once '../../config/Database.php';
require_once '../../models/User.php';
// Connect db
$database = new Database();
$db = $database->connect();
$user = new User($db);
try {
// Get posted data
$data = json_decode(file_get_contents("php://input"));
if(empty($data->email) || empty($data->password)) {
throw new Exception("Please enter all fields");
}
$user->email = $data->email;
$user->password = $data->password;
if ($user->login()) {
// Create token
$key = 'ajdZiWodDaAs1123';
$iat = time();
$payload = [
'iss' => 'localhost',
'aud' => 'localhost',
'iat' => $iat,
'nbf' => $iat,
'exp' => $iat + 259200000, // 3 days
'data' => [
"id" => $user->id
]
];
$token = JWT::encode($payload, $key, 'HS256');
echo json_encode(
array(
"id" => $user->id,
"full_name" => $user->fname ." ".$user->lname,
"email" => $user->email,
"token" => $token
)
);
} else {
throw new Exception("Invalid credentials");
}
} catch (Exception $e) {
http_response_code(400);
echo json_encode(
array('message' => $e->getMessage())
);
}
?>
axios
import axios from 'axios';
const base_url = 'http://localhost/classroom-api';
const route = '/api/user';
export const login = async (userData) => {
const res = await axios.post(base_url + route + '/login.php', userData);
console.log(res);
};
although it does work in postman

Browsers will first send an OPTIONS request to check for CORS headers.
Add this right after the headers:
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS')
exit('ok');

Related

How to send a response in PHP to a request made through the javascript fetch API?

I have an application in PHP, which receives data from the client that is in another domain. Data arrives from the fetch API via the POST method, but PHP doesn't send a response to the fetch API.
foo.com/endpoint.php:
<?php
include_once('database/connection.php');
header('Content-Type: application/json');
$ip = $_POST["ip"];
$city = $_POST["city"];
$state = $_POST["state"];
$country = $_POST["country"];
$category = $_POST["category"];
// Checking if the req ip already have registered other req
$ip_query = "SELECT * FROM registers WHERE `ip` = '$ip'";
$ip_result = mysqli_query($conn, $ip_query);
$ip_check = mysqli_fetch_assoc($ip_result);
if (!$ip_check) {
// registering data after validation
$new_query = "INSERT INTO `registers` (`ip`, `city`, `state`, `country`, `category`, `created`) VALUES ('$ip', '$city', '$state', '$country', '$category', '2022-07-21 00:00:01')";
$new_create = mysqli_query($conn, $new_query);
$result = array(
'ok' => true,
'status' => 200
);
// sending response
http_response_code(200);
echo json_encode($result);
} else {
// sending response if already registered
http_response_code(503);
}
Client side fetch code:
fetch(this.url, {
method: 'POST',
mode: 'no-cors',
body: this.getFormValues(),
headers: {
"Accept": "application/json",
'Content-Type': 'application/json'
}
})
.then(resp => resp.json())
.then(data => {
console.log(data)
if (data.ok) {
this.Metrics.setSent()
} else {
throw Error(r.statusText)
}
})
.then(() => {
this.Metrics.setSent()
this.Metrics.dismiss()
})
.catch(erro => {
console.log("Erro: ",erro)
this.Metrics.dismiss()
});
It's all right about storing data, my problem is just sending the response :(
PHP does not parse the POST body into JSON automatically. To fix this, you have to add json_decode() to your code like this:
$ip = json_decode($_POST, true)["ip"];
I hadn't noticed that when making a request using the "no-cors" mode i'd get an opaque response.
I just added the code below to the beginning of my PHP file, changed the fetch mode to "cors" and everything worked as it was supposed to work:
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept, Authorization');
header("Access-Control-Allow-Credentials: true");
$method = $_SERVER['REQUEST_METHOD'];
if ($method == "OPTIONS") {
header('Access-Control-Allow-Origin: *');
header("Access-Control-Allow-Headers: X-API-KEY, Origin, X-Requested-With, Content-Type, Accept, Access-Control-Request-Method,Access-Control-Request-Headers, Authorization") ;
header("HTTP/1.1 200 OK");
die();
}
I made the adaptations suggested by #brrrrrrr and updated the queries to prevent SQL injections.
Thx everyone.

Fetch API Post request fails with "Request Failed SyntaxError: Unexpected end of JSON input"

Here is my GET request which works:
function getTodos() {
fetch(window.location.href + 'api/todo')
.then(response => response.json())
.then(json => drawTodos(json))
.catch(error => showToastMessage('Failed to retrieve todos...'));
}
But now I am trying to do a POST request but it fails
todo as shown in console.log
{
"id": "ghCWaYWQTh",
"title": "aaa",
"description": "bbb",
"done": false
}
function postTodo(todo) {
let options = {
method : 'POST',
headers : {
"Content-type": "application/json"
},
body : JSON.stringify(todo)
};
console.log(options);
fetch(window.location.href + 'api/todo',options)
.then(response => response.json()) // convert to json
.then(json => console.log(json)) //print data to console
.catch(err => console.log('Request Failed', err)); // Catch errors
console.log(todo);
}
I cannot see a syntax error in my options variable?
-- the backend is in PHP --
I cannot see a syntax error in my options variable?
-- the backend is in PHP the get request works the post fails --
$requestType = $_SERVER['REQUEST_METHOD'];
$body = file_get_contents('php://input');
$pathCount = count($path);
require_once "dbconfig.php";
switch ($requestType) {
case 'GET':
$query = "select * from todos";
$result = mysqli_query($conn, $query);
$todos = array();
while($todo = mysqli_fetch_assoc($result)) {
$todos[] = $todo;
}
echo json_encode($todos);
break;
case 'POST':
$data = json_decode($body);
$id = $data->id;
$title = $data->title;
$description = $data->description;
$done = $data->done;
$query = "INSERT INTO todos(id, title, description, done)
VALUES ('" . $id . "', '" . $title . "', '" . $description . "', " . $done . ")";
// echo $query;
if (mysqli_query($conn, $query) or die("Insert Query Failed")) {
echo json_encode(array("message" => "Todo Inserted Successfully", "status" => true));
} else {
echo json_encode(array("message" => "Failed ToDo Not Inserted ", "status" => false));
}
break;
default:
http_response_code(501);
die();
break;
This POST works with Postman, but not from Javascript
Your error is throwed from this
.then(response => response.json()) // convert to json
Because your response from BE API is 500 and the body of response can not be convert to Json

Why is axios not sending the correct post data?

Why is PHP saying "undefined index request"? The json format looks completely correct to me.
let json = JSON.stringify(
{ request: "getUser" },
{ username: "test" }
);
const response = await axios.post('http://localhost/projects/serverFiles/index.php', json);
My PHP
<?php
ini_set("log_errors", 1);
header('Access-Control-Allow-Origin: *');
header('Content-Type: application/json');
echo print_r($_POST["request"]);
?>

Integrate Postman code into webpage. Javascript fetch client side, php server side

I've built a backend that inserts and reads contents from a database with PHP and MySQLi. I've setup the PHP as REST API endpoints and can GET and POST correctly using Postman. I'm trying to create a client side endpoint to send the API requests but can't figure out how to correctly integrate the code from Postman into the client side.
This is the server side endpoint to GET from the database:
<?php
include_once('config.php');
$task = isset($_GET['task']) ? mysqli_real_escape_string($conn, $_GET['task']) : "";
$sql = "SELECT * FROM `my_to_do_db`.`my_to_do_tb` WHERE task='{$task}';";
$get_data_query = mysqli_query($conn, $sql) or die(mysqli_error($conn));
if(mysqli_num_rows($get_data_query)!=0){
$result = array();
while($r = mysqli_fetch_array($get_data_query)){
extract($r);
$result[] = array("Task" => $task, "Date" => $date, 'Priority' => $priority);
}
$json = array("status" => 1, "info" => $result);
}
else{
$json = array("status" => 0, "error" => "To-Do not found!");
}
#mysqli_close($conn);
// Set Content-type to JSON
header('Content-type: application/json');
echo json_encode($json);
It works correctly when I GET with Postman. Here is the code Postman exports when I click "code" (Javascript fetch):
var urlencoded = new URLSearchParams();
var requestOptions = {
method: 'GET',
body: urlencoded,
redirect: 'follow'
};
fetch("http://localhost/endPointTest/info.php?task=Build API CRUD app", requestOptions)
.then(response => response.text())
.then(result => console.log(result))
.catch(error => console.log('error', error));
Here's how I've been trying to integrate it into a client side page:
<!DOCTYPE html>
<html>
<head>
<title>Get Info API client side</title>
</head>
<body>
<h3 class="displayData"></h3>
<button type="submit" id="getData">Submit</button>
<script type="text/javascript">
const displayData = document.querySelector('.displayData')
document.getElementById('getData').addEventListener
('click', getData);
var urlencoded = new URLSearchParams();
var requestOptions = {
method: 'GET',
body: urlencoded,
redirect: 'follow'
};
function getData(){
fetch("http://localhost/endPointTest/info.php?task=Do some stuff", requestOptions)
.then(response => {
return response.json()
})
.then(data => {
console.log(data)
displayData.innerHTML = data
})
}
</script>
</body>
</html>
My question is basically: how can I integrate the code from Postman into real world pages?
It turns out the problem was that Postman is for testing and doesn't work like a browser. CORS isn't an issue with Postman but it is for a browser, after I added the needed header to the PHP page the API was able to connect.

Decompress GZIP string response from a PHP server in NodeJS

I have an existing PHP code that is doing a curl request to a 3rd-party PHP server.
The 3rd-party server returns a GZIP string.
In PHP, I can use gzdecode to decode the gzip string.
How can I do it in NodeJS/Javascript? I tried using decompress-response with no avail.
Also tried using got instead of request, enabled auto-decompress, also doesn't work.
Edit: Also tried zlib and pako, also doesn't work.
Sample Code [ PHP ]
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_URL => $params,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 3000000,
CURLOPT_ENCODING => '',
CURLOPT_CUSTOMREQUEST => "GET",
));
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo false;
} else {
$response = gzdecode($response);
echo $response;
}
This is the solution that works for me.
I used got instead of axios because I can't get it to work there.
I set my request options:
const requestOptions = {
encoding: null, // this is important
headers: {
"Accept-Encoding": "gzip",
}
...
};
Don't forget that encoding: null line, because without that, the response will be automatically converted to a string. ( We need a buffer to make this work )
Then I created a function like this to handle my request:
const zlib = require("zlib");
async function performRequest(url, options) {
try {
const response = await got(url, options);
if (response.headers["content-encoding"] === "gzip") {
const body = response.body;
try {
const dezziped = zlib.gunzipSync(response.body);
response.body = JSON.parse(dezziped.toString());
} catch (error) {
response.body = body;
}
}
return response.body;
} catch (error) {
return error;
}
}
Note: This is a synchronous operation, you can use gunzip instead if you want to do the async way.

Categories