虛擬主機常禁用 file_get_contents、fsockopen 等網路 IO 函式防禦 DDOS。本文提供 **cURL 完整封裝**、**自動偵測降級**、**超時與錯誤處理** 的生產級解決方案。
<?php
/**
* 通用 HTTP GET 取得內容
* 自動偵測 file_get_contents / cURL 可用性
* 支援 HTTPS、超時、重導向、自定義 Header
*/
function http_get($url, array $options = []) {
$defaults = [
'timeout' => 10, // 連線+讀取總超時(秒)
'connect_timeout' => 5, // 連線階段超時
'follow_location' => true, // 跟隨 3xx 重導向
'max_redirects' => 5,
'ssl_verify' => true, // 驗證 SSL 憑證
'headers' => [], // 額外請求標頭
'user_agent' => 'PHP-HTTP-Client/1.0',
];
$opts = array_merge($defaults, $options);
// 優先使用 file_get_contents(原生、效能較好)
if (ini_get('allow_url_fopen') && function_exists('file_get_contents')) {
$ctx = stream_context_create([
'http' => [
'method' => 'GET',
'timeout' => $opts['timeout'],
'header' => array_merge(
['User-Agent: ' . $opts['user_agent']],
$opts['headers']
),
'follow_location' => $opts['follow_location'],
'max_redirects' => $opts['max_redirects'],
'ignore_errors' => true, // 取得 4xx/5xx 內容
],
'ssl' => [
'verify_peer' => $opts['ssl_verify'],
'verify_peer_name' => $opts['ssl_verify'],
],
]);
$content = @file_get_contents($url, false, $ctx);
if ($content !== false) {
return ['content' => $content, 'info' => ['method' => 'file_get_contents']];
}
// 失敗則降級 cURL
}
// cURL 實作
if (!function_exists('curl_init')) {
throw new RuntimeException('file_get_contents 與 cURL 皆不可用');
}
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => $url,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => $opts['timeout'],
CURLOPT_CONNECTTIMEOUT => $opts['connect_timeout'],
CURLOPT_FOLLOWLOCATION => $opts['follow_location'],
CURLOPT_MAXREDIRS => $opts['max_redirects'],
CURLOPT_SSL_VERIFYPEER => $opts['ssl_verify'],
CURLOPT_SSL_VERIFYHOST => $opts['ssl_verify'] ? 2 : 0,
CURLOPT_USERAGENT => $opts['user_agent'],
CURLOPT_HTTPHEADER => array_merge(
['User-Agent: ' . $opts['user_agent']],
$opts['headers']
),
CURLOPT_ENCODING => 'gzip, deflate', // 自動解壓
]);
$content = curl_exec($ch);
$errno = curl_errno($ch);
$info = curl_getinfo($ch);
curl_close($ch);
if ($errno !== CURLE_OK) {
throw new RuntimeException("cURL error ($errno): " . curl_strerror($errno));
}
return ['content' => $content, 'info' => $info];
}
// 使用範例
try {
$result = http_get('https://api.example.com/data', [
'timeout' => 15,
'headers' => ['Authorization: Bearer ' . $token],
]);
$data = json_decode($result['content'], true);
} catch (Exception $e) {
error_log("HTTP GET failed: " . $e->getMessage());
}
<?php
function http_post($url, $data, array $options = []) {
$defaults = [
'timeout' => 15,
'content_type' => 'application/json',
];
$opts = array_merge($defaults, $options);
$postData = is_array($data) ? json_encode($data) : $data;
if (ini_get('allow_url_fopen') && function_exists('file_get_contents')) {
$ctx = stream_context_create([
'http' => [
'method' => 'POST',
'header' => "Content-Type: {$opts['content_type']}\r\n" .
"Content-Length: " . strlen($postData),
'content' => $postData,
'timeout' => $opts['timeout'],
],
]);
$result = @file_get_contents($url, false, $ctx);
if ($result !== false) return $result;
}
// cURL POST
$ch = curl_init($url);
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => $postData,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => $opts['timeout'],
CURLOPT_HTTPHEADER => [
'Content-Type: ' . $opts['content_type'],
'Content-Length: ' . strlen($postData),
],
CURLOPT_SSL_VERIFYPEER => true,
]);
$result = curl_exec($ch);
curl_close($ch);
return $result;
}
php.iniextension=curl 或 extension=php_curl.dll;libssh2.dll, libcrypto-*.dll, libssl-*.dll 在 PHP 目錄或 System32# Ubuntu/Debian
apt-get install php-curl
systemctl restart php8.1-fpm
# CentOS/RHEL
yum install php-curl
systemctl restart php-fpm
# 編譯安裝 PHP 時
./configure --with-curl=/usr/local/curl ...
curl_multi_* 或連線池(GuzzleHttp/Client 內建)CURLOPT_SSL_VERIFYPEER = true,若需忽略請配合 CURLOPT_CAINFO 指定自簽憑證CURLOPT_TIMEOUT 與 CURLOPT_CONNECTTIMEOUT,避免阻塞進程CURLOPT_MAXREDIRS = 5 防無限循環現代建議:新專案直接使用 GuzzleHTTP 或 HTTPlug,已封裝上述所有細節,支援 PSR-18、中介軟體、非同步請求。