PHP SoapClient : What is NS2 - php

I'm New to webservices i'm trying to call webservice with soapClient() and it's generating Request XML which is not in expected format
Below is expected format of request XML
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Body>
<ns2:EndUserRequest xmlns:ns2="http://www.example.net/EndUserRequest">
<ns2:companyCode>MD</ns2:companyCode>
<ns2:customerBranch>60</ns2:customerBranch>
<ns2:customerNumber>112946</ns2:customerNumber>
<ns2:endUserName>Some Name</ns2:endUserName>
<ns2:ContactName />
<ns2:address />
<ns2:city />
<ns2:state />
<ns2:postalCode />
<ns2:email />
<ns2:phoneNumber />
<ns2:countryCode>US</ns2:countryCode>
</ns2:EndUserRequest>
</soapenv:Body>
</soapenv:Envelope>
Below is XML Request generating by my code
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://www.emaple.com/EndUserRequest">
<SOAP-ENV:Body>
<ns1:EndUserRequest xmlns:ns1="http://www.example.net/EndUserRequest">
<companyCode>MD</companyCode>
<customerBranchNumber>360</customerBranchNumber>
<customerNumber>53494711</customerNumber>
<endUserName>ABCED</endUserName>
<ContactName></ContactName>
<address></address>
<city></city>
<state></state>
<postalCode></postalCode>
<email></email>
<phoneNumber></phoneNumber>
<countryCode>US</countryCode>
</ns1:EndUserRequest>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
Below is my code
$client = new SoapClient('https://api-beta.example.com:443/enduser/v1/enduserlist?wsdl', array(
"trace" => 1,
"stream_context" => stream_context_create($streamContext),
'cache_wsdl' => WSDL_CACHE_NONE
));
$endUserRequest = new stdClass;
$endUserRequest->companyCode = 'MD';
$endUserRequest->customerBranchNumber = '560';
$endUserRequest->customerNumber = '59471321';
$endUserRequest->endUserName = 'Somename';
$endUserRequest->ContactName = '';
$endUserRequest->address = '';
$endUserRequest->city = '';
$endUserRequest->state = '';
$endUserRequest->postalCode = '';
$endUserRequest->email = '';
$endUserRequest->phoneNumber = '';
$endUserRequest->countryCode = 'US';
$requestSoapVar = new SoapVar($endUserRequest, SOAP_ENC_OBJECT,null,null,'EndUserRequest','http://www.example.com/EndUserRequest');
$res = $client->GetEndUsers($requestSoapVar);
echo '<textarea style="width:600px;height:500px">';
echo "\n-------Request Header------\n";
echo $client->__getLastRequestHeaders();
echo "\n-------Request------\n";
echo $client->__getLastRequest();
echo "\n-------Response Header------\n";
echo $client->__getLastResponseHeaders();
echo "\n-------Response------\n";
echo $client->__getLastResponse();
echo '</textarea>';
echo '<textarea style="width:600px;height:500px">';
print_r($res);
echo '</textarea>';

Every member of your object must be a SoapVar object because there is a namespace for them. Just encode your object as the follwing example shows.
$oEndUserRequest = new StdClass();
$oEndUserRequest->companyCode = new SoapVar(
'MD',
XSD_STRING,
null,
null,
'companyCode',
'http://www.example.com/EndUserRequest'
);
Just do it for everey class member and you 'll get the expected result.
For advanced reason here 's an example how to change the prefix of the namespace. You have to know, that the PHP SoapClient object nor the SoapVar object have a way to manually set a namespace prefix. In a normal case it is unnecessary to set a prefix for a namespace.
The PHP SoapClient object has a __doRequest method, in which you can edit the XML. You have to Code your own SoapClient extending the PHP SoapClient.
class MySoapClient extends SoapClient {
public function __doRequest($sRequest, $sLocation, $sAction, $iVersion, $iOneWay = 0) {
$sRequest = str_replace('ns1', 'ns2', $sRequest);
$this->__last_request = $sRequest;
return parent::__doRequest(ltrim($sRequest), $sLocation, $sAction, $iVersion, $iOneWay);
}
}
In my eyes it is not neccessary to change the namepace prefix. If so, just use the __doRequest method for your purpose.

Related

SOAP-ERROR: Encoding: object has no 'ACCION' property

