How to use a SOAP API for Perl? - php

I'm trying to adapt the following PHP code in Perl. It's a bioDBnet SOAP API. I tried following the example on the SOAP::WSDL module (under SYNOPSIS) but it doesn't connect. I get an error message:
ATTEMPT 1
#!perl -w
use SOAP::WSDL;
my $client = SOAP::WSDL->new(
wsdl => "http://biodbnet.abcc.ncifcrf.gov/webServices/bioDBnet.wsdl",
);
Error message: cannot import document for namespace >http://schemas.xmlsoap.org/soap/encoding/< without location at /Library/Perl/5.16/SOAP/WSDL/Expat/WSDLParser.pm line 90.
ATTEMPT 2
Next I tried using the SOAP::LITE module. I followed the sample code from HERE (under 6.b. client).
#!perl -w
use SOAP::Lite;
my $client = SOAP::Lite ->
service('http://biodbnet.abcc.ncifcrf.gov/webServices/bioDBnet.wsdl');
my %db2dbParams;
$db2dbParams{'input'} = "Gene Symbol";
$db2dbParams{'outputs'} = "Gene ID, Ensembl Gene ID";
$db2dbParams{'inputValues'} = "MYC,A1BG";
$db2dbParams{'taxonId'} = "9606";
$db2dbRes = $client->db2db(%db2dbParams);
print $db2dbRes;
The code above doesn't print anything. How do I get the bioDBnet SOAP API to work for Perl?

