#php #https
#php #https
Вопрос:
Curl имеет функцию для ручного указания, на какой IP-адрес разрешить хост. Например:
curl https://www.google.com --resolve "www.google.com:443:173.194.72.112"
Это особенно полезно при использовании HTTPS. Если бы это был просто HTTP-запрос, я мог бы добиться того же, указав IP-адрес напрямую и добавив заголовок host. Но в HTTPS это приведет к разрыву соединения, поскольку хост SSL-сертификата будет сравниваться с IP-адресом, а не с заголовком хоста.
Мой вопрос в том, как я могу сделать то же самое в PHP?
Комментарии:
1. Возможно
CURLOPT_IPRESOLVE
…!?2. Из php.net//manual/en/function.curl-setopt.php : «Позволяет приложению выбирать, какие IP-адреса использовать при разрешении имен хостов. Это интересно только при использовании имен хостов, которые разрешают адреса, используя более одной версии IP, возможными значениями являются CURL_IPRESOLVE_WHATEVER, CURL_IPRESOLVE_V4, CURL_IPRESOLVE_V6, по умолчанию CURL_IPRESOLVE_WHATEVER.». Это не то, что я хочу. Я хочу указать полный IP-адрес.
3. Вы правы, мой плохой.
Ответ №1:
Хотя ответ @deceze верен, живой пример может быть полезен. Мне нужно CURLOPT_RESOLVE
было, потому что я пытался подключиться напрямую к IP-адресу с дополнительным Host: www.example.com
заголовком, но поскольку сервер использовал SNI, это не сработало.
Раньше я CURLOPT_RESOLVE
решал свою проблему. Этот код позволяет мне подключаться к серверу SNI по выбранному мной IP-адресу:
$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);
Ответ №2:
Согласно списку изменений, поддержка CURLOPT_RESOLVE
была добавлена в версии 5.5.0.
Обратите внимание, что на момент написания статьи это еще даже не задокументировано, но, согласно этому сообщению об ошибке, в качестве аргумента принимается массив.
Ответ №3:
Несмотря на то, что это старый вопрос, стоит заметить, что при использовании CURL на нескольких серверах с использованием этой CURLOPT_RESOLVE
опции существует кэш DNS, который необходимо очистить перед повторным использованием CURL, иначе CURL будет указывать на первый сервер независимо от curl_setopt($ch, CURLOPT_RESOLVE, $resolve);
настроек.
Единственный способ сделать эту работу — добавить в $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