I have a PHP script which calls a web service created in SAP, I already validated it with soapui5 and it works fine, but PHP throws the following message:
SOAP-ERROR: Encoding: object has no 'ACCION' property
PHP code :
$url = 'https://www.ceramicaitalia.com/wssap/zwebservice1.wsdl';
$client = new SoapClient($url);
echo PHP_EOL;
$xmlr = new SimpleXMLElement("<ZWS_WEBSERVICE1></ZWS_WEBSERVICE1>");
$xmlr->addChild('login', '***');
$xmlr->addChild('password', '******');
$xmlr->addChild('ACCION', '/');
$params = new stdClass();
$params->xml = $xmlr->asXML();
$client->ZWS_WEBSERVICE1($params);
$result = $client->ZWS_WEBSERVICE1('RTA');
print_r($result);
Test in soapui5 :
Request :
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope"
xmlns:urn="urn:sap-com:document:sap:rfc:functions">
<soap:Header/>
<soap:Body>
<urn:ZWS_WEBSERVICE1>
<ACCION>/</ACCION>
</urn:ZWS_WEBSERVICE1>
</soap:Body>
</soap:Envelope>
Response :
<env:Envelope xmlns:env="http://www.w3.org/2003/05/soap-envelope">
<env:Header/>
<env:Body>
<n0:ZWS_WEBSERVICE1Response xmlns:n0="urn:sap-com:document:sap:rfc:functions">
<RTA>1.5</RTA>
</n0:ZWS_WEBSERVICE1Response>
</env:Body>
</env:Envelope>
You don't need to set root element. You can to xml as array param. Library will auto set matched elements. If you have multiple element with same name but different namespace you can check SoapVar. Working sample is below.
<?php
$url = 'https://www.ceramicaitalia.com/wssap/zwebservice1.wsdl';
$client = new SoapClient($url, ['trace' => true]);
$params = ['ACCION' => '/'];
$client->ZWS_WEBSERVICE1($params);
$result = $client->ZWS_WEBSERVICE1('RTA');
print_r($result);
?>

Change format of the output XML , generated from PHP SoapClient?

I am trying to create this :
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Header>
<AccessKey xmlns="http://eatright/membership" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<Value>67a4ef47-9ddf-471f-b6d0-0000c28d57d1</Value>
</AccessKey>
</s:Header>
<s:Body>
<WebUserLogin xmlns="http://eatright/membership">
<loginOrEmail>1083790</loginOrEmail>
<password>thomas</password>
</WebUserLogin>
</s:Body>
</s:Envelope>
I created this PHP code
class ChannelAdvisorAuth
{
public $AccessKey ;
public function __construct($key)
{
$this->AccessKey = $key;
}
}
$AccessKey = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
$url = "http://ws.eatright.org/service/service.svc?wsdl";
$client = new SoapClient($url, array("trace" => 1, "exception" => 0));
$auth = new ChannelAdvisorAuth($AccessKey);
$header = new SoapHeader("AccessKey", "Value", $AccessKey, false);
$client->__setSoapHeaders($header);
$result = $client->ValidateAccessKey();
echo "REQUEST:\n" . $client->__getLastRequest() . "\n";
The output of the above PHP code is :
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://eatright/membership" xmlns:ns2="AccessKey">
<SOAP-ENV:Header>
<ns2:Value>xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx</ns2:Value>
</SOAP-ENV:Header>
<SOAP-ENV:Body>
<ns1:ValidateAccessKey/>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
How to change the PHP code to output the XML as requested by web service provider?
How to replace the "SOAP-ENV" to "S"?
Is there is a way to remove the NS1 and NS2? and also adjust the whole format of the XML to meet the requirements? thanks
You don't need to worry about SOAP-ENV, ns1 or ns2 - they are just prefixes referring to the namespaces. As long as the full namespaces are correct, it's going to be alright.
I think the SOAP header should be made like this:
$access_key = new stdClass();
$access_key->Value = 'XXX';
$hdr = new SoapHeader('http://eatright/membership', 'AccessKey', $access_key);
$client->__setSoapHeaders($hdr);
I don't see a purpose of xmlns:i in the first example - there are no elements having XSI attributes.
I'm not sure what to do with the body. In your first example, there is a call to the WebUserLogin operation, while in your PHP code you are trying to call ValidateAccessKey.
Have you tried reading the WSDL file which is pointed by $url
Ok I found the problem and I will add it here in case someone looking for same issue.
$access_key = new stdClass();
$access_key->Value = 'xxxxxxxxxxxxxxxxxxx';
// Create the SoapClient instance
$url = "http://ws.eatright.org/service/service.svc?wsdl";
$client = new SoapClient($url, array("trace" => 1, "exception" => 0));
$hdr = new SoapHeader('http://eatright/membership', 'AccessKey', $access_key);
$client->__setSoapHeaders($hdr);
$soapParameters = array('loginOrEmail ' => $username, 'password' => $password);
$login = new stdClass();
$login->loginOrEmail='LoginID';
$login->password='Password';
$result = $client->WebUserLogin($login);

PHP and a soap call with a complex parameter

