Issue
I recently migrated my code which was completely functional on the previous server but on the new server, POST requests are not working but GET requests work fine. Also, the issue seems to occur when i send POST requests to endpoints on the same server. When i send POST requests to external servers, the code works well. Upon debugging, the data being sent via (POST) is not being received on the endpoint and data is being sent via cURL.
I am using this function to callAPI endpoints:
function CallAPI($method = "GET", $url = "", $data = false, $credentials = "") {
try {
if (isset($url) && !empty($url)) {
$curl = curl_init();
curl_setopt($curl, CURLOPT_CUSTOMREQUEST, $method);
if (!empty($credentials)) {
curl_setopt($curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
curl_setopt($curl, CURLOPT_USERPWD, $credentials);
}
if ($method === "POST" || $method === "PUT") {
curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
curl_setopt($curl, CURLOPT_HTTPHEADER, ['Content-Type: application/x-www-form-urlencoded']);
} else if ($method === "GET") {
$url = sprintf("%s?%s", $url, http_build_query($data));
}
curl_setopt($curl, CURLOPT_TIMEOUT, 60);
curl_setopt($curl, CURLOPT_URL, $url);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true);
$response = curl_exec($curl);
if ($response === false) {
throw new Exception("cURL error: " . curl_error($curl));
}
$httpCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
curl_close($curl);
if ($httpCode < 200 || $httpCode >= 300) {
throw new Exception("HTTP error: " . $httpCode);
}
return $response;
} else {
return false;
}
} catch (Exception $e) {
// error_log("Error in CallAPI: " . $e->getMessage());
return false;
}
}
For the purpose of debugging, i have created a simple script to simply output the data being sent over:
<?php
$response['status'] = "OK";
$data = !empty($_POST) ? $_POST : file_get_contents("php://input");
if (!empty($data)) {
$phpArray = json_decode($data, true);
$response['message'] = 'Data received successfully';
$response['data'] = $phpArray;
}
$response['status'] = 'Endpoint successfully reached.';
$response['method'] = $_SERVER['REQUEST_METHOD'];
$response['rawdata'] = $data;
echo json_encode($response);
exit;
?>
Server Details
Previous Server:
CentOS 8
cPanel WHM
PHP 8.1
New Server:
CentOS 8
CyberPanel
PHP 8.1
What i have tried:
- Checked if PHP is properly installed.
- Checked it cURL and extensions have been properly installed.
- Tried sending POST requests to new server from other servers.
EDIT Upon further debugging and investigation, It turns out that the issue is with the data being sent over which has been unchange before, during and after migration. Here is a sample of the data:
$msg = "<h3>Hello ".ucwords($name).",</h3> We received your quotation request.<br/>Thank you for your interest in our services.<br/>Your quotation has been generated and attached to this email.<br/>We look forward to providing you with our services.<br/><hr/><small>Please note that a 60% upfront payment may be required before services are provided.</small><br/><small>Please note that this message is an automated response.</small><br/><p><p>You may need to download a PDF viewer program such as Adobe PDF Reader in order to view the attached document or you may simply download the document on your device and open the file using your browser.</p><strong><h5>Regards</h5>Support Team</strong><br/></p>";
$invoice = array(
"action" => "addQuote",
"type" => "document",
"ipaddress" => getIpAddress(),
"customer" => array(
"name" => $name,
"email" => $email,
"phone" => alphaNumeric($phone)
),
"products" => $cart,
"document" => array(
"name" => "quotation",
"date" => "",
"currency" => "",
"link" => ""
),
"mail" => array(
"subject" => $subject,
"to" => $email,
"bcc" => $info,
"text" => $msg,
"from" => $support,
"entity" => "Example Entity"
),
"sms" => array(
"to" => $phone,
"text" => "Hi ".ucwords($name).", Please find your quotation for requested services at $email. Thank you for your business.",
"token" => "f4eb27cea7255cea4d1ffabf593372e8"
),
"entity" => "5d14995453d10a56bd7c1d68"
);
$argv = json_encode(array("data" => $invoice));
$document = CallAPI("POST", "https://api.endpoint.com/", $argv);
print_r($document);
I started by using simple string data to see if POST and cURL works and i got a response from the server.
Then i also tried to comment out part of the $invoice
variable properties. I noticed that when i comment out either the msg
in the mail
property or text
in the sms
property, like just commenting out either of those properties and the server will send back a response.
Realization: Upon logging print_r(strlen($argv));
i realize that my code only runs and returns a response if the length is less than or equal to 1024
Leads me to question if:
- There is an issue with
json_encode
/json_decode
. (I also tried a combination ofhtmlentities
andjson_encode
to no success) - There is a limit to the data that can be posted (I tried increasing
post_max_size
inphp.ini
)
Has anyone else encountered this? Is there any way to solve this?
Solution
I finally found the answer and the difference in the servers to be that on the new server, when i POST request with a body, the client may include the "Expect: 100-continue" header. This header tells the server to respond with a "100 Continue" status before sending the actual request body.
To fix the issue, I included curl_setopt($curl, CURLOPT_HTTPHEADER, array('Expect:'));
in my CallAPI function.
Here is my updated CallAPI function:
function CallAPI($method = "GET", $url = "", $data = false, $credentials = "") {
try {
if (isset($url) && !empty($url)) {
$curl = curl_init();
curl_setopt($curl, CURLOPT_CUSTOMREQUEST, $method);
if (!empty($credentials)) {
curl_setopt($curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
curl_setopt($curl, CURLOPT_USERPWD, $credentials);
}
if ($method === "POST" || $method === "PUT") {
curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
} else if ($method === "GET") {
$url = sprintf("%s?%s", $url, http_build_query($data));
}
curl_setopt($curl, CURLOPT_TIMEOUT, 60);
curl_setopt($curl, CURLOPT_URL, $url);
curl_setopt($curl, CURLOPT_HTTPHEADER, array('Expect:'));
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true);
$response = curl_exec($curl);
if ($response === false) {
throw new Exception("cURL error: " . curl_error($curl));
}
$httpCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
curl_close($curl);
if ($httpCode < 200 || $httpCode >= 300) {
throw new Exception("HTTP error: " . $httpCode);
}
return $response;
} else {
return false;
}
} catch (Exception $e) {
// error_log("Error in CallAPI: " . $e->getMessage());
return false;
}
}
Answered By - Quatban Taco Answer Checked By - Dawn Plyler (WPSolving Volunteer)