SOAP XML-запрос с использованием PHP не работает - возможно, проблема с заголовками - PullRequest
0 голосов
/ 23 января 2019

Мне нужно опубликовать на URL клиента (в случае, если это важно, клиент на платформе .Net), используя SOAP и XML.Запрос должен выглядеть примерно так:

<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:tem="http://tempuri.org/" xmlns:XXX="http://schemas.datacontract.org/2004/07/XXXAPI.Entities.XXX" xmlns:XXX1="http://schemas.datacontract.org/2004/07/XXXAPI.Entities.Admin"> <soap:Header/>    <soap:Body>
      <tem:SaveXXXStatus>
         <!--Optional:-->
         <tem:req>
            <!--Optional:-->
            <XXX:AWBNumber>69184678146</XXX:AWBNumber>
            <!--Optional:--> 
               … etc. …
            <!--Optional:-->
            <XXX:pincode></XXX:pincode>
         </tem:req>
         <!--Optional:-->
         <tem:profile>
            <!--Optional:-->
            <XXX1:Api_type>S</XXX1:Api_type>
            <!--Optional:-->
            <XXX1:Area></XXX1:Area>
            <!--Optional:-->
            <XXX1:LicenceKey>xxxxxxxxxxxxxxxxxxx</XXX1:LicenceKey>
            <!--Optional:-->
            <XXX1:LoginID>XXXYYY</XXX1:LoginID>
            <!--Optional:-->
            <XXX1:Version>1</XXX1:Version>
         </tem:profile>
      </tem:SaveXXXStatus>    </soap:Body> </soap:Envelope>

Я использую следующий код:

        $ch = curl_init();
        //var_dump($ch);

        curl_setopt($ch, CURLOPT_URL,"https://example.com?wsdl");
        curl_setopt($ch, CURLOPT_HTTPHEADER, array(
            'tem:"http://tempuri.org/"',
            'Content-Type: text/xml',
            'XXX:"http://schemas.datacontract.org/2004/07/XXXAPI.Entities.XXX"'
            'XXX1:"http://schemas.datacontract.org/2004/07/XXXAPI.Entities.Admin"'
        ));
        //curl_setopt($ch, CURLOPT_USERPWD, "XXXYYY:xxxxxxxxxxxxx"); //Probably not needed
    curl_setopt($ch, CURLOPT_POST, 1);
        $strRequest = "";
        $strRequest .= "AWBNumber=69184678161";
… etc….
        $strRequest .= "&pincode=";
        $strRequest .= "&Api_type=S";
        $strRequest .= "&Area=";
        $strRequest .= "&LicenceKey=xxxxxxxx";
        $strRequest .= "&LoginID=XXXYYY";
        $strRequest .= "&Version=1";
        curl_setopt($ch, CURLOPT_POSTFIELDS,$strRequest);

        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        $server_output = curl_exec($ch);
        var_dump($server_output);

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

В любом случае, комбинация не работает - в результате я получаю строку нулевой длины ($ server_output).Как правильно передать заголовки и что еще нужно исправить здесь?

Ответы [ 2 ]

0 голосов
/ 24 января 2019

Как я уже упоминал в комментариях, было бы намного проще использовать класс PHP SoapClient и объекты в качестве сущностей. Вот небольшой пример того, как вы можете решить свою проблему.

PHP-клиент Soap

PHP получил собственную сборку в SoapClient, которая работает довольно хорошо. Посмотрите, как инициализировать клиент для разработки.

