CURLOPT_POSTFIELDS makes a POST. An array would be sent as multipart form data, so encode JSON yourself. CURLOPT_USERPWD handles HTTP Basic authentication.
<?php
$token = ['Authorization: Bearer shop-demo-token'];
foreach ([[[], 1, 2], [$token, 9, 0], [$token, 1, 2]] as [$auth, $id, $qty]) {
$ch = curl_init('http://127.0.0.1:8218/orders');
curl_setopt_array($ch, [CURLOPT_RETURNTRANSFER => true, CURLOPT_HEADER => true,
CURLOPT_POSTFIELDS => json_encode(['product_id' => $id, 'qty' => $qty]),
CURLOPT_HTTPHEADER => ['Content-Type: application/json', ...$auth]]);
$response = curl_exec($ch); // headers, blank line, body
preg_match('/^(Location|WWW-Authenticate): .*$/mi', $response, $header);
echo curl_getinfo($ch, CURLINFO_RESPONSE_CODE), ' ', trim($header[0] ?? '-'), ' ',
substr($response, curl_getinfo($ch, CURLINFO_HEADER_SIZE));
}Output
401 WWW-Authenticate: Bearer {"title":"Missing or wrong token"}
422 - {"title":"Invalid order","errors":{"product_id":"unknown","qty":"1 to 10"}}
201 Location: /orders/5001 {"id":5001,"product_id":1,"qty":2}Each new handle opens its own connection. A share handle from curl_share_init_persistent() (PHP 8.5) outlives the request, so later requests on the same FPM or Apache 129 worker reuse its DNS cache and connections. It refuses cookies, which would leak between users.
<?php
$ch = curl_init('http://127.0.0.1:8218/products/1');
curl_setopt_array($ch, [CURLOPT_RETURNTRANSFER => true,
CURLOPT_SHARE => curl_share_init_persistent([CURL_LOCK_DATA_DNS, CURL_LOCK_DATA_CONNECT])]);
curl_exec($ch);
printf("worker %d: %d new connection(s)\n", getmypid(), curl_getinfo($ch, CURLINFO_NUM_CONNECTS));Output
worker 187725: 1 new connection(s) worker 187725: 0 new connection(s) worker 187725: 0 new connection(s)
With plain curl_share_init(), all three requests connected anew. Apache passes Authorization to $_SERVER only with CGIPassAuth On, and without it every order failed with 401.