Answer to the exact question
Does the sslcafile option in the client configuration take absolute precedence over the openssl.cafile directive in php.ini?
Yes. When the Zend Http Client is configured with sslcafile (or sslcapath for the stream adapter) the underlying PHP stream wrapper or cURL receives that path directly. PHP never falls back to the openssl.cafile value for that request. The openssl.cafile setting only applies when the client does not supply its own CA file.
In environments where verify_peer is enabled, how does the client behave if the sslcafile is provided but the system‑level CA bundle is missing?
With verify_peer (and verify_host) set to true, the client will attempt to validate the server’s certificate chain against the certificates in the supplied sslcafile only. If that file does not contain a complete chain (root + intermediates) or is unreadable by the web‑server user, the handshake fails with "certificate verify failed". The absence of a system CA bundle is irrelevant because the client never consults it when a custom bundle is present.
Why this matters
The Zend Http Client does not merge the two sources; it simply uses whichever path was supplied last in the request context. This behavior matches the design of PHP’s stream wrapper and cURL: options passed to the wrapper override global defaults.
Practical steps to avoid failures
Verify OpenSSL support in PHP:
php -i | grep -i openssl
Make sure OpenSSL support is enabled and that openssl.cafile is either empty or points to a valid bundle.
Prepare a single PEM bundle that includes the root and any intermediate certificates in the correct order.
Set the client adapter explicitly and provide the CA file path:
// Using the stream adapter
$client = new Zend\Http\Client();
$client->setAdapter('Zend\Http\Client\Adapter\Stream');
$client->setConfig([
'sslcapath' => '/etc/ssl/certs/ca-bundle.pem', // or 'sslcafile'
'sslverifypeer' => true,
'sslverifyhost' => true,
]);
// Using the curl adapter
$client->setAdapter('Zend\Http\Client\Adapter\Curl');
$client->setConfig([
'curloptions' => [CURLOPT_CAINFO => '/etc/ssl/certs/ca-bundle.pem'],
'sslverifypeer' => true,
'sslverifyhost' => true,
]);
Check file permissions: the web‑server user (e.g., www‑data, apache, www‑www) must have read access to the bundle file.
Test the bundle directly with cURL:
curl -v --cacert /etc/ssl/certs/ca-bundle.pem https://your.server
A successful handshake confirms the bundle is valid.
Enable Zend Http Client logging to see the exact error if validation still fails:
$client->setConfig(['log' => true]);
Review the log for "SSL: certificate verify failed" messages.
What to do if the system CA bundle is missing but you rely on it
Do not depend on openssl.cafile when you provide sslcafile. If you need the system bundle for other parts of the application, keep it in php.ini and simply leave the client configuration empty; the client will then use the global setting.
Missing diagnostic detail that could alter the recommendation
Could you confirm which adapter you are using (Stream or Curl)? The exact option names differ between adapters, and a mismatch can silently ignore the CA file you set.