【问题标题】:remove soap headers from response before turning into simplexml object在变成 simplexml 对象之前从响应中删除肥皂头
【发布时间】:2020-10-09 13:15:41
【问题描述】:

我正在使用 Curl 来执行一个肥皂请求。 现在看起来头中返回了一个错误,使我无法使用函数 simplexml_load_string 将返回的字符串转换为 simplexml 对象。您可以在下面找到 simplexml 函数中响应失败的部分:

<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><SOAP-ENV:Header><SOAP-SEC:Signature xmlns:SOAP-SEC="http://schemas.xmlsoap.org/soap/security/2000-12"><ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#"><ds:SignedInfo><ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#dsa-sha1"/><ds:Reference URI="#Body"><ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/><ds:DigestValue>HV+/cOkUjNCdH5xuiLlGSHVgkUo=</ds:DigestValue></ds:Reference><ds:SignatureValue>MCwCFHXmoMrDUOScwMQ5g76OfxouICjBAhQtGKAorJLUQ0bA0UaKIe1gtmQPgA==</ds:SignatureValue></ds:SignedInfo></ds:Signature></SOAP-SEC:Signature></SOAP-ENV:Header><SOAP-ENV:Body xmlns:SOAP-SEC="http://schemas.xmlsoap.org/soap/security/2000-12" SOAP-SEC:id="Body">

有没有办法隔离肥皂正文内容并使用 simplexml_load_string 仅解析该部分?

在 curl 请求下方:

$headers = array(
              "Content-type: text/xml;charset=\"utf-8\"",
              "Accept: text/xml",
              "Cache-Control: no-cache",
              "Pragma: no-cache",
              "Content-length: ".strlen($xml_post_string),
          ); 

          $url = $soapUrl;

          $ch = curl_init();
          curl_setopt($ch, CURLOPT_URL, $url);
          curl_setopt($ch, CURLOPT_POST, true);
          curl_setopt($ch, CURLOPT_POSTFIELDS, $xml_post_string);
          curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
          curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
          curl_setopt($ch, CURLOPT_HEADER, 0);
          curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);

          $response = curl_exec($ch); 
          curl_close($ch);
$xml = simplexml_load_string(html_entity_decode($response), 'SimpleXMLElement', LIBXML_NOCDATA);

        echo $xml->asXML();

        if ($xml === false) {
          echo "Failed to load XML: ";

          foreach(libxml_get_errors() as $error) {
            echo "<br>", $error->message;
          }
        } else {
          var_dump($xml);
        }












【问题讨论】:

标签: php xml curl soap


【解决方案1】:

仅举一些示例 XML 内容,这对于任何文件都会有所不同,但只是显示了您可以如何访问数据...

<SOAP-ENV:Body
    xmlns:SOAP-SEC="http://schemas.xmlsoap.org/soap/security/2000-12"
    SOAP-SEC:id="Body">
        <BodyContent>SomeData</BodyContent>
        <OtherContent>2</OtherContent>
</SOAP-ENV:Body>

那就是使用XPath来查找&lt;SOAP-ENV:Body&gt;标签的情况

$xml->registerXPathNamespace("SOAP-ENV", "http://schemas.xmlsoap.org/soap/envelope/");
$bodyBlock = $xml->xpath("//SOAP-ENV:Body")[0];

(请注意,xpath() 返回匹配列表,使用 [0] 只使用第一个)。

下一部分取决于正在处理的消息,但正如我给出的示例中的子元素没有命名空间前缀一样,您可以使用-&gt;children() 提取这些子元素,这样可以简化对内容的访问。主要部分是此时$bodyBlock 包含这个...

<SOAP-ENV:Body xmlns:SOAP-SEC="http://schemas.xmlsoap.org/soap/security/2000-12" SOAP-SEC:id="Body">
        <BodyContent>SomeData</BodyContent>
        <OtherContent>2</OtherContent>
</SOAP-ENV:Body>

所以把它放在你的原始代码中......

$xml = simplexml_load_string($response, 'SimpleXMLElement', LIBXML_NOCDATA);

