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);
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]);
How can I make Soap request using Curl php by using below soap format and url? I have tried avaliable solutions online and none of them worked out.
$soap_request = '<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="urn:alisonwsdl" 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:Header>
<credentials>
<alisonOrgId>9ReXlYlpOThe24AWisE</alisonOrgId>
<alisonOrgKey>C2owrOtRegikaroXaji</alisonOrgKey>
</credentials>
</soap:Header>
<SOAP-ENV:Body>
<q1:login xmlns:q1="urn:alisonwsdl">
<email xsi:type="xsd:string">email</email>
<firstname xsi:type="xsd:string">fname</firstname>
<lastname xsi:type="xsd:string">lname</lastname>
<city xsi:type="xsd:string">city</city>
<country xsi:type="xsd:string">country</country>
<external_id xsi:type="xsd:string"></external_id>
</q1:login>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>';
Url
https://alison.com/api/service.php?wsdl
Assuming you already have php_soap extension installed, you can access the SOAP API like this:
<?php
$client = new SoapClient('https://alison.com/api/service.php?wsdl', array(
'stream_context' => stream_context_create(array(
'ssl' => array(
'verify_peer' => false,
'verify_peer_name' => false,
'allow_self_signed' => true
)
))
));
You might want to define the header for authentication as well
$auth = array(
'alisonOrgId' => '9ReXlYlpOThe24AWisE',
'alisonOrgKey' => 'C2owrOtRegikaroXaji'
);
$header = new SoapHeader('https://alison.com/api/service.php?wsdl', 'credentials', $auth, false);
$client->__setSoapHeaders($header);
Then you can get the list of functions available
// Get function list
$functions = $client->__getFunctions ();
echo "<pre>";
var_dump ($functions);
echo "</pre>";
die;
Or call a function right away, like this:
// Run the function
$obj = $client->__soapCall("emailExists", array(
"email" => "test#email.com"
));
echo "<pre>";
var_dump ($obj);
echo "</pre>";
die;
After struggling for a week I was able to find something in this tutorial here on youtube https://www.youtube.com/watch?v=6V_myufS89A and I was able to send requests to the API successifuly, first read my xml format above before continuing with my solution
$options = array('trace'=> true, "exception" => 0);
$client = new \SoapClient('your url to wsdl',$options);
//if you have Authorization parameters in your xml like mine above use SoapVar and SoapHeader as me below
$params = new \stdClass();
$params->alisonOrgId = 'value here';
$params->alisonOrgKey = 'value here';
$authentication_parameters = new \SoapVar($params,SOAP_ENC_OBJECT);
$header = new \SoapHeader('your url to wsdl','credentials',$authentication_parameters);
$client->__setSoapHeaders(array($header));
print_r($client->__soapCall("Function here",'Function parameter here or left it as null if has no parameter'));
//or call your function by
print_r($client->yourFunction($function_parameters));
}
Hope this will help someone out there struggling with soap requests that contains authentication informations
I have a working XML request body, which I'm trying to send via PHP to a SOAP server:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tns="urn:servicewsdl" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/">
<SOAP-ENV:Body>
<mns:getQuote xmlns:mns="urn:getquoteswsdl" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<authorisation xsi:type="tns:Authorisation">
<username xsi:type="xsd:string">****</username>
<password xsi:type="xsd:string">****</password>
</authorisation>
<symbol xsi:type="xsd:string">****</symbol>
</mns:getQuote>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
I tried passing the params in an array like so:
$result = $client->getQuote(array('username' => '****', 'password' => '****'), array('symbol' => '****'));
but it returns me an error:
SOAP-ERROR: Encoding: object has no 'username' property
you probably need to put the username/password array inside authorisation like:
$result = $client->getQuote(array('authorisation'=>array('username' => '****', 'password' => '****')), array('symbol' => '****'));
or, maybe you should send it an object instead:
$params = new stdClass();
$params->authorisation = new stdClass();
$params->authorisation->username = '****';
$params->authorisation->password = '****';
$params->symbol = '****';
$result = $client->getQuote($params);
EDIT: From the comments, in the end, getQuote was accessed via PHP in this method:
$auth = new stdClass();
$auth->username = '****';
$auth->password = '****';
$symbol = '****';
$result = $client->getQuote($auth, $symbol);
I had a heck of a time working with PHP and SOAP as well. I seem to recall a similar situation where I used the standard PHP class (new stdClass()) to help build the object with params. Here's the questions/answer page.
How can I add Attributes to a PHP SoapVar Object?
I hope it helps.
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
I get the error message : "looks like we got no XML document" .
This is my php script :
<?php
$client = new SoapClient("http://ws-argos.cls.fr/argosDws/services/DixService?wsdl", array('trace' => 1, "exceptions" => 0));
$result = $client->getXml(array (
'username' => 'my username',
'password' => 'my password',
'platformId' => '1',
'nbPassByPtt' => 100,
'nbDaysFromNow' => 10,
'mostRecentPassages' => true
));
echo "====== REQUEST HEADERS =====" . PHP_EOL;
var_dump($client->__getLastRequestHeaders());
echo "========= REQUEST ==========" . PHP_EOL;
var_dump($client->__getLastRequest());
echo "========= RESPONSE =========" . PHP_EOL;
var_dump($result);
and this is the result of __getLastRequest() :
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:ns1="http://service.dataxmldistribution.argos.cls.fr/types">
<SOAP-ENV:Body>
<ns1:xmlRequest>
<ns1:username>my username</ns1:username>
<ns1:password>my password</ns1:password>
<ns1:platformId>1</ns1:platformId>
<ns1:nbPassByPtt>100</ns1:nbPassByPtt>
<ns1:nbDaysFromNow>10</ns1:nbDaysFromNow>
<ns1:mostRecentPassages>true</ns1:mostRecentPassages>
</ns1:xmlRequest>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
and this is how the request should look according to the documentation :
<soap:Envelope
xmlns:soap=”http://www.w3.org/2003/05/soap-envelope”
xmlns:typ=”http://service.dataxmldistribution.argos.cls.fr/types”>
<soap:Header/>
<soap:Body>
<typ:xmlRequest>
<typ:username>mturiot</typ:username>
<typ:password>qt</typ:password>
<typ:platformId>1</typ:platformId>
<typ:nbPassByPtt>2</typ:nbPassByPtt>
<typ:nbDaysFromNow>10</typ:nbDaysFromNow>
<typ:mostRecentPassages>true</typ:mostRecentPassages>
</typ:xmlRequest>
</soap:Body>
</soap:Envelope>
What am i doing wrong ? Any help is appreciated !
I came across the same problem, I turned to get solution in a different way.
It might not be the best way, but it works.
Source for the solution found here
$param = array(
'username'=>$username,
'password'=>$password,
'platformId'=>$platformId,
'nbDaysFromNow'=>20
);
$client = new SoapClient("http://ws-argos.cls.fr/argosDws/services/DixService?wsdl",
array('trace' => 1,
"exceptions" => 0,
'style'=> SOAP_DOCUMENT,
'use'=> SOAP_LITERAL));
$results = $client->getXml($param);
$results = $client->__getLastResponse();
//Handle BOM
$xml = explode("\r\n", $results);
//The resultant CDATA is at 6th tag
$response = preg_replace( '/^(\x00\x00\xFE\xFF|\xFF\xFE\x00\x00|\xFE\xFF|\xFF\xFE|\xEF\xBB\xBF)/', "", $xml[6] );
//Get the CDATA content alone
$explode1 = explode("<return>", $response);
$xmlVar = explode("</return>", $explode1[1]);
$finalXML = $xmlVar[0];
//Convert string as XML
$xmlElem = simplexml_load_string('<xml>' . $finalXML . '</xml>');
echo $xmlElem;