Fix PHP Warning: file_get_contents() SSL operation failed โ€” certificate verify failed

intermediate๐Ÿ˜ PHP2026-05-17| PHP 5.6+, PHP 7.x, PHP 8.x on Linux (Ubuntu, Debian, CentOS), macOS, Windows with XAMPP/WAMP; Apache or Nginx with OpenSSL

Error Message

Warning: file_get_contents(): SSL operation failed with code 1. OpenSSL Error messages: error:14090086:SSL routines:ssl3_get_server_certificate:certificate verify failed
#php#file_get_contents#ssl#openssl#https#curl

TL;DR โ€” Quick Fix

PHP can't verify the SSL certificate of the remote server when you call file_get_contents() on an HTTPS URL. Point PHP at a valid CA bundle in php.ini and you're done:

; In php.ini
openssl.cafile=/etc/ssl/certs/ca-certificates.crt

Restart your web server after saving. Need something working right now in a local script? Skip to the stream context approach โ€” but avoid disabling SSL verification in production. Seriously.

The Error

Warning: file_get_contents(): SSL operation failed with code 1. OpenSSL Error messages:
error:14090086:SSL routines:ssl3_get_server_certificate:certificate verify failed

Warning: file_get_contents(): Failed to enable crypto
Warning: file_get_contents(https://example.com/api): failed to open stream: operation failed

PHP throws this when file_get_contents() tries to fetch an HTTPS URL but OpenSSL can't match the remote certificate against any trusted Certificate Authority (CA). A few situations reliably trigger it:

  • Fresh PHP install with no CA bundle configured in php.ini
  • PHP upgraded but openssl.cafile still points to a stale or deleted bundle
  • The target server uses a self-signed or expired certificate
  • macOS, XAMPP, or WAMP โ€” these ship without system CA roots baked into OpenSSL

Fix 1 โ€” Point php.ini at the CA Bundle (Recommended)

Start by confirming the CA bundle actually exists on your system:

# Debian / Ubuntu
ls /etc/ssl/certs/ca-certificates.crt

# CentOS / RHEL / Fedora
ls /etc/pki/tls/certs/ca-bundle.crt

# macOS (after `brew install openssl`)
ls /usr/local/etc/openssl/cert.pem

Find your active php.ini with php --ini, then add these two lines under the [openssl] section:

[openssl]
openssl.cafile=/etc/ssl/certs/ca-certificates.crt
curl.cainfo=/etc/ssl/certs/ca-certificates.crt

Both lines matter. The first covers file_get_contents(); the second covers the curl extension, which you'll likely use too. Restart the server:

# Apache
sudo systemctl restart apache2   # or httpd

# Nginx + PHP-FPM
sudo systemctl restart php8.2-fpm
sudo systemctl restart nginx

Fix 2 โ€” Switch to curl Instead of file_get_contents

Honestly, curl is the better tool for this job anyway. It gives you explicit control over timeouts, redirects, and SSL โ€” plus readable error messages when something goes wrong:

<?php
function https_get(string $url): string|false {
    $ch = curl_init($url);
    curl_setopt_array($ch, [
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_FOLLOWLOCATION => true,
        CURLOPT_CAINFO         => '/etc/ssl/certs/ca-certificates.crt',
        CURLOPT_SSL_VERIFYPEER => true,
        CURLOPT_SSL_VERIFYHOST => 2,
        CURLOPT_TIMEOUT        => 15,
    ]);
    $response = curl_exec($ch);
    if (curl_errno($ch)) {
        error_log('curl error: ' . curl_error($ch));
    }
    curl_close($ch);
    return $response;
}

$data = https_get('https://example.com/api/data');

Notice CURLOPT_SSL_VERIFYHOST => 2 โ€” that's the correct value (not true, not 1). Value 2 tells curl to check that the certificate's Common Name actually matches the hostname you're connecting to.

Fix 3 โ€” Download a Fresh CA Bundle (XAMPP / WAMP / macOS)

Windows and macOS dev stacks often ship without any system CA roots. The fix is a one-time download of the Mozilla CA bundle, maintained by the curl project:

# Download cacert.pem
curl -o /path/to/cacert.pem https://curl.se/ca/cacert.pem

Then wire it up in php.ini:

openssl.cafile=C:\xampp\php\extras\ssl\cacert.pem
curl.cainfo=C:\xampp\php\extras\ssl\cacert.pem

Restart Apache from the XAMPP control panel. The bundle is ~200 KB and covers all major public CAs.

Fix 4 โ€” Pass a Stream Context (Per-Request CA Path)

No access to php.ini? Set the CA bundle directly in the call:

<?php
$context = stream_context_create([
    'ssl' => [
        'verify_peer'       => true,
        'verify_peer_name'  => true,
        'cafile'            => '/etc/ssl/certs/ca-certificates.crt',
    ],
]);

$result = file_get_contents('https://example.com/api', false, $context);

This is handy for shared hosting environments where you can't edit php.ini globally. Keep verification enabled โ€” just point it at the right bundle.

Last Resort โ€” Disable SSL Verification (Dev Only)

Use this only on your local machine. It strips all certificate protection and opens you up to man-in-the-middle attacks. Never deploy this to production:

<?php
// โš ๏ธ DEVELOPMENT ONLY โ€” exposes you to MITM attacks
$context = stream_context_create([
    'ssl' => [
        'verify_peer'      => false,
        'verify_peer_name' => false,
    ],
]);

$result = file_get_contents('https://example.com/api', false, $context);

Special Case โ€” Self-Signed Certificate

Internal services often use self-signed certs. Don't disable verification โ€” just point PHP at that specific cert instead of the system CA bundle:

<?php
$context = stream_context_create([
    'ssl' => [
        'verify_peer'       => true,
        'verify_peer_name'  => true,
        'cafile'            => '/path/to/self-signed-cert.pem',
    ],
]);

$result = file_get_contents('https://internal-service.local/api', false, $context);

Export the cert from your browser or ask whoever runs the internal service for the .pem file.

Verify the Fix

Quick sanity check from the terminal:

# Test via CLI
php -r "echo file_get_contents('https://www.google.com') ? 'OK' : 'FAILED';"

If that still fails, check what CA file PHP is actually reading:

php -r "print_r(openssl_get_cert_locations());"

Look at default_cert_file. Blank or pointing to a missing path? That's your problem. Set openssl.cafile in php.ini to a path that exists.

After restarting the server, confirm PHP loaded the updated settings:

php -i | grep -E 'cafile|cainfo'

Update CA Certificates on the OS

Sometimes the bundle itself is outdated โ€” especially on servers that haven't been touched in a while. Reinstall it from the OS package manager:

# Debian / Ubuntu
sudo apt-get install --reinstall ca-certificates
sudo update-ca-certificates
# CentOS / RHEL
sudo yum reinstall ca-certificates
sudo update-ca-trust

Related Error Notes