How is PHP 5.3 SOAP request formed? - php

I am trying to write some code to talk to the SmarterMail API, but I can't seem to make PHP format the request properly. The [ugly] code I have so far is:
<?php
function array_to_params($in_arr) {
$out_arr = array();
foreach( $in_arr as $key => $value ) {
$out_arr[] = new SoapParam($value, $key);
}
return $out_arr;
}
echo "<pre>";
$soapClient = new SoapClient(
"http://mailserver.net/Services/svcDomainAdmin.asmx?WSDL",
array('trace' => true)
);
var_dump($soapClient->__getTypes());die();
$soap_user_params = array(
'blank' => 'blank', //if I don't have a dummy entry the first parameter doesn't show up.
'AuthUserName' => 'admin',
'AuthPassword' => 'derp'
);
$soap_user_params = array_to_params($soap_user_params);
$error = FALSE;
try {
$info = $soapClient->__soapCall("GetAllDomains", $soap_user_params);
// $info = $soapClient->GetAllDomains($soap_user_params); //same results
} catch (SoapFault $fault) {
$error = TRUE;
printf("Error %s: %s\n", $fault->faultcode, $fault->faultstring);
}
if( !$error ) {
var_dump($info);
echo "\nRequest: " . htmlentities($soapClient->__getLastRequest());
}
echo "</pre>";
?>
For reference, the WSDL for this function is:
<s:element name="GetAllDomains">
<s:complexType>
<s:sequence>
<s:element minOccurs="0" maxOccurs="1" name="AuthUserName" type="s:string"/>
<s:element minOccurs="0" maxOccurs="1" name="AuthPassword" type="s:string"/>
</s:sequence>
</s:complexType>
</s:element>
The example request given is:
<?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:Body>
<GetAllDomains xmlns="http://tempuri.org/">
<AuthUserName>string</AuthUserName>
<AuthPassword>string</AuthPassword>
</GetAllDomains>
</soap:Body>
</soap:Envelope>
But the request generated by my code is:
<?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:GetAllDomains/>
<AuthUserName>admin</AuthUserName>
<AuthPassword>derp</AuthPassword>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
You can see that the username and password parameters are not contained within the GetAllDomains section for some reason. As well, in the code you can see that I have to pass a dummy parameter in first because whatever is first does not show up in the request. Also, I cannot simply pass in an associative array because the keys are not used as parameter names, it puts in 'param1' and 'param2' instead.
I should note that the server accepts the request and spits back a message about the auth failing. There is a built-in SOAP request tester on the server, and when the request fits the given example it works normally.
Everything I've looked up in the PHP docs and through Google seems to indicate that it should not be this difficult. :(
Any help is GREATLY appreciated.
note: I am running PHP 5.3.8 on Apache 2.2 on FreeBSD, built and installed via ports today.
post-answer-edit:
Thanks to Gian's answer below I've gotten this working and greatly simplified the code:
<?php
echo "<pre>";
$soapClient = new SoapClient( "http://mailserver.net/Services/svcDomainAdmin.asmx?WSDL", array( 'trace' => true ) );
$soap_user_params = array(
'AuthUserName' => 'admin',
'AuthPassword' => 'derp'
);
try {
$info = $soapClient->__soapCall("GetAllDomains", array( 'parameters' => $soap_user_params ) );
var_dump($info);
echo "\nRequest:\n" . htmlentities($soapClient->__getLastRequest());
} catch (SoapFault $fault) {
printf("Error %s: %s\n", $fault->faultcode, $fault->faultstring);
}
echo "</pre>";

My apologies for the mis-directed close. I misunderstood what you were trying to do at first.
Sifting through the soapCall documentation comments, there are a couple things I'd suggest trying. First off, this:
$soap_user_params = array(
'parameters' => array (
'AuthUserName' => 'admin',
'AuthPassword' => 'derp'
)
);
Apparently your parameters need to be an element in an associative array with the key 'parameters'. Weird, huh?
Failing that, you may need to nest this even deeper! The _ array entry does not appear to be documented anywhere obvious, but this seems to be something that the commenters on the PHP docs were suggesting. So maybe this:
$soap_user_params = array(
'parameters' => array (
'AuthUserName' => array('_' => 'admin'),
'AuthPassword' => array('_' => 'derp')
)
);

Related

Soap requests with Curl PHP

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

