Create Soap Auth request in PHP - php

I'm new with SOAP and trying to connect it with PHP but without positive results. Maybe you can give me a hand
SOAP 1.2 Request
POST /XXXservice.asmx HTTP/1.1
Host: XXX.prueba.com
Content-Type: application/soap+xml; charset=utf-8
Content-Length: length
<?xml version="1.0" encoding="utf-8"?>
<soap12:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap12="http://www.w3.org/2003/05/soap-envelope">
<soap12:Body>
<GetAcData xmlns="https://prueba.com/">
<Userid>string</Userid>
<Password>string</Password>
</GetAcData>
</soap12:Body>
</soap12:Envelope>
SOAP 1.2 Response
HTTP/1.1 200 OK
Content-Type: application/soap+xml; charset=utf-8
Content-Length: length
<?xml version="1.0" encoding="utf-8"?>
<soap12:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap12="http://www.w3.org/2003/05/soap-envelope">
<soap12:Body>
<GetAcDataResponse xmlns="https://prueba.com/">
<XX>xml</GetAcDataResult>
</GetAcDataResponse>
</soap12:Body>
</soap12:Envelope>
I used the following code but I'm getting this message:
SOAP-ERROR: Parsing WSDL: Couldn't load from 'https://XXX.YYYY.com/XXXservice.asmx' : Premature end of data in tag html line 3
<?php
$options = array(
'Userid' => 'xx',
'Password' => 'xx',
);
$client = new SoapClient("https://XXX.YYYY.com/XXXservice.asmx", $options);
$result = $client('GetAcData');
?>

First of all you need an endpoint url of your webservice, that provides you the wsdl content. As #camelsWrittenInCamelCase has written in his comment, you should try https://XXX.YYYY.com/XXXservice.asmx?wsdl instead of https://XXX.YYYY.com/XXXservice.asmx.
Next you should wrap all your soap client stuff in a try/catch block, to get all possible exceptions and the most informations in case of an error.
try {
$client = new \SoapClient(
'https://XXX.YYYY.com/XXXservice.asmx?wsdl',
[
'cache_wsdl' => WSDL_CACHE_NONE,
'exceptions' => true,
'soap_version' => SOAP_1_2,
'trace' => true,
]
);
} catch (\SoapFault $fault) {
echo "<pre>";
var_dump($fault);
echo "</pre>";
echo "<pre>";
var_dump($client->__getLastRequest());
echo "</pre>";
echo "<pre>";
var_dump($client->__getLastResponse());
echo "</pre>";
}
As shown in the example above the soap client is initialized with an options array. We use the trace option, to enable tracing for getting the last send request and response. Additionally wie use the exception option, to force the client to throw exceptions in case of any error. Further more we disable caching the wsdl settings as long as you are developing. If you are going into production, this option should be set to WSDL_CACHE_DISK or WSDL_CACHE_MEMORY.
Now you need to know, which functions and types (complex types) your webservice provides. For this purpose you can do the following.
// getting the functions of your webservice
echo "<pre>";
var_dump( $client->__getFunctions() );
echo "</pre>";
// getting the types of your webservice
echo "<pre>";
var_dump( $client->__getTypes() );
echo "</pre>";
Since I do not know the exact scope of your web service, I'll just assume that the webservice delivers a method called DetAcData with two parameters Userid and Password. With this informations I can only guess, how the right call could look like. For detailed informations I 'd need the output of __getFunctions() and __getTypes().
An examplary call could look like this.
try {
$client = new \SoapClient(
'https://XXX.YYYY.com/XXXservice.asmx?wsdl',
[
'cache_wsdl' => WSDL_CACHE_NONE,
'exceptions' => true,
'soap_version' => SOAP_1_2,
'trace' => true,
]
);
$data = new \stdClass();
$data->Userid = 'YourUserId';
$data->Username = 'YourUsername';
$result = $client->GetAcData($data);
// $result will be an object
echo "<pre>";
var_dump($result);
echo "</pre>";
} catch (\SoapFault $fault) {
// error handling
}
Further more you can write data objects for every complex type mentioned in the functions and types output from your webservice. You can add a classmap to the options array when instantiating your soap client, so that every response and request will automatically be parsed in the corresponding data object. How soap client classmaps work is explained in the php documentation.
Just have a try. I 'm sure you will get it on your own. ;)

