I wanna build a request with php soap client.
The provider sent us a sample request.
here is my code;
$client = new SoapClient('http://myurl.com/TrevooWS.svc?wsdl' , array('trace' => true, 'exception' => false));
$auth_ns = 'http://schemas.datacontract.org/2004/07/Trevoo.WS.Entities.Authentication.IO';
$base_ns = 'http://schemas.datacontract.org/2004/07/Trevoo.WS.Entities.Base';
$object = new stdClass();
$form = new stdClass();
$form->Username = new SoapVar( 'USER' , XSD_STRING , null , null, 'trev1', $auth_ns);
$form->Password = new SoapVar( 'PASS' , XSD_STRING , null , null, 'trev1', $auth_ns);
$form->IsTestMode = new SoapVar( 1 , XSD_INTEGER, null , null, 'trev1', $auth_ns);
$form->ClientName = new SoapVar( 'CLIENT' , XSD_STRING , null , null, 'trev1', $auth_ns);
$form->ClientIP = new SoapVar( '0' , XSD_STRING , null , null, 'trev1', $auth_ns);
$object->request = new stdClass();
$object->request->Form = new SoapVar($form , SOAP_ENC_OBJECT, null , null, 'tem', $base_ns);
$object->request->Form->enc_namens = $auth_ns;
$object->request->Form->enc_name = 'trev1';
$object->request->enc_namens = $base_ns;
$object->request->enc_name = 'tem';
try{
$result = $client->Login( $object );
var_dump($result);
} catch (SoapFault $e){
echo $e;
var_dump($client->__getLastRequest());
var_dump($client->__getLastResponse());
}
Expected request from provider. They sent this sample request.
<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:tem="http://tempuri.org/" xmlns:trev="http://schemas.datacontract.org/2004/07/Trevoo.WS.Entities.Base" xmlns:trev1="http://schemas.datacontract.org/2004/07/Trevoo.WS.Entities.Authentication.IO">
<soapenv:Header />
<soapenv:Body>
<tem:Login>
<tem:request>
<trev1:Form>
<trev1:ClientIP>0</trev1:ClientIP>
<trev1:ClientName>s</trev1:ClientName>
<trev1:IsTestMode>0</trev1:IsTestMode>
<trev1:Password>PASSWORD</trev1:Password>
<trev1:Username>USERNAME</trev1:Username>
</trev1:Form>
</tem:request>
</tem:Login>
</soapenv:Body>
</soapenv:Envelope>
What I get;
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://schemas.datacontract.org/2004/07/Trevoo.WS.Entities.Authentication.IO" xmlns:ns2="http://tempuri.org/">
<SOAP-ENV:Body>
<ns2:Login>
<ns2:request>
<ns1:Form>
<ns1:Username>USERNAME</ns1:Username>
<ns1:Password>PASSWORD</ns1:Password>
<ns1:IsTestMode>1</ns1:IsTestMode>
<ns1:ClientName>CLIENT</ns1:ClientName>
<ns1:ClientIP>0</ns1:ClientIP>
</ns1:Form>
</ns2:request>
</ns2:Login>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
This is response for Login method.
<?xml version="1.0" encoding="UTF-8"?>
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body>
<s:Fault>
<faultcode xmlns:a="http://schemas.microsoft.com/net/2005/12/windowscommunicationfoundation/dispatcher">a:InternalServiceFault</faultcode>
<faultstring xml:lang="tr-TR">String reference not set to an instance of a String.
Parameter name: s</faultstring>
<detail>
<ExceptionDetail xmlns="http://schemas.datacontract.org/2004/07/System.ServiceModel" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<HelpLink i:nil="true" />
<InnerException i:nil="true" />
<Message>String reference not set to an instance of a String.
Parameter name: s</Message>
<StackTrace>at System.Text.Encoding.GetBytes(String s)
at Trevoo.Utilities.Crypto.MD5Hash(String input) in c:\Trevoo_TFS\*****\trunk\main\Trevoo\Projects\Core\Trevoo.Core\Utilities\Crypto.cs:line 131
at Trevoo.Accounts.AuthController.ReadonlyLogin(LoginRequest request) in c:\Trevoo_TFS\*****\trunk\main\Trevoo\Projects\Core\Trevoo.Core\Accounts\AuthController.cs:line 22
at Trevoo.Accounts.AuthController.Login(LoginRequest request) in c:\Trevoo_TFS\*****\trunk\main\Trevoo\Projects\Core\Trevoo.Core\Accounts\AuthController.cs:line 10
at Trevoo.WS.Services.Base.Login(T_LoginRequest request) in c:\Trevoo_TFS\*****\trunk\main\Trevoo\Projects\WS\Trevoo.WS\Services\Authentication\Login.cs:line 13
at SyncInvokeLogin(Object , Object[] , Object[] )
at System.ServiceModel.Dispatcher.SyncMethodInvoker.Invoke(Object instance, Object[] inputs, Object[]& outputs)
at System.ServiceModel.Dispatcher.DispatchOperationRuntime.InvokeBegin(MessageRpc& rpc)
at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage5(MessageRpc& rpc)
at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage11(MessageRpc& rpc)
at System.ServiceModel.Dispatcher.MessageRpc.Process(Boolean isOperationContextSet)</StackTrace>
<Type>System.ArgumentNullException</Type>
</ExceptionDetail>
</detail>
</s:Fault>
</s:Body>
</s:Envelope>
I couldnt see what is wrong. Could you help me?
you need to order elements as expected
Ordering must be;
->ClientIP
->ClientName
->IsTestMode
->Password
->Username
Related
I have an associative array:
$params = [
'trid' => null,
'merchantCode' => null,
'paymentMethod' => null,
'returnUrl' => site_url(null),
'notificationUrl' => site_url(null),
'language' => 'null',
'currency' => 'null',
'isTestMode' => false,
'productsXml' => null,
'needInvoice' => true,
(Nulls hold actual values in reality)
When I check __getLastRequest I completly lose the keys in the generated XML.
SoapClient,
$soap = new SoapClient(null, $options);
$soap->__soapCall('Request', $params);
$request = $soap->__getLastRequest();
Please note that I have a NON WSDL connection to the endpoint.
The generated XML will have a field value of <param[keyNum] xsi:type="xsd:typeOfVariable"> instead of having the actual key value from the associative array, <trid> for example.
<SOAP-ENV:Body><ns1:Request><param0 xsi:type="xsd:string">null</param0><param1 xsi:type="xsd:string">null</param1></Request>
Contrary to what the PHP manual says, it seems arguments is never interpreted as an associative array.
If we try this simple test:
<?php
$options = ['location'=>'http://localhost/unknown', 'uri'=>'test', 'trace'=>true];
$soap = new SoapClient(null, $options);
try
{
$soap->__soapCall('Request', ['foo'=>1, 'bar'=>2]);
}
catch(SoapFault $e)
{
header('Content-type: text/xml');
echo $soap->__getLastRequest();
}
?>
we get:
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="test" 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:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<SOAP-ENV:Body>
<ns1:Request>
<param0 xsi:type="xsd:int">1</param0>
<param1 xsi:type="xsd:int">2</param1>
</ns1:Request>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
We see that the parameter names are ignored.
Now if we try what the other answer suggests (wrap the array in another array):
<?php
$options = ['location'=>'http://localhost/unknown', 'uri'=>'test', 'trace'=>true];
$soap = new SoapClient(null, $options);
try
{
$soap->__soapCall('Request', [['foo'=>1, 'bar'=>2]]);
}
catch(SoapFault $e)
{
header('Content-type: text/xml');
echo $soap->__getLastRequest();
}
?>
we get:
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="test" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:ns2="http://xml.apache.org/xml-soap" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<SOAP-ENV:Body>
<ns1:Request>
<param0 xsi:type="ns2:Map">
<item>
<key xsi:type="xsd:string">foo</key>
<value xsi:type="xsd:int">1</value>
</item>
<item>
<key xsi:type="xsd:string">bar</key>
<value xsi:type="xsd:int">2</value>
</item>
</param0>
</ns1:Request>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
We see that there is a single parameter whose type is Map. That's not what we want.
The solution is to use the SoapParam class:
<?php
$options = ['location'=>'http://localhost/unknown', 'uri'=>'test', 'trace'=>true];
$soap = new SoapClient(null, $options);
try
{
$soap->__soapCall('Request', [new SoapParam(1, 'foo'), new SoapParam(2, 'bar')]);
}
catch(SoapFault $e)
{
header('Content-type: text/xml');
echo $soap->__getLastRequest();
}
?>
Now we get what we wanted:
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="test" 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:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<SOAP-ENV:Body>
<ns1:Request>
<foo xsi:type="xsd:int">1</foo>
<bar xsi:type="xsd:int">2</bar>
</ns1:Request>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
Note that you can easily convert an associative array to SOAP parameters like this:
function getSoapParams($params)
{
$a = [];
foreach($params as $name=>$value)
$a[] = new SoapParam($value, $name);
return $a;
}
According to notes in the documentation
If you want to call __soapCall, you must wrap the arguments in another array as follows:
$params = array('username'=>'name', 'password'=>'secret');
<?php
$client->__soapCall('login', array($params));
?>
The following line:
$soap->__soapCall('Request', $params);
Should be:
$soap->__soapCall('Request', [$params]);
I have XML document:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Header/>
<soapenv:Body>
<saml2p:ArtifactResolve xmlns:saml2p="urn:oasis:names:tc:SAML:2.0:protocol" Version="2.0"
IssueInstant="2020-06-01T10:25:15+02:00">
<saml2:Issuer xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion">TEST</saml2:Issuer>
<saml2p:Artifact>AAQAAKFbFR94fxqmioAqjJUwfHTFVHTDBTVHdBwwTW+ehcM19zsk=</saml2p:Artifact>
</saml2p:ArtifactResolve>
</soapenv:Body>
</soapenv:Envelope>
I try to do this in this way:
$results = array();
$filename = 'cert.p12';
$password = 'certpass';
$priv_key = openssl_pkcs12_read(file_get_contents($filename), $results, $password);
$doc = new DOMDocument();
$doc->loadXML($xml);
$xp = new DOMXPath($doc);
$xp->registerNamespace('soapenv', 'http://schemas.xmlsoap.org/soap/envelope/');
$xp->registerNamespace('saml2p','urn:oasis:names:tc:SAML:2.0:protocol');
$xp->registerNamespace('saml2','urn:oasis:names:tc:SAML:2.0:assertion');
$xp->registerNamespace('ds',XMLSecurityDSig::XMLDSIGNS);
$artifactResolveNode = $xp->query('/*[local-name()=\'Envelope\']/*[local-name()=\'Body\']/*[local-name()=\'ArtifactResolve\']')->item(0);
if($artifactResolveNode){
$objDSig = new XMLSecurityDSig();
$objDSig->setCanonicalMethod(XMLSecurityDSig::EXC_C14N);
$objDSig->addReference(
$artifactResolveNode,
XMLSecurityDSig::SHA256,
array('http://www.w3.org/2000/09/xmldsig#enveloped-signature', 'http://www.w3.org/2001/10/xml-exc-c14n#'),
array('force_uri' => true)
);
$objKey = new XMLSecurityKey(XMLSecurityKey::RSA_SHA256, array('type' => 'private'));
$objKey->loadKey($results['pkey'], FALSE);
$objDSig->sign($objKey);
$objDSig->add509Cert($results['cert']);
$objDSig->appendSignature($doc->documentElement());
echo $doc->saveXML();
}
Output with Singnature in wrong location is:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Header/>
<soapenv:Body>
<saml2p:ArtifactResolve xmlns:saml2p="urn:oasis:names:tc:SAML:2.0:protocol" Version="2.0" IssueInstant="2020-06-01T10:25:15+02:00" Id="pfx97783ab1-0339-0f2e-b759-9e9c07e347b0">
<saml2:Issuer xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion">TEST</saml2:Issuer><saml2p:Artifact>AAQAAKFbFR94fxqmioAqjJUwfyUtjJbv0uEPB7ooopodBwwTW+ehcM19zsk=</saml2p:Artifact></saml2p:ArtifactResolve>
</soapenv:Body>
<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:SignedInfo>
(...)
</soapenv:Envelope>
I want to put Signature node between ISSUER and ARTIFACT. This location is very important to correct send SOAP Envelope.
It is possible?
I found!
I need add code below:
$artifactNode = $xp->query('/*[local-name()=\'Envelope\']/*[local-name()=\'Body\']/*[local-name()=\'ArtifactResolve\']/*[local-name()=\'Artifact\']')->item(0);
and append Signature like this:
$objDSig->insertSignature($artifactResolveNode,$artifactNode);
I've been searching around for a solution to my problem, but to no avail. I'm trying to send a soap request through a Wordpress plugin using the following:
function soapRequest($soapUsername, $soapNonce, $soapDateTime, $soapPassword) {
$wsdl = 'http://www.beautyfort.com/api/wsdl/v2/wsdl.wsdl';
$trace = true;
$exceptions = false;
$client = new SoapClient($wsdl, array('trace' => $trace, 'exceptions' => $exceptions));
// Must be a stdClass (and not an array)
$auth = new stdClass();
$auth->Username = $soapUsername;
$auth->Nonce = $soapNonce;
$auth->Created = $soapDateTime;
$auth->Password = $soapPassword;
$header = new SoapHeader('http://www.beautyfort.com/api/', 'AuthHeader', $auth);
$client->__setSoapHeaders($header);
$xml_array['TestMode'] = 'true';
$xml_array['StockFileFormat'] = 'JSON';
$xml_array['SortBy'] = 'StockCode';
try {
$response = $client->GetStockFile($xml_array);
}
catch (Exception $e) {
log_me("Error!");
log_me($e -> getMessage());
log_me('Last response: '. $client->__getLastResponse());
}
log_me('Last request: '. $client->__getLastRequest());
log_me($response);
}
This produces the following request:
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:ns1="http://www.beautyfort.com/api/">
<SOAP-ENV:Header>
<ns1:AuthHeader>
<ns1:Username>joetest</ns1:Username>
<ns1:Nonce>htflFfIKM4</ns1:Nonce>
<ns1:Created>2019-02-09T10:13:51.000Z</ns1:Created>
<ns1:Password>NGFjYTJiNzJmOWY2MzBmY2M2MjJkNjg1MDgyMWRjMzQxOGY1YTNjYQ==</ns1:Password>
</ns1:AuthHeader>
</SOAP-ENV:Header>
<SOAP-ENV:Body>
<ns1:GetStockFileRequest>
<ns1:TestMode>true</ns1:TestMode>
<ns1:StockFileFormat>JSON</ns1:StockFileFormat>
<ns1:SortBy>StockCode</ns1:SortBy>
</ns1:GetStockFileRequest>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
And I get an invalid credentials error. I've also been testing in SoupUI and the following request works:
<soapenv:Envelope
xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:api="http://www.beautyfort.com/api/">
<soapenv:Header>
<api:AuthHeader>
<api:Username>joetest</api:Username>
<api:Nonce>tJrsRlQt6i</api:Nonce>
<api:Created>2019-02-06T23:34:11.000Z</api:Created>
<api:Password>ZTBhMmE5OGY4YTNlZWIzZTE0ZTc2ZjZiZDBhM2RhMjJmNzAxNzYwZA==</api:Password>
</api:AuthHeader>
</soapenv:Header>
<soapenv:Body>
<api:GetStockFileRequest>
<api:TestMode>true</api:TestMode>
<api:StockFileFormat>JSON</api:StockFileFormat>
<!--Optional:-->
<api:FieldDelimiter>,</api:FieldDelimiter>
<!--Optional:-->
<api:StockFileFields>
<!--1 or more repetitions:-->
<api:StockFileField>StockCode</api:StockFileField>
<api:StockFileField>Category</api:StockFileField>
<api:StockFileField>Brand</api:StockFileField>
<api:StockFileField>Collection</api:StockFileField>
<api:StockFileField>Category</api:StockFileField>
</api:StockFileFields>
<api:SortBy>StockCode</api:SortBy>
</api:GetStockFileRequest>
</soapenv:Body>
</soapenv:Envelope>
Now the only differences I can see (apart from the optional fields) is the names of the namespace, and the use of the Xml tag at the top of the request. Both of these shouldn't matter right? I'd really appreciate your help on this as I've been scratching my head for ages.
Thank you in advance!
Your perfect just need to set UTC timezone and secret format like below:
base64 encoded(sha1(Nonce . Created . Secret))
I need to add the following complex header with different namespace and types to my SoapClient Header.
<soapenv:Header xmlns:wsa="http://www.w3.org/2005/08/addressing">
<wsse:Security soapenv:mustUnderstand="1" 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>
<wsse:Username>****</wsse:Username>
<wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">*****</wsse:Password>
</wsse:UsernameToken>
</wsse:Security>
<wsa:Action>/IntS5/S5WS</wsa:Action>
</soapenv:Header>
As proposed in other answers I tried the following approach in my php project.Since I need WSA Addressing, I set the wsa:Action with security header together.
$header_part = '<wsse:Security soapenv:mustUnderstand="1" 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><wsse:Username>****</wsse:Username><wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">****</wsse:Password>'
. '</wsse:UsernameToken></wsse:Security><wsa:Action>/IntS5/S5WS</wsa:Action>';
$soap_var_header = new SoapVar($header_part, XSD_ANYXML, null, null, null);
$soap_header = new SOAPHeader('http://www.w3.org/2005/08/addressing', 'wsa', $soap_var_header);
$client->__setSoapHeaders($soap_header);
Some how __soapCall returns me the following error.
SoapFault exception: [Client] DTD are not supported by SOAP.I am not sure if it's related to header or the parameters of the putCall. Anybody can help me ?
EDIT: The problem is probably related with the namespace of the HEADER/Envelope.
The request which is sent to server looks like this.
UPDATED
<?xml version="1.0" encoding="UTF-8"?>
<env:Envelope xmlns:env="http://www.w3.org/2003/05/soap-envelope" xmlns:ns1="http://ws.s5.mediasat.de/" xmlns:ns2="http://www.w3.org/2005/08/addressing">
<env:Header>
<wsse:Security env:mustUnderstand="1" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<wsse:UsernameToken>
<wsse:Username>****</wsse:Username>
<wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">*****</wsse:Password>
</wsse:UsernameToken>
</wsse:Security>
<wsa:Action xmlns:wsa="http://www.w3.org/2005/08/addressing">/IntS5/S5WS</wsa:Action>
</env:Header>
<env:Body>
<ns1:putCall>
<transaction>createIncident</transaction>
<transactionSender>Request</transactionSender>
<caseDataModel>
<senderId>7</senderId>
<ticketTypeId>102</ticketTypeId>
<title>test</title>
<priorityId>101</priorityId>
<categoryId>128</categoryId>
<description>Description</description>
<ticketNumberSender>INCC00000743809</ticketNumberSender>
<createTypeId>701</createTypeId>
<serviceId>B001APP05K</serviceId>
<categoryId>128</categoryId>
<serviceRecipientId>77888</serviceRecipientId>
<serviceLocationSAPCode>V135</serviceLocationSAPCode>
</caseDataModel>
</ns1:putCall>
</env:Body>
</env:Envelope>
The request that works on SOAP UI
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ws="http://ws.s5.mediasat.de/">
<soapenv:Header xmlns:wsa="http://www.w3.org/2005/08/addressing">
<wsse:Security soapenv:mustUnderstand="1" 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>
<wsse:Username>***</wsse:Username>
<wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">***</wsse:Password>
</wsse:UsernameToken>
</wsse:Security>
<wsa:Action>/IntS5/S5WS</wsa:Action>
</soapenv:Header>
<soapenv:Body>
<ws:putCall>
<transaction>createIncident</transaction>
<transactionSender>Request</transactionSender>
<caseDataModel>
<senderId>7</senderId>
<ticketTypeId>102</ticketTypeId>
<title>test</title>
<priorityId>101</priorityId>
<categoryId>128</categoryId>
<description>Description</description>
<ticketNumberSender>INCC00000743809</ticketNumberSender>
<createTypeId>701</createTypeId>
<serviceId>B001APP05K</serviceId>
<categoryId>128</categoryId>
<serviceRecipientId>77888</serviceRecipientId>
<serviceLocationSAPCode>V135</serviceLocationSAPCode>
</caseDataModel>
</ws:putCall>
</soapenv:Body>
</soapenv:Envelope>
Is there anyway to set/override the namespace for the header?
You should generate the header procedurally instead of using the string.
Example:
<?php
$client = new SoapClient(null, array(
'location' => "http://localhost/soap/",
'uri' => "http://ws.s5.mediasat.de/",
'soap_version' => SOAP_1_2
));
$username = '***';
$password = '***';
$sec_namespace = 'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd';
$wsa_namespace = 'http://www.w3.org/2005/08/addressing';
// prepare security token
$node1 = new \SoapVar($username, XSD_STRING, null, null, 'Username', $sec_namespace);
$xml = new XMLWriter(); // this is a little hacky, but no other way to set the type as far as I know
$xml->openMemory();
$xml->startElementNS('wsse', 'Password',$sec_namespace);
$xml->writeAttribute('Type', 'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText');
$xml->Text($password);
$xml->endElement();
$node2 = new \SoapVar($xml->outputMemory(), XSD_ANYXML);
$token = new \SoapVar(array($node1, $node2), SOAP_ENC_OBJECT, null, null, 'UsernameToken', $sec_namespace);
$security = new \SoapVar(array($token), SOAP_ENC_OBJECT, null, null, 'Security', $sec_namespace);
$soap_header_sec = new \SOAPHeader($sec_namespace, 'Security', $security, true);
// prepare action token
$action = new \SoapVar('/IntS5/S5WS', XSD_STRING, null, null, 'Action', $wsa_namespace);
$soap_header_action = new \SOAPHeader($wsa_namespace, 'Action', $action, false);
// set prepared headers
$client->__setSoapHeaders(
[$soap_header_sec,$soap_header_action]
);
$client->putCall();
This will produce the valid envelope with all namespaces set:
<?xml version="1.0" encoding="utf-8"?>
<env:Envelope xmlns:env="http://www.w3.org/2003/05/soap-envelope" xmlns:ns1="http://ws.s5.mediasat.de/" xmlns:ns2="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:ns3="http://www.w3.org/2005/08/addressing" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:enc="http://www.w3.org/2003/05/soap-encoding">
<env:Header>
<ns2:Security env:mustUnderstand="true">
<ns2:UsernameToken>
<ns2:Username>***</ns2:Username>
<wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">***</wsse:Password>
</ns2:UsernameToken>
</ns2:Security>
<ns3:Action>/IntS5/S5WS</ns3:Action>
</env:Header>
<env:Body>
<ns1:putCall env:encodingStyle="http://www.w3.org/2003/05/soap-encoding" />
</env:Body>
</env:Envelope>
The name space "http://www.w3.org/2005/08/addressing" is not bound to the prefix "wsa".
The "mustUnderstand" attribute must use the prefix "env" not "soapenv".
You can declare the missing namespace locally. You just have to fix you header_part to look like this:
header_part = '<wsse:Security env:mustUnderstand="1" 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><wsse:Username>****</wsse:Username><wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">****</wsse:Password>'
. '</wsse:UsernameToken></wsse:Security><wsa:Action xmlns:wsa="http://www.w3.org/2005/08/addressing">/IntS5/S5WS</wsa:Action>';
Note: Maybe it is obvious but it is kind of dangerous to assume that the prefix for the "http://www.w3.org/2003/05/soap-envelope" will always be "env". The framework can change this at any time. If you want to be on the really safe side you might prefer to bind the namespace locally to a new prefix:
<wsse:Security soapenv:mustUnderstand="1" xmlns:soapenv="http://www.w3.org/2003/05/soap-envelope" ...
But having one namespace bound to two different prefixes will make things even harder to read and understand so I would say it is a question of taste.
Hye
I'm trying to use a WebService with SOAP in PHP. But the SoapVar creates my DOM XML with double XML tag
My code :
$xmlContent = '<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:tem="http://tempuri.org/" xmlns:com="http://schemas.datacontract.org/2004/07/Commun.Metier">
<soapenv:Header/>
<soapenv:Body>
<tem:SendData> ....';
$soapClient = new SoapClient("URL OF THE WSDL", array('trace' => 1, 'location' => 'URL OF THE SERVICE', 'uri' => 'URL OF THE SERVICE'));
$myXML = new SoapVar($xmlContent, XSD_ANYXML);
try {
$result = $soapClient->__soapCall("SendData", array('SendData' => $myXML));
} catch (Exception $e) {
var_dump($e);
}
The problem is that I have an exception Bad request because the XML I'm sending haves 2 XML tags and Soap Enveloppe :
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://tempuri.org/">
<SOAP-ENV:Body><?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:tem="http://tempuri.org/" xmlns:com="http://schemas.datacontract.org/2004/07/Commun.Metier">
<soapenv:Header/>
<soapenv:Body>
<tem:SendData>
How can I cancel this double tag ?
Thanks