Building array for consuming complex wsdl - PHP - php

I am having some issues, and yes, i am probably out of my league, but I do this for learning.
I am trying to consume a SOAP service, and i cannot, for the life of me build an array that the server accepts.
WSDL is visible here:
http://metrolive.telenor.no/kapaks-facade-soap-web/services/KapaksFacade70SoapWrapper/wsdl
I can do this and it works perfectly fine:
$tlf = new SoapVar(
array(
new SoapVar(
array(
'ns2:connectionNumber' => 12345678,
'ns2:connectionNumberType' => "T",
'ns2:requestedProduct' => "OA"
), SOAP_ENC_OBJECT, null, null, null, 'http://web.soap.v70.kapaks.facade.metro2.telenor.com'
)
), SOAP_ENC_OBJECT, null, null, null, 'http://dto.common.v70.kapaks.facade.metro2.telenor.com'
);
$client = new SoapClient($kapaks_wsdl, $wsdl_options);
$result = $client->validateProductSoap($tlf);
This produces this xml: (From wireshark)
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org /soap/envelope/"
xmlns:ns1="http://web.soap.v70.kapaks.facade.metro2.telenor.com"
xmlns:ns2="http://dto.common.v70.kapaks.facade.metro2.telenor.com">
<SOAP-ENV:Header/><SOAP-ENV:Body><ns1:validateProductSoap><ns1:BOGUS>
<ns2:connectionNumber>12345678</ns2:connectionNumber>
<ns2:connectionNumberType>T</ns2:connectionNumberType>
<ns2:requestedProduct>OA</ns2:requestedProduct></ns1:BOGUS>
</ns1:validateProductSoap></SOAP-ENV:Body></SOAP-ENV:Envelope>
But, i need to request properties from the "address" node(Is it node?). I can not figure out how to map this into the array, i have been at this for days...
This XML works in curl: (Straigt from SoaP-UI)
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:web="http://web.soap.v70.kapaks.facade.metro2.telenor.com"
xmlns:dto="http://dto.common.v70.kapaks.facade.metro2.telenor.com">
<soapenv:Header/>
<soapenv:Body>
<web:validateProductSoap>
<web:arg_0_0>
<dto:address>
<dto:houseLetter>A</dto:houseLetter>
<dto:houseNumber>12</dto:houseNumber>
<dto:municipalityNumber>0000</dto:municipalityNumber>
<dto:streetCodeType>V</dto:streetCodeType>
<dto:streetName>Street</dto:streetName>
</dto:address>
<dto:requestedProduct>OA</dto:requestedProduct>
</web:arg_0_0>
</web:validateProductSoap>
</soapenv:Body>
</soapenv:Envelope>
The curl approach gives me an xml response, but i need the array/object that soapclient produces, to be able to pass it to the front-end view.
How can i produce a soapclient request that will request what is inside the address tag? Or make an array/object that is identical to what soapclient delivers?

