Soap client, how to call a function over HTTPS with Basic HTTP Authentication

Tio picture Tio · Feb 10, 2011 · Viewed 13.5k times · Source

This problem has been killing me for the entire day.

I have a client web service https://*.asmx?WSDL, with Basic HTTP Authentication..

If I use SoapUI to connect to the webservice, everything works perfectly with no errors whatsoever..

The problem is when I switch to PHP...

I managed to connect to it, and I can get the function list from the server using soapclient extension for php ( I'm using PHP 5.3.0 ).

When I try to call a function using the soapclient extension for PHP I get the following error:

Fatal error: Uncaught SoapFault exception: [HTTP] Error Fetching http headers in C:\www\xpto_Atestes\soapclient.php:26 Stack trace: #0 [internal function]: >SoapClient->__doRequest('***...', 'http://****...', 1, 0) #1 >C:\www\xpto_Atestes\soapclient.php(26): SoapClient->__soapCall('login', Array) #2 {main} >thrown in C:\www\xpto_Atestes\soapclient.php on line 26

More clear error ( when I do a print_r of the result of the call):

[faultstring] => Error Fetching http headers
[faultcode] => HTTP

With the following headers being sent:

POST /*.asmx HTTP/1.1 Host: *.pt Connection: Keep-Alive User-Agent: >PHP-SOAP/5.3.0 Content-Type: text/xml; charset=utf-8 SOAPAction: "http://**/Login" >Content-Length: 264 Authorization: Basic AUTHSECRETPASS

I'm calling it like this:

$soapParams = array('login' => 'HTTP_LOGIN',
'password' => 'HTTP_PASS',
'authentication' => SOAP_AUTHENTICATION_BASIC,
'trace' => 1,
'exceptions' => 0
);
$client = new SoapClient("https://****.asmx?WSDL", $soapParams); echo "Connected
"; $params = array('account' => '', 'msisdn'=>'NUMBER', 'password'=>'PASSWORD'); $result = $client->__soapCall("login", $params);

After a while googling and trying to find out what the problem could be, I switched to nusoap.. which to my misery it gave an error also:

Error

HTTP Error: socket read of headers timed out

Request

POST /**.asmx HTTP/1.0 Host: *.pt User-Agent: NuSOAP/0.9.5 (1.123) Content-Type: text/xml; charset=ISO-8859-1 SOAPAction: "http://****/Login" Authorization: Basic AUTHSECRETPASS Content-Length: 481

NUMBERPASSWORD

Response

I'm calling it like this:

$client = new nusoap_client("https://**.asmx?WSDL", true);
$client->setCredentials('HTTPUSER','HTTPPASS','basic');
$params = array( 'account' => '', 'msisdn'=>'NUMBER', 'password'=>'PASSWORD' );
$result = $client->call('Login', $params);

With nusoap I also tried to enable enable curl extension to make the calls:

$client->setUseCurl(true);

But no such luck, it kept on giving an error:

HTTP Error: cURL ERROR: 56: Failure when receiving data from the peer url: http://*********.asmx
content_type:
http_code: 0
header_size: 0
request_size: 750
filetime: -1
ssl_verify_result: 0
redirect_count: 0
total_time: 21.015
namelookup_time: 0
connect_time: 0
pretransfer_time: 0
size_upload: 462
size_download: 0
speed_download: 0
speed_upload: 21
download_content_length: -1
upload_content_length: -1
starttransfer_time: 0
redirect_time: 0

I'm 100% sure that nothing is wrong with the webservice, if I can call it from SoapUI without any problem I don't see why I can't call it from PHP.

I rally don't know what more I can do.. I think I tried everything...

Edit: I just tried another Soap Class for PHP, this time from Zend..

The result is:

Fatal error: Uncaught SoapFault exception: [WSDL] SOAP-ERROR: Parsing WSDL: Couldn't load from 'https://**.asmx?WSDL' : failed to load external entity "https://*.asmx?WSDL" in C:\www\xpto_Atestes\Zend\Soap\Client\Common.php:51 Stack trace:
#0 C:\www\xpto_Atestes\Zend\Soap\Client\Common.php(51): SoapClient->SoapClient('https://**...', Array)
#1 C:\www****_Atestes\Zend\Soap\Client.php(1032): Zend_Soap_Client_Common->__construct(Array, 'https://**...', Array)
#2 C:\www****_Atestes\Zend\Soap\Client.php(1188): Zend_Soap_Client->_initSoapClientObject()
#3 C:\www***_Atestes\Zend\Soap\Client.php(1112): Zend_Soap_Client->getSoapClient() #4 [internal function]: Zend_Soap_Client->__call('Login', Array)
#5 C:\www****_Atestes\zend.php(28): Zend_Soap_Client->Login(Array)
#6 {main} thrown in

Answer

Tio picture Tio · Oct 21, 2011

Just to answer myself, in case anyone else would like to also know how I solved it.

The problem was the following, the request XML for one of the webservices had to be in this format:

<?xml version="1.0" encoding="utf-8" ?>
<SOAP-ENV:Envelope SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" 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:Body>
        <ns123:IsTokenValid xmlns:ns123="http://www.xxxxxxx.com">
            <ns123:token xsi:type="xsd:string">'.$this->loginToken.'</ns123:token>
        </ns123:IsTokenValid>
    </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

When I mention the prefix, I'm referring to the ns123 part. The problem is that none of the libraries produced the correct XML to send to the server, they would never put the prefix, so the request never worked.

I first solved it, by going directly to the NuSoap class and changed the code in one the classes, but then I discovered I could make my own request XML with NuSoap, witch resulted in the following code:

$nsValue = rand(1000, 9000);
$requestXml = '<?xml version="1.0" encoding="utf-8" ?>
<SOAP-ENV:Envelope SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" 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:Body>
<ns'.$nsValue.':IsTokenValid xmlns:ns'.$nsValue.'="http://www.xxxxxxx.com">
<ns'.$nsValue.':token xsi:type="xsd:string">'.$this->loginToken.'</ns'.$nsValue.':token>
</ns'.$nsValue.':IsTokenValid>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>';
$result = WebService::CallWebService($this->endPoint, 'http://www.xxxxxxx.com/IsTokenValid', $requestXml, $this->httpUser, $this->httpPass);

The WebService::CallWebService is just a wrapper to NuSoap class that does something like this ( and also has error handling, set's HTTP authentication etc ):

$client = new nusoap_client($webServiceLink, false);
$result = $client->send($request, $soapAction, '', self::$timeout, self::$responseTimeout);

Iain and everyone else, hope this is clear.