PHP SoapClient 的复杂 Headers

Complex Headers for PHP SoapClient

我需要将以下具有不同命名空间和类型的复合体 header 添加到我的 SoapClient Header。

<soapenv:Header xmlns:wsa="http://www.w3.org/2005/08/addressing">
    <wsse:Security soapenv:mustUnderstand="1" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
        <wsse:UsernameToken>
            <wsse:Username>****</wsse:Username>
            <wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">*****</wsse:Password>
        </wsse:UsernameToken>
    </wsse:Security>
    <wsa:Action>/IntS5/S5WS</wsa:Action>
</soapenv:Header>

正如其他答案中所建议的那样,我在 php project.Since 中尝试了以下方法我需要 WSA 寻址,我将 wsa:Action 与安全 header 一起设置。

    $header_part = '<wsse:Security soapenv:mustUnderstand="1" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">'
         . '<wsse:UsernameToken><wsse:Username>****</wsse:Username><wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">****</wsse:Password>'
         . '</wsse:UsernameToken></wsse:Security><wsa:Action>/IntS5/S5WS</wsa:Action>';

    $soap_var_header = new SoapVar($header_part, XSD_ANYXML, null, null, null);
    $soap_header = new SOAPHeader('http://www.w3.org/2005/08/addressing', 'wsa', $soap_var_header);
    $client->__setSoapHeaders($soap_header);

我怎么__soapCall returns 出现以下错误。

SoapFault 异常:[Client] DTD 不受 SOAP.I 支持我不确定它是否与 header 或 putCall 的参数有关。任何人都可以帮助我吗?

编辑: 问题可能与 HEADER/Envelope.

的命名空间有关

发送到服务器的请求如下所示。 已更新

<?xml version="1.0" encoding="UTF-8"?>
                    <env:Envelope xmlns:env="http://www.w3.org/2003/05/soap-envelope" xmlns:ns1="http://ws.s5.mediasat.de/" xmlns:ns2="http://www.w3.org/2005/08/addressing">
                        <env:Header>
                            <wsse:Security env:mustUnderstand="1" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
                                <wsse:UsernameToken>
                                    <wsse:Username>****</wsse:Username>
                                    <wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">*****</wsse:Password>
                                </wsse:UsernameToken>
                            </wsse:Security>
                            <wsa:Action xmlns:wsa="http://www.w3.org/2005/08/addressing">/IntS5/S5WS</wsa:Action>
                        </env:Header>
                        <env:Body>
                            <ns1:putCall>
                                <transaction>createIncident</transaction>
                                <transactionSender>Request</transactionSender>
                                <caseDataModel>
                                    <senderId>7</senderId>
                                    <ticketTypeId>102</ticketTypeId>
                                    <title>test</title>
                                    <priorityId>101</priorityId>
                                    <categoryId>128</categoryId>
                                    <description>Description</description>
                                    <ticketNumberSender>INCC00000743809</ticketNumberSender>
                                    <createTypeId>701</createTypeId>
                                    <serviceId>B001APP05K</serviceId>
                                    <categoryId>128</categoryId>
                                    <serviceRecipientId>77888</serviceRecipientId>
                                    <serviceLocationSAPCode>V135</serviceLocationSAPCode>
                                </caseDataModel>
                            </ns1:putCall>
                        </env:Body>
                    </env:Envelope>

在 SOAP 上工作的请求UI

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ws="http://ws.s5.mediasat.de/">
    <soapenv:Header xmlns:wsa="http://www.w3.org/2005/08/addressing">
        <wsse:Security soapenv:mustUnderstand="1" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
            <wsse:UsernameToken>
                <wsse:Username>***</wsse:Username>
                <wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">***</wsse:Password>
            </wsse:UsernameToken>
        </wsse:Security>
        <wsa:Action>/IntS5/S5WS</wsa:Action>
    </soapenv:Header>
    <soapenv:Body>
        <ws:putCall>
            <transaction>createIncident</transaction>
            <transactionSender>Request</transactionSender>
            <caseDataModel>
                <senderId>7</senderId>
                <ticketTypeId>102</ticketTypeId>
                <title>test</title>
                <priorityId>101</priorityId>
                <categoryId>128</categoryId>
                <description>Description</description>
                <ticketNumberSender>INCC00000743809</ticketNumberSender>
                <createTypeId>701</createTypeId>
                <serviceId>B001APP05K</serviceId>
                <categoryId>128</categoryId>
                <serviceRecipientId>77888</serviceRecipientId>
                <serviceLocationSAPCode>V135</serviceLocationSAPCode>
            </caseDataModel>
        </ws:putCall>
    </soapenv:Body>
