Writing xml using php soap library - php

I have issue and I don't know how to correctly write complex SOAP like this:
<entry>
<key>KEY</key>
<value xsi:type="ns1:Param">
<oid>OID</oid>
</value>
</entry>
Looks like I'm almost done, but I have error like this:
"SOAP-ERROR: Encoding: object has no 'oid' property"
Below is my current code:
$key = new SoapVar('key', XSD_STRING, null, null, 'key');
$oid = new SoapVar('oid', XSD_STRING, null, null, 'oid');
$value = new SoapVar([$oid], SOAP_ENC_OBJECT, 'Param', 'URL', 'value');
$entry = new SoapVar([$key, $value], SOAP_ENC_OBJECT, null, null, 'entry');
Thanks for help in advance!

Finally fixed using this code!:
$key = new SoapVar('KEY', XSD_STRING, null, null, 'key');
$value = new SoapVar(['oid' => 'OID'], XSD_ANYTYPE, 'Param', 'URL', 'value');
$entry = new SoapVar([$key, $value], SOAP_ENC_OBJECT, null, null, 'entry');

Related

Add attribute to SoapVar

I am struggling in adding an attribute to a SoapVar-Element.
This is the structure i want to creat:
<SOAP-ENV:Body>
<ns:ServiceRequest>
<ns:Method>PING</ns:Method>
<ns:Property Name="name1">foo</ns:Property>
<ns:Property Name="name2">bar</ns:Property>
</ns:ServiceRequest>
</SOAP-ENV:Body>
but this is all i get:
<SOAP-ENV:Body>
<ns1:ServiceRequest>
<ns1:Method>PING</ns1:Method>
<ns1:Property>foo</ns1:Property>
<ns1:Property>bar</ns1:Property>
</ns1:ServiceRequest>
</SOAP-ENV:Body>
This is my code to create one of the "Property"-nodes:
$node = new SoapVar( 'foo', XSD_STRING, null, null, 'Property', $namespace);
I already tried replacing the 'foo' with an array or an object but nothing worked.
$Property['_'] = 'foo';
$Property['Name'] = 'name1';
$node = new SoapVar( $Property, SOAP_ENC_OBJECT);
... which results in:
<_>foo</_>
<Name>name1</Name>
Let me know if you need more information

Build SOAP header

i need use a SOAP webservice for a project.
The webservice requires authentication via a SOAP header like this:
<soap:Header>
<wsse:Security soap:mustUnderstand="true" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<wsse:UsernameToken>
<wsse:Username>STAGING_WS</wsse:Username>
<wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">ANDREANI</wsse:Password>
</wsse:UsernameToken>
</wsse:Security>
</soap:Header>
So, i tried build the headers using SoapHeader class as below:
$ns = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd";
$auth = new \StdClass();
$auth->Username = new \SoapVar('STAGING_WS', XSD_STRING, NULL, $ns, NULL, $ns);
$auth->Password = new \SoapVar('ANDREANI', XSD_STRING, NULL, $ns, NULL, $ns);
$token = new \StdClass();
$token->UsernameToken = new \SoapVar($auth, SOAP_ENC_OBJECT, NULL, $ns, 'UsernameToken', $ns);
$security = new \SoapVar(new \SoapVar($token, SOAP_ENC_OBJECT, NULL, $ns, 'UsernameToken', $ns), SOAP_ENC_OBJECT, NULL, $ns, 'Security', $ns);
$header = new \SoapHeader('wsse', 'Security', $security, true);
But, the generatd header is not equal:
<env:Envelope xmlns:env="http://www.w3.org/2003/05/soap-envelope" xmlns:ns1="http://www.andreani.com.ar" xmlns:ns2="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:ns3="wsse">
<env:Header>
<ns3:Security env:mustUnderstand="true">
<ns2:UsernameToken>
<ns2:Username>STAGING_WS</ns2:Username>
<ns2:Password>ANDREANI</ns2:Password>
</ns2:UsernameToken>
</ns3:Security>
</env:Header>
<env:Body>
<ns1:ConfirmarCompra/>
</env:Body>
</env:Envelope>
Any ideas ?
Try changing the last line to:
$header = new \SoapHeader($ns, 'Security', $security, true);
This will make the namespace of the Security tag to be the same as UsernameToken, Username and Password tags. The local name for the security namespace will be still ns2 and not wsse but that doesn't really matter. The correct SOAP Server must accept it as long as the namespace url is correct.

Getting the XML as string for a SoapVar variable - without a webservice (locally)?