Don't use a SOAP::Lite service method, mostly it doesn't work.
Build the soap structure manually. I tried to follow the php xml as much as possible, though most of prefixes is not necessary.
use strict;
use warnings;
use Data::Dumper;
use SOAP::Lite;
#use SOAP::Lite +trace=>'all';
$uri = 'urn:bioDBnet';
$proxy = 'http://biodbnet.abcc.ncifcrf.gov/webServices/biodbnetSoapServer.php';
$tns = 'urn:bioDBnet';
$soap = SOAP::Lite->new(uri => $uri,proxy => $proxy);
$soap->envprefix('SOAP-ENV');
$soap->encprefix('SOAP-ENC');
$soap->ns($tns,'tns1');
$soap->on_action(sub{$tns.'#db2db'});
#request = (SOAP::Data->name(db2dbParams => \SOAP::Data->value(
SOAP::Data->name(input => 'Gene Symbol'),
SOAP::Data->name(outputs => 'Gene ID, Ensembl Gene ID'),
SOAP::Data->name(inputValues => 'MYC,A1BG'),
SOAP::Data->name(taxonId => 9606),
))->type('ns1:db2dbParams'),
);
$db2db = $soap->db2db(#request);
if ($match = $db2db->match('/Envelope/Body/db2dbResponse')) {
print "match ok: $match\n";
$result = $db2db->result;
print Dumper($result);
} else {
print "match nok: $match\n";
}
This produces the required output from the server.

Your second scripts works, except the db2db part.
My guess is that the SOAP XML envelope send to the server is not in a good shape, when sending with SOAP::LITE.
I've enabled debugging on the second line:
#!/usr/bin/perl -w
use SOAP::Lite +trace =>'debug';
#use SOAP::Lite;
my $client = SOAP::Lite->service('http://biodbnet.abcc.ncifcrf.gov/webServices/bioDBnet.wsdl');
$inputs = $client->getInputs();
print $inputs;
$input = "Gene Symbol";
$outputs = $client->getOutputsForInput($input);
print $outputs;
$dirOutputs = $client->getDirectOutputsForInput($input);
print $dirOutputs;
.. From your Attempt 2:
# doesn't work, the created XML envelope is not in a good shape
my %db2dbParams;
$db2dbParams{'input'} = "Gene Symbol";
$db2dbParams{'outputs'} = "Gene ID, Ensembl Gene ID";
$db2dbParams{'inputValues'} = "MYC,A1BG";
$db2dbParams{'taxonId'} = "9606";
$db2dbRes = $client->db2db(%db2dbParams);
print $db2dbRes;
.. I also tried to rewrite this using SOAP:Data...but failed.
# doesn't work, the created XML envelope is not in a good shape
$db2dbRes = $client->db2db(
SOAP::Data->name("db2dbParams")->type("ns1:db2dbParams")->prefix("ns1:db2db")->uri("urn:bioDBnet") =>
SOAP::Data->type("string")->name("input" => "Gene Symbol"),
SOAP::Data->type("string")->name("inputValues" => "MYC,MTOR"),
SOAP::Data->type("string")->name("outputs" => "Gene ID, Affy ID"),
SOAP::Data->type("string")->name("taxonId" => "9606")
);
print $db2dbRes;
Switched over to PHP to see a working request.
I've enabled debugging on the PHP script to print the request headers
and fetch the working XML request done from PHP and reuse it as POST content from PERL. Basically, by adding the trace parameter on the SoapClient and then dumping the last reqeust headers.
<?php
$wsdl = "http://biodbnet.abcc.ncifcrf.gov/webServices/bioDBnet.wsdl";
$client = new SoapClient($wsdl, ['trace' => 1]);
$inputs = $client->getInputs();
print $inputs;
$input = "Gene Symbol";
$outputs = $client->getOutputsForInput($input);
print $outputs;
$dirOutputs = $client->getDirectOutputsForInput($input);
print $dirOutputs;
$db2dbParams['input'] = "Gene Symbol";
$db2dbParams['outputs'] = "Gene ID, Ensembl Gene ID";
$db2dbParams['inputValues'] = "MYC,A1BG";
$db2dbParams['taxonId'] = "9606";
$db2dbRes = $client->db2db($db2dbParams);
print $db2dbRes;
echo "====== REQUEST HEADERS =====" . PHP_EOL;
var_dump($client->__getLastRequestHeaders());
echo "========= REQUEST ==========" . PHP_EOL;
var_dump($client->__getLastRequest());
echo "========= RESPONSE =========" . PHP_EOL;
var_dump($db2dbRes);
This prints headers together with XML and the expected output is:
Gene Symbol Gene ID Ensembl Gene ID
MYC 4609 ENSG00000136997
A1BG 1 ENSG00000121410
I'm included the "working" XML request data into $message and do a POST request.
#!/usr/bin/perl -w
use strict;
use LWP::UserAgent;
use HTTP::Request;
my $message = '<?xml version="1.0" encoding="UTF-8" ?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:ns1="urn:bioDBnet" 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:db2db>
<db2dbParams xsi:type="ns1:db2dbParams">
<input xsi:type="xsd:string">Gene Symbol</input>
<taxonId xsi:type="xsd:string">9606</taxonId>
<inputValues xsi:type="xsd:string">MYC,A1BG</inputValues>
<outputs xsi:type="xsd:string">Gene ID, Ensembl Gene ID</outputs>
</db2dbParams>
</ns1:db2db>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>';
my $userAgent = LWP::UserAgent->new();
my $request = HTTP::Request->new(POST => 'http://biodbnet.abcc.ncifcrf.gov/webServices/biodbnetSoapServer.php'); # ?debug=1
$request->content($message);
$request->content_type("text/xml; charset=utf-8");
my $response = $userAgent->request($request);
if($response->code == 200) {
print $response->as_string;
}
else {
print $response->error_as_HTML;
}
Finally: next to header output we finally got some data:
<?xml version="1.0" encoding="UTF-8" ?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:ns1="http://biodbnet.abcc.ncifcrf.gov/webServices/bioDBnet"
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:db2dbResponse>
<return xsi:type="xsd:string">Gene Symbol Gene ID Ensembl Gene ID
MYC 4609 ENSG00000136997 A1BG 1 ENSG00000121410
</return>
</ns1:db2dbResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
Now, all you need to do is to extract the return element inside the ns1:db2dbResponse from $response->as_string (probably using LibXML).
In other words: this bypasses SOAP::Lite and uses LWP and a simply POST request with XML, the parsing the XML response. You lose the automatical extraction and have to handle return data manually.

Related

SoapClient Formatted with "Soap-env" but the request don't need this

I need send request for authenticate a SOAP via PHP SoapClient, but the request mount is result on "Not Found" after send.
On resume, using postman (plugin for chrome) i receive sucessful and the format XML mounted on a service is one and on another service is other. (each service mounted the XML different)
Via Postman i send this format (XML):
Work Correctly: I receive the correct response from server.
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<AutenticarUsuario xmlns="http://tempuri.org/PortalUAU_WS/Autenticador">
<Login>example</Login>
<Senha>123456</Senha>
</AutenticarUsuario>
</soap:Body>
</soap:Envelope>
Via SoapClient(PHP) he mount this format (XML):
Don't Work: I Receive "Not Found" no errors, no exceptions only "Not Found".
CODE PHP
public function authUauWeb(){
$soap = new \SoapClient($this->_wsEndpoint . 'Autenticador.asmx?WSDL', ['trace' => 1]);
$result = $soap->AutenticarUsuario(['Login' => $this->_wsData->user, 'Senha' => $this->_wsData->pass]);
//GET COOKIE SESSION
$headers = $soap->__getLastResponseHeaders();
$headers_init = strpos($headers, 'PortalUAU=');
if($headers_init !== false){
$headers = substr($headers, $headers_init);
$headers_end = strpos($headers, ';');
$headers = substr($headers, 0, $headers_end);
$headers = explode('=', $headers);
}
if(isset($result->AutenticarUsuarioResult) && $result->AutenticarUsuarioResult == 'True' && gettype($headers) == 'array'){
$this->_wsConnected = $headers;
}else{
$this->_wsConnected = false;
}
return $this->_wsConnected;
}
XML STRUCTURE FROM PHP
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://tempuri.org/PortalUAU_WS/Autenticador" xmlns:ns2="http://200.178.248.110:90/PortalUAU_WS_HLG/Autenticador.asmx" xmlns:ns3="text/xml; charset=utf-8">
<SOAP-ENV:Header>
<ns2:SOAPAction/>
<ns3:ContentType/>
</SOAP-ENV:Header>
<SOAP-ENV:Body>
<ns1:AutenticarUsuario>
<ns1:Login>example</ns1:Login>
<ns1:Senha>123456</ns1:Senha>
</ns1:AutenticarUsuario>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
As we say here on Brazil "My kick" is about this soap vs SOAP-ENV and ns1: present on tags from xml.
Thanks!

Extract a value from a SOAP Response in PHP

I need to a value from this SOAP response. The value is in the loginresponse / return element. Here's the response:
<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:body soap-env:encodingstyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:ns1="urn:DBCentralIntf-IDBCentral">
<ns1:loginresponse>
<return xsi:type="xsd:string"><**THIS IS THE VALUE I NEED**></return>
</ns1:loginresponse>
</soap-env:body>
Here's how I'm trying to parse:
$response = curl_exec($ch);
curl_close($ch);
$xml = simplexml_load_string($response, NULL, NULL, "http://schemas.xmlsoap.org/soap/envelope/");
$ns = $xml->getNamespaces(true);
$soap = $xml->children($ns['SOAP-ENV']);
$res = $soap->Body->children($ns['NS1']);
print_r($res->LoginResponse->Return);
But I get an empty object.
Thanks for your help!
Instead of using cURL and attempting to parse the XML response, consider using the PHP SOAP client. You may need to install PHP SOAP or enable it in your PHP configuration. (I'm using PHP on Windows, so I just had to uncomment extension=php_soap.dll in php.ini.)
If you have SOAP installed, you can get the WSDL from the provider of the web service you're using. Based on Googling this value in the XML you showed: xmlns:ns1="urn:DBCentralIntf-IDBCentral", I'm guessing you can find it here, but you'll probably have better luck finding it since you know for sure what web service you're using.
After you have the WSDL, using the PHP SOAP client is super easy:
$client = new SoapClient('path/to/your.wsdl');
$response = $client->Login(['username', 'password']);
$theValueYouNeed = $response->loginresponse->return;
UPDATE:
Removing the namespaces clears things up a bit (although a hack). Here my new code:
$response = curl_exec($ch);
curl_close($ch);
$cleanxml = str_ireplace(['SOAP-ENV:', 'SOAP:'], '', $response);
$cleanxml = str_ireplace('NS1:','', $cleanxml);
$xml = simplexml_load_string($cleanxml);
echo $xml->Body->LoginResponse->return[0];

SOAP php client : blank request

im trying to use the php soap client to make a soap call, but it keeps giving me " Request cannot be blank. Please provide request details. ". What am I doing wrong here?
$username = 'myusername_example';
$password = '123456787';
$url = "http://trail.dexceldesigns.com/m2m/APIwsdls/SessionService/SessionService.wsdl";
$soapclient = new \SoapClient($url);
try{
$params = array(
'Username' => $username,
'Password' => $password
);
$response = $soapclient->LogIn($params);
}
catch(\SoapFault $fault)
{
echo '<br/>'.$fault->getLine();
echo '<br/>Message: '.$fault->getMessage();
echo '<br/>Trace: '.$fault->getTraceAsString();
echo '<br/><br/>'.$fault->getCode();
echo '<br/><br/>'.$fault->getFile();
}
var_dump($soapclient->__getLastRequest());
EDIT:
Output for var_dump($soapclient->__getLastRequest()); is always coming as NULL
EDIT:2 (this is the request according to the documentation)
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://schemas.datacontract.org/2004/07/NPhase.UnifiedWebService.APIs.v2.Contract.SessionService" xmlns:ns2="http://nphase.com/unifiedwebservice/v2">
<SOAP-ENV:Body>
<ns2:LogIn>
<ns2:Input>
<ns1:Username>?</ns1:Username>
<ns1:Password>?</ns1:Password>
</ns2:Input>
</ns2:LogIn>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>

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

How do I make this exact soap call?

To start off with, I am a beginner at soap.
I am trying to make a soap call to a service and was given a working sample that comes from talend. What I need is to make a similar call in PHP.
The output from talend is as follows, (extracted from the HTTP request)
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<root>
<request>
<username>a#a.com</username>
<password>md5sumlookalike</password>
<webservice>GetCust</webservice>
<refid>12343321</refid>
<message>reserv#123</message>
</request>
</root>
</soap:Body>
</soap:Envelope>
So I wrote a little bit of PHP as it works as a scripting language as well for where it will be called from. Trying to understand how to make a soap call I came up with this bit.
<?php
// Yes I know about the diffrent port issue here. So I wgeted and stored it for use next to script
# $soapClient = new SoapClient("http://123.123.123.123:8088/services", array("trace" => true));
$soapClient = new SoapClient("wsdl", array("trace" => true));
$error = 0;
try {
$info = $soapClient->__soapCall("invoke",
array
(
new SoapParam("a#a.com", "username"),
new SoapParam("md5sumish", "password"),
new SoapParam("GetCust", "webservice"),
new SoapParam("1234321", "refid"),
new SoapParam("reserv#123", "message")
)
);
} catch (SoapFault $fault) {
$error = 1;
echo 'ERROR: '.$fault->faultcode.'-'.$fault->faultstring;
}
if ($error == 0) {
print_r($output_headers);
echo 'maybe it worked\n';
unset($soapClient);
}
?>
I end up seeing the following in the HTTP request via wireshark. The server just does not know what to do with this and does not respond. I am unsure what/where I need to go from here.
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://talend.org/esb/service/job">
<SOAP-ENV:Body>
<ns1:invokeInput>a#a.com</ns1:invokeInput>
<password>md5sumish</password>
<webservice>GetCust</webservice>
<refid>1234321</refid>
<message>reserv#123</message>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
So I have to ask is how to get rid of the ns1:invokeInput and make it username. Along with bring the rest of the format into line so the request looks like the output from talend?
Here is a working little script I did in php to call a talend tutorial service exported as soap:
//....
if (sizeof($_POST) > 0) {
$name = $_POST['name'];
$city = $_POST['city'];
$client = new SoapClient("http://192.168.32.205:8080/DirectoryService/services/DirectoryService?wsdl", array( 'trace' => 1));
$result = $client->runJob(array(
'--context_param',
'Name=' . $_POST['name'],
'--context_param',
'City=' . $_POST['city']
));
}
//...
Talend seems to be very "basic" regarding how parameters are given.
With this code it was working fine.

Categories