</soapenv:Envelope>

set/override 是否有 header 的命名空间?

  1. 名称 space“http://www.w3.org/2005/08/addressing”未绑定到前缀 "wsa"。

  2. "mustUnderstand" 属性必须使用前缀 "env" 而不是 "soapenv"。

您可以在本地声明缺失的名称space。你只需要修复你 header_part 看起来像这样:

header_part = '<wsse:Security env:mustUnderstand="1" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">'
     . '<wsse:UsernameToken><wsse:Username>****</wsse:Username><wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">****</wsse:Password>'
     . '</wsse:UsernameToken></wsse:Security><wsa:Action xmlns:wsa="http://www.w3.org/2005/08/addressing">/IntS5/S5WS</wsa:Action>';

注意: 也许这很明显,但是假设“http://www.w3.org/2003/05/soap-envelope”的前缀总是 "env" 有点危险。该框架可以随时更改此设置。如果您想真正安全起见,您可能更愿意将名称 space 在本地绑定到新前缀:

<wsse:Security soapenv:mustUnderstand="1" xmlns:soapenv="http://www.w3.org/2003/05/soap-envelope" ...

但是将一个名字space绑定到两个不同的前缀会使事情更难阅读和理解,所以我认为这是一个品味问题。

您应该按程序生成 header 而不是使用字符串。

示例:

<?php

$client = new SoapClient(null, array(
    'location' => "http://localhost/soap/",
    'uri' => "http://ws.s5.mediasat.de/",
    'soap_version'   => SOAP_1_2
));

$username = '***';
$password = '***';
$sec_namespace = 'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd';
$wsa_namespace = 'http://www.w3.org/2005/08/addressing';

// prepare security token
$node1 = new \SoapVar($username, XSD_STRING, null, null, 'Username', $sec_namespace);

$xml = new XMLWriter(); // this is a little hacky, but no other way to set the type as far as I know
$xml->openMemory();
$xml->startElementNS('wsse', 'Password',$sec_namespace);
$xml->writeAttribute('Type', 'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText');
$xml->Text($password);
$xml->endElement();
$node2 = new \SoapVar($xml->outputMemory(), XSD_ANYXML);

$token = new \SoapVar(array($node1, $node2), SOAP_ENC_OBJECT, null, null, 'UsernameToken', $sec_namespace);
$security = new \SoapVar(array($token), SOAP_ENC_OBJECT, null, null, 'Security', $sec_namespace);
$soap_header_sec = new \SOAPHeader($sec_namespace, 'Security', $security, true);

// prepare action token
$action = new \SoapVar('/IntS5/S5WS', XSD_STRING, null, null, 'Action', $wsa_namespace);
$soap_header_action = new \SOAPHeader($wsa_namespace, 'Action', $action, false);

// set prepared headers
$client->__setSoapHeaders(
    [$soap_header_sec,$soap_header_action]
 );

$client->putCall();

这将生成包含所有命名空间集的有效信封:

<?xml version="1.0" encoding="utf-8"?>
<env:Envelope xmlns:env="http://www.w3.org/2003/05/soap-envelope" xmlns:ns1="http://ws.s5.mediasat.de/" xmlns:ns2="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:ns3="http://www.w3.org/2005/08/addressing" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:enc="http://www.w3.org/2003/05/soap-encoding">
  <env:Header>
    <ns2:Security env:mustUnderstand="true">
      <ns2:UsernameToken>
        <ns2:Username>***</ns2:Username>
        <wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">***</wsse:Password>
      </ns2:UsernameToken>
    </ns2:Security>
    <ns3:Action>/IntS5/S5WS</ns3:Action>
  </env:Header>
  <env:Body>
    <ns1:putCall env:encodingStyle="http://www.w3.org/2003/05/soap-encoding" />
  </env:Body>
</env:Envelope>