Hi

I need to manipulate a soap call before it's sent off to the soap server. Currently my soap call is constructed as follows:

<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<SOAP-ENV:Body>
    <ns1:SubmitStringLead>
        <xmlLead xsi:type="xsd:string">
            <strXml>
                <Lead>
                    <General>
                        <dealer>419</dealer>
                        <source ref="1334923054">randomstring</source>
                        <enquiry>1</enquiry>
                        <subtype>4</subtype>
                        <comment />
                    </General>
                    <Prospect>
                        <title />
                        <name>test</name>
                        <surname />
                        <email>test@test.com</email>
                        <home />
                        <work />
                        <mobile>0123456789</mobile>
                        <idnumber />
                        <comment />
                        <area />
                        <national>true</national>
                        <license>true</license>
                    </Prospect>
                    <Item>
                        <id>1234567</id>
                        <purchaseDate>Now</purchaseDate>
                    </Item>
                </Lead>
            </strXml>
        </xmlLead>
    </ns1:SubmitStringLead>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>

I need it to look exactly like the following...and I can't stress "exactly" enough. The soap server is on a microsoft platform and is fussy as hell.

<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  <soap:Body>
    <SubmitStringLead xmlns="">
      <strXml>
          <Lead>
              <General>
                  <dealer>419</dealer>
                  <source ref="1334923054">randomstring</source>
                  <enquiry>1</enquiry>
                  <subtype>4</subtype>
                  <comment />
              </General>
              <Prospect>
                  <title />
                  <name>test</name>
                  <surname />
                  <email>test@test.com</email>
                  <home />
                  <work />
                  <mobile>0123456789</mobile>
                  <idnumber />
                  <comment />
                  <area />
                  <national>true</national>
                  <license>true</license>
              </Prospect>
              <Item>
                  <id>1234567</id>
                  <purchaseDate>Now</purchaseDate>
              </Item>
          </Lead>
      </strXml>
    </SubmitStringLead>
  </soap:Body>
</soap:Envelope>

Anyone help will be enormously appreciated.

Dani AI

Generated

Nice catch, @Venom Rush. What bit you here was RPC/encoded vs document/literal. Your first attempt (non-WSDL, RPC/encoded) produced an envelope with an encodingStyle and RPC wrapper, while the Microsoft endpoint clearly wants doc/literal. Switching to WSDL mode and calling the method with an array lets PHP read the binding from the WSDL and emit the exact doc/literal shape, namespaces, and SOAPAction the server expects. If you ever must do non-WSDL, set style => SOAP_DOCUMENT and use => SOAP_LITERAL so PHP does not generate RPC/encoded. Also consider disabling WSDL caching while testing (cache_wsdl => WSDL_CACHE_NONE). See the SoapClient constructor options for details. PHP manual: SoapClient::__construct. (php.net)

For @Topi Ojala’s XSLT idea, you first need the full outbound message. Enable tracing and inspect the exact envelope and headers that PHP sent. Example below. The relevant APIs are documented here: __getLastRequest and __getLastRequestHeaders. (php.net)

$client = new SoapClient($wsdl, [
  'soap_version' => SOAP_1_1,
  'trace'        => 1,
  'cache_wsdl'   => WSDL_CACHE_NONE,
]);

$payload = '<Lead>...</Lead>';                         // build your XML
$params  = ['strXml' => new SoapVar($payload, XSD_ANYXML)];
$result  = $client->SubmitStringLead($params);

file_put_contents('last-request.xml', $client->__getLastRequest());

If your <strXml> content is getting escaped (e.g., &lt;Lead&gt;), wrap it in a SoapVar with XSD_ANYXML as above so it is inserted as raw XML, which many .NET doc/lit services expect. PHP manual: SoapVar. Background on XSD_ANYXML is noted in a PHP bug discussion. PHP bug #34449. (php.net)

Only as a last resort, subclass SoapClient and override __doRequest to tweak the raw envelope, but prefer fixing binding/style first. PHP manual: __doRequest. (php.net)

Recommended Answers

All 5 Replies

Do you have any experience with XSLT? Since SOAP messages are actually XML documents, you can transform them with the XSLT language.

Your biggest concerns seem to be renaming elements and injecting the character data into new elements. Keywords for XSL functions are xsl:template, xsl:match and xsl:apply-templates

Try searching for a tutorial online (please avoid W3Schools).

Thanks Topi. I'll look into this.

P.S. I tend to avoid W3Schools at all costs ;)

XSLT looks like something I could use but I first need to get the entire soap request (including the envelope) so that I can manipulate it.

I found a function which I thought would return everything but it only includes line 6-34 of my first example. If I can get the entire request, then altering it shouldn't be a problem.

This is the function I found:

class MSSoapClient extends SoapClient {

    function __doRequest($request, $location, $action, $version) {
        $namespace = "";

        $dom = new DOMDocument('1.0');
        $dom->loadXML($request);

        // Manipulate xml here

        $request = $dom->saveXML();

        // parent call
        return parent::__doRequest($request, $location, $action, $version);
    }
}

Does anyone know how I can get the entire soap call?

So my issue has been solved. It seems that the way I was making my soap request was causing issues.

This is how I was making my soap request:

$name = 'test';
$email = 'test@test.com';
$cell = '0123456789';
$stockid = '1234567';
$ref = time();

$xmlLead = '<strXml><Lead xmlns="">
    <General>
        <dealer>419</dealer>
        <source ref="'.$ref.'">string</source>
        <enquiry>1</enquiry>
        <subtype>4</subtype>
        <comment />
    </General>
    <Prospect>
        <title />
        <name>'.$name.'</name>
        <surname />
        <email>'.$email.'</email>
        <home />
        <work />
        <mobile>'.$cell.'</mobile>
        <idnumber />
        <comment />
        <area />
        <national>true</national>
        <license>true</license>
    </Prospect>
    <Item>
        <id>'.$stockid.'</id>
        <purchaseDate>Now</purchaseDate>
    </Item>
</Lead></strXml>';

$client = new SoapClient(NULL,

        array(

        "location" => "WSDL goes here",

        'soap_version'   => SOAP_1_1,

        "style"    => SOAP_RPC,

        "trace"      => 1,

        "exceptions" => 0

           ));

print($client->__soapCall(

        /* SOAP Method Name */

        "SubmitStringLead",

        /* Parameters */

        array(

            new SoapParam(

                /* Parameter Value */

                $xmlLead,

                /* Parameter Name */

                "xmlLead"

        )),

        /* Options */

        array(

            /* SOAP Method Namespace */

            "uri" => "",

            /* SOAPAction HTTP Header for SOAP Method */

            "soapaction" => ""

        )). "\n");

And this is how I'm doing it now:

$name = 'test';
$email = 'test@test.com';
$cell = '0123456798';
$stockid = '1234567';
$ref = time();

$xmlLead = '<Lead><General><dealer>419</dealer><source ref="' . $ref . '">string</source><enquiry>1</enquiry><subtype>4</subtype><comment /></General><Prospect><title /><name>' . $name . '</name><surname /><email>' . $email . '</email><home /><work /><mobile>' . $cell . '</mobile><idnumber /><comment /><area /><national>true</national><license>true</license></Prospect><Item><id>' . $stockid . '</id><purchaseDate>Now</purchaseDate></Item></Lead>';

$client = new SoapClient('WSDL goes here', array('soap_version' => SOAP_1_1, "trace" => 1, "exceptions" => 0));

$result = $client->SubmitStringLead(array('strXml' => $xmlLead));
commented: Thanks for sharing. +13

Hopefully that helps those out there having similar issues.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.