Related

PHP To Call a SOAP Webservice

i would like some help please.
I am trying to call a webservice using PHP and i am having problems with different kind of messages.
The WSDL is "http://195.144.16.7/ElastrakEDI/ElastrakEDI.asmx?WSDL" and the Web Service is Called GetPartMaster. The username and password at first are both TESTUID and TESTPWD ( for testing purposes ).
The XML Below is the Request
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:edi="http://elastrak.gr/edi/">
<soap:Header>
<edi:AuthHeader>
<!--Optional:-->
<edi:Username>TESTUID</edi:Username>
<!--Optional:-->
<edi:Password>TESTPWD</edi:Password>
</edi:AuthHeader>
</soap:Header>
<soap:Body>
<edi:GetPartMaster/>
</soap:Body>
</soap:Envelope>
This XML is the response
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Header>
<AuthHeader xmlns="http://elastrak.gr/edi/">
<Username>TESTUID</Username>
<Password>TESTPWD</Password>
</AuthHeader>
</soap:Header>
<soap:Body>
<GetPartMasterResponse xmlns="http://elastrak.gr/edi/">
<GetPartMasterResult>
<elastrakPartMasterFile xmlns="">
<PartMasterURL>http://195.144.16.7/elastrakEDI/Temp/Parts/OTWKOJL4.txt</PartMasterURL>
<ErrorCode/>
<ErrorDescription/>
</elastrakPartMasterFile>
</GetPartMasterResult>
</GetPartMasterResponse>
</soap:Body>
</soap:Envelope>
I have tried the php code below but still cant get it to work
<?php
$wsdl = 'http://195.144.16.7/ElastrakEDI/ElastrakEDI.asmx?WSDL';
$trace = true;
$exceptions = true;
$xml_array['Username'] = 'TESTUID';
$xml_array['Password'] = 'TESTPWD';
$client = new SoapClient($wsdl, array('trace' => $trace, 'exceptions' => $exceptions));
$client = new SoapClient($wsdl);
$response = $client->GetPartMaster($xml_array);
try
{
$client = new SoapClient($wsdl, array('trace' => $trace, 'exceptions' => $exceptions));
$response = $client->GetPartMaster($xml_array);
}
catch (Exception $e)
{
echo "Error!";
echo $e -> getMessage ();
echo 'Last response: '. $client->__getLastResponse();
}
$response = $response->GetPartMaster->PartMasterURL;
var_dump($response);
?>
Thank you again for your time and Help.
Your request is currently wrongly constructed as you must take into account that therse is actually thow parts in the request:
the SOAP header, containing the username and password
the SOAP body, containing the GetPartMaster element
Take a look to the SoapClient class and the __setSoapHeaders method.
This is why I strongly advise you to use a WSDL to PHP generator to send SOAP Request as it will allow you to easily construct the request and then handle the response while using the OOP approach and not wondering how to send the parameters. Using the generated PHP SDK and a good IDE such as PhpStorm or any Eclipse based IDE with autocompletion, it'll be easy to find your way. Try the PackageGenerator project.

SOAP request in PHP in CURL

