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!



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