Curl Timeout в PHP (отлично работает в CLI) - PullRequest
0 голосов
/ 01 мая 2019

У меня возникла проблема, когда я запускаю два веб-сайта локально на моей машине с Windows ( a .ryan и b .ryan) . Проблема, с которой я сталкиваюсь, не возникает в реальной среде (под управлением CentOS7) . Сценарий в b .ryan делает запрос CURL на a .ryan :

* Rebuilt URL to: http://a.ryan/
* Hostname a.ryan was found in DNS cache
*   Trying 192.168.0.64...
* TCP_NODELAY set
* Connected to a.ryan (192.168.0.64) port 80 (#0)
> GET / HTTP/1.1
Host: a.ryan
User-Agent: Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)
Accept: */*

* Operation timed out after 10000 milliseconds with 0 bytes received
* Curl_http_done: called premature == 1
* Closing connection 0

Как видите - время ожидания истекло. Я пробовал использовать более длительный режим (с теми же результатами) , хотя на самом деле он должен быть почти мгновенным.

В настоящее время я использую следующую функцию:

function getHTML($url) {
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
    curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10); 
    curl_setopt($ch, CURLOPT_TIMEOUT, 10);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
    curl_setopt($ch, CURLOPT_HEADER, 0);
    curl_setopt($ch, CURLOPT_FOLLOWLOCATION, TRUE);
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
    curl_setopt($ch, CURLOPT_SSLVERSION, 3);
    curl_setopt($ch, CURLOPT_PROXY, '');
    curl_setopt($ch, CURLOPT_HTTPPROXYTUNNEL, false);
    curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)');
    curl_setopt($ch, CURLOPT_VERBOSE, true);
    curl_setopt($ch, CURLOPT_STDERR, fopen('curl.txt', 'w+'));
    $tmp = curl_exec($ch);
    curl_close($ch);
    if ($tmp != false) {
        return $tmp;
    }
}

По общему признанию, здесь есть много опций, которые могут не присутствовать - однако это является результатом попытки найти несколько решений, найденных в сети. Просто чтобы уточнить, я получаю точно такой же ответ, опубликованный выше, когда я использую:

function getHTML($url) {
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10); 
    curl_setopt($ch, CURLOPT_TIMEOUT, 10);
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_VERBOSE, true);
    curl_setopt($ch, CURLOPT_STDERR, fopen('curl.txt', 'w+'));
    $tmp = curl_exec($ch);
    curl_close($ch);
    if ($tmp != false) {
        return $tmp;
    }
}

Надеюсь, это дает представление о настройках, которые я пробовал с помощью метода PHP Curl, чтобы обойти эту проблему.

Когда я запускаю Curl в командной строке, он работает нормально:

* Rebuilt URL to: a.ryan/
*   Trying 192.168.0.64...
* TCP_NODELAY set
* Connected to a.ryan (192.168.0.64) port 80 (#0)
> GET / HTTP/1.1
> Host: a.ryan
> User-Agent: curl/7.55.1
> Accept: */*
>
< HTTP/1.1 302 Moved Temporarily
< Server: nginx/1.12.0
< Date: Wed, 01 May 2019 11:34:12 GMT
< Content-Type: text/html; charset=UTF-8
< Transfer-Encoding: chunked
< Connection: keep-alive
< X-Powered-By: PHP/5.6.30
< Set-Cookie: PHPSESSID=9898j4cia9s888jn24gr4be8m5; path=/
< Expires: Thu, 19 Nov 1981 08:52:00 GMT
< Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
< Pragma: no-cache
< location: /home
<
* Connection #0 to host a.ryan left intact

Я также отключил все настройки IPv6 на своих сетевых интерфейсах на этом компьютере, поскольку у меня изначально сложилось впечатление, что эта проблема была вызвана разрешениями IPv6 вместо IPv4, но это не имело никакого значения.

Вот копия моего файла hosts, если это поможет.

# Copyright (c) 1993-2009 Microsoft Corp.
#
# This is a sample HOSTS file used by Microsoft TCP/IP for Windows.
#
# This file contains the mappings of IP addresses to host names. Each
# entry should be kept on an individual line. The IP address should
# be placed in the first column followed by the corresponding host name.
# The IP address and the host name should be separated by at least one
# space.
#
# Additionally, comments (such as these) may be inserted on individual
# lines or following the machine name denoted by a '#' symbol.
#
# For example:
#
#102.54.94.97   rhino.acme.com  # source server
#38.25.63.10    x.acme.com  # x client host
# localhost name resolution is handled within DNS itself.
#127.0.0.1  localhost
#::1    localhost
127.0.0.1   localhost.localdomain localhost MyPCName
127.0.0.1   a.ryan
127.0.0.1   b.ryan

EDIT

Забыл упомянуть - если я запускаю скрипт в CLI, он тоже работает нормально. Так что на самом деле это специфично для запуска скрипта через браузер. (Использование Winginx для обслуживания сайта)

1 Ответ

0 голосов
/ 01 мая 2019

Полагаю, возможно, что веб-сервер (или, возможно, глупая эвристика брандмауэра, настроенная для блокировки вредоносных сканеров веб-уязвимостей?) Был настроен на блокировку запросов, которые явно лгут о пользовательском агенте , потому что запрос, который не работает, лжет о том, что Internet Explorer 10, и это совершенно очевидно, настоящий GET-запрос Internet Explorer выглядит как

GET / HTTP/1.1
Accept: text/html, application/xhtml+xml, */*
Accept-Language: nb-NO
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko
Accept-Encoding: gzip, deflate
Host: 127.0.0.1:9999
Connection: Keep-Alive

, который имеет довольно много отличий от вашего поддельного запроса, в то время как запрос, который действительно работает, правдиво претендует на значение curl/7.55.1

.. что произойдет, если вы измените User-Agent на

curl_setopt($ch, CURLOPT_USERAGENT, 'libcurl/'.(curl_version()['version']).' PHP/'.PHP_VERSION);

? или даже просто

curl_setopt($ch, CURLOPT_USERAGENT, 'curl/7.55.1');

?

...