I made a workaround. At this point i don't care how its done, just that it is done. Still, if someone has the answer on how to do it the correct way, i would like to see it.
I am using nusoap thats is updated for newer php (https://github.com/econea/nusoap) , and i send raw xml with that.
function adresse($kmune1,$street1,$hnum1,$hletter1)
{
require '..\vendor\econea\nusoap\src\nusoap.php';
$endpoint = "http://user:pw#metrolive.telenor.no:80/kapaks-facade-soap-web/services/KapaksFacade70SoapWrapper";
$client2 = new nusoap_client($endpoint, false);
$client2->soap_defencoding = 'UTF-8';
$client2->decode_utf8 = false;
$XMLrequest = '<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:web="http://web.soap.v70.kapaks.facade.metro2.telenor.com" xmlns:dto="http://dto.common.v70.kapaks.facade.metro2.telenor.com">
<soapenv:Header/>
<soapenv:Body>
<web:validateProductSoap>
<web:arg_0_0>
<dto:address>
<dto:houseLetter>'.$hletter1.'</dto:houseLetter>
<dto:houseNumber>'.$hnum1.'</dto:houseNumber>
<dto:municipalityNumber>'.$kmune1.'</dto:municipalityNumber>
<dto:streetCodeType>V</dto:streetCodeType>
<dto:streetName>'.$street1.'</dto:streetName>
</dto:address>
<dto:requestedProduct>OA</dto:requestedProduct>
</web:arg_0_0>
</web:validateProductSoap>
</soapenv:Body>
</soapenv:Envelope>';
$result = $client2->send($XMLrequest, $endpoint, null);
$result=json_decode(json_encode($result));
return $result;
}

Related

How to add attributes to elements when making request with SoapClient

I need to make a SOAP call and a request shoul look like this:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:soap="xxxxxx">
<soapenv:Header/>
<soapenv:Body>
<soap:getOptions>
<arg0 username="?" password="?">
<getOptionsBusinessData/>
</arg0>
</soap:getOptions>
</soapenv:Body>
</soapenv:Envelope>
Is that possible with PHP SoapClient?
Tried many things all of which resulted in java nullpoint exception. Now I'm trying
$xml_string = '<getOptions>
<arg0 username="xxxx" password="xxxx">
<getOptionsBusinessData/>
</arg0>
</getOptions>';
$client = new \SoapClient('https://example.com?wsdl');
$args = array(new \SoapVar($xml_string, XSD_ANYXML));
$res = $client->__soapCall('getOptions', $args);
return $res;
Got different kind of error SoapFault Cannot find dispatch method for {}getOptions. I'm stuck! How do I unstuck?
Do not pass xml string as parameter. SoapClient is supposed to generate the XML for you. Try following call:
$client = new \SoapClient('https://example.com?wsdl');
$res = $client->getOptions(array('username' => 'xxx', 'password' => 'xxx'));
return $res;

Connecting to SOAP server with PHP

I am new to Soap and WSDLs. I am trying to replicate this example transaction using Soap in PHP.
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:open="http://example.com/">
<soapenv:Header/>
<soapenv:Body>
<open:processEvent>
<authenticationToken>
<userName>1</userName>
<password>password1234</password>
</authenticationToken>
<sourceThirdPartyId>1</sourceThirdPartyId>
<dealerEndpointId>4</dealerEndpointId>
<eventType>GetAdvisorConfig</eventType>
<payload></payload>
<payloadVersion>STAR-5.5.4</payloadVersion>
</open:processEvent>
</soapenv:Body>
</soapenv:Envelope>
So far I am able to make a connection to the soap server, but am unsure how to insert the required variables.
$soapClient = new SoapClient("https://example.com?wsdl", array('soap_version' => SOAP_1_2,'trace' => 1 ));
echo("\nDumping client object functions:\n");
var_dump($soapClient->__getFunctions());
$response = $soapClient->__soapCall("processEvent",array("processEvent"=>"GetAdvisorConfig"));
echo("\nReturning value of __soapCall() call: ".$response);

SoapClient calling webservice

I am trying to call a SOAP based webservice. Following is the WSDL for my webservice
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:var="some_namespace">
<soapenv:Header/>
<soapenv:Body>
<var:SomeServiceRequest name="xxx" school="yyy" format="pdf" senderName1="aaa" />
</soapenv:Body>
</soapenv:Envelope>
Now I have tried all the possibilities to call this webservice using the SoapClient class in PHP. I am always getting 'Invalid XML' in response.
Following is the way seems the most obvious but I dont understand why its not working:
$soapclient = new SoapClient($this->getWSDLUrl(), array('trace' =>true,
'soap_version' => SOAP_1_2,
));
$headerbody = array('UsernameToken'=>array('Username'=>'someusername',
Password'=>'somepassword'));
$header = new SoapHeader('https://xxx/SoapConnector','Security',$headerbody);
$soapclient->__setSoapHeaders($header);
$oResponse = $soapclient->SomeService(array('name'=>'asd', 'school'=>'sdf','format'=>'asdf'));

how to generate a soap request in php from this xml?

I'm tired of trying to send a request with SOAP. this is my xml
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:tem="http://tempuri.org/" xmlns:bpf="http://schemas.datacontract.org/2004/07/Bpf.Security.Common" xmlns:bpf1="http://schemas.datacontract.org/2004/07/Bpf.Security.Authentication.Common">
<soapenv:Header>
<InfoTag xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.w3.org/BaufestProductivityFramework">
<ClientIp xmlns="http://schemas.datacontract.org/2004/07/Bpf.Common.Service">200.125.145.10</ClientIp>
<CompanyId xmlns="http://schemas.datacontract.org/2004/07/Bpf.Common.Service">1</CompanyId>
<UserName xmlns="http://schemas.datacontract.org/2004/07/Bpf.Common.Service">someUser</UserName>
</InfoTag>
</soapenv:Header>
<soapenv:Body>
<tem:LogIn>
<tem:token>
<bpf:type>
<bpf1:Description>someDesc</bpf1:Description>
<bpf1:Id>1</bpf1:Id>
<bpf1:Name>someDesc</bpf1:Name>
</bpf:type>
<bpf:password>somePass</bpf:password>
<bpf:userName>someUser</bpf:userName>
</tem:token>
</tem:LogIn>
</soapenv:Body>
</soapenv:Envelope>
this function send the header with a namespace, but there are more than one... I have to send them all?
private function __getHeaders() {
$ns = 'http://schemas.xmlsoap.org/soap/envelope/'; //Namespace of the WS.
$ip = $_SERVER['REMOTE_ADDR'];
//Body of the Soap Header.
$headerbody = array('ClientIp' => $ip,
'CompanyId' => 1,
'UserName' => 'someUser'
);
//Create Soap Header.
$header = new SOAPHeader($ns, 'InfoTag', $headerbody);
return $header;
}
public function prepareWs(){
$wsdl="the web service";
$client = new SoapClient($wsdl, array('trace' => true));
//Set the Headers of Soap Client.
$header = $this->__getHeaders();
$client->__setSoapHeaders($header);
I try to send this body, I inspected exception with soap fault but the message only returns "bad request NULL NULL NULL".
$params = new stdClass();
$params = new SoapVar("<tem:token>
<bpf:type xmlns:bpf="http://schemas.datacontract.org/2004/07/Bpf.Security.Common">
<bpf1:Description xmlns:bpf1="http://schemas.datacontract.org/2004/07/Bpf.Security.Authentication.Common">someDesc</bpf1:Description>
<bpf1:Id xmlns:bpf1="http://schemas.datacontract.org/2004/07/Bpf.Security.Authentication.Common">1</bpf1:Id>
<bpf1:Name xmlns:bpf1="http://schemas.datacontract.org/2004/07/Bpf.Security.Authentication.Common">someName</bpf1:Name>
</bpf:type>
<bpf:password xmlns:bpf="http://schemas.datacontract.org/2004/07/Bpf.Security.Common">somePass</bpf:password>
<bpf:userName xmlns:bpf="http://schemas.datacontract.org/2004/07/Bpf.Security.Common">someUser</bpf:userName>
</tem:token>", XSD_ANYXML);
$response = $client->Login($params);
}
With CURL I can send this XML and recieved the XML response too, but with SOAPClient I can't send this request.
I hope someone can help me, thanks.
This is the code I can see with firebug, the only thing I get is "bad request". When I use __getLastRequest() I see the same...
I guess the headers should not be sent correctly, however the __setSoapHeaders function returns true.
This is the output:
<soap-env:envelope xmlns:ns1="http://tempuri.org/" xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/">
<soap-env:header>
<soap-env:contextinformation>
<item>
<key>ClientIp</key>
<value>127.0.0.1</value>
</item>
<item>
<key>CompanyId</key>
<value>1</value>
</item>
<item>
<key>UserName</key>
<value>someUser</value>
</item>
</soap-env:contextinformation>
</soap-env:header>
<soap-env:body>
<tem:login>
<tem:token>
<bpf:type>
<bpf1:description>someDesc</bpf1:description>
<bpf1:id>1</bpf1:id>
<bpf1:name>someName</bpf1:name>
</bpf:type>
<bpf:password>somePass</bpf:password>
<bpf:username>someUser</bpf:username>
</tem:token>
</tem:login>
</soap-env:body>
</soap-env:envelope>
SoapHeader treats arrays rather arbitrarily. If you ever want to use an array, consider using ArrayObject instead of the native construct.
However, you don't need an array at all since you're only trying to construct a single element in your header. And because each of your internal elements (eg. ClientIP) has a unique namespace, you can't just pass in a basic object. Instead, you have to specify a particular namespace for each element using the SoapVar class, which allows you to wrap normal PHP data in a "SOAP-ready" container that SoapClient can understand and translate.
$innerNS = "http://www.w3.org/BaufestProductivityFramework";
$outerNS = "http://schemas.datacontract.org/2004/07/Bpf.Common.Service";
$tag = new stdClass();
$tag->ClientIP = new SoapVar("200.125.145.10", XSD_STRING, null, null, null, $innerNS);
$tag->CompanyId = new SoapVar(1, XSD_INT, null, null, null, $innerNS);
$tag->UserName = new SoapVar("someUser", XSD_STRING, null, null, null, $innerNS);
$client->__setSoapHeaders(new SoapHeader($outerNS, 'InfoTag', $tag));
Finally, as a rule, don't manually write XML! Consider re-writing your SOAP body code like the header code shown here. You ought to be able to deal specifically with the content of the XML, not its structure.

simple php SoapClient example for paypal needed

Could I get a simple example of using PHP's SoapClient class to make an empty call to Paypal with nothing but the version number? I have the correct WSDL url and server url, so that's not what I need help with. This is what I have:
public function SOAPcall($function, $args=array()) {
$args['Version'] = '63.0';
$args = new SoapVar($args, SOAP_ENC_ARRAY, $function.'_Request');
$args = array(new SoapVar($args, SOAP_ENC_ARRAY, $function.'_Req', 'urn:ebay:api:PayPalAPI'));
$results = $this->soapClient->__soapCall($function, $args, array('location' => $this->activeKeys['certificate']), $this->soapOptions);
}
I hope it's okay I am not showing everything. The body of the request comes out completely wrong, as you can see below:
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:ns1="urn:ebay:api:PayPalAPI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ns2="urn:ebay:apis:eBLBaseComponents">
<SOAP-ENV:Header>
<ns1:RequesterCredentials>
<ns2:Credentials>
<ns2:Username>xxx</ns2:Username>
<ns2:Password>xxx</ns2:Password>
<ns2:Signature>xxx</ns2:Signature>
</ns2:Credentials>
</ns1:RequesterCredentials>
</SOAP-ENV:Header>
<SOAP-ENV:Body>
<ns1:GetBalanceReq xsi:type="ns1:GetBalance_Req">
<xsd:string>63.0</xsd:string>
</ns1:GetBalanceReq>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
It should look like this:
<?xml version=”1.0” encoding=”UTF-8”?>
<SOAP-ENV:Envelope xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”
xmlns:SOAP-ENC=”http://schemas.xmlsoap.org/soap/encoding/”
xmlns:SOAP-ENV=”http://schemas.xmlsoap.org/soap/envelope/”
xmlns:xsd=”http://www.w3.org/2001/XMLSchema”
SOAP-ENV:encodingStyle=”http://schemas.xmlsoap.org/soap/encoding/”
><SOAP-ENV:Header>
<RequesterCredentials xmlns=”urn:ebay:api:PayPalAPI”>
<Credentials xmlns=”urn:ebay:apis:eBLBaseComponents”>
<Username>api_username</Username>
<Password>api_password</Password>
<Signature/>
<Subject/>
</Credentials>
</RequesterCredentials>
</SOAP-ENV:Header>
<SOAP-ENV:Body>
<specific_api_name_Req xmlns=”urn:ebay:api:PayPalAPI”>
<specific_api_name_Request>
<Version xmlns=urn:ebay:apis:eBLBaseComponents”>service_version
</Version>
<required_or_optional_fields xsi:type=”some_type_here”> data
</required_or_optional_fields>
</specific_api_name_Request>
</specific_api_name_Req>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
Of course, Paypal throws a "Version is not supported" error.
This is the cleanest solution I could come up with:
$client = new SoapClient( 'https://www.sandbox.paypal.com/wsdl/PayPalSvc.wsdl',
array( 'soap_version' => SOAP_1_1 ));
$cred = array( 'Username' => $username,
'Password' => $password,
'Signature' => $signature );
$Credentials = new stdClass();
$Credentials->Credentials = new SoapVar( $cred, SOAP_ENC_OBJECT, 'Credentials' );
$headers = new SoapVar( $Credentials,
SOAP_ENC_OBJECT,
'CustomSecurityHeaderType',
'urn:ebay:apis:eBLBaseComponents' );
$client->__setSoapHeaders( new SoapHeader( 'urn:ebay:api:PayPalAPI',
'RequesterCredentials',
$headers ));
$args = array( 'Version' => '71.0',
'ReturnAllCurrencies' => '1' );
$GetBalanceRequest = new stdClass();
$GetBalanceRequest->GetBalanceRequest = new SoapVar( $args,
SOAP_ENC_OBJECT,
'GetBalanceRequestType',
'urn:ebay:api:PayPalAPI' );
$params = new SoapVar( $GetBalanceRequest, SOAP_ENC_OBJECT, 'GetBalanceRequest' );
$result = $client->GetBalance( $params );
echo 'Balance is: ', $result->Balance->_, $result->Balance->currencyID;
This produces the following XML request document, which, at the time of writing, was being successfully accepted and processed by PayPal:
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:ns1="urn:ebay:apis:eBLBaseComponents" xmlns:ns2="urn:ebay:api:PayPalAPI"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<SOAP-ENV:Header>
<ns2:RequesterCredentials>
<ns1:Credentials xsi:type="Credentials">
<Username>***</Username>
<Password>***</Password>
<Signature>***</Signature>
</ns1:Credentials>
</ns2:RequesterCredentials>
</SOAP-ENV:Header>
<SOAP-ENV:Body>
<ns2:GetBalanceReq xsi:type="GetBalanceRequest">
<GetBalanceRequest xsi:type="ns2:GetBalanceRequestType">
<ns1:Version>71.0</ns1:Version>
<ns2:ReturnAllCurrencies>1</ns2:ReturnAllCurrencies>
</GetBalanceRequest>
</ns2:GetBalanceReq>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
In response to some of the other comments on this page:
I'm fairly certain the OP has read the API doc, because that's where the example XML came from that he is trying to reproduce using PHP SOAP library.
The PayPal PHP API has some shortcomings, the biggest one being that it fails to work with E_STRICT warnings turned on. It also requires PEAR, so if you are not currently using PEAR in your project it means dragging in quite a lot of new code, which means more complexity and potentially more risk, in order to achieve what should be two or three fairly simple XML exchanges for a basic implementation.
The NVP API looks pretty good too, but I'm a glutten for punishment, so I chose the hard path. :-)
Did you check out the API's provided by PayPal here? And a direct link to the PHP SOAP API download.
And here is a link to the NVP API which PayPal recommends you use.
PHP has a very easy to use soapClass.
Which can be found here.
http://www.php.net/manual/en/class.soapclient.php

Categories