Curl具有手动指定要将主机解析到的IP的功能。例如:
curl https://www.google.com --resolve "www.google.com:443:173.194.72.112"
这在使用HTTPS时特别有用。如果它只是一个HTTP请求,我可以通过直接指定IP地址并添加主机头来实现相同的目的。但是在HTTPS中会破坏连接,因为SSL证书主机将与IP地址而不是主机头进行比较。
我的问题是,我怎样才能在PHP中做同样的事情?
根据the changelog的说法,在5.5.0中增加了对CURLOPT_RESOLVE
的支持。
请注意,在撰写本文时,它甚至尚未记录,但根据this bug report,它将数组作为参数。
虽然@ deceze的答案是正确的,但实际的例子可能会有用。我需要CURLOPT_RESOLVE
,因为我试图通过额外的Host: www.example.com
标头直接连接到IP地址,但由于服务器使用SNI,这不起作用。
我用CURLOPT_RESOLVE
来解决我的问题。此代码允许我使用我选择的IP地址连接到SNI服务器:
$resolve = array(sprintf(
"%s:%d:%s",
$hostname,
$port,
$host_ip
));
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RESOLVE, $resolve);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$result = curl_exec($ch);
curl_close($ch);
尽管这是一个值得注意的问题值得注意的是,当使用CURLOPT_RESOLVE
选项将CURL用于多个服务器时,需要在再次使用CURL之前清除DNS缓存,否则无论curl_setopt($ch, CURLOPT_RESOLVE, $resolve);
设置如何,CURL都将指向第一个服务器。
使这项工作的唯一方法是在$resolve
数组中添加一个解析字符串,其中最后一个服务器使用前缀为“ - ”:
$servers = [ '192.0.2.1', '192.0.2.2', '192.0.2.3' ];
foreach ($servers as $idx => $server) {
$resolve = [];
// Remove the last server used from the DNS cache
if($idx){
$last_server = $server[$idx-1];
$resolve[] = "-example.com:443:{$last_server}";
}
// resolve the new server
$resolve[] = "example.com:443:{$server}";
$ch = curl_init();
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 1);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_DNS_CACHE_TIMEOUT, 0);
curl_setopt($ch, CURLOPT_RESOLVE, $resolve);
curl_setopt($ch, CURLOPT_URL, "https://example.com/some/path");
curl_setopt($ch, CURLOPT_VERBOSE, 1);
$result = curl_exec($ch);
$info = curl_getinfo($ch);
echo $info['primary_ip']."\n";
curl_close($ch);
}
正如这里指出的那样:https://bugs.php.net/bug.php?id=74135