DEV3 Technologies home

DEV3 Developer Forum

How do I send a JSON POST request with cURL in PHP and handle errors?

PHP helpSolved0 views
dev3 ·

I need to call a REST API from PHP with a JSON body and a Bearer token, read the response, and handle timeouts or non-200 responses. My attempts return an empty string or false.

#php#curl#api

0

1 reply

dev3 · Accepted answer

Use curl_init with the right options, check both transport errors and HTTP status.

function apiPost(string $url, array $payload, string $token): array
{
    $ch = curl_init($url);
    curl_setopt_array($ch, [
        CURLOPT_POST           => true,
        CURLOPT_POSTFIELDS     => json_encode($payload, JSON_THROW_ON_ERROR),
        CURLOPT_RETURNTRANSFER => true,          // return body instead of printing it
        CURLOPT_HTTPHEADER     => [
            'Content-Type: application/json',
            'Accept: application/json',
            'Authorization: Bearer ' . $token,
        ],
        CURLOPT_CONNECTTIMEOUT => 5,
        CURLOPT_TIMEOUT        => 20,
        CURLOPT_FOLLOWLOCATION => false,
    ]);

    $body = curl_exec($ch);

    if ($body === false) {
        $err = curl_error($ch);
        curl_close($ch);
        throw new RuntimeException("cURL error: $err");
    }

    $status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
    curl_close($ch);

    $data = json_decode($body, true, 512, JSON_THROW_ON_ERROR);

    if ($status >= 400) {
        throw new RuntimeException("API returned HTTP $status: " . ($data['message'] ?? $body));
    }
    return $data;
}

Why you got false or empty output

  • Without CURLOPT_RETURNTRANSFER the response is printed and curl_exec returns true.
  • TLS problems: "SSL certificate problem: unable to get local issuer certificate" means your PHP has no CA bundle. Set curl.cainfo in php.ini to a current cacert.pem. Do not disable verification (CURLOPT_SSL_VERIFYPEER => false) in production, it removes the protection of HTTPS.
  • Sending an array to CURLOPT_POSTFIELDS posts multipart/form-data, not JSON. Encode it yourself.
  • Missing Content-Type: application/json makes many APIs ignore the body.
  • Redirects: a 301/302 from HTTP to HTTPS turns a POST into a GET if followed; use the final HTTPS URL.

Pitfalls

  • Always set timeouts. The default is no timeout and a slow API hangs your PHP workers.
  • Retry only idempotent requests, with exponential backoff.
  • For production code, consider Guzzle or Symfony HttpClient (composer require guzzlehttp/guzzle), which wrap all of this.

Convert a command line request to PHP with the curl to code tool.

0

Your reply

Every post is reviewed by DEV3 before it appears. Usually reviewed within 24 hours.

Markdown supported. Use ``` for code blocks. Images are not allowed.