if ($xml === false) {
    echo "Failed to load XML: ";
    
    foreach(libxml_get_errors() as $error) {
        echo "<br>", $error->message;
    }
} else {
    // Search for the Body element (this is in the SOAP-ENV namespace)
    $xml->registerXPathNamespace("SOAP-ENV", "http://schemas.xmlsoap.org/soap/envelope/");
    $bodyBlock = $xml->xpath("//SOAP-ENV:Body")[0];
    
    // If the content does not have a namespace, extract the children from the default namespace
    $body = $bodyBlock->children();
    
    // You can now access the content.
    echo $body->BodyContent.PHP_EOL;
    echo $body->OtherContent;
    
}

在正文中输出两个值....

SomeData
2

【讨论】:

    【解决方案2】:

    我现在没有答案,但您首先需要将 curl 与 XML 处理分开。您应该首先从 curl 记录您的结果,并确保它是理智的并且符合您的期望。如果是,然后继续解析它。 curl 不应以任何方式破坏/更改您的数据,但请求本身(标头等)可能会更改服务器的响应。

    由于我无法验证您的服务器,因此我将不再使用您提供的内容。我已经关闭了&lt;SOAP-ENV:Body&gt; 标记并将XML 转换为可读,但除此之外它保持不变。这段代码可以毫无问题地解析 XML,然后完全按照预期发出它。

    $response = <<<'TAG'
    <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
        <SOAP-ENV:Header>
            <SOAP-SEC:Signature xmlns:SOAP-SEC="http://schemas.xmlsoap.org/soap/security/2000-12">
                <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
                    <ds:SignedInfo>
                        <ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#dsa-sha1" />
                        <ds:Reference URI="#Body">
                            <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" />
                            <ds:DigestValue>HV+/cOkUjNCdH5xuiLlGSHVgkUo=</ds:DigestValue>
                        </ds:Reference>
                        <ds:SignatureValue>MCwCFHXmoMrDUOScwMQ5g76OfxouICjBAhQtGKAorJLUQ0bA0UaKIe1gtmQPgA==</ds:SignatureValue>
                    </ds:SignedInfo>
                </ds:Signature>
            </SOAP-SEC:Signature>
        </SOAP-ENV:Header>
        <SOAP-ENV:Body xmlns:SOAP-SEC="http://schemas.xmlsoap.org/soap/security/2000-12" SOAP-SEC:id="Body"></SOAP-ENV:Body>
    </SOAP-ENV:Envelope>
    TAG;
    
    $xml = simplexml_load_string(html_entity_decode($response), 'SimpleXMLElement', LIBXML_NOCDATA);
    
    echo '<pre>';
    print_r(htmlspecialchars($xml->asXML()));
    echo '</pre>';
    
    

    输出与输入完全相同,只是它包含 XML 指令并将 body 标签转换为自关闭:

    <?xml version="1.0"?>
    <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
        <SOAP-ENV:Header>
            <SOAP-SEC:Signature xmlns:SOAP-SEC="http://schemas.xmlsoap.org/soap/security/2000-12">
                <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
                    <ds:SignedInfo>
                        <ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#dsa-sha1"/>
                        <ds:Reference URI="#Body">
                            <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
                            <ds:DigestValue>HV+/cOkUjNCdH5xuiLlGSHVgkUo=</ds:DigestValue>
                        </ds:Reference>
                        <ds:SignatureValue>MCwCFHXmoMrDUOScwMQ5g76OfxouICjBAhQtGKAorJLUQ0bA0UaKIe1gtmQPgA==</ds:SignatureValue>
                    </ds:SignedInfo>
                </ds:Signature>
            </SOAP-SEC:Signature>
        </SOAP-ENV:Header>
        <SOAP-ENV:Body xmlns:SOAP-SEC="http://schemas.xmlsoap.org/soap/security/2000-12" SOAP-SEC:id="Body"/>
    </SOAP-ENV:Envelope>
    

    因此,以此为基准。在执行任何其他操作之前将您的 curl 响应写入文本文件,然后将该文本文件读回并执行逻辑。您对字符串 XML 应用的任何转换也应该被记录下来并进行比较,以确保它符合您的预期。在生产环境中,您可以跳过它,但这只会在调试过程中有所帮助。

    另外,我不太确定html_entity_decode 的意义何在。如果您正在接收 XML(根据您的请求 mime 类型指定),那么它不应该应用任何转义序列,但也许您也有例外情况。

    【讨论】:

      猜你喜欢
      • 2016-09-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-01-01
      • 1970-01-01
      • 2019-09-05
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多