使用PHP的SOAP XML请求无法正常工作-可能是标题问题

时间:2019-01-23 16:42:03

标签: php xml soap php-curl

我需要使用SOAP和XML发布到客户端的URL(如果客户端在.Net平台上很重要)。该请求应如下所示:

<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);

This post显示可以将标头(信封等)简单地添加到POSTFIELDS字符串中,但是我尝试了一下,但是它没有用。除此之外,这似乎是一种骇客!

无论如何,没有任何组合有效-我得到一个长度为零的字符串($ server_output)。传递标头的正确方法是什么,还有什么需要在此处解决的?

2 个答案:

答案 0 :(得分:1)

几天前我也陷入困境...但是尝试过这种方式并获得了结果

$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);

答案 1 :(得分:0)

正如我在评论中已经提到的,使用PHP SoapClient类中的构建和将对象作为实体会容易得多。这是一个小例子,说明如何解决问题。

PHP Soap客户端

PHP在SoapClient中拥有自己的构建,可以很好地运行。看看如何初始化客户端以进行开发。

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 "</pre>";

    if ($client) {
        echo "<pre>";
        var_dump($client->__getLastRequest(), $client->__getLastResponse());
        echo "</pre>";
    }
}

这是SoapClient类的简单初始化,带有开发选项。将trace选项设置为true可启用客户端内部功能__getLastRequest()__getLastResponse()的使用。因此,您可以看到客户端发送的内容以及响应的内容(如果有)。我正在用它来检查客户端已发送的xml。

简单的实体,可以被肥皂使用

SOAP将自身定义为复杂和简单的类型定义。如果调用客户端自己的__getTypes()函数,则可以看到此信息。将显示许多结构和简单的类型定义,它们存储在给定的wsdl文件或wsdl文件中提到的xsd文件中。有了这些信息,我们就能构建自己的对象。在此示例中,我使用简单的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);

请记住,这是一个简短的示例,不完整,会导致肥皂故障。但是我在这里做了什么? xml中的req节点是一个对象。您可以在上面提到的__getTypes()函数输出中找到该对象的定义。在此示例中,我将该对象编译为具有属性stdClass的{​​{1}}。 AWBNumber本身是AWBNumber对象。由于soap客户端使用的命名空间,我们使用soap var。定义属性后,我们将SoapVar对象编码为肥皂对象,它也是一个req实例。

毕竟,我们使用编码参数调用webservice方法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> 对象,并将其附加到父对象,最后使用完整的编码数据调用webservice方法。

像馅饼一样简单,嗯?