It's have been already several days since I'm trying to figure out SOAP but no success :( Any chance to know how can I create PHP(curl) SOAP request to look like this?
POST /WebServices/domain.asmx HTTP/1.1
Host: webservices.domain.ru
Content-Type: text/xml; charset=utf-8
Content-Length: length
SOAPAction: "http://www.domain.ru/GetVariants"
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Header>
<AuthentificationHeader xmlns="http://www.domain.ru/">
<Login>string</Login>
<Password>string</Password>
<PartnerId>string</PartnerId>
</AuthentificationHeader>
</soap:Header>
<soap:Body>
<GetVariants xmlns="http://www.domain.ru/">
<RequestParameters>xml</RequestParameters>
</GetVariants>
</soap:Body>
</soap:Envelope>
Also I have following data:
WSDL:
http://webservices.domain.ru/WebServices/domainXml.asmx?WSDL
Soap action:
http://webservices.domain.ru/WebServices/domainXml.asmx?op=GetVariants
Basically:
PHP's support for SOAP just sucks.
You need to use your WSDL to generate your PHP classes, so you can build a Request object.
You will get something like this:
class SomeClass
{
var $name; //NCName
}
class SomeOtherClass
{
var $value; //anonymous2
}
.
.
.
There are some WSDL to PHP scripts out there. (Google wsdl to php)
Then you do something like this.
$soapClient = new SoapClient($this->_wsdlUrl, array(
'trace' => true,
'exceptions' => true,
'uri' => $this->_endPoint,
'location' => $this->_endPoint,
'local_cert' => $this->certificatePath,
'allow_self_signed' => true,
'soap_version' => SOAP_1_2,
));
// Build the SOAP client object, with your properties.
//After that, you have to call:
$yourContainerObject = new YourContainerObject(); // The top SOAP XML node
$yourContainerObject->SomeChildNode = new SomeChildNode();
$yourContainerObject->SomeChildNode->Name = 'John';
.
.
.
$soapResponse = $soapClient->GetVariants($yourContainerObject);
print_r(soapResponse); // to see what you get
The "GetVariants" method doesn't need to be implemented, so you don't get confused and ask yourself where do I get that from.It is described in WSLD and PHP's SOAP client knows that it is just a SOAP action.
This should be an more advanced example of creating SOAP requests via PHP.
I hope you get the basic flow of this.

PHP Nusoap - SOAP Request not working

Hello i am very new to webservice, in php with below code i am trying to make soap request as shown in below XML, but it says Error
HTTP Error: Unsupported HTTP response status 405 Method Not Allowed (soapclient->response has contents of the response)
Questions:
How to pass headers?
How to pass FetchCalendarRequest with request like in XML?
I have used Nusoap here but if you have a SOAP PHP class solution it is also invited.
My code:
<?php
require_once('../lib/nusoap.php');
$client = new nusoap_client("http://webservices.test.com/ows/5.1/Availability.wsdl");
$err = $client->getError();
if ($err)
{
client_debug_error_message('Constructor error', $err, $client);
exit;
}
// Call the SOAP method
$result = $client->call(
'FetchCalendar',
array(
'StayDateRange' => array(
'StartDate' => '2013-10-01',
'EndDate' => '2013-10-10',
),
),
);
// Check for a fault
if ($client->fault)
{
debug_preformatted('Fault', $result);
}
else
{
// Check for errors
$err = $client->getError();
if ($err)
{
debug_preformatted('Error', $err);
}
else
{
debug_preformatted('Result', $result);
}
}
// Display the request and response
client_debug_dump($client);
XML :
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Header>
<OGHeader transactionID="005435" timeStamp="2008-12-09T13:26:56.4056250-05:00" xmlns="http://webservices.test.com/og/4.3/Core/">
<Origin entityID="OWS" systemType="WEB" />
<Destination entityID="WEST" systemType="ORS" />
</OGHeader>
</soap:Header>
<soap:Body>
<FetchCalendarRequest xmlns:a="http://webservices.test.com/og/4.3/Availability/" xmlns:hc="http://webservices.test.com/og/4.3/HotelCommon/" xmlns="http://webservices.test.com/ows/5.1/Availability.wsdl">
<HotelReference chainCode="AXA" hotelCode="AXAMUM" />
<StayDateRange>
<hc:StartDate>2013-10-01</hc:StartDate>
<hc:EndDate>2013-10-10</hc:EndDate>
</StayDateRange>
<GuestCount>
<hc:GuestCount ageQualifyingCode="ADULT" count="1" />
<hc:GuestCount ageQualifyingCode="CHILD" count="0" />
</GuestCount>
</FetchCalendarRequest>
</soap:Body>
</soap:Envelope>
Post Url :http://000.000.000.00:8080/ows_ws_51/Availability.asmx
Soap Action : http://webservices.test.com/ows/5.1/Availability.wsdl#FetchCalendar
Edit: Working Solution 16 Sep 2013
This solution is with Soap PHP Class only I want it to work with Nusoap bow.
<?php
$wsdl = "http://###.###.###.##:8080/ows_ws_51/Availability.asmx?wsdl";
$client = new SoapClient($wsdl, array( 'soap_version' => SOAP_1_1,'trace' => true,));
//=========== Header Setting ============
$ns = 'http://webservices.micros.com/og/4.3/Availability/'; //Namespace of the WS.//Body of the Soap Header.
$strHeaderComponent_Session = <<<XML
<OGHeader transactionID="005435" timeStamp="2008-12-09T13:26:56.4056250-05:00" xmlns="http://webservices.micros.com/og/4.3/Core/">
<Origin entityID="OWS" systemType="WEB" />
<Destination entityID="WEST" systemType="ORS" />
</OGHeader>
XML;
$objVar_Session_Inside = new SoapVar($strHeaderComponent_Session, XSD_ANYXML, null, null, null);
$objHeader_Session_Outside = new SoapHeader($ns , 'SessionHeader', $objVar_Session_Inside);
// More than one header can be provided in this array.
$client->__setSoapHeaders(array($objHeader_Session_Outside));
//============== Request ================
$xml = <<<XML
<FetchCalendarRequest xmlns:a="http://webservices.micros.com/og/4.3/Availability/" xmlns:hc="http://webservices.micros.com/og/4.3/HotelCommon/" xmlns="http://webservices.micros.com/ows/5.1/Availability.wsdl">
<HotelReference chainCode="AXA" hotelCode="{$DdlHotels}" />
<StayDateRange>
<hc:StartDate>{$Arrive}</hc:StartDate>
<hc:EndDate>{$Depart}</hc:EndDate>
</StayDateRange>
<GuestCount>
<hc:GuestCount ageQualifyingCode="ADULT" count="1" />
<hc:GuestCount ageQualifyingCode="CHILD" count="0" />
</GuestCount>
</FetchCalendarRequest>
XML;
$args = array(new SoapVar($xml, XSD_ANYXML));
try
{
$response = $client->__soapCall( 'FetchCalendar', $args );
}
catch (SoapFault $e)
{
echo "Error: {$e}"; exit;
}
You can use PHP's built in SOAP library to create a SOAP client and call a method from the WSDL, try something like this:
$client = new SoapClient($wsdl, array( 'soap_version' => SOAP_1_1,
'trace' => true,
));
try {
$params = array(
//Your parameters here
);
$res = $client->__soapCall( 'SoapMethod', $params );
return $res;
} catch (SoapFault $e) {
echo "Error: {$e}";
}
//for debugging what the outgoing xml looks like
$client->__getLastRequest();
The WSDL should help structure the xml for your params. If you cannot get that to work the way you want you could try passing the xml yourself using SoapVar() and setting the encode to XSD_ANYXML.
If you also need to add additional header information take a look at this example from the PHP docs.
$params = array(//your params as specified by documentation);
$result = $client->call(array("Availability"=>$params));
Might I suggest trying to learn SOAP with a different example web service. The wsdl document published for this service appears to be incomplete, as they have entered the incorrect SOAP address for the Availability service. With an incorrect or incomplete WSDL document, the SOAP library you are using will not be able to form a valid SOAP request and send it to the correct endpoint.
<wsdl:service name="AvailabilityService">
<wsdl:port name="AvailabilityPort" binding="tns:AvailabilityBinding">
<soap:address location="http://tempuri.org"/>
</wsdl:port>
</wsdl:service>
As you can see, the AvailabilityService endpoint is described as http://tempuri.org, which is explained as a default test namespace here.
In your original post, you have the 'POST URL' described as http://000.000.000.00:8080/ows_ws_51/Availability.asmx. How is anyone supposed to try the example, if you list the 'POST URL' an as obviously invalid URL.
You have also listed the WSDL document as http://webservices.test.com/ows/5.1/Availability.wsdl, which is also an invalid URL.
Here is a PHP example, accessing a valid WSDL document, using PHP's built-in SOAP library, which can be enabled by enabling the php_soap.dll extension in your php.ini file.
<?php
$wsdl = "http://www.restfulwebservices.net/wcf/StockQuoteService.svc?wsdl";
$client = new SoapClient($wsdl, array(
"trace" => 1,
"exceptions" => 0));
$parameters = array("request" => "IBM");
$value = $client->GetStockQuote($parameters);
$json = json_encode($value);
echo $json;
Note: The following is more of a comment than an answer. I leave it here for further reference as it would not fit into a comment box and it references existing Q&A possible worth for future visitors
You ask two questions regarding Nusoap here:
How to pass headers?
How to pass FetchCalendarRequest with request like in XML?
The first one How to pass headers? has been outlined already in this Q&A:
NuSoap PHP webservice with soap headers
As you have not written specifically in your question what of this (and possible other of the) existing Q&A didn't work for you, this might not suit your needs but you need to give detailed feedback first I'd say.
The second question How to pass FetchCalendarRequest with request like in XML? you probably mean how to call a SOAP action or method ("Request") that has been named in a WSDL. This has already been covered as well for Nusoap on the Stackoverflow website:
Nusoap use existing WSDL how to?
As you have not written specifically in your question what of this (and possible other of the) existing Q&A didn't work for you, this might not suit your needs but you need to give detailed feedback first I'd say to turn this into a concrete programming question.
BTW Stackoverflow works best by asking one question at a time.

PHP SoapClient: Action mismatch

I am trying to use the PHP SoapClient extension to communicate with an external SOAP server.
This is my code:
$this->_client = new SoapClient(SOAP_TAGGING_URL, array(
'trace' => 1,
'soap_version' => SOAP_1_2,
'cache_wsdl' => WSDL_CACHE_NONE,
'exceptions' => true,
'uri' => SOAP_URI,
));
try {
$actionHdr = array();
$actionHdr[] = new SoapHeader(SOAP_TAGGING_URL, 'Action', 'GetMessagesByTagsByGroup');
$this->_client->__setSoapHeaders($actionHdr);
$info = $this->_client->GetMessagesByTagsByGroup(
new SoapParam($this->params['mPID'], 'ParentMessageID'),
new SoapParam($gid, 'GroupId'),
new SoapParam(REQUEST_TOKEN, 'RequestToken'),
new SoapParam(ACCESS_TOKEN, 'AccessToken'),
new SoapParam(ACCESS_TOKEN_SECRET, 'AccessTokenSecret')
);
} catch (SoapFault $fault) {
print("\n<br/>SOAP server returned the following ERROR: ".$fault->faultcode."-".$fault->faultstring);
}
echo "\n<br/>SOAP request: ". htmlentities($this->_client->__getLastRequest());
echo "\n<br/>SOAP response: ". htmlentities($this->_client->__getLastResponse());
This is the response I get (formatting added):
SOAP server returned the following ERROR: s:Sender-The SOAP action specified on the message, '', does not match the HTTP SOAP Action, 'http://tempuri.org/ITagging/GetMessagesByTagsByGroup'.
SOAP request:
<?xml version="1.0" encoding="UTF-8"?>
<env:Envelope xmlns:env="http://www.w3.org/2003/05/soap-envelope" xmlns:ns1="http://tempuri.org/" xmlns:ns2="https://mywebserver.com/myWSDL.svc/ws?wsdl">
<env:Header>
<ns2:Action>GetMessagesByTagsByGroup</ns2:Action>
</env:Header>
<env:Body>
<ns1:GetMessagesByTagsByGroup/>
<GroupId>2178</GroupId>
<RequestToken>odwedwo09i0jACqbbjsw6KnlCA=</RequestToken>
<AccessToken>OlVbHurPJrNrEFR54Y0hV9kI/TZs=</AccessToken>
<AccessTokenSecret>js1kerfe453FLuaXpL 892DY o=</AccessTokenSecret>
</env:Body>
</env:Envelope>
SOAP response:
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://www.w3.org/2005/08/addressing">
<s:Header>
<a:Action s:mustUnderstand="1">http://www.w3.org/2005/08/addressing/fault</a:Action>
</s:Header>
<s:Body>
<s:Fault>
<s:Code>
<s:Value>s:Sender</s:Value>
<s:Subcode>
<s:Value>a:ActionMismatch</s:Value>
</s:Subcode>
</s:Code>
<s:Reason>
<s:Text xml:lang="en-US">The SOAP action specified on the message, '', does not match the HTTP SOAP Action, 'http://tempuri.org/ITagging/GetMessagesByTagsByGroup'. </s:Text>
</s:Reason>
<s:Detail>
<a:ProblemHeaderQName>a:Action</a:ProblemHeaderQName>
</s:Detail>
</s:Fault>
</s:Body>
</s:Envelope>
I thought I added the 'Action' parameter in the header, but clearly that is not the place to put it. Or am I doing something else wrong?
Unfortunately I cannot try NuSoap because I have no control over the server.
Thank you,
gm
It means meant that not only you must specify the HTTP header SOAPAction: "http://www.bla.com:MyAction"
but you need to specify also in the SOAP Envelope the header:
Check these links for some ref:
SOAP ACTION
You're passing it as SoapHeader, but actually it is HTTP header.
The way I found to do it is: http://lt.php.net/manual/en/soapclient.dorequest.php by setting $action parameter.
You'll probably need to extend SoapClient class to do it using less lines of code.

Why is PHP's SoapClient creating a different namespace for the header than the body?

I'm trying to communicate with the eWay server and had everything working until we ended up needing to switch to a different API. The problem is that SoapClient is creating a different namespace for the header (that includes the authentication) then from the body, which, obviously, doesn't get me any results. Instead, I get eWay's servers saying it must have the authentication information.
Here's my code:
$client = new SoapClient($url.'?WSDL', array('trace'=>TRUE));
// Set our SOAP Headers for authentication
$header_body = array(
'eWAYCustomerID' => $gateway['customer_id'],
'Username' => $gateway['username'],
'Password' => $gateway['password']
);
$header_var = new SoapVar($header_body, SOAP_ENC_OBJECT);
$header = new SOAPHeader('http://www.eway.com.au/gateway/managedpayment', 'eWAYHeader', $header_body);
//$client->__setSoapHeaders($header);
try {
$response = $client->__soapCall($action, $xml, null, $header);
} catch (SoapFault $e)
{
echo 'SOAP Fault: '. $e->getMessage()."<br>\n";
}
As you can see, I've tried it with and without using a SoapVar for the header, all with no luck.
Here's the XML request that is being created:
<soap-env:envelope xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="https://www.eway.com.au/gateway/managedpayment" xmlns:ns2="http://www.eway.com.au/gateway/managedpayment">
<soap-env:header>
<ns2:ewayheader>
<ewaycustomerid>87654321</ewaycustomerid>
<username>test#eway.com.au</username>
<password>test123</password>
</ns2:ewayheader>
</soap-env:header>
<soap-env:body>
<ns1:createcustomer>...</ns1:createcustomer>
This may be an obvious question, but did you try specifying the typename and type namespace in the SoapVar() call?

Categories