<code>try {
    $client = new \SoapClient('https://example.com?wsdl', [
        'cache_wsdl' )> WSDL_CACHE_NONE,
        'exceptions' => true,
        'trace' => true,
    ]);
} catch (\SoapFault $fault) {
    echo "<pre>";
    var_dump($fault->getMessage());
    echo "
"; if ($ client) { echo "
";
        var_dump($client->__getLastRequest(), $client->__getLastResponse());
        echo "
"; } }

Это простая инициализация класса SoapClient с опциями разработки. Установка для опции trace значения true позволяет использовать внутренние функции клиентов __getLastRequest() и __getLastResponse(). Таким образом, вы можете видеть, что отправил клиент и как выглядит ответ, если таковой имеется. Я использую это для проверки XML, отправленного клиентом.

Простые объекты как объекты, которые могут быть использованы мылом

SOAP определяет себя как сложные и простые определения типов. Это можно увидеть, если вы вызываете собственную функцию __getTypes(). Будет отображено множество структур и простых определений типов, которые хранятся в данном файле wsdl или в файлах xsd, упомянутых в файле wsdl. С помощью этой информации мы можем построить свой собственный объект. В этом примере я использую простые stdClass объекты. В производственной манере вы должны использовать вычисленные собственные объекты.

$req = new \stdClass();
$req->AWBNumber = new \SoapVar(
    69184678146, 
    XSD_INT, 
    null, 
    null, 
    'AWBNumber', 
    'http://schemas.datacontract.org/2004/07/XXXAPI.Entities.XXX'
);
$encodedReq = new \SoapVar($req, SOAP_ENC_OBJECT, null, null, 'req', 'http://tempuri.org/');

$saveXXXStatus = new \stdClass();
$saveXXXStatus->req = $encodedReq;
$encodedSaveXXXStatus = new \SoapVar($saveXXXStatus, SOAP_ENC_OBJECT, null, null, 'SaveXXXStatus, 'http://tempuri.org/');

// send the content with the soap client
$result = $client->SaveXXXStatus($encodedSaveXXXStatus);

Пожалуйста, имейте в виду, что это короткий пример, который является неполным и приведет к ошибке мыла. Но что я здесь сделал? Узел req в вашем xml - это объект. Вы найдете определение этого объекта в выводе вышеупомянутой функции __getTypes(). В этом примере я скомпилировал этот объект как stdClass со свойством AWBNumber. AWBNumber сам по себе является SoapVar объектом. Мы используем soap var из-за пространств имен, которые используются мыльным клиентом. После определения свойства мы кодируем объект req как мыльный объект, который также является экземпляром SoapVar.

В конце концов мы вызываем метод веб-сервиса SaveXXXStatus с закодированным параметром.

Последний запрос

Если вы отправите этот пример, последний запрос должен выглядеть следующим образом:

<ns1:envelope xmlns:ns1="http://www.w3.org/2003/05/soap-envelope" 
    xmlns:ns2="http://tempuri.org/"
    xmlns:ns3="http://schemas.datacontract.org/2004/07/XXXAPI.Entities.XXX">
    <ns1:body>
        <ns2:SaveXXXStatus>
            <ns2:req>
                <ns3:AWBNumber>69184678146</ns3:AWBNumber>
            </ns2:req>
        </ns2:SaveXXXStatus>
    </ns1:body>
</ns1:envelope>

Как я уже говорил, это всего лишь пример. Вы должны закодировать все узлы как SoapVar объекты и добавить его к родителям и, наконец, вызвать метод веб-сервиса с полными закодированными данными.

Просто как пирог, хм?

0 голосов
/ 23 января 2019

Я тоже застрял в этом несколько дней назад ... но попробовал так и получил результаты

$xml_post_string ='<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:tem="http://tempuri.org/" xmlns:XXX="http://schemas.datacontract.org/2004/07/XXXAPI.Entities.XXX" xmlns:XXX1="http://schemas.datacontract.org/2004/07/XXXAPI.Entities.Admin"> <soap:Header/>    <soap:Body>
  <tem:SaveXXXStatus>
     <!--Optional:-->
     <tem:req>
        <!--Optional:-->
        <XXX:AWBNumber>69184678146</XXX:AWBNumber>
        <!--Optional:--> 
           … etc. …
        <!--Optional:-->
        <XXX:pincode></XXX:pincode>
     </tem:req>
     <!--Optional:-->
     <tem:profile>
        <!--Optional:-->
        <XXX1:Api_type>S</XXX1:Api_type>
        <!--Optional:-->
        <XXX1:Area></XXX1:Area>
        <!--Optional:-->
        <XXX1:LicenceKey>xxxxxxxxxxxxxxxxxxx</XXX1:LicenceKey>
        <!--Optional:-->
        <XXX1:LoginID>XXXYYY</XXX1:LoginID>
        <!--Optional:-->
        <XXX1:Version>1</XXX1:Version>
     </tem:profile>
  </tem:SaveXXXStatus>    </soap:Body> </soap:Envelope>';

 $headers = array(
            "Content-type: text/xml;charset=\"utf-8\"",
            "Accept: text/xml",
            "Cache-Control: no-cache",
            "Pragma: no-cache",
            "SOAPAction: url",
            "Content-length: " . strlen($xml_post_string),
        );
$ch = curl_init();
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 1);
        curl_setopt($ch, CURLOPT_URL, 'yoururl');
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
        curl_setopt($ch, CURLOPT_TIMEOUT, 10);
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $xml_post_string);
        curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
        $response = curl_exec($ch);
print_r($response);
...