Consider this simple snippet of code:
<?php
# http://php.net/manual/en/soapvar.soapvar.php
$parm = array();
$parm[] = new SoapVar('123', XSD_STRING, null, null, 'customerNo' );
$parm[] = new SoapVar('THIS', XSD_STRING, null, null, 'selection' );
$parm[] = new SoapVar('THAT', XSD_STRING, null, null, 'selection' );
$out = new SoapVar($parm, SOAP_ENC_OBJECT);
var_dump($out);
?>
On the thread it is taken from, it is claimed that it would produce something like the following XML:
<customerNo>123</customerNo>
<selection>THIS</selection>
<selection>THAT</selection>
... however, only thing I can see with var_dump() is something like this:
object(SoapVar)#4 (2) {
["enc_type"]=>
int(301)
["enc_value"]=>
array(3) {
[0]=>
object(SoapVar)#1 (3) {
["enc_type"]=>
int(101)
["enc_value"]=>
string(3) "123"
["enc_name"]=>
string(10) "customerNo"
}
[1]=> ...
How could I get the expected XML of a SoapVar object, without calling an actual remote webservice?
Ok, thanks to Inspect XML created by PHP SoapClient call before/without sending the request, I think I got it solved - one needs to create a separate debug SoapClient extended class, here is the modified OP code with it:
<?php
#<!-- # http://php.net/manual/en/class.soapvar.php -->
class SoapClientDebug extends SoapClient
{
public function __doRequest($request, $location, $action, $version, $one_way = 0) {
// Add code to inspect/dissect/debug/adjust the XML given in $request here
//echo "$request\n"; // OK, but XML string in single line
$doc = new DomDocument('1.0');
$doc->preserveWhiteSpace = false;
$doc->formatOutput = true;
$doc->loadXML($request);
$xml_string = $doc->saveXML();
echo "$xml_string\n";
// Uncomment the following line, if you actually want to do the request
// return parent::__doRequest($request, $location, $action, $version, $one_way);
return ""; # avoids the PHP Fatal error: Uncaught SoapFault exception: [Client] SoapClient::__doRequest() returned non string value in .../__thisfile__.php:32
}
}
# http://php.net/manual/en/soapvar.soapvar.php
$parm = array();
$parm[] = new SoapVar('123', XSD_STRING, null, null, 'customerNo' );
$parm[] = new SoapVar('THIS', XSD_STRING, null, null, 'selection' );
$parm[] = new SoapVar('THAT', XSD_STRING, null, null, 'selection' );
$out = new SoapVar($parm, SOAP_ENC_OBJECT);
var_dump($out);
//~ $dbgclient = new SoapClientDebug(NULL); # "URI of the WSDL file or NULL if working in non-WSDL mode." http://php.net/manual/en/soapclient.soapclient.php
$dbgclient = new SoapClientDebug(null, array('location' => "http://localhost/soap.php",
'uri' => "http://test-uri/"));
$dbgclient->testVar($out);
?>
This, at end, will print out:
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://test-uri/" 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:testVar>
<param0 xsi:type="SOAP-ENC:Struct">
<customerNo xsi:type="xsd:string">123</customerNo>
<selection xsi:type="xsd:string">THIS</selection>
<selection xsi:type="xsd:string">THAT</selection>
</param0>
</ns1:testVar>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
... which is what I wanted, I guess...

How to generate the following SOAP XML request?

The SOAP API I am using, needs the request XML formatted as below:
<SOAP-ENV:Body>
<ns1:functionName/>
<UserID>WEB</UserID>
<Attribute>
<ID>83</ID>
<Value>34343</Value>
</Attribute>
<Attribute>
<ID>84</ID>
<Value>45343</Value>
</Attribute>
</SOAP-ENV:Body>
I have gone through almost all "multiple element" related questions here on StackOverflow but still can't figure it out.
Here is what I am trying at the moment:
$args = new ArrayObject();
$args->UserID = WEB;
$Attribute = new stdClass();
$Attribute->ID = 83;
$Attribute->Value = 34343;
$args->append(new SoapParam($Attribute, 'Attribute'));
$Attribute = new stdClass();
$Attribute->ID = 84;
$Attribute->Value = 45343;
$args->append(new SoapParam($Attribute, 'Attribute'));
$soapClient->functionName($args);
Can someone please help me out with this?
I would advise you to use a WSDL to php generator as you'll deal with abstracted classes that match the required parameter and the operations so you won't have to figure out the correct syntax, it will be automaticcally done by the generated package.
Two generators:
Mine: https://github.com/WsdlToPhp/PackageGenerator
From others: https://github.com/wsdl2phpgenerator/wsdl2phpgenerator
Good luck
Finally managed to figure it out. Hope the below code helps someone:
$args = array();
$args[] = new SoapVar('WEB', XSD_STRING, null, null, 'UserID');
$obj = new stdClass();
$obj->ID = 83;
$obj->Value = 34343;
$args[] = new SoapVar($obj, SOAP_ENC_OBJECT, null, null, 'Attribute');
$obj = new stdClass();
$obj->ID = 84;
$obj->Value = 45343;
$args[] = new SoapVar($obj, SOAP_ENC_OBJECT, null, null, 'Attribute');
$soapClient->functionName(new SoapVar($args, SOAP_ENC_OBJECT));

