在 PHP 開發中,使用 file_get_contents 直接讀取 HTTPS 網址時,常遇到 failed to open stream: Invalid argument 或 SSL operation failed 錯誤。本文提供兩種經驗證的解決方案,並深度解析底層原理,幫助你徹底搞定 HTTPS 請求問題。
Warning: file_get_contents(): failed to open stream: Invalid argument in ...
Warning: file_get_contents(): SSL operation failed with code 1...
根本原因:PHP 的 OpenSSL 擴展未啟用,或憑證驗證失敗(自簽名憑證、憑證鏈不全、CN 不匹配等)。
; 找到並取消註釋
extension=php_openssl.dll ; Windows
extension=openssl.so ; Linux/macOS
# Apache
sudo systemctl restart apache2
# 或 Nginx + PHP-FPM
sudo systemctl restart php-fpm
sudo a2enmod ssl
sudo systemctl restart apache2
優點:原生函數直用,支援流上下文精細控制。
缺點:需服務器權限,共享主機可能無法操作。
cURL 內建 OpenSSL,且提供豐富的 SSL 控制選項,是最通用的替代方案:
<?php
/**
* 通用 HTTPS 獲取函數(支援自簽名憑證、超時控制、Header 自定義)
*/
function getHttpsContent(string $url, array $options = []): string|false {
$ch = curl_init();
$defaultOpts = [
CURLOPT_URL => $url,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_SSL_VERIFYPEER => false, // 生產環境建議 true 並配合 CURLOPT_CAINFO
CURLOPT_SSL_VERIFYHOST => false, // 生產環境建議 2
CURLOPT_TIMEOUT => 30,
CURLOPT_CONNECTTIMEOUT => 10,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_MAXREDIRS => 5,
CURLOPT_USERAGENT => 'Mozilla/5.0 (compatible; PHP-HTTP-Client)',
];
curl_setopt_array($ch, $defaultOpts + $options);
$result = curl_exec($ch);
$errno = curl_errno($ch);
$error = curl_error($ch);
curl_close($ch);
if ($errno) {
error_log("cURL Error [$errno]: $error for URL: $url");
return false;
}
return $result;
}
// 使用示例
$html = getHttpsContent('https://api.example.com/data');
if ($html !== false) {
$data = json_decode($html, true);
// 處理數據...
}
方案二中關閉驗證(CURLOPT_SSL_VERIFYPEER = false)僅適合開發/測試。生產環境必須驗證憑證:
$caCertPath = '/etc/ssl/certs/ca-certificates.crt'; // 系統 CA 憑證包路徑
// 或下載 cacert.pem: https://curl.se/ca/cacert.pem
$options = [
CURLOPT_SSL_VERIFYPEER => true,
CURLOPT_SSL_VERIFYHOST => 2,
CURLOPT_CAINFO => $caCertPath,
// 若對方使用自簽名憑證,需指定該憑證公鑰
// CURLOPT_CAINFO => '/path/to/custom-ca.crt',
];
$html = getHttpsContent('https://secure-api.example.com', $options);
| 維度 | 啟用 OpenSSL + file_get_contents | cURL 替代方案 |
|---|---|---|
| 適用場景 | 有服務器控制權、偏好原生函數 | 共享主機、需精細控制、跨平台部署 |
| SSL 控制力度 | 透過 stream context 設定 | 選項豐富,業界標準 |
| 效能 | 略優(無進程開銷) | 極高,支援並發 |
| 錯誤診斷 | 較難 | curl_error() 詳細 |
| 推薦指數 | ⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
CURLOPT_CAINFO 必須指向有效的 cacert.pemCURLOPT_SSLVERSION => CURL_SSLVERSION_TLSv1_2file_get_contents,可用 stream_context_create(['ssl'=>['verify_peer'=>false]]) 臨時繞過總結:有權限就啟用 OpenSSL 用原生函數,無權限或追求健壯性就用 cURL 封裝。生產環境務必啟用憑證驗證,配置正確的 CA 憑證路徑,這是保障數據傳輸安全的底線。