title: PHP SOAP request to navision webservice
body: <p>For days I've been struggling to get a connection between a PHP webshop and a navision server with NTLM authentication. Now that the connection and authentication is done, I'm having problems with doing a correct request.</p>
  
  <p>For this example I try to use a function (ItemPriceDiscInventory) to retrieve price information.</p>
  
  <p>The url I have from the customer is: <a href="http://IP:PORT/MSIteminfoTest/WS/Saniceve%20BV/Codeunit/ItemPriceDiscInventory">http://IP:PORT/MSIteminfoTest/WS/Saniceve%20BV/Codeunit/ItemPriceDiscInventory</a> </p>
  
  <p>I have tried 2 methods to make the request:</p>
  
  <p><strong>curl post with raw XML</strong></p>
  
  <p>The raw XML is given by the customer. This is the same XML the test program (SOACleaner) gives me when entered the (local) WSDL file.</p>
  
  <pre><code>$request = '
  &lt;InputItemPriceDiscInventory_PortGetPriceDiscInvInformation xmlns="http://xyrow.com"&gt;
  &lt;Body xmlns=""&gt;
  &lt;GetPriceDiscInvInformation xmlns="urn:microsoft-dynamics-schemas/codeunit/ItemPriceDiscInventory"&gt;
    &lt;itemPriceDiscInventory&gt;
      &lt;Item xmlns="urn:microsoft-dynamics-nav/xmlports/x50005"&gt;
        &lt;Klantnummer /&gt;
        &lt;Artikelnr /&gt;
        &lt;Aantal /&gt;
        &lt;KortingsPercentage1 /&gt;
        &lt;KortingsPercentage2 /&gt;
        &lt;NettoPerEenheid /&gt;
        &lt;BeschikbareVoorraad /&gt;
        &lt;WebShopVoorraad /&gt;
      &lt;/Item&gt;
    &lt;/itemPriceDiscInventory&gt;
    &lt;customerNo&gt;1234&lt;/customerNo&gt;
    &lt;itemNo&gt;5678&lt;/itemNo&gt;
    &lt;quantityVarDec&gt;1&lt;/quantityVarDec&gt;
  &lt;/GetPriceDiscInvInformation&gt;
  &lt;/Body&gt;
  &lt;/InputItemPriceDiscInventory_PortGetPriceDiscInvInformation&gt;';
  </code></pre>
  
  <p>My request:</p>
  
  <pre><code>$ch = curl_init(); 
  $headers = array( 
        'Method: POST', 
          'Connection: Keep-Alive',       
          'Content-Type: text/xml; charset=utf-8',             
          "Host: {$ip}:{$port}",
          "Accept: */*"                       
      );      
  curl_setopt($ch, CURLOPT_URL,            $url );        
  curl_setopt($ch, CURLOPT_RETURNTRANSFER, true );
  curl_setopt($ch, CURLOPT_POST,           true );        
  curl_setopt($ch, CURLOPT_POSTFIELDS,    $request); 
  curl_setopt($ch, CURLOPT_USERPWD, 'usr:pass');
  curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_NTLM );
  curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);          
  curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);     
  curl_setopt($ch, CURLOPT_FAILONERROR, 0);
  </code></pre>
  
  <p>This returns the WSDL file, no matter what POST values I include. If I include the header <code>'SOAPAction: "ItemPriceDiscInventory"'</code> it gives me the error:</p>
  
  <pre><code>&lt;s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"&gt;&lt;s:Body&gt;&lt;s:Fault&gt;&lt;faultcode xmlns:a="urn:microsoft-dynamics-schemas/error"&gt;a:System.Net.WebException&lt;/faultcode&gt;&lt;faultstring xml:lang="nl-NL"&gt;Soap message is invalid!&lt;/faultstring&gt;&lt;detail&gt;&lt;string xmlns="http://schemas.microsoft.com/2003/10/Serialization/"&gt;Soap message is invalid!&lt;/string&gt;&lt;/detail&gt;&lt;/s:Fault&gt;&lt;/s:Body&gt;&lt;/s:Envelope&gt; 
  </code></pre>
  
  <p>The WSDL looks like:</p>
  
  <pre><code>&lt;definitions targetNamespace="urn:microsoft-dynamics-schemas/codeunit/ItemPriceDiscInventory" xmlns="http://schemas.xmlsoap.org/wsdl/" xmlns:tns="urn:microsoft-dynamics-schemas/codeunit/ItemPriceDiscInventory"&gt;
  &lt;types&gt;
      &lt;schema elementFormDefault="qualified" targetNamespace="urn:microsoft-dynamics-nav/xmlports/x50005" xmlns="http://www.w3.org/2001/XMLSchema" xmlns:tns="urn:microsoft-dynamics-nav/xmlports/x50005"&gt;
          &lt;complexType name="Item"&gt;
              &lt;sequence&gt;
                  &lt;element minOccurs="1" maxOccurs="1" name="Klantnummer" type="string"/&gt;
                  &lt;element minOccurs="1" maxOccurs="1" name="Artikelnr" type="string"/&gt;
                  &lt;element minOccurs="1" maxOccurs="1" name="Aantal" type="string"/&gt;
                  &lt;element minOccurs="1" maxOccurs="1" name="KortingsPercentage1" type="string"/&gt;
                  &lt;element minOccurs="1" maxOccurs="1" name="KortingsPercentage2" type="string"/&gt;
                  &lt;element minOccurs="1" maxOccurs="1" name="NettoPerEenheid" type="string"/&gt;
                  &lt;element minOccurs="1" maxOccurs="1" name="BeschikbareVoorraad" type="string"/&gt;
                  &lt;element minOccurs="1" maxOccurs="1" name="WebShopVoorraad" type="string"/&gt;
              &lt;/sequence&gt;
          &lt;/complexType&gt;
          &lt;complexType name="ItemPriceDiscInvInfo" mixed="true"&gt;
              &lt;sequence&gt;
                  &lt;element minOccurs="1" maxOccurs="1" name="Item" type="tns:Item"/&gt;
              &lt;/sequence&gt;
          &lt;/complexType&gt;
          &lt;element name="ItemPriceDiscInvInfo" type="tns:ItemPriceDiscInvInfo"/&gt;
      &lt;/schema&gt;
      &lt;schema elementFormDefault="qualified" targetNamespace="urn:microsoft-dynamics-schemas/codeunit/ItemPriceDiscInventory" xmlns="http://www.w3.org/2001/XMLSchema"&gt;
          &lt;element name="GetPriceDiscInvInformation"&gt;
              &lt;complexType&gt;
                  &lt;sequence&gt;
                      &lt;element minOccurs="1" maxOccurs="1" name="itemPriceDiscInventory" type="q1:ItemPriceDiscInvInfo" xmlns:q1="urn:microsoft-dynamics-nav/xmlports/x50005"/&gt;
                      &lt;element minOccurs="1" maxOccurs="1" name="customerNo" type="string"/&gt;
                      &lt;element minOccurs="1" maxOccurs="1" name="itemNo" type="string"/&gt;
                      &lt;element minOccurs="1" maxOccurs="1" name="quantityVarDec" type="decimal"/&gt;
                  &lt;/sequence&gt;
              &lt;/complexType&gt;
          &lt;/element&gt;
          &lt;element name="GetPriceDiscInvInformation_Result"&gt;
              &lt;complexType&gt;
                  &lt;sequence&gt;
                      &lt;element minOccurs="1" maxOccurs="1" name="itemPriceDiscInventory" type="q2:ItemPriceDiscInvInfo" xmlns:q2="urn:microsoft-dynamics-nav/xmlports/x50005"/&gt;
                  &lt;/sequence&gt;
              &lt;/complexType&gt;
          &lt;/element&gt;
      &lt;/schema&gt;
  &lt;/types&gt;
  &lt;message name="GetPriceDiscInvInformation"&gt;
      &lt;part name="parameters" element="tns:GetPriceDiscInvInformation"/&gt;
  &lt;/message&gt;
  &lt;message name="GetPriceDiscInvInformation_Result"&gt;
      &lt;part name="parameters" element="tns:GetPriceDiscInvInformation_Result"/&gt;
  &lt;/message&gt;
  &lt;portType name="ItemPriceDiscInventory_Port"&gt;
      &lt;operation name="GetPriceDiscInvInformation"&gt;
          &lt;input name="GetPriceDiscInvInformation" message="tns:GetPriceDiscInvInformation"/&gt;
          &lt;output name="GetPriceDiscInvInformation_Result" message="tns:GetPriceDiscInvInformation_Result"/&gt;
      &lt;/operation&gt;
  &lt;/portType&gt;
  &lt;binding name="ItemPriceDiscInventory_Binding" type="tns:ItemPriceDiscInventory_Port"&gt;
      &lt;binding transport="http://schemas.xmlsoap.org/soap/http" xmlns="http://schemas.xmlsoap.org/wsdl/soap/"/&gt;
      &lt;operation name="GetPriceDiscInvInformation"&gt;
          &lt;operation soapAction="urn:microsoft-dynamics-schemas/codeunit/ItemPriceDiscInventory:GetPriceDiscInvInformation" style="document" xmlns="http://schemas.xmlsoap.org/wsdl/soap/"/&gt;
          &lt;input name="GetPriceDiscInvInformation"&gt;
              &lt;body use="literal" xmlns="http://schemas.xmlsoap.org/wsdl/soap/"/&gt;
          &lt;/input&gt;
          &lt;output name="GetPriceDiscInvInformation_Result"&gt;
              &lt;body use="literal" xmlns="http://schemas.xmlsoap.org/wsdl/soap/"/&gt;
          &lt;/output&gt;
      &lt;/operation&gt;
  &lt;/binding&gt;
  &lt;service name="ItemPriceDiscInventory"&gt;
      &lt;port name="ItemPriceDiscInventory_Port" binding="tns:ItemPriceDiscInventory_Binding"&gt;
          &lt;address location="http://IP:PORT/MSIteminfoTest/WS/Saniceve%20BV/Codeunit/ItemPriceDiscInventory" xmlns="http://schemas.xmlsoap.org/wsdl/soap/"/&gt;
      &lt;/port&gt;
  &lt;/service&gt;
  &lt;/definitions&gt;
  </code></pre>
  
  <p><strong>PHP SoapClient request</strong></p>
  
  <p>Ok, I thought, try the SOAP functionality of PHP. I used a NTLMSoapClient class for the authentication, which seems to be OK. 
  If I construct the client in WSDL mode, with the URL given above, it can't parse the WSDL:</p>
  
  <pre><code>[WSDL] SOAP-ERROR: Parsing WSDL: Couldn't load from 'URL' : Start tag expected, '&lt;' 
  </code></pre>
  
  <p>But if I do it in non WSDL mode, and give the location in the parameters, I'm having some result... </p>
  
  <pre><code>    stream_wrapper_unregister('http'); 
  stream_wrapper_register('http', 'MyServiceProviderNTLMStream') or die("Failed to register protocol");
  
  $client = new MyServiceNTLMSoapClient(null,array(   'location' =&gt; $url,
                                                      'uri'      =&gt; "http://schemas.xmlsoap.org/wsdl/soap/",
                                                      'trace'    =&gt; 1));  
  
  $itemPriceDiscInventory = array(
                  "Item" =&gt; array(
                      "Klantnummer" =&gt; null,
                      "Artikelnr" =&gt; null,
                      "Aantal" =&gt; null,
                      "KortingsPercentage" =&gt; null,
                      "NettoPerEenheid" =&gt; null,
                      "Voorraad" =&gt; null
                  )
              );
  
  $params = array(
              "itemPriceDiscInventory" =&gt; $itemPriceDiscInventory,
              "customerNo" =&gt; '0000265',
              "itemNo" =&gt; 'SAN483539',
              "quantityVarDec" =&gt; '1.0'
  );
  
  
  echo $client-&gt;GetPriceDiscInvInformation($params);  
  
  stream_wrapper_restore('http');
  </code></pre>
  
  <p>This results in an error. If I get the last request and response it gives me:</p>
  
  <pre><code>&lt;?xml version="1.0" encoding="UTF-8"?&gt;
  &lt;SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ns2="http://xml.apache.org/xml-soap" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"&gt;
  &lt;SOAP-ENV:Body&gt;
      &lt;ns1:GetPriceDiscInvInformation&gt;
          &lt;param0 xsi:type="ns2:Map"&gt;
              &lt;item&gt;
                  &lt;key xsi:type="xsd:string"&gt;itemPriceDiscInventory&lt;/key&gt;
                  &lt;value xsi:type="ns2:Map"&gt;
                      &lt;item&gt;
                          &lt;key xsi:type="xsd:string"&gt;Item&lt;/key&gt;
                          &lt;value xsi:type="ns2:Map"&gt;
                              &lt;item&gt;
                                  &lt;key xsi:type="xsd:string"&gt;Klantnummer&lt;/key&gt;
                                  &lt;value xsi:nil="true"/&gt;
                              &lt;/item&gt;
                              &lt;item&gt;
                                  &lt;key xsi:type="xsd:string"&gt;Artikelnr&lt;/key&gt;
                                  &lt;value xsi:nil="true"/&gt;
                              &lt;/item&gt;
                              &lt;item&gt;
                                  &lt;key xsi:type="xsd:string"&gt;Aantal&lt;/key&gt;
                                  &lt;value xsi:nil="true"/&gt;
                              &lt;/item&gt;
                              &lt;item&gt;
                                  &lt;key xsi:type="xsd:string"&gt;KortingsPercentage&lt;/key&gt;
                                  &lt;value xsi:nil="true"/&gt;
                              &lt;/item&gt;
                              &lt;item&gt;
                                  &lt;key xsi:type="xsd:string"&gt;NettoPerEenheid&lt;/key&gt;
                                  &lt;value xsi:nil="true"/&gt;
                              &lt;/item&gt;
                              &lt;item&gt;
                                  &lt;key xsi:type="xsd:string"&gt;Voorraad&lt;/key&gt;
                                  &lt;value xsi:nil="true"/&gt;
                              &lt;/item&gt;
                          &lt;/value&gt;
                      &lt;/item&gt;
                  &lt;/value&gt;
              &lt;/item&gt;
              &lt;item&gt;
                  &lt;key xsi:type="xsd:string"&gt;customerNo&lt;/key&gt;
                  &lt;value xsi:type="xsd:string"&gt;0000265&lt;/value&gt;
              &lt;/item&gt;
              &lt;item&gt;
                  &lt;key xsi:type="xsd:string"&gt;itemNo&lt;/key&gt;
                  &lt;value xsi:type="xsd:string"&gt;SAN483539&lt;/value&gt;
              &lt;/item&gt;
              &lt;item&gt;
                  &lt;key xsi:type="xsd:string"&gt;quantityVarDec&lt;/key&gt;
                  &lt;value xsi:type="xsd:string"&gt;1.0&lt;/value&gt;
              &lt;/item&gt;
          &lt;/param0&gt;
      &lt;/ns1:GetPriceDiscInvInformation&gt;
  &lt;/SOAP-ENV:Body&gt;
  &lt;/SOAP-ENV:Envelope&gt;
  </code></pre>
  
  <p>Response:</p>
  
  <pre><code>&lt;s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"&gt;
  &lt;s:Body&gt;
      &lt;s:Fault&gt;
          &lt;faultcode xmlns:a="urn:microsoft-dynamics-schemas/error"&gt;a:Microsoft.Dynamics.Nav.Service.WebServices.ServiceBrokerException&lt;/faultcode&gt;
          &lt;faultstring xml:lang="nl-NL"&gt;Parameter itemPriceDiscInventory in method GetPriceDiscInvInformation in service ItemPriceDiscInventory is null!&lt;/faultstring&gt;
          &lt;detail&gt;
              &lt;string xmlns="http://schemas.microsoft.com/2003/10/Serialization/"&gt;Parameter itemPriceDiscInventory in method GetPriceDiscInvInformation in service ItemPriceDiscInventory is null!&lt;/string&gt;
          &lt;/detail&gt;
      &lt;/s:Fault&gt;
  &lt;/s:Body&gt;
  </code></pre>
  
  <p></p>
  
  <p>So, it seems that he is trying to parse it, but the request is not in correct format. Note: I don't know exactly what the uri parameter has to be. Is this something I can read from the WSDL?</p>
  
  <p>If I look at the request that the customer gave me and the SOAP request, it differs a lot (first one doesn't looks like SOAP at all), but with the SOAP request, it seems to be that I get a bit closer.</p>
  
  <p>Any thoughts on this?</p>