SOAP WSDL PHP client connecting to .Net Server

I need to integrate a web service, and its being like to days, and the closest I get is the following, maybe some of you have more experience than me in this kind of web service.
The XML request I need to generate is the following
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:v2="http://v2.services.cangooroo.net/" xmlns:can="Cangooroo.Webservice.V2">
<soapenv:Header/>
<soapenv:Body>
<v2:getCityData>
<v2:credentialClient>
<can:UserName>?</can:UserName>
<can:Password>?</can:Password>
</v2:credentialClient>
<v2:countryId>US</v2:countryId>
</v2:getCities>
</soapenv:Body>
</soapenv:Envelope>
My PHP code
$client = new SoapClient("http://v2.cangooroo.net/ws/2013/common_a.asmx?WSDL", array(
"trace" => 1,
"compression" => SOAP_COMPRESSION_ACCEPT | SOAP_COMPRESSION_GZIP,
));
$login = array();
$login[] = new SoapVar('*', XSD_STRING, null, null, 'UserName', 'Cangooroo.Webservice.V2' );
$login[] = new SoapVar('*', XSD_STRING, null, null, 'Password', 'Cangooroo.Webservice.V2' );
$rest = array();
$rest[] = new SoapVar($login, SOAP_ENC_OBJECT, null, null, 'credentialClient' );
$rest[] = new SoapVar('US', XSD_STRING, null, null, 'countryId');
$options = array('location' => 'http://v2.cangooroo.net/ws/2013/common_a.asmx');
try {
$resp = $client->__soapCall('getCityData', $rest, $options);
print_r($resp);
echo "Request:<pre>" . htmlentities($client->__getLastRequest()) . "</pre>";
}catch (SoapFault $e){
echo "REQUEST:<pre>" . htmlentities($client->__getLastRequest()) . "</pre>";
/*print_r($e);*/
The actual xml the PHP code above generates
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:ns1="Cangooroo.Webservice.V2" xmlns:ns2="http://ws_2013.services.cangooroo.net/">
<SOAP-ENV:Body>
<ns2:getCityData>
<ns1:UserName>*</ns1:UserName>
<ns1:Password>*</ns1:Password>
</ns2:getCityData><countryId>US</countryId></SOAP-ENV:Body></SOAP-ENV:Envelope>
Iam not really sure if this is the best way to do it, but I tryed others, with __soapCall,
__doRequest, this last one I got the soapClient php core class extended (as a try) to connect, and nothing seems to work. Pls, I could use a little help here. Tks guys.
If you check the wsdl file in http://v2.cangooroo.net/ws/2013/common_a.asmx?WSDL you can see the definition of the getCityData
<s:element name="getCityData">
<s:complexType>
<s:sequence>
<s:element minOccurs="0" maxOccurs="1" name="credential" type="s1:ClientCredential"/>
<s:element minOccurs="0" maxOccurs="1" name="countryId" type="s:string"/>
</s:sequence>
</s:complexType>
</s:element>
the operation getCityData has a credential parameter, not a credentialClient that is what you have in the code that you posted. I've tried with this code:
$wsdlAddress = "http://v2.cangooroo.net/ws/2013/common_a.asmx?WSDL";
$options = array(
"soap_version" => SOAP_1_2,
"cache_wsdl" => WSDL_CACHE_NONE,
"exceptions" => false
);
$webServiceClient = new SoapClient($wsdlAddress, $options);
$requestData = array(
"countryId" => "US",
"credential" => array(
"UserName" => "username",
"Password" => "Password",
),
);
$response = $webServiceClient->__soapCall("getCityData", array("getCityData" => $requestData));
echo "<h2>getCityData Operation Test:</h2>";
echo "<pre>";
print_r($response);
echo "</pre>";
in the response i can see Err: Login_Fail - Invalid user or password., i think i'm getting a valid response. Try with my code and adapt it to your needs.
Happy coding

PHP NuSOAP parameters not included in request

I am trying to send a SOAP request with a header and lots of parameters. This is not the first time I have used NuSOAP and have never had problems with it before. However what is new to me is I am including a header which may be what is causing the problem. Below is the code for my request:
$client = new nusoap_client($url,'wsdl','','','','');
$header =
"<ETGHeader>
<VersionRequest>1.0.0</VersionRequest>
<Originator>
<Signature>Signature</Signature>
<LoginData>
<Name>Name</Name>
<Password>Password</Password>
</LoginData>
</Originator>
</ETGHeader>";
$client->setHeaders($header);
$param = array(
"Settings" => array(
"param1" => "1",
"param2" => "2",
"param3" => "3"
)
);
// Call the WebService
$result = $client->call('GetListVehicleType', array('parameters' => $param), '', '', false, true);
echo '<pre>' . htmlspecialchars($client->request, ENT_QUOTES) . '</pre>';
Here is the request that is being sent:
<?xml version="1.0" encoding="ISO-8859-1"?><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:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"><SOAP-ENV:Header><ETGHeader>
<VersionRequest>1.0.0</VersionRequest>
<Originator>
<Signature>Signature</Signature>
<LoginData>
<Name>Name</Name>
<Password>Password</Password>
</LoginData>
</Originator>
</ETGHeader></SOAP-ENV:Header><SOAP-ENV:Body><GetListVehicleType xmlns="http://url"/></SOAP-ENV:Body></SOAP-ENV:Envelope>
None of my parameters are being included in the request.
Any help much appreciated
Alex
Might be a problem with NuSOAP, recoded it using PHP's inbuilt SoapClient and got it working.

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);

