Resolution
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.
Implementation Steps
- Obtain a Trusted Bundle: Download the current CA bundle from a trusted source, such as the curl project (
curl.se/ca/cacert.pem).
- Place the File: Move
cacert.pem to a directory accessible by the PHP process (e.g., /etc/ssl/certs/php/ or a dedicated project config folder).
- Configure php.ini: Set the
openssl.cafile directive to the absolute path of the file:
openssl.cafile="/path/to/cacert.pem"
- Restart Services: Restart your web server (Apache/Nginx) or PHP-FPM process to apply the changes.
Prioritization and Logic
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.
- System Defaults: If neither directive is configured in
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).
Verification
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.
Diagnostic Note
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.