I'm trying to pass a fairly complex parameter string which I have an XML example of and I'm trying to encode it properly using PHP. The example request I was given is this:
<?xml version="1.0" standalone="no"?>
<SOAP-ENV:Envelope xmlns:SOAPSDK1="http://www.w3.org/2001/XMLSchema" xmlns:SOAPSDK2="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAPSDK3="http://schemas.xmlsoap.org/soap/encoding/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Body xmlns:tns="http://172.16.53.121/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:ns="http://www.amtrak.com/TrainStatus/2006/01/01" xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/" xmlns:wsdns1="http://www.amtrak.com/schema/2006/01/01" xmlns:http="http://schemas.xmlsoap.org/wsdl/http/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<TrainStatusRQ xmlns="http://www.amtrak.com/schema/2006/01/01" xmlns:ota="http://www.opentravel.org/OTA/2003/05" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" Version="1.0" EchoToken="TestToken">
<POS>
<ota:Source>
<ota:RequestorID Type="WAS" ID="ToBeProvidedByAmtrak">
<ota:CompanyName CompanyShortName="ToBeProvidedByAmtrak"/>
</ota:RequestorID>
</ota:Source>
</POS>
<TrainStatusInfo TrainNumber="3">
<TravelDate>
<ota:DepartureDateTime>2006-01-07</ota:DepartureDateTime>
</TravelDate>
<Location LocationCode="KNG"/>
</TrainStatusInfo>
</TrainStatusRQ>
</SOAP-ENV:Body>
And I'm going to call it use it like this
try
{
$client = new SoapClient($soapURL, $soapOptions);
$trainStatus = $client->processTrainStatus($TrainStatusRQ);
var_dump($trainStatus);
//var_dump($client->__getTypes());
}
catch(SoapFault $e)
{
echo "<h2>Exception Error!</h2></b>";
echo $e->faultstring;
}
Its the encoding of $TrainStatusRQ that I cant seem to figure out since there are attributes and multilevel parameters. This is as close as I have gotten.
$RQStruc = array(
"POS" => array(
"Source"=> array(
"RequestorID" => array(
'type'=>'WAS',
'ID'=>'0',
'CompanyName'=>array(
'CompanyShortName'=>"0"
)
)
)
),
"TrainStatusInfo" => array(
'TrainNumber'=>$TrainNumber,
'TravelDate' => array(
'DepartureDateTime' => array(
'_' => $today
)
),
"Location" => array(
'LocationCode'=>$LocationCode
)
)
);
$TrainStatusRQ = new SoapVar($RQStruc, XSD_ANYTYPE, "TrainStatusRQ","http://www.amtrak.com/schema/2006/01/01" );
I had similar problems when dealing with a .NET service.
What I ended up with was assembling the structure as plain string.
$p = array();
foreach ($items as $item) {
$p[] = "
<MyEntity class='entity'> // the attribute was required by .NET
<MyId>{$item->SomeID}</MyId>
<ItemId>{$item->ItemId}</ItemId>
<Qty>{$item->Qty}</Qty>
</MyEntity>";
}
$exp = implode("\n", $p);
$params['MyEntity'] = new \SoapVar("<MyEntity xmlns='http://schemas.microsoft.com/dynamics/2008/01/documents/MyEntity'>$exp</MyEntity>", XSD_ANYXML);
Worked without problems.
Passing in the XML as a string with XSD_ANYXML as the type was the answer. I also needed to leave out the third and fourth parameters in the SoapVar() function call.
$XML = '<TrainStatusRQ xmlns="http://www.amtrak.com/schema/2006/01/01" xmlns:ota="http://www.opentravel.org/OTA/2003/05" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" Version="1.0" EchoToken="TestToken">
<POS>
<ota:Source>
<ota:RequestorID Type="WAS" ID="foo">
<ota:CompanyName CompanyShortName="bat"/>
</ota:RequestorID>
</ota:Source>
</POS>
<TrainStatusInfo TrainNumber="'.$TrainNumber.'">
<TravelDate>
<ota:DepartureDateTime>'.$Today.'</ota:DepartureDateTime>
</TravelDate>
</TrainStatusInfo>
</TrainStatusRQ>';
$TrainStatusRQ = new SoapVar($XML,XSD_ANYXML);

soap:Envelope SOAP-ENV:Envelope PHP