PHP SOAP Header construction

So basically I want the SOAP header to be like this:
<soapenv:Header>
<v1:loginDetails>
<v11:Id>0</v11:Id>
<v11:username>MEMBERS</v11:username>
$ <v11:password>0x909711E5,0xE301F82A,0x0E2783CC,0xAF6BC3DB,0x57727CFB</v11:password>
</v1:loginDetails>
</soapenv:Header>
<soapenv:Body>
<v11:GetNextAvailableMemberNumberRequest>
<v11:Id>1</v11:Id>
<v11:memberId>1</v11:memberId>
</v11:GetNextAvailableNumberRequest>
</soapenv:Body>
</soapenv:Envelope>
But instead, now I have this:
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://www..com/membership/types/v1_0">
<SOAP-ENV:Header>
<ns1:loginDetails>
<item><key>siteId</key><value>0</value></item>
<item><key>Username</key><value>MEMBERSHIP</value></item>
<item><key>Password</key><value>P#ssw0rd</value></item>
</ns1:loginDetails>
</SOAP-ENV:Header>
<SOAP-ENV:Body>
<ns1:GetNextAvailableMemberNumberRequest/>
<param1>1</param1>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
And this is the php code that I'm currently using:
$client = new SOAPClient('http://192.168.180.128:8010//membershipService?wsdl',array('trace' => true));
$client->__setSoapHeaders(null);
$headerbody = array ('siteId' => '0','Username' => 'MEMBERSHIP',
'Password' => 'P#ssw0rd');
$header = new SOAPHeader('http://www.com/club/services/membership/types/v1_0','loginDetails',$headerbody);
$client->__setSoapHeaders($header);
Where have I gone wrong? I seems unable to construct the header properly.
Just try to use an anonymous class instead of an array :
// Use standard class and set magic properties.
$header = new stdClass();
$header->siteId = '0';
$header->Username = 'MEMBERSHIP';
$header->Password = 'P#ssw0rd';
Casting the array of parameters to an object works pretty well
$auth = (object)array(
'Username' => 'AzureDiamond',
'Password' => 'hunter2',
);
$header = new SOAPHeader('http://my.ns/','loginDetails',$auth);
However, I find that it still doesn't get namespaces quite right. The above produces
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns2="http://my.ns/">
<SOAP-ENV:Header>
<ns2:loginDetails>
<Username>AzureDiamond</Username>
<Password>hunter2</Password>
</ns2:loginDetails>
</SOAP-ENV:Header>
....
And you'll see that although the 'loginDetails' tag is in the requested namespace, it's child elements are not.
I just encountered a very similar problem.
To fix it, you need to use the SoapVar class. This allows you to control what namespace to use for each tag.
$client = new SOAPClient('http://192.168.180.128:8010//membershipService?wsdl',array('trace' => true));
$ns = 'http://www.com/club/services/membership/types/v1_0';
$headerbody = new SoapVar([
new SoapVar('0', XSD_STRING, null, null, 'siteId', $ns),
new SoapVar('MEMBERSHIP', XSD_STRING, null, null, 'Username', $ns),
new SoapVar('P#ssw0rd', XSD_STRING, null, null, 'Password', $ns),
], SOAP_ENC_OBJECT);
$header = new SOAPHeader($ns,'loginDetails',$headerbody);
$client->__setSoapHeaders($header);
Your request's soap header should look something like this with this:
<SOAP-ENV:Header>
<ns1:loginDetails>
<ns1:siteId>0</ns2:siteId>
<ns1:Username>MEMBERSHIP</ns2:Username>
<ns1:Password>P#ssw0rd</ns2:Password>
</ns1:loginDetails>
</SOAP-ENV:Header>
There was typo:
$header = NEW stdClass() ;
$headerbody = array ('Id' => '0','username' => 'MEMBERSHIP',
'password' => 'P#ssw0rd');
Please refer the link
http://php.net/manual/en/class.soapheader.php
Also make sure that you are passing correct namespace (first parameter) in SOAPHeader constructor

Categories