PHP file_get_contents Возвращает несовместимые частичные данные для HTTP-запросов - PullRequest
1 голос
/ 08 мая 2020

Я пытаюсь использовать PHP SoapClient для выполнения запросов к стороннему приложению. Когда я создаю объект SoapClient, я получаю сообщение об ошибке о преждевременном завершении данных для WSDL. Пытаясь диагностировать ошибку, я обнаружил, что file_get_contents () для WSDL URI не возвращает весь XML. Фактически, он часто возвращает разное количество WSDL. Вот моя тестовая программа:

$xml = file_get_contents('https://webservices3.autotask.net/atservices/1.6/atws.wsdl');
echo $xml . "\n";
echo strlen($xml). "\n";

Я получаю около 57 Кбайт каждый раз (195628 - правильное значение), иногда больше и очень редко я получаю все XML. Я считаю, что это проблема PHP, потому что оболочка l oop для вызова curl или wget по 100 раз для этого URI в 100% случаев возвращает весь файл. Я использую PHP 5.4.16, который, как я знаю, старый (2013 г.), но этот процесс работал около месяца, а затем полностью остановился.

Я пробовал менять таймауты, версии протокола HTTP, PHP настройки памяти, но я не могу понять, почему file_get_contents так себя ведет. Любые предложения приветствуются.

Тест на изгиб:

for a in $( seq 1 100 ); do curl -o wsdl.$a https://webservices3.autotask.net/atservices/1.6/atws.wsdl; done

Тест Wget:

for a in $( seq 1 100 ); do wget -O wsdl.$a https://webservices3.autotask.net/atservices/1.6/atws.wsdl; done

Обновление 1:

Установка maxlen на какой-то тупой большой число не влияет на поведение:

$xml = file_get_contents('https://webservices3.autotask.net/atservices/1.6/atws.wsdl', false, null, 0, 999999);
echo $xml . "\n";
echo strlen($xml). "\n";

Обновление 2:

$ curl -s -D /dev/stderr -- https://webservices3.autotask.net/atservices/1.6/atws.wsdl > /dev/null
HTTP/1.1 200 OK
Content-Type: text/xml
Last-Modified: Wed, 29 Apr 2020 14:38:25 GMT
Accept-Ranges: bytes
ETag: "39163cd7331ed61:0"
Server: Microsoft-IIS/8.5
X-Powered-By: ASP.NET
Content-Security-Policy: default-src 'self' https: *;script-src 'self' 'unsafe-inline' 'unsafe-eval' https: *;style-src 'self' 'unsafe-inline';img-src 'self' https://walkme.psa.datto.com/Images/ data: https://www.datto.com/img/
Date: Fri, 08 May 2020 15:22:28 GMT
Content-Length: 195628

Вот заголовки ответов, поскольку PHP сообщает о них:

$xml = file_get_contents('https://webservices3.autotask.net/atservices/1.6/atws.wsdl');
echo $xml . "\n";
echo strlen($xml). "\n";
echo var_dump($http_response_header);

array(11) {
  [0]=> string(15) "HTTP/1.1 200 OK"
  [1]=> string(22) "Content-Type: text/xml"
  [2]=> string(44) "Last-Modified: Wed, 29 Apr 2020 14:38:25 GMT"
  [3]=> string(20) "Accept-Ranges: bytes"
  [4]=> string(25) "ETag: "39163cd7331ed61:0""
  [5]=> string(25) "Server: Microsoft-IIS/8.5"
  [6]=> string(21) "X-Powered-By: ASP.NET"
  [7]=> string(228) "Content-Security-Policy: default-src 'self' https: *;script-src 'self' 'unsafe-inline' 'unsafe-eval' https: *;style-src 'self' 'unsafe-inline';img-src 'self' https://walkme.psa.datto.com/Images/ data: https://www.datto.com/img/ "
  [8]=> string(35) "Date: Fri, 08 May 2020 15:26:54 GMT"
  [9]=> string(22) "Connection: keep-alive"
  [10]=> string(22) "Content-Length: 195628"
}