I'm trying to login to an API using built-in soap functions of PHP. I got a result like this.
[LoginResult]=> false,
[ErrorMsg] => Login failed with the reason : The security object is invalid
This is what required by the API provider.
<?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>
<Login xmlns="http://tempuri.org/Example/Service1">
<objSecurity>
<WebProviderLoginId>test</WebProviderLoginId>
<WebProviderPassword>test</WebProviderPassword>
<IsAgent>false</IsAgent>
</objSecurity>
<OutPut />
<ErrorMsg />
</Login>
</soap:Body>
</soap:Envelope>
&, here is what I was able to produce using functions.
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://tempuri.org/Example/Service1">
<SOAP-ENV:Body>
<ns1:Login>
<objSecurity>
<WebProviderLoginId>test</WebProviderLoginId>
<WebProviderPassword>test</WebProviderPassword>
<IsAgent>false</IsAgent>
</objSecurity>
<OutPut/>
<ErrorMsg/>
</ns1:Login>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
Here is the code I used to send the request.
<?php
class objSecurity {
function objSecurity($s, $i, $f) {
$this->WebProviderLoginId = $s;
$this->WebProviderPassword = $i;
$this->IsAgent = $f;
}
}
class nextObject {
function nextObject($objSecurity) {
$this->objSecurity=$pobjSecurity;
$this->OutPut=NULL;
$this->ErrorMsg=NULL;
}
}
$url = 'http://example.com/sampleapi/test.asmx?WSDL';
$client = new SoapClient($url, array("soap_version" => SOAP_1_1,"trace" => 1));
$struct = new objSecurity('test', 'test', false);
$data = new nextObject($struct);
$soapstruct2 = new SoapVar($data, SOAP_ENC_OBJECT);
print_r(
$client->__soapCall(
"Login",
array(new SoapParam($soapstruct2, "inputStruct"))
)
);
echo $client->__getLastRequest();
?>
These are the differences I found.
In my request xmlns:xsi is missing.
Requirement starts with <soap:Envelope, But my request starts with <SOAP-ENV:Envelope.
There is an extra xmlns:ns1 in my request.
& The function name tag starts with ns1:.
Please help me to make my request into the required format.
I don't know much about the SOAP and I'm using PHP version 5.3.13 with CakePHP 2.3.0. Sorry, for my bad English.
Here is the solution. :)
<?php
$url = 'http://example.com/sampleapi/test.asmx?WSDL';
$client = new SoapClient($url, array("soap_version" => SOAP_1_1,"trace" => 1));
$user_param = array (
'WebProviderLoginId' => "test",
'WebProviderPassword' => "test",
'IsAgent' => false
);
$service_param = array (
'objSecurity' => $user_param,
"OutPut" => NULL,
"ErrorMsg" => NULL
);
print_r(
$client->__soapCall(
"Login",
array($service_param)
)
);
echo $client->__getLastRequest();
?>
& the request was:
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://tempuri.org/Example/Service1">
<SOAP-ENV:Body>
<ns1:Login>
<ns1:objSecurity>
<ns1:WebProviderLoginId>test</ns1:WebProviderLoginId>
<ns1:WebProviderPassword>test</ns1:WebProviderPassword>
<ns1:IsAgent>false</ns1:IsAgent>
</ns1:objSecurity>
</ns1:Login>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
Thanks to this link.
PHP SOAP Request not right

Using complex structure with SOAP

The problem is that I cannot succeed to send an array of class through SOAP to a specific web service that I cannot change his structure.
Here below you'll see the schema of the Soap function:
http://www.elyotech.com/share/yoni/forum/developpeznet-soap.jpg
Here you'll find the code I'm corresponding to it:
$s = new soapclient($URL_WEBSERVICE,array('wsdl'=>true,"trace"=>true));
$params = new stdClass();
$params->loginInfo = new stdClass();
$params->loginInfo->UserName = 'username';
$params->loginInfo->Password = 'password';
$params->loginInfo->LanguageCode = 'en';
$params->reservation = new stdClass();
$params->reservation->EmailRecipient2 = 'yonia#yopmail.com';
$params->reservation->EmailRecipient3 = 'yonia2#yopmail.com';
$params->reservation->FirstName = 'Yoni'
foreach($extras as $id=>$extra)
{
$params->Extras[$id]= new stdClass();
$params->Extras[$id]->SelectedExtra = new stdClass();
$params->Extras[$id]->ExtensionData = new stdClass();
$params->Extras[$id]->SelectedExtra->Amount = 1;
$params->Extras[$id]->SelectedExtra->ID = $extra;
}
Here is the SOAP request that is sent:
<?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>
<ns1:CreateReservation>
<ns1:loginInfo>
<ns1:UserName>monusername</ns1:UserName>
<ns1:Password>monpass</ns1:Password>
<ns1:LanguageCode>en</ns1:LanguageCode>
</ns1:loginInfo>
<ns1:reservation>
<ns1:EmailRecipient2>yonia#yopmail.com</ns1:EmailRecipient2>
<ns1:EmailRecipient3>yonia2#yopmail.com</ns1:EmailRecipient3>
<ns1:FirstName>Yoni</ns1:FirstName>
</ns1:reservation>
</ns1:CreateReservation>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
In this Soap request, I cannot find the Extras array of objects.
Do you have any idea of how I should create my object in order to send it correctly?

Categories