file_get_contents() 或 fopen() 讀取遠端 URL 時出現 couldn't resolve host name,本質是 **DNS 解析失敗**。常見於 VPS、Docker 容器、本地開發環境的 `/etc/resolv.conf` 配置缺失或錯誤。本文提供快速修復與永久優化方案。
Warning: file_get_contents(): couldn't resolve host name in /path/to/script.php on line 10
getaddrinfo)。/etc/resolv.conf` 可能為空、指向不可用 DNS、或被覆蓋。# SSH 登入 VPS
vi /etc/resolv.conf
# 替換為可靠公開 DNS(推薦順序)
nameserver 114.114.114.114 # 國內電信/聯通/移動優化
nameserver 8.8.8.8 # Google Public DNS
nameserver 1.1.1.1 # Cloudflare DNS
nameserver 223.5.5.5 # 阿里云 DNS
# 保存退出,無需重啟服務,即時生效
# 測試 DNS 解析
dig @114.114.114.114 www.example.com
nslookup www.example.com 8.8.8.8
# PHP 端驗證
php -r 'var_dump(@file_get_contents("https://www.example.com"));'
# 1. 編輯配置
sudo vi /etc/systemd/resolved.conf
[Resolve]
DNS=114.114.114.114 8.8.8.8 1.1.1.1
FallbackDNS=223.5.5.5
Cache=yes
# 2. 重啟並啟用
sudo systemctl restart systemd-resolved
sudo systemctl enable systemd-resolved
# 3. 確保符號連結正確
ls -l /etc/resolv.conf
# 應指向 ../run/systemd/resolve/stub-resolv.conf
sudo vi /etc/netplan/01-netcfg.yaml
network:
version: 2
ethernets:
eth0:
dhcp4: true
nameservers:
addresses: [114.114.114.114, 8.8.8.8, 1.1.1.1]
search: [local]
sudo netplan apply
nmcli con mod "System eth0" ipv4.dns "114.114.114.114 8.8.8.8"
nmcli con mod "System eth0" ipv4.ignore-auto-dns yes
nmcli con up "System eth0"
# Dockerfile
RUN echo "nameserver 114.114.114.114\nnameserver 8.8.8.8" > /etc/resolv.conf
# 或 docker run 參數
docker run --dns=114.114.114.114 --dns=8.8.8.8 myimage
# docker-compose.yml
services:
app:
dns:
- 114.114.114.114
- 8.8.8.8
<?php
function safeFileGetContents(string $url, int $timeout = 10): string|false {
$ctx = stream_context_create([
'http' => [
'timeout' => $timeout,
'header' => 'User-Agent: PHP/' . PHP_VERSION,
],
'ssl' => [
'verify_peer' => true,
'verify_peer_name' => true,
]
]);
$content = @file_get_contents($url, false, $ctx);
if ($content === false) {
$error = error_get_last();
error_log("file_get_contents failed for $url: " . ($error['message'] ?? 'unknown'));
}
return $content;
}
// 重試機制(指數退避)
function fetchWithRetry(string $url, int $maxRetry = 3): string|false {
for ($i = 0; $i < $maxRetry; $i++) {
$result = safeFileGetContents($url);
if ($result !== false) return $result;
sleep(pow(2, $i)); // 1s, 2s, 4s
}
return false;
}
?>
| 誤區 | 事實 |
|---|---|
| 以為是 PHP 代碼錯誤 | 實際是系統網路層 DNS 解析失敗 |
| 修改 php.ini 解決 | php.ini 無 DNS 相關設定 |
| 重啟 PHP-FPM 即可 | DNS 解析由 libc 處理,與 PHP 進程無關 |
| 只配置一個 DNS | 單點故障風險高,建議 2-3 組不同服務商 |
修正 `/etc/resolv.conf` 或系統級 DNS 配置後,`file_get_contents()`、`cURL`、`SoapClient`、`PDO` 連線等所有網路操作即可恢復正常解析。