I am trying to connect to a Web Service which is password protected and the url is https. I can’t figure out how to authenticate before the script makes a request. It seems like it makes a request as soon as I define the service. For instance, if I put in:
$client = new SoapClient("https://example.com/WSDL/nameofservice",
array('trace' => 1,)
);
and then go to the site on the browser, I get:
Fatal error: Uncaught SoapFault exception:
[WSDL] SOAP-ERROR: Parsing WSDL: Couldn't load from
'https://example.com/WSDL/nameofservice' in /path/to/my/script/myscript.php:2
Stack trace: #0 /path/to/my/script/myscript.php(2):
SoapClient->SoapClient('https://example...', Array) #1 {main} thrown in
/path/to/my/script/myscript.php on line 2
If I try defining the service as a Soap Server, like:
$server= new SoapServer("https://example.com/WSDL/nameofservice");
I get:
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Body>
<SOAP-ENV:Fault>
<faultcode>WSDL</faultcode>
<faultstring>
SOAP-ERROR: Parsing WSDL:
Couldn't load from 'https://example.com/WSDL/nameofservice'
</faultstring>
</SOAP-ENV:Fault>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
I haven’t tried sending a raw request envelope yet to see what the server returns, but that may be a workaround. But I was hoping someone could tell me how I can set it up using the php built-in classes. I tried adding “userName” and “password” to the array, but that was no good. The problem is that I can’t even tell if I’m reaching the remote site at all, let alone whether it is refusing the request.
The problem seems to be that the WSDL document is somehow protected (basic authentication – I don’t thinkg that digest authentication is supported with
SoapClient, so you’d be out of luck in this case) and that theSoapClienttherefore cannot read and parse the service description.First of all you should try to open the WSDL location in your browser to check if you’re presented an authentication dialog. If there is an authentication dialog you must make sure that the
SoapClientuses the required login credentials on retrieving the WSDL document. The problem is thatSoapClientwill only send the credentials given with theloginandpasswordoptions (as well as thelocal_certoption when using certificate authentication) on creating the client when invoking the service, not when fetching the WSDL (see here). There are two methods to overcome this problem:Add the login credentials to the WSDL url on the
SoapClientconstructor callThis should be the most simple solution – but in PHP Bug #27777 it is written that this won’t work either (I haven’t tried that).
ext/curlor manually through your browser or viawgetfor example, store it on disk and instantiate theSoapClientwith a reference to the local WSDL.This solution can be problematic if the WSDL document changes as you have to detect the change and store the new version on disk.
If no authentication dialog is shown and if you can read the WSDL in your browser, you should provide some more details to check for other possible errors/problems.
This problem is definitively not related to the service itself as
SoapClientchokes already on reading the service descripion document before issuing a call to the service itself.EDIT:
Having the WSDL file locally is a first step – this will allow the
SoapClientto know how to communicate with the service. It doesn’t matter if the WSDL is directly served from the service location, from another server or is read from a local file – service urls are coded within the WSDL soSoapClientalways knows where to look for the service endpoint.The second problem now is that
SoapClienthas no support for the WS-Security specifications natively, which means you must extendSoapClientto handle the specific headers. An extension point to add the required behaviour would beSoapClient::__doRequest()which pre-processes the XML payload before sending it to the service endpoint. But I think that implementing the WS-Security solution yourself will require a decent knowledge of the specific WS-Security specifications. Perhaps WS-Security headers can also be created and packed into the XML request by usingSoapClient::__setSoapHeaders()and the appropriateSoapHeaders but I doubt that this will work, leaving the customSoapClientextension as the lone possibility.A simple
SoapClientextension would beFor a basic WS-Security authentication you would have to add the following to the SOAP-header:
But as I said above: I think that much more knowledge about the WS-Security specification and the given service architecture is needed to get this working.
If you need an enterprise grade solution for the whole WS-* specification range and if you can install PHP modules you should have a look at the WSO2 Web Services Framework for PHP (WSO2 WSF/PHP)