passing multiple WSDL header variables to SOAP server

I am using SOAP web services for the first time and i am having a problem in calling the SOAP server. I searched through WSDL SOAP request not i am not able to solve my problem. This is the snippet of my WSDL
<s:complexType name="VerHeader">
<s:sequence>
<s:element minOccurs="0" maxOccurs="1" name="HD1" type="s:string"/>
<s:element minOccurs="0" maxOccurs="1" name="HD2" type="s:string"/>
<s:element minOccurs="0" maxOccurs="1" name="HD3" type="s:string"/>
</s:sequence>
<s:anyAttribute/>
</s:complexType>
I have to send username, password and some ID in these HD1, HD2 and HD3 variables. I have also tried these links Passing a PHP array in a SOAP call and Sending a Soap Header with a WSDL Soap Request with PHP
Here is what i have tried but not working, every time i run my code it send failure message, can you figure it out what's wrong with my code or my logic?
$soap = new SoapClient("http://example.com/verifyrecord.asmx?WSDL");
$header = array('HD1'=>'000000023','HD2'=>'val2','HD3'=>'val2');
$header = new SoapHeader('http://www.example.com/', 'VerHeader ', $header);
$soap->__setSoapHeaders(array($header));
Solved the problem. I solved it not by using php functions but creating an xml file manually and sending it to the soap server. I've posted an example of my answer so that it might be helpful to others. Thanks all for the help.
// the xml to send
$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>
<VerHeader xmlns="http://www.example.com/">
<HD1>000000000117</HD1>
<HD1>user</HD1>
<HD1>password</HD1>
</VerHeader>
</soap:Header>
<soap:Body>
<m:VerifyTransaction xmlns:m="http://www.example.com/">
<m:object1>45344</m:object1>
<m:object2>5545437</m:object2>
</m:VerifyTransaction>
</soap:Body>
</soap:Envelope>';
// build your http request
$context = stream_context_create(array(
'http' => array(
'method' => 'POST',
'header' => "Content-type: text/xml\r\n",
'validateRequest'=>false,
'content' => $xml,
'timeout' => 10,
),
));
// send it
echo $xmlstring = file_get_contents('http://example.com/VerifyThis/VerifyThis.asmx?wsdl', false, $context);
shouldn't this
new SoapHeader('http://www.example.com/', 'VerHeader ', $header);
be
new SoapHeader('http://www.example.com/verifyrecord', 'VerHeader ', $header);
try like this i did used this for my uk mail api .. and it worked
<?php
$LoginWebRequest = new stdClass();
$LoginWebRequest->Username = 'xxx cant show here xxx';
$LoginWebRequest->Password = 'xxx cant show here xxx';
//echo "<pre>"; print_r($LoginWebRequest); "</pre>"; exit;
$Login = new stdClass();
$Login->loginWebRequest = $LoginWebRequest;
//echo "<pre>"; print_r($Login); "</pre>"; exit;
$soapClient = new SoapClient('https://qa-api.ukmail.com/Services/UKMAuthenticationServices/UKMAuthenticationService.svc?wsdl');
$LoginResponse = $soapClient->Login($Login);
?>

Categories