Обновить 3:

Поврежденный заголовок Content-Length из PHP с gzip:

$ctx = stream_context_create(array(
    'http' => array(
        'header' => "Accept-Encoding: gzip\r\n"
     )
));
$xml = file_get_contents('https://webservices3.autotask.net/atservices/1.6/atws.wsdl', false, $ctx);
echo var_dump($http_response_header);

array(12) {
  [0]=> string(15) "HTTP/1.1 200 OK"
  [1]=> string(22) "Content-Type: text/xml"
  [2]=> string(44) "Last-Modified: Wed, 29 Apr 2020 14:35:51 GMT"
  [3]=> string(20) "Accept-Ranges: bytes"
  [4]=> string(24) "ETag: "b376e7b331ed61:0""
  [5]=> string(25) "Server: Microsoft-IIS/8.5"
  [6]=> string(21) "X-Powered-By: ASP.NET"
  [7]=> string(228) "Content-Security-Policy: default-src 'self' https: *;script-src 'self' 'unsafe-inline' 'unsafe-eval' https: *;style-src 'self' 'unsafe-inline';img-src 'self' https://walkme.psa.datto.com/Images/ data: https://www.datto.com/img/ "
  [8]=> string(35) "Date: Fri, 08 May 2020 15:44:12 GMT"
  [9]=> string(22) "Connection: keep-alive"
  [10]=> string(22) "ntCoent-Length: 195628"
  [11]=> string(22) "Content-Encoding: gzip"

}

Обновление 4:

Заголовки из curl с gzip (обратите внимание, что они выглядят правильно):

$ curl --compressed -s -D /dev/stderr -- https://webservices3.autotask.net/atservices/1.6/atws.wsdl > /dev/null
HTTP/1.1 200 OK
Content-Type: text/xml
Content-Encoding: gzip
Last-Modified: Wed, 29 Apr 2020 14:35:51 GMT
Accept-Ranges: bytes
ETag: "807d37b331ed61:0"
Vary: Accept-Encoding
Server: Microsoft-IIS/8.5
X-Powered-By: ASP.NET
Content-Security-Policy: default-src 'self' https: *;script-src 'self' 'unsafe-inline' 'unsafe-eval' https: *;style-src 'self' 'unsafe-inline';img-src 'self' https://walkme.psa.datto.com/Images/ data: https://www.datto.com/img/
Date: Fri, 08 May 2020 16:12:13 GMT
Content-Length: 13192

Мне удалось заставить SoapClient не использовать gzip, и это решило проблему, хотя и неэффективно. У нас все еще нет причины root для PHP искажения заголовков.

// Autotask Client options
$auth_opts = array(
    'login'    => $username,
    'password' => $password,
    'trace'    => 1,
    'http'     => array(
        'header' => array(
            'Accept-Encoding' => 'identity' // here be dragons
        )
    )
);

Обновление 5:

Мы подтвердили, что это все еще воспроизводимо в PHP 7.2. Я обнаружил ошибку с командой PHP.

Ответы [ 2 ]

1 голос
/ 08 мая 2020

webservices3.autotask. net имеет неправильный заголовок в ответе

HTTP/1.1 200 OK
Content-Type: text/xml
Accept-Ranges: bytes
Server: Microsoft-IIS/8.5
X-Powered-By: ASP.NET
Cteonnt-Length: 195628
Cache-Control: private
Content-Encoding: gzip
Transfer-Encoding: chunked

Примечание: Cteonnt-Length: 195628 должно быть Content-Length: 195628

Вот почему file_get_contents не может правильно обработать запрос.

Итак, исправляем ответ или ставим maxlen

UPD: Это перепутанный заголовок. Это должно работать { ссылка }

0 голосов
/ 12 мая 2020

Похоже, это ошибка в PHP. В конце вопроса есть ссылка на ошибку отчет.

...