I'm trying to create proper wsdl based soap request but with no success, here is example of what I need:
soap.xml:
<?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>
<AuthMember xmlns="http://tempuri.org/">
<somefield>string</somefield>
</AuthMember>
</soap:Header>
<soap:Body>
<AuthenticateMember xmlns="http://tempuri.org/" />
</soap:Body>
</soap:Envelope>
My result is:
soap.xml:
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://tempuri.org/" xmlns:ns2="http://schemas.xmlsoap.org/ws/2002/07/utility">
<SOAP-ENV:Header>
<ns2:AuthMember>
<somefield>somefieldvalue</somefield>
</ns2:AuthMember>
</SOAP-ENV:Header>
<SOAP-ENV:Body>
<ns1:AuthenticateMember/>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
this is my php code:
class SoapHeaderAuthMember
{
public $somefield;
public function __construct($somefield)
{
$this->somefield = $somefield;
}
}
$client = new SoapClient( 'https://www.somepage.com/service.asmx?WSDL',
array("exceptions"=>0, "trace" => 1 )
);
$authMember = new SoapHeaderAuthMember('somefieldvalue');
$soapHeaders[] = new SoapHeader('http://schemas.xmlsoap.org/ws/2002/07/utility', 'AuthMember', $authMember);
$client->__setSoapHeaders($soapHeaders);
$client->__soapCall('AuthenticateMember',array());
see,
1.it generates SOAP-ENV:Envelope instead of SOAP-ENV:Envelope
2.in header: I have ns2:AuthMember instead of AuthMember
3.in body I have ns1:AuthenticateMember instead of AuthenticateMember xmlns="http://tempuri.org/"
How can I get proper xml ? I've looked through php functions manuals and cannot find the answer, googling did not give me success results for my case.
Could you please help ?
The result that has been generated is what has been requested in the code, but an explanation of some attributes of namespaces is in order:
Each of the tags in an XML document has a fully-qualified form which is defined by the namespace and the tag name (even if it is in the 'default' namespace with no explicit namespace declaration). The fully-qualified version is typically written as {namespace}tag. By resolving the fully-qualified name it is possible to determine whether the representation of two elements is the same.
Namespaces are associated with elements in multiple ways including explicit namespace inclusion with the element
Example:
<AuthMember xmlns="http://tempuri.org/">
resolving to fully-qualified name {http://tempuri.org/}AuthMember
and via namespace-associated prefix
Example:
<... xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Header>
resolving to {http://schemas.xmlsoap.org/soap/envelope/}Header
The prefix is in scope for the element in which the prefix was declared and any contained elements. The actual prefix used is not important (soap, SOAP-ENV or randomprefix could be used for the http://schemas.xmlsoap.org/soap/envelope/ namespace), although good practice is to use something meaningful.
Given that, the fully-qualified elements in the 'desired' and 'actual' documents are almost the same, the anomaly being the header element AuthMember. In your desired you indicate a namespace of http://tempuri.org/ for a fully-qualified {http://tempuri.org/}AuthMember. In the actual the prefix association results in a fully-qualified {http://schemas.xmlsoap.org/ws/2002/07/utility}AuthMember.
This is the result of the SoapHeader instantiation specifying the ...utility namespace for AuthMember. Changing that statement in your code to use the http://tempuri.org/ namespace should result in the actual document matching the desired.
Related
I'm having troubles parsing an XML object in PHP. I'm using Laravel 5.8
Here is one of my tries:
$xml = new \SimpleXMLElement($formatted, LIBXML_BIGLINES);
var_dump($xml->children('soapenv', true)->Envalop->Body->children('ns3', true)->getAddressBookResponse->addressBook[0]->businessUnit);
And I'm getting the following error:
Call to a member function children() on null
I have tried different variations of creating and accessing the SimpleXMLElement but always with the same result. I'm getting back an empty object of typeSimpleXMLElement
Here is a sample XML that I'm using as input (coming from SOAP API call):
<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Body>
<ns3:getAddressBookResponse xmlns:ns2="http://oracle.e1.bssv.JPRCUST0/"
xmlns:ns3="http://oracle.e1.bssv.JPR01000/">
<e1MessageList>
<e1Messages>
<message>Description: All records for the query have not been returned.
</message>
</e1Messages>
</e1MessageList>
<addressBook>
<businessUnit>123456</businessUnit>
<categoryCodesAddressBook>
<categoryCode001>XXX</categoryCode001>
<categoryCode002>XXX</categoryCode002>
</categoryCodesAddressBook>
<description1>MOHAMEDHASSANALI</description1>
</addressBook>
<addressBook>
<businessUnit>789789</businessUnit>
<categoryCodesAddressBook>
<categoryCode001>YYY</categoryCode001>
<categoryCode002>YYY</categoryCode002>
</categoryCodesAddressBook>
<description1>ALIHASSANAHMED</description1>
</addressBook>
</ns3:getAddressBookResponse>
</soapenv:Body>
</soapenv:Envelope>
That is not just XML, but SOAP. I suggest using a SOAP library (like ext/soap).
It's Envelope not Envalop. And this is the element in you $xml variable.
If you want to treat it as just XML, do not rely on the namespaces prefixes but the actual namespace URIs (the values of the xmlns attributes). Prefixes can change. A prefix like ns3 is auto generated by a SOAP library, just adding/removing an element with another namespace could change it. So define constants or variables for the XMLNS values and use them.
const XMLNS_SOAP = 'http://schemas.xmlsoap.org/soap/envelope/';
const XMLNS_ADDRESSES = 'http://oracle.e1.bssv.JPR01000/';
$envelope = new \SimpleXMLElement($formatted, LIBXML_BIGLINES);
var_dump(
$envelope->children(XMLNS_SOAP)->Body->children(XMLNS_ADDRESSES)->getAddressBookResponse->children('')->addressBook[0]->businessUnit
);
Xpath expressions (SimpleXMLElement::xpath()) allow for conditional fetching. This avoids problems if an element is missing, but you will have to register your own prefixes for the namespaces.
const XMLNS_SOAP = 'http://schemas.xmlsoap.org/soap/envelope/';
const XMLNS_ADDRESSES = 'http://oracle.e1.bssv.JPR01000/';
$envelope = new \SimpleXMLElement($formatted, LIBXML_BIGLINES);
$envelope->registerXpathNamespace('s', XMLNS_SOAP);
$envelope->registerXpathNamespace('a', XMLNS_ADDRESSES);
var_dump(
$envelope->xpath('(s:Body/a:getAddressBookResponse/addressBook)[1]/businessUnit')
);
I am having a SOAP request which goes like
<SOAP-ENV:Body>
<ns2:get>
<ns2:arg0>
<ns1:type xsi:type="ns1:Type">
.....
</ns1:type>
</ns2:arg0>
</ns2:get>
</SOAP-ENV:Body>
currently I am getting error saying that, 'type is not created' because of the namespace in arg0, I guess the Namespace is coming because the previous node has the same namespace and the child is not suppose to go with the same namespace, following is the expected request by my WSDL.
<SOAP-ENV:Body>
<ns2:get>
<arg0>
<ns1:type xsi:type="ns1:Type">
.....
</ns1:type>
<arg0>
</ns2:get>
</SOAP-ENV:Body>
Please brief me, how to remove a namespace before sending the request. I am using stdClass and soapVar() method to create the arg0 variable.
How to change my Soapenv:Envelope parameter from this:
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:ejb="http://ejb.gateway.ebpp.fawryis.com/"
xmlns:ns3678="http://tempuri.org">
to this:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ejb="http://ejb.gateway.ebpp.fawryis.com/">
How to set the nusoap client Soapenv so it can be the same as the second format?
Also in every element there is xmlns empty attribute:
<process xmlns="http://ejb.gateway.ebpp.fawryis.com/">
<arg0 xmlns=""><Request xmlns="">
How to remove those xmlns attributes?
Here is my code:
$client = new nusoap_client($wsdl_path, TRUE);
$client->namespaces = array(
'SOAP-ENV'=>"http://schemas.xmlsoap.org/soap/envelope/",
'ejb'=>"http://ejb.gateway.ebpp.fawryis.com/"
);
$parameters = array(//the parameters );
$result = $client->call("process", $parameters);
Thank you
I understand you could fork Nusoap project and customize nusoap.php source code to return exactly what you whish. But notice that some people are telling us we don't need to bother with this prefix SOAP-ENV. If you do not care about which one is being serialized (SOAP-ENV or soap prefix), keep using the original nusoap project. Remember to enter the same namespace.
Here some extra information:
You can use any string you like as a namespace prefix, just as long as
it maps to the appropriate namespace name. The reason why the spec
bothers with telling us the notational conventions is that prefix
names (e.g., SOAP-ENV) aren't normative.
Source: SOAP-ENV vs. soapenv
...as long as soap and SOAP-ENV refer to the same namespace URI, then
everything will be OK.
Source: SOAP-ENV: vs. soap:Envelope
...can be any allowed string - it does not matter to the XML parser as
long as the correct namespace URL has been given.
Source: SOAP Envelope namespace
I previously managed to call a .NET service using PHP's SoapClient library without too many issues, but now I face a scenario where I have to access the same services in non-WSDL mode.
I seem to have created, more or less, the correct XML structure to send through to the service, but the server does not seem to be picking up the variables I am sending.
Based on output from SOAPUI, I should be attempting to generate the following SOAP call:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:int="http://someservices.com/">
<soapenv:Header/>
<soapenv:Body>
<int:getService>
<int:foo>String value for foo</int:foo>
<int:bar>String value for bar</int:bar>
</int:getService>
</soapenv:Body>
</soapenv:Envelope>
The output that I am generating with SOAPClient is:
<?xml version="1.0" encoding="UTF-8"?> <env:Envelope xmlns:env="http://www.w3.org/2003/05/soap-envelope" xmlns:ns1="http://someservices.com" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:enc="http://www.w3.org/2003/05/soap-encoding">
<env:Body>
<ns1:getService env:encodingStyle="http://www.w3.org/2003/05/soap-encoding">
<foo xsi:type="xsd:string">String value for foo</foo>
<bar xsi:type="xsd:string">String value for bar</bar>
</ns1:getService>
</env:Body>
</env:Envelope>
The error returned from the .NET service is "bar expected!" - indicating, at the very least, that the service is not picking up my second parameter.
I am constructing my soap call using the following:
$foo = 'String value for foo';
$bar = 'String value for bar';
$options = array(
'trace' => 1,
'exceptions' => 1,
'uri' => 'http://someservices.com',
'soapaction' => 'http://someservices.com/getService',
'soap_version' => SOAP_1_2,
'type_map' => array('type_ns' => 'int')
);
$response = $soapclient->__soapCall('getService', array( new SoapParam($foo, 'foo'), new SoapParam($bar, 'bar')), $options);
I am not sure what the issue is. Right now I am guessing that it might be an xmlns attribute issue. Note that the SOAPUI call specifies the int: in front of the function calls and parameters. I have tried to specify this xmlns but without luck. As you can see xmlns generated by Soap Client call is:
xmlns:ns1
Any help would be greatly appreciated.
As it turns out, having the namespace labelled as ns1 instead of int was not the issue.
The problem was that the getService parameter was being prefixed with the namespace ns1, whilst the variables foo and bar were not.
As such, this was resolved by appending "ns1:" to the Soap Params in the soapCall function, as follows:
$response = $soapclient->__soapCall('getService', array( new SoapParam($foo, 'ns1:foo'), new SoapParam($bar, 'ns1:bar')), $options);
Here's the call I'm trying to make:
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Header xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<urn:SessionHeader xmlns:urn="http://www.mywebservice.com/webservices/SoapService" xmlns="http://www.mywebservice.com/webservices/SoapService" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<urn:sessionId xmlns:urn="http://www.mywebservice.com/webservices/SoapService">LOGINTOKEN=your instance name</urn:sessionId>
</urn:SessionHeader>
</soap:Header>
<soap:Body xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<ns2:login xmlns:ns2="http://www.mywebservice.com/webservices/SoapService">
<wsUser>
<entityId>0</entityId>
<password>your password</password>
<username>your username</username>
</wsUser>
</ns2:login>
</soap:Body>
But I'm having trouble finding out how to set up the custom headers in PHP5's Soap. With nuSoap I could just put the whole thing into a variable and then use $client->setHeader($headerVar) but I can't find anything similar in PHP. If I could replicate this one call, I can figure the rest out. Any help would be appreciated!
Thanks in advance!
Update: I've gone through tutorial after tutorial, and read the PHP docs, but nothing seems to work. I can do what I want with curl (as well as nuSoap) but I thought the native PHP5 Soap would be easier and possibly more stable. I guess not...
Update 2
Here's the code I'm trying:
$soapurl = 'http://www.mywebservice.com/webservices/SoapService?wsdl';
$client = new SoapClient($soapurl,array('trace'=>true));
$token = "LOGINTOKEN=your instance name";
$header = new SoapHeader('http://www.mywebservice.com/webservices/SoapService', 'SessionHeader', array('sessionId' => $token));
$client->__setSoapHeaders($header);
$client->login(array("wsUser" => array('entityId'=>'0','username'=>'my username','password'=>'my password')));
And the error I get:
**Fatal error**: Uncaught SoapFault exception: [ns1:InvalidSecurity] An error was discovered processing the <wsse:Security> header in C:\www\soap\index.php:12 Stack trace: #0 C:\www\soap\index.php(12): SoapClient->__call('login', Array) #1 C:\www\soap\index.php(12): SoapClient->login(Array) #2 {main} thrown in C:\www\soap\index.php on line 12
Update 3
So it looks like the "sessionId" is being sent as "key" with the token sent as "value".
*REQUEST*:
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://www.mywebservice.com/webservices/SoapService">
<SOAP-ENV:Header>
<ns1:SessionHeader><item><key>sessionId</key><value>LOGINTOKEN=my token</value></item>
</ns1:SessionHeader>
</SOAP-ENV:Header>
<SOAP-ENV:Body><ns1:login><wsUser><entityId>0</entityId><password>my password</password><username>my username</username></wsUser></ns1:login></SOAP-ENV:Body></SOAP-ENV:Envelope>
Have you tried the SoapHeader class to construct your header? Would something like this work?
//Assume $token holds your login token and $client holds the SoapClient object
$header = new SoapHeader('http://www.mywebservice.com/webservices/SoapService', 'SessionHeader', array('sessionId' => $token));
$client->__setSoapHeaders($header);
That should create the header and add it to the SoapClient. Every subsequent call using the SoapClient will then have that header set. As to the exact format, I wouldn't worry too much. You sample XML uses an alias for the namespace called urn. PHP probably won't arrive at exactly the same alias but it should still work. Also I don't think that declaring the xmlns in every child element is needed. I think that a child node automatically inherits the namespace of its parent in XML, but I'm not 100% certain on that. The bottom line is that as long as the right URL's are declared in the namespaces it should be fine even if the XML doesn't exactly match your example.
One other thing you could try-have you switched on tracing in the SoapClient? This is one of the parameters that can be passed to the constructor and it enables you to view the XML SOAP requests and responses. If it still doesn't work using the SoapHeader class try switching tracing on to see what's being sent and received.