SSL certificate problem: unable to get local issuer certificate in PHP OpenSSL
0 reputation · 02 Nov 2020, 12:51 UTC
0 reputation · 02 Nov 2020, 12:51 UTC
PHP utilizes the OpenSSL extension to validate certificates during TLS handshakes for HTTPS requests. When the underlying library cannot locate a trusted root CA bundle, the system triggers a validation failure.
The php.ini configuration provides openssl.cafile and openssl.capath to define these trust stores. However, there is often a discrepancy between the default CA paths used by the operating system's OpenSSL installation and the paths recognized by the PHP runtime environment, particularly when deploying across different OS distributions.
Given these configuration requirements, what is the recommended method for ensuring consistent CA bundle resolution without hardcoding OS-specific paths? How does PHP prioritize the openssl.cafile directive relative to the system-level OpenSSL defaults?
To resolve the "unable to get local issuer certificate" error without hardcoding OS-specific paths, the recommended method is to bundle a trusted CA certificate file (such as cacert.pem) within your project or a known application directory and reference it via an absolute path in the php.ini configuration.
curl.se/ca/cacert.pem).cacert.pem to a directory accessible by the PHP process (e.g., /etc/ssl/certs/php/ or a dedicated project config folder).openssl.cafile directive to the absolute path of the file:
openssl.cafile="/path/to/cacert.pem"
PHP's OpenSSL extension follows a specific hierarchy when searching for root certificates to validate a TLS handshake. The prioritization generally functions as follows:
openssl.cafile: This directive takes the highest priority. If a valid path is provided here, PHP uses this specific file and ignores other sources.openssl.capath: If cafile is not set, PHP looks for a directory containing multiple certificate files as specified in this directive.php.ini, the OpenSSL extension falls back to the default certificate store compiled into the system's OpenSSL library (which varies significantly between Windows, macOS, and Linux distributions).To verify that the configuration is active, run the following command in your terminal:
php -i | grep openssl.cafile
If the output matches your configured path, the runtime is correctly pointing to the bundle. You can further verify by attempting a file_get_contents('https://google.com') call in a script; a lack of warnings indicates successful validation.
Are you using the cURL extension for these requests? If so, you may also need to set curl.cainfo in php.ini, as cURL sometimes ignores the general OpenSSL settings depending on the PHP version and build.
Use comments to ask for clarification. Post a solution as an answer.
34,775 reputation · 02 Nov 2020, 23:56 UTC
While openssl.cafile and openssl.capath set global defaults, you can supply a custom bundle on a per‑request basis. Use stream_context_create for file_get_contents or curl_setopt with CURLOPT_CAINFO. This technique is handy for CI pipelines or when you need to trust a private CA without touching php.ini.
$ctx = stream_context_create([
'ssl' => [
'verify_peer' => true,
'cafile' => '/tmp/custom_ca.pem',
],
]);
file_get_contents('https://example.com', false, $ctx);
After changing openssl.cafile, verify the effective path with phpinfo() or by inspecting openssl_get_cert_chain() output. Remember that a PHP SAPI restart is required for php.ini changes to take effect.