TL;DR — 素早い修正
PHPがfile_get_contents()でHTTPS URLを呼び出す際、リモートサーバーのSSL証明書を検証できない状態です。php.iniで有効なCAバンドルをPHPに指定すれば解決します:
; php.ini に記述
openssl.cafile=/etc/ssl/certs/ca-certificates.crt
保存後にWebサーバーを再起動してください。ローカルスクリプトで今すぐ動かす必要がある場合は、ストリームコンテキストのアプローチに進んでください。ただし、本番環境でSSL検証を無効にするのは避けてください。本当に危険です。
エラーの内容
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がfile_get_contents()でHTTPS URLを取得しようとした際、OpenSSLがリモート証明書を信頼された認証局(CA)と照合できない場合にこのエラーが発生します。主に以下の状況で起きます:
php.iniにCAバンドルが設定されていない、PHPを新規インストールした直後- PHPをアップグレードしたが、
openssl.cafileが古いまたは削除されたバンドルを指している - 対象サーバーが自己署名証明書または期限切れの証明書を使用している
- macOS、XAMPP、またはWAMP — これらはOpenSSLにシステムCAルートが組み込まれていない状態で配布される
修正1 — php.ini でCAバンドルを指定する(推奨)
まず、CAバンドルがシステムに実際に存在するか確認します:
# Debian / Ubuntu
ls /etc/ssl/certs/ca-certificates.crt
# CentOS / RHEL / Fedora
ls /etc/pki/tls/certs/ca-bundle.crt
# macOS (`brew install openssl` 実行後)
ls /usr/local/etc/openssl/cert.pem
php --iniで使用中のphp.iniを確認し、[openssl]セクションに以下の2行を追加します:
[openssl]
openssl.cafile=/etc/ssl/certs/ca-certificates.crt
curl.cainfo=/etc/ssl/certs/ca-certificates.crt
両方の行が必要です。1行目はfile_get_contents()に、2行目はcurl拡張モジュールに対応します。サーバーを再起動してください:
# Apache
sudo systemctl restart apache2 # または httpd
# Nginx + PHP-FPM
sudo systemctl restart php8.2-fpm
sudo systemctl restart nginx
修正2 — file_get_contents の代わりに curl を使う
正直なところ、この用途にはcurlの方が適しています。タイムアウト、リダイレクト、SSLを明示的に制御でき、問題が発生した際のエラーメッセージも読みやすいです:
<?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');
CURLOPT_SSL_VERIFYHOST => 2に注目してください — これが正しい値です(trueでも1でもありません)。値2は、証明書のCommon Nameが接続先のホスト名と実際に一致するかをcurlが確認するよう指定します。
修正3 — 新しいCAバンドルをダウンロードする(XAMPP / WAMP / macOS)
WindowsとmacOSの開発環境はシステムCAルートなしで配布されることが多いです。curlプロジェクトが管理するMozilla CAバンドルを一度ダウンロードするだけで解決します:
# cacert.pem をダウンロード
curl -o /path/to/cacert.pem https://curl.se/ca/cacert.pem
次にphp.iniで設定します:
openssl.cafile=C:\xampp\php\extras\ssl\cacert.pem
curl.cainfo=C:\xampp\php\extras\ssl\cacert.pem
XAMPPコントロールパネルからApacheを再起動してください。バンドルは約200 KBで、主要なパブリックCAをすべてカバーしています。
修正4 — ストリームコンテキストを使う(リクエストごとのCAパス指定)
php.iniにアクセスできない場合は、呼び出し時に直接CAバンドルを指定します:
<?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);
これはphp.iniをグローバルに編集できない共有ホスティング環境で便利です。検証は有効のまま — 正しいバンドルを指定するだけです。
最終手段 — SSL検証を無効にする(開発環境限定)
ローカルマシンのみで使用してください。これにより証明書の保護がすべて取り除かれ、中間者攻撃の危険にさらされます。本番環境には絶対にデプロイしないでください:
<?php
// ⚠️ 開発環境限定 — MITM攻撃のリスクあり
$context = stream_context_create([
'ssl' => [
'verify_peer' => false,
'verify_peer_name' => false,
],
]);
$result = file_get_contents('https://example.com/api', false, $context);
特殊ケース — 自己署名証明書
内部サービスでは自己署名証明書がよく使われます。検証を無効にするのではなく、システムCAバンドルの代わりにその特定の証明書をPHPに指定してください:
<?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);
ブラウザから証明書をエクスポートするか、内部サービスの管理者に.pemファイルを依頼してください。
修正の確認
ターミナルから簡単なサニティチェックを行います:
# CLIでテスト
php -r "echo file_get_contents('https://www.google.com') ? 'OK' : 'FAILED';"
それでも失敗する場合は、PHPが実際に読み込んでいるCAファイルを確認します:
php -r "print_r(openssl_get_cert_locations());"
default_cert_fileを確認してください。空白または存在しないパスを指している場合、それが原因です。php.iniのopenssl.cafileを実際に存在するパスに設定してください。
サーバーを再起動した後、PHPが更新された設定を読み込んでいるか確認します:
php -i | grep -E 'cafile|cainfo'
OS上のCA証明書を更新する
バンドル自体が古い場合もあります — 特にしばらく手が付けられていないサーバーでよく起こります。OSのパッケージマネージャーから再インストールしてください:
# Debian / Ubuntu
sudo apt-get install --reinstall ca-certificates
sudo update-ca-certificates
# CentOS / RHEL
sudo yum reinstall ca-certificates
sudo update-ca-trust

