为什么 cURL 可以通过命令行正常连接,但不能在 PHP 中连接?

Reasons why cURL would connect fine over command line, but not in PHP?

最近一段稳定了一段时间的代码开始出现问题。它与 GameStop 建立连接以在那里检索页面。多年来工作正常,但现在返回超时。

起初我以为涉及某种 IP 或用户代理阻止。然而,我已经在 DigitalOcean 和 Vultr 上启动了全新的机器,并且都遇到了同样的问题。虽然,所有机器都能够通过命令行使用 cURL 并正常检索页面。

奇怪的是,代码也可以在我的本地开发机器上运行,这是一个 Windows 盒子。所以,不确定 PHP 运行ning on Linux 是否有问题?

<?php

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL,'https://www.gamestop.com/');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLINFO_HEADER_OUT, true);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 0);
curl_setopt($ch, CURLOPT_TIMEOUT, 10);
//curl_setopt($ch, CURLOPT_SSLVERSION, 6); -explicitly use TLS v1.2

$html = curl_exec($ch);
$info = curl_getinfo($ch);
$error = curl_error($ch);
curl_close($ch);

echo '<pre>' . var_export($error, true) . '</pre>'
     . '<pre>' . var_export($info, true) . '</pre>'
    . 'HTML: <textarea>' . $html . '</textarea>';

?>

上面的代码 returns 在我尝试 运行 的任何非本地环境中超时。在相同的环境中,可以通过命令行使用 cURL 获取页面。我发现了一些类似的问题,但大多数都指向 SSL/TLS 版本的问题。也尝试对此进行测试(参见注释行),但结果相同。

问题的一部分是,我不确定是否有真正的方法来调试来自服务器的超时,因为实际上任何事情都可能导致它。我得到的唯一真正线索是它可以在 Windows 机器上运行,并且在更高环境中可以在命令行上运行。任何帮助或见解将不胜感激!

编辑:也能够在 Windows Server 2016 VM 上重现该问题。

虽然它并没有真正解释为什么会发生这种情况,但我能够通过在PHP中使用shell_exec执行来解决这个问题直接命令行 cURL,然后 retrieve/process 结果。

很可能是因为 curl-cli 自动添加了 user-agent header,而 libcurl/php 没有。

some sort of IP or user-agent blocking involved. However, I have spun up brand new machines on both DigitalOcean and Vultr, and both experience the same issue

在 DigitalOcean/Vultr 上设置 VM 不会自动使 libcurl 添加 user-agent headers 到您的 https 请求。可以通过以下方式完成:

curl_setop($ch,CURLOPT_USERAGENT,"curl/".(curl_version()["version"])); // User-Agent: curl/7.52.1

模仿curl-cli的user-agent字符串,或类似

的字符串
curl_setopt($ch,CURLOPT_USERAGENT,"Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36");

假装你是 Google Chrome 版本 71,运行 Windows 7 x64。

许多网站(例如 Wikipedia.com)会阻止缺少 User-Agent header.

的 http 请求