Warning: fopen(): Unable to find the wrapper "https"
- did you forget to enable it when you configured PHP?
PHP 的 file_get_contents 依賴 OpenSSL 擴展 才能支援 https:// 協議封裝協定。預設編譯或安裝時若未啟用 OpenSSL,將無法直接讀取 HTTPS 資源。
php.ini;extension=openssl; → extension=opensslextension_dir 指向正確的 `ext` 目錄# Ubuntu/Debian
sudo apt-get install php-openssl
# 或指定版本
sudo apt-get install php8.1-openssl
# CentOS/RHEL/Rocky
sudo yum install php-openssl
# 或
sudo dnf install php-openssl
# 重啟 PHP-FPM
sudo systemctl restart php-fpm
cURL 是專為 URL 傳輸設計的庫,支援 HTTPS、HTTP/2、憑證驗證、代理、超時控制、重定向追蹤等豐富功能,是生產環境請求外部 API 的標準選擇。
<?php
/**
* 通用 HTTP 請求函數 (支援 GET/POST、HTTPS、標頭、超時、重定向)
*
* @param string $url 目標 URL
* @param int $timeout 超時秒數
* @param array $headers 額外請求標頭 ['Header-Name: value', ...]
* @param array $postData POST 資料 (關聯陣列),為空則 GET
* @return string|false 回應內容,失敗回傳 false
*/
function http_request(string $url, int $timeout = 30, array $headers = [], array $postData = []) {
if (!function_exists('curl_init')) {
throw new RuntimeException('cURL 擴展未安裝');
}
$ch = curl_init();
// 基礎設定
curl_setopt_array($ch, [
CURLOPT_URL => $url,
CURLOPT_RETURNTRANSFER => true, // 回傳字串而非直接輸出
CURLOPT_HEADER => false, // 不包含回應標頭
CURLOPT_FOLLOWLOCATION => true, // 自動追蹤 301/302 重定向
CURLOPT_MAXREDIRS => 5, // 最大重定向次數
CURLOPT_TIMEOUT => $timeout, // 總超時
CURLOPT_CONNECTTIMEOUT => 10, // 連線超時
CURLOPT_SSL_VERIFYPEER => true, // 驗證 SSL 憑證 (生產環境必須開啟)
CURLOPT_SSL_VERIFYHOST => 2, // 驗證主機名
// CURLOPT_CAINFO => '/path/to/cacert.pem', // 若憑證驗證失敗,指定 CA 憑證包
CURLOPT_USERAGENT => 'PHP-cURL/'.phpversion(),
]);
// 自訂標頭
if ($headers) {
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
}
// POST 請求
if ($postData) {
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($postData));
}
$response = curl_exec($ch);
if ($response === false) {
$error = curl_error($ch);
$errno = curl_errno($ch);
curl_close($ch);
error_log("cURL error [$errno]: $error for URL: $url");
return false;
}
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
// 可選:非 2xx 視為失敗
if ($httpCode < 200 || $httpCode >= 300) {
error_log("HTTP $httpCode for URL: $url");
// 視業務決定是否回傳 false 或內容
}
return $response;
}
// 使用範例
$html = http_request('https://api.example.com/users', 10, ['Authorization: Bearer token123']);
$json = http_request('https://api.example.com/data', 10, ['Content-Type: application/json'], ['key' => 'value']);
<?php
function multi_request(array $urls, int $timeout = 30): array {
$mh = curl_multi_init();
$handles = [];
$results = [];
foreach ($urls as $i => $url) {
$ch = curl_init($url);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => $timeout,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_SSL_VERIFYPEER => true,
]);
curl_multi_add_handle($mh, $ch);
$handles[$i] = $ch;
}
$running = null;
do {
curl_multi_exec($mh, $running);
curl_multi_select($mh, 0.1); // 避免 CPU 空轉
} while ($running > 0);
foreach ($handles as $i => $ch) {
$results[$i] = [
'content' => curl_multi_getcontent($ch),
'http_code' => curl_getinfo($ch, CURLINFO_HTTP_CODE),
'error' => curl_error($ch),
];
curl_multi_remove_handle($mh, $ch);
curl_close($ch);
}
curl_multi_close($mh);
return $results;
}
| 方案 | 優點 | 缺點 | 建議場景 |
|---|---|---|---|
| 開啟 OpenSSL + file_get_contents | 程式碼簡潔、無額外依賴 | 功能極簡、無超時控制、無標頭控制、難除錯 | 極簡單的 GET 請求、開發測試 |
| cURL (同步) | 功能完整、標準庫、效能好、支援並發 | 程式碼較冗長 | ✅ 生產環境標準選擇 |
| Guzzle / Symfony HttpClient | PSR-18/PSR-7 相容、中介軟體、異步、重試、Mock 測試 | Composer 依賴 | 現代框架專案 (Laravel/Symfony/獨立) |
CURLOPT_SSL_VERIFYPEER => false (僅開發) 或信任 CA。CURLOPT_CAINFO。建議專案統一使用 cURL 或成熟 HTTP Client 套件,徹底解決 HTTPS 請求問題並獲得企業級功能支援。