Pragmatism in the real world

Selecting the service port with PHP's SoapClient

I’m currently integrating with a SOAP service which has two different services defined.

The relevant part of the WSDL is:

<wsdl:service name="Config">
    <wsdl:port name="BasicHttpBinding_IConfiguration" binding="tns:BasicHttpBinding_IConfiguration">
        <soap:address location="http://nonsecure.example.com/Configuration.svc"/>
    </wsdl:port>
    <wsdl:port name="BasicHttpsBinding_IConfiguration" binding="tns:BasicHttpsBinding_IConfiguration">
        <soap:address location="https://secure.example.com/Configuration.svc"/>
    </wsdl:port>
</wsdl:service>

I discovered that PHP’s SoapClient will select the first port it encounters and doesn’t provide a way to select another one. This was a nuisance as I wanted to use the SSL one.

Through research, I discovered that I can use __setLocation():

$client->__setLocation('https://secure.example.com/Configuration.svc');

However, I don’t control that endpoint, so I would rather select based on the port’s name.

As I couldn’t find a way to get the data from SoapClient, I decided to parse the WSDL myself and pull the information out. I don’t do a lot with XML namespaces, so had to look up how to handle them and then how to extract the right data using XPath.

As I had to look it up, I’m putting it here, so I can find it again more easily!

I converted my new found knowledge into a method to extract the location attribute from the <soap:address> element of the <wsdl:port> with the correct name element:

function getLocationForPort($wsdl, $portName)
{
    $file = file_get_contents($wsdl);

    $xml = new SimpleXmlElement($file);

    $query = "wsdl:service/wsdl:port[@name='$portName']/soap:address";
    $address = $xml->xpath($query);
    if (!empty($address)) {
        $location = (string)$address[0]['location'];
        return $location;
    }

    return false;
}

Xpath is ideal for this job!

Usage is simply:

$client = new SoapClient($wsdl);
$sslLocation = getLocationForPort($wsdl, 'BasicHttpsBinding_IConfiguration');
if ($sslLocation) {
    $client->__setLocation($location);
}
// work with $client as normal

Now, all my calls to the SOAP service are via SSL as they should be!

One thought on “Selecting the service port with PHP's SoapClient

  1. Hi Rob,

    In my case "wsdl:service/wsdl:port[@name='$portName']/soap:address" did not work. Instead I used: "wsdl:service/wsdl:port[@name='$portName']/child::*". Also this:
    if ($sslLocation) {
    $client->__setLocation($location);
    }
    Should be:
    if ($sslLocation) {
    $client->__setLocation($sslLocation);
    }

    Cheers,
    Ehsan

Comments are closed.