PHP 7.4中get_headers/file_get_contents无法访问Twitter图片URL但curl可用
问题现象
使用get_headers获取Twitter图片头部信息时失败,报错:
Name or service not known in php shell code on line 1
执行代码:
print_r(get_headers("https://pbs.twimg.com/media/FE9eUxLXEBAeyn3.jpg"));
完整报错内容:
PHP Warning: get_headers(): php_network_getaddresses: getaddrinfo failed: Name or service not known in php shell code on line 1
PHP Warning: get_headers(https://pbs.twimg.com/media/FE9eUxLXEBAeyn3.jpg): failed to open stream: php_network_getaddresses: getaddrinfo failed: Name or service not known in php shell code on line 1
但使用curl可正常请求该地址,代码如下:
$ch = curl_init(); curl_setopt($ch, CURLOPT_URL,"https://pbs.twimg.com/media/FE9eUxLXEBAeyn3.jpg"); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $server_output = curl_exec($ch); curl_close($ch); echo $server_output;
返回结果(二进制图片内容以PuTTY重复字符显示):
PuTTYPuTTYPuTTYPuTTYPuTTYPuTTYPuTTYPuTTYPuTTYPuTTYPuTTYPuTTYPuTTYPuTTYPuTTYPuTTYPuTTYPuTTYPuTTYPuTTYPuTTYPuTTYPuTTYPuTTYPuTTYPuTTYPuTTYPuTTYPuTTYPuTTYPuTTYPuTTYPuTTYPuTTYPuTTYPuTTYPuTTYPuTTYPuTTYPuTTYPuTTYPuTTYPu
环境与基础排查
- 服务器系统:CentOS 7
- PHP版本:7.4
- 已确认
allow_url_fopen启用:
执行命令:
php -i | grep "fopen"
结果:
allow_url_fopen => On => On
- 重启httpd服务后问题未解决
DNS相关排查操作
- 执行
gethostbynamel解析域名:
var_dump(gethostbynamel("pbs.twimg.com"));
结果:
bool(false);
- 执行
dns_get_record查询:
var_dump(dns_get_record("pbs.twimg.com", DNS_ANY, $authoritative_name_servers, $additional_records, true));
报错:
PHP Warning: dns_get_record(): Numeric DNS record type must be between 1 and 65535, '268435456' given in php shell code on line 1
- 查看查询返回的服务器记录:
var_dump($authoritative_name_servers, $additional_records);
结果:
array(0) { } array(0) { }
- 开启curl verbose模式查看请求详情:
$ch = curl_init(); curl_setopt($ch, CURLOPT_URL,"https://pbs.twimg.com/media/FE9eUxLXEBAeyn3.jpg"); $stderrh=tmpfile(); curl_setopt_array($ch,array(CURLOPT_VERBOSE=>1,CURLOPT_STDERR=>$stderrh)); $server_output = curl_exec($ch); rewind($stderrh); $stderr=stream_get_contents($stderrh); fclose($stderrh); var_dump($stderr);
返回的stderr内容(乱码显示):
PuTTYPuTTYPuTTYPuTTYPuTTYPuTTYPuTTYPuTTYPuTTYPuTTYPuTTYPuTTYPuTTYPuTTY
PuTTYPuTTYPuTTYPuTTYPuTTYPuTTYPuTTYPuTTYPuTTYPuTTYPuTTYPuTTYPuTTYPuTTY
PuTTYPuTTYPuTTYPuTTYPuTTYPuTTYPuTTYPuTTYPuTTYPuTTYPuTTYPuTTYPuTTYPuTTYPuTTYPuTTYPuTTYPuTTYPuTTYPuTTYPuTTY
分析与解决方案
核心原因
curl与PHP原生网络函数(get_headers、gethostbynamel等)依赖的DNS解析机制不同:
- curl可能使用了独立的DNS配置或缓存,能正常解析目标域名
- PHP原生函数依赖系统默认DNS配置,但当前系统DNS无法解析
pbs.twimg.com,导致域名解析失败
解决步骤
修改系统DNS配置
编辑/etc/resolv.conf,添加可靠的公共DNS服务器:nameserver 8.8.8.8 nameserver 1.1.1.1保存后重启网络服务:
systemctl restart network为PHP原生函数指定DNS
如果修改系统DNS无效,可通过stream_context_set_default强制PHP使用指定DNS:$context = stream_context_create([ 'socket' => [ 'dns' => '8.8.8.8' ] ]); stream_context_set_default($context); // 再次执行get_headers print_r(get_headers("https://pbs.twimg.com/media/FE9eUxLXEBAeyn3.jpg"));替代方案:用curl获取头部信息
直接使用curl替代get_headers获取MIME类型等头部数据:$ch = curl_init(); curl_setopt($ch, CURLOPT_URL, "https://pbs.twimg.com/media/FE9eUxLXEBAeyn3.jpg"); curl_setopt($ch, CURLOPT_NOBODY, true); // 仅获取头部 curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_HEADER, true); $headers = curl_exec($ch); curl_close($ch); // 解析并提取Content-Type $headerLines = explode("\n", trim($headers)); foreach($headerLines as $line) { if(str_starts_with($line, 'Content-Type:')) { echo $line; break; } }
内容的提问来源于stack exchange,提问作者Daniyal Ahmed

