I have a two fold problem with setting SOAP headers. Primarily, I've never done it before and two, I can't seem to find a good solution on here for doing so. I apologize if there are exact duplicates, and please point me in the right direction if there are.
I need to set the following xmlns:xsi and xmlns:xsd data sets on the soap:Envelope. I also need to set an xmlns attribute on the first tag in the XML (rough example).
The first part needs to be added, the second part is already in there when I do a __getLastRequest(). And the third part needs to be added (just the SendPurchases xmlns attribute).
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/
xmlns:ns1="urn:[taken out for security purposes]">
<soap:Body>
<SendPurchases xmlns="urn:...">
</SendPurchases>
</soap:Body>
Would I need to use the header() for this?
I am using PHP's SOAP client. Any help at all is greatly appreciated!
EDIT:
I went with another route, thank you for all your answers though!
I had a simular problem with the envelope, I made a fix for that. I will post the fix with the data you provided, You will have to check if everything is oke:
The custom class to edit the request:
class CustomSoapClient extends SoapClient {
function __doRequest($request, $location, $action, $version) {
$request = str_replace('<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:xsd="http://www.w3.org/2001/XMLSchema">', '', $request);
// parent call
return parent::__doRequest($request, $location, $action, $version);
}
}
Setup the soap client:
$client = new CustomSoapClient($wsdl,
array(
'features' => SOAP_SINGLE_ELEMENT_ARRAYS,
'exceptions' => true,
'trace' => 1,
'soap_version' => SOAP_1_2,
)
);
The request:
//notice that the envelope is in the request! also you need to change the urn
$request = '
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/xmlns:ns1="urn:[taken out for security purposes]">
<soap:Body>
<SendPurchases xmlns="urn:...">
</SendPurchases>
</soap:Body>
</SOAP-ENV:Envelope>';
$xmlvar = new SoapVar($request, XSD_ANYXML);
$result = $client->Controleer($xmlvar);
print_r($result); // finally check the result
I hope this will help you :)
A verbose example of the correct implementation using PHP's SoapClient can be found here: http://www.php.net/manual/en/soapclient.soapclient.php#97273
Related
I need to send a post request with Guzzle for a project I am working on and keep getting a 400 Bad request error with the message 'Invalid XML Data'. I tried lots of different combinations as far as the settings go and am getting the same error message in all cases.
Did anyone else run into this issue? Any ideas why this is? I appreciate any help in advance.
$xml = $this->getXml();
$client = new GuzzleHttp\Client();
try {
$credentials = base64_encode('username:pass');
$res = $client->post('https://www.example.com',['headers' => ['Content-Type' => 'text/xml; charset=UTF8', 'Authorization' => 'Basic '.$credentials], 'body' => $xml]);
} catch (\GuzzleHttp\Exception\ClientException $e) {
dd($e->getResponse()->getBody()->getContents());
}
For the $xml value, I tried the following:
$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:Body>
<GetCustomerInfo xmlns="http://tempUri.org/">
<CustomerID>1</CustomerID>
<OutputParam />
</GetCustomerInfo>
</soap:Body>
</soap:Envelope>';
My main objective for the time being is to simply resolve this specific client error for invalid XML and reach the server.
The XML looks good, so the code should work. Do you have more details in the response? Maybe position in the XML or something else.
Just a side note: you can use auth option instead of setting Authentication header by hands.
I have a client call with a WSSE Security Header:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Header><wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"><wsse:UsernameToken wsu:Id="UsernameToken-7BCCD9337425FBA038149772606059420"><wsse:Username>USERNAME</wsse:Username><wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">PASSWORD</wsse:Password><wsse:Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">NONCE</wsse:Nonce><wsu:Created>2017-06-17T19:01:00.594Z</wsu:Created></wsse:UsernameToken></wsse:Security></soapenv:Header>
<soapenv:Body>
<ns:FUNCTION/>
</soapenv:Body>
</soapenv:Envelope>
As SoapServer I have a simple one:
// the SOAP Server options
$options=array(
'trace' => true
, 'cache_wsdl' => 0
, 'soap_version' => SOAP_1_1
, 'encoding' => 'UTF-8'
);
$wsdl = 'http://localhost/index.php?wsdl';
$server = new \SoapServer($wsdl, $options);
$server->setClass('ServerClass');
$server->handle();
$response = ob_get_clean();
echo $response;
As soon the property MustUnderstand = 1, then I become from the server the exception: Header not understood.
How to understand the header?
How to make the WSSE validation on the SoapServer side?
The solution is very tricky! I don't know why is this handled by this way from the SoapServer, but here is the solution:
class ServerClass {
public function Security($data) {
// ... do nothing
}
public function myFunction(){
// here the body function implementation
}
}
We need to define a function in our class, which is handling the soap request with the name of the header tag, which is holding the soap:mustUnderstand property. The function doesn't need to be implemented in some way.
That's all!
Mutatos' question / answer got me on the right track. I was working outside of a class structure so what worked for me was the following:
function Security($data)
{
$username = $data->UsernameToken->Username;
$password = $data->UsernameToken->Password;
//check security credentials here
}
$server = new SoapServer("schema/wsdls/FCI_BookingPullService.wsdl", array('soap_version' => SOAP_1_2));
$server->addFunction("Security");
$server->handle();
Essentially a function with the same name as the SOAP header "<wsse:Security>" (ignore the namespace) is being defined, then telling the server to use that to process the header with the 'addFunction' method.
Not ideal from a scope point of view, if that's an issue, try the class approach.
I'm generating a WSDL and I need to change the function name in the response to match the name from the client (which I have no control over).
Here's the WSDL response I'm getting:
<SOAP-ENV:Envelope SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://localhost:8000/soap/index.php?wsdl" 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>
<ns1:fooFunctionResponse>
<return xsi:type="xsd:boolean">true</return>
</ns1:fooFunctionResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
I need the line <ns1:fooFunctionResponse> to read <ns1:fooFunctionAcknowledgement>.
Here is my Soap server:
if (isset($_GET['wsdl'])) {
ini_set('soap.wsdl_cache_enabled', 0);
$soapAutoDiscover = new \Zend\Soap\AutoDiscover(new \Zend\Soap\Wsdl\ComplexTypeStrategy\ArrayOfTypeSequence());
$soapAutoDiscover->setBindingStyle(array('style' => 'document'));
$soapAutoDiscover->setOperationBodyStyle(array('use' => 'literal'));
$soapAutoDiscover->setClass('SoapFunction');
$soapAutoDiscover->setUri(http://localhost:8000/soap/index.php);
$soapAutoDiscover->handle();
} else {
$soap = new \Zend\Soap\Server(null, array("soap_version" => SOAP_1_2, 'uri' => 'http://localhost:8000/soap/index.php?wsdl', 'classmap' => array('Identification', 'RemoteIdentification')));
$soap->setClass('SoapFunction');
$soap->handle();
}
I've found this line of code in the Zend framework (Autodiscover.php line 514) which looks like it controls the naming of the function:
$element = [
'name' => $functionName . 'Response',
'sequence' => $sequence
];
But changing it does nothing at all, the parent method is never called. I've no idea how to solve this problem, please help.
I've discovered that this line does change the function name, however I'm using SoapUI to test my API, and from SoapUI I always see Response instead of whatever I change the string to. In Chrome, I see Acknowledgement.
Why does SoapUI show a different function name?
I don't know much about Zend Framework and/or it's structure. But I think you can simply extend the class containing the response() method and overwrite the method.
// Example Zend Class
class Zend_Class {
public function response()
{
// ...
}
}
// Your own Class
class Own_Class extends Zend_Class
{
public function ResponseBoohoo()
{
return parent::response();
}
}
If I totally and utterly misunderstood you, I apologize. :)
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.
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.