PHP SoapClient "Body must be present in a SOAP envelope" error - php

I faced with very strange issue when tried to use PHP SoapClient for this service http://bws.neteven.com/NWS/2.
I have to setup an authentication header. Request body should be empty. The code, which I used is below:
$client = new SoapClient("http://bws.neteven.com/NWS/2", array("trace" => 1, "exception" => 1));
$auth = array(//the params are not valid of course
'Method' => 'TestConnection',
'Login' => 'login',
'Seed' => 'seed',
'Stamp' => 'stamp',
'Signature' => 'signature'
);
$client->__setSoapHeaders(new SoapHeader('auth', 'AuthenticationHeader', $auth));
$client->__soapCall('TestConnection',array(null));
After that I used $client->__getLastRequest() to see what is final XML of the request. However I can see that the header and body params were not setup properly.
$client->__getLastRequest() outputs plain text like this:
MethodTestConnectionLoginloginSeedseedStampstampSignaturesignature
Which doesn't look like valid XML. So of course I get SoapFault exception with the text "Body must be present in a SOAP envelope".
Does anybody knows why header and body are not wrapped by required XML tags?
Any issue in the code? Because I saw lots of examples of PHP SoapClient usage with the same approach. In addition I tried a few test WSDL services and had valid requests and responses there.
Could it be a problem of provided WSDL schema?
Or a problem of my server configuration? I use PHP 5.6.3, php_soap extension is enabled.
Hope you guys can help me. Any your thoughts would be really appreciated.
Thank you.

The code example I found has a different URL...
http://bws.neteven.com/NWS/2 vs http://ws.neteven.com/NWS
$client = new SoapClient("http://ws.neteven.com/NWS", array("trace" => 1, "exception" => 1));
$auth = array(//the params are not valid of course
'Method' => 'TestConnection',
'Login' => 'login',
'Seed' => 'seed',
'Stamp' => 'stamp',
'Signature' => 'signature'
);
$client->__setSoapHeaders(new SoapHeader('auth', 'AuthenticationHeader', $auth));
$client->__soapCall('TestConnection',array(null));
Also, you can call methods like this without using __soapCall (even though it would be doing the same thing).
$result = $client->echo(array("EchoInput" => "ReturnMe"));
var_dump($result->EchoOutput);
$result = $client->TestConnection();
var_dump($result->TestConnectionResult);

Related

Laravel, soap API required login

I am having a little trouble with the SOAP API I need to consume. It requires authorization, so I log in with the following.
Basically, I need to log in with the following, I don't get a "Login Required", which is fine.
$client = new \SoapClient('localwsdlfile.wsdl', array(
'local_cert' => 'localcert.pem',
'passphrase' => 'passphrase',
'location' => 'https://wsmurl/login/'
));
$response = $client->Get(array(
"AccessKey" => "accesskey",
"ProductID" => "SOMEPRODUCT",
"Scope" => "SOMESCOPE",
"Parameters" => array('Param' => array('_' => 'DATATOLOOKUP', 'id'=>'MOREDATATOLOOKUP'))
));
print_r($response);
So, basically, in the client, I need to uncomment the line
'location' => 'https://wsmurl/login/'
If I don't, I get this login error. The server I am trying to consume has a cache, so I no longer need to send this login for future operations for the next 10 minutes.
So, now, I have logged in, I can go the following, with success.
$client = new \SoapClient('localwsdlfile.wsdl', array(
'local_cert' => 'localcert.pem',
'passphrase' => 'passphrase',
// 'location' => 'https://wsmurl/login/' // Uncomment to login
));
$response = $client->Get(array(
"AccessKey" => "accesskey",
"ProductID" => "SOMEPRODUCT",
"Scope" => "SOMESCOPE",
"Parameters" => array('Param' => array('_' => 'DATATOLOOKUP', 'id'=>'MOREDATATOLOOKUP'))
));
print_r($response);
If I keep 'location' => 'https://wsmurl/login/' uncommented, I get errors about not sending a valid WSDL.
So in summary:-
I am consuming this soap API in Laravel, using PHP's SoapClinet per the above code.
My understanding is that the soap service I am trying to consume required login first.
After quite a lot of testing, I managed to get to the point there were no errors by including the line 'location' => 'https://wsmurl/login/' as shown above in the call to SoapClient.
This seems to be required the first time I call this soap service I guess it is logging me in. If I don't include it, I get the error
"SoapFault
Login Required"
So, if I include the line 'location' => 'https://wsmurl/login/', it appears to log me in, but I now get the error
"SoapFault
looks like we got no XML document"
If I keep the line, I continue to get this error
"SoapFault
looks like we got no XML document"
Removing the line then gives me the expected SOAP response and all is ok.
I have tried catching for errors using try{} ... catch{} looking for exceptions/errors etc, but it isn't catching the "Login Required" or "Looks like we got no XML document" as faults.
So, I guess, is there a better way to detect this condition so I can either send or not without the line or is there a better way to login to the service (note, it just uses the cert and passphrase).
Thanks in advance, I hope the little re-write above makes it clearer.
Because the location for the login and localwsdlfile.wsdl is different, I could not do it with one call. So we created a function using curl to login and if login is successful it will proceed to the soap client. Thanks to Brian from freelancer for his assistance here.
$client = new SoapClient('wsdl/VocusSchemas/localwsdlfile.wsdl', array(
'trace' => 1,
'exception' => true
));
try {
$response = $client->Get(array(
// "AccessKey" => "MADAITABNSAATOT1",
"AccessKey" => "accesskey",
"ProductID" => "SOMEPRODUCT",
"Scope" => "SOMESCOPE",
"Parameters" => array('Param' => array('_' => 'DATATOLOOKUP', 'id' => 'MOREDATATOLOOKUP'))
));

How to send parameters in soap request in php in __soapcall() function

i want to send a below xml request to the server which is sending ok by using soap UI but not in php:
<ns:AgentLogin>
<ns:AgentLoginRQ>
<ns:Authentication>
<ns:DBName>************</ns:DBName>
<ns:IP>************</ns:IP>
</ns:Authentication>
<ns:AgentABTA>************</ns:AgentABTA>
<ns:UserName>************</ns:UserName>
<ns:Password>************</ns:Password>
</ns:AgentLoginRQ>
</ns:AgentLogin>
i create soap client like this
$client = new \SoapClient("https://digicom-poc-ota.inspiretec.com/TravelinkCEService.svc?wsdl");
which is ok and then create soap call function like this
$data = array('AgentABTA'=>'DIGICOM_POC_DEMO'
,'UserName'=>'************'
,'Password'=>'************'
,'Products'=>'************'
);
$result = $client->__soapCall('AgentLogin',$data);
__soapcall give me error of empty request body.
Hope this might help you out:
$client = new \SoapClient("your_wsdl_link", [
'trace' => true
]);
$params = [
'AgentLoginRQ' => [
'DBName' => 'DATABASE_NAME',
'AgentABTA' => '****',
'UserName' => '****',
'Password' => '********',
'Products' => '',
]
];
$result = $client->YourFunction($params);
This is surely because of the array data structure which is incorrect according to the WSDL. You should definitively use a WSDL to php generator which is nowadays common. It helps structuring the request data and easily handle the response all with an OOP approach.
You should take a look to the PackageGenerator project which could really help you deal with this SOAP Web Service.

Ebay API returns "Service operation is unknown" and "Missing SOA operation name header" errors when using PHP

I'd like to make a soap call to the eBay api and finds products by keywords. With the help of eBay documentation and other online resources, I came up with this code:
$client = new \SoapClient('http://developer.ebay.com/webservices/finding/latest/FindingService.wsdl');
$soap_headers = array(
new \SoapHeader('X-EBAY-SOA-OPERATION-NAME', 'findItemsByKeywords'),
new \SoapHeader('X-EBAY-SOA-SERVICE-VERSION', '1.3.0'),
new \SoapHeader('X-EBAY-SOA-REQUEST-DATA-FORMAT', 'XML'),
new \SoapHeader('X-EBAY-SOA-GLOBAL-ID', 'EBAY-US'),
new \SoapHeader('X-EBAY-SOA-SECURITY-APPNAME', '<there would be the key>'),
);
$client->__setSoapHeaders($soap_headers);
// Call wsdl function
$result = $client->__soapCall("findItemsByKeywords", array("keywords" => "Potter"));
However, this code results in an error:
"Service operation is unknown,
500 Internal Server Error - SoapFault"
I tried changing the first line into this (don't know why it should make a difference, but I saw it somewhere):
$client = new \SoapClient(NULL, array(
"location" => 'http://svcs.sandbox.ebay.com/services/search/FindingService/v1',
'uri' => 'http://svcs.sandbox.ebay.com/services/search/FindingService/v1')
);
And now this result in this error: Missing SOA operation name header,
500 Internal Server Error - SoapFault
Does anybody know what causes these errors to occur and how to fix them?
Thank you, Mike!
The following code works.
define('APP_ID', '*** Your App ID ***');
$wsdl = 'http://developer.ebay.com/webservices/finding/latest/FindingService.wsdl';
// For sandbox
$endpoint_uri = 'http://svcs.sandbox.ebay.com/services/search/FindingService/v1';
// For production
//$endpoint_uri = 'http://svcs.ebay.com/services/search/FindingService/v1';
// We'll use this namespace explicitly for the 'keywords' tag,
// because the SoapClient doesn't apply it automatically.
$ns = 'http://www.ebay.com/marketplace/search/v1/services';
// The SOAP function
$operation = 'findItemsByKeywords';
$http_headers = implode(PHP_EOL, [
"X-EBAY-SOA-OPERATION-NAME: $operation",
"X-EBAY-SOA-SECURITY-APPNAME: " . APP_ID,
]);
$options = [
'trace' => true,
'cache' => WSDL_CACHE_NONE,
'exceptions' => true,
'location' => $endpoint_uri,
//'uri' => 'ns1',
'stream_context' => stream_context_create([
'http' => [
'method' => 'POST',
'header' => $http_headers,
]
]),
];
$client = new \SoapClient($wsdl, $options);
try {
$wrapper = new StdClass;
$wrapper->keywords = new SoapVar('harry potter', XSD_STRING,
null, null, null, $ns);
$result = $client->$operation(new SoapVar($wrapper, SOAP_ENC_OBJECT));
var_dump($result);
} catch (Exception $e) {
echo $e->getMessage();
}
As already mentioned, one of the issues is that you pass X-EBAY-SOA-* values as SOAP headers. The service expects them as HTTP headers:
HTTP Headers or URL Parameters—Each Finding API call requires certain
HTTP headers or URL parameters. For example, you must specify your
AppID in the X-EBAY-SOA-SECURITY-APPNAME header or SECURITY-APPNAME
URL parameter. Similarly, you must always specify the call name in the
X-EBAY-SOA-OPERATION-NAME header or OPERATION-NAME URL parameter.
Other headers are optional or conditionally required.
The second issue is that the SoapClient location option is not specified. It should contain an URI to one of the service endpoints. Otherwise, the API returns Service operation is unknown error.
Finally, the SoapClient doesn't put the keywords into Ebay's namespace:
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://www.ebay.com/marketplace/search/v1/services">
<SOAP-ENV:Body>
<ns1:findItemsByKeywordsRequest>
<keywords>harry potter</keywords>
</ns1:findItemsByKeywordsRequest>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
As a result, the API returns an error: Keywords value required.. So I've specified the namespace for the keywords tag explicitly.
Also note the use of different endpoint URIs for sandbox and for production.
The thing is, the service expects HTTP Headers (or query string parameters, apparently, by reading their guide a bit).
With __setSoapHeaders you are, well, setting SOAP Headers.
Try this, for instance
$wsdl = 'http://developer.ebay.com/webservices/finding/latest/FindingService.wsdl';
$appID = 'YOUR KEY/ID';
$headers = implode(PHP_EOL, [
"X-EBAY-SOA-OPERATION-NAME: findItemsByKeywords",
"X-EBAY-SOA-SECURITY-APPNAME: $appID"
]);
$options = [
'trace' => true,
'cache' => WSDL_CACHE_NONE,
'exceptions' => true,
'stream_context' => stream_context_create([
'http' => [
'header' => $headers
]
]),
];
$client = new SoapClient($wsdl, $options);
$response = $client->findItemsByKeywords([
'keywords' => 'Potter'
]);

Using SoapClient in php in mule

I am using the following php script in mule. When i am running this php file individually(through wamp) i am able to get the required output.
<?php
$client1=new SoapClient('example/v2_soap?wsdl', array('trace' => 1, 'connection_timeout' => 120));
$username = '******';
$password = '******';
//retreive session id from login
$session = $client1->login(
array(
'username' => $username,
'apiKey' => $password,
)
);
$result= $client1->catalogProductInfo(
array(
'sessionId' => $session->result,
'productId' => 1,
)
);
print_r($result);
return $result;
?>
But i want to run the following script through mule. So when i am running it through mule i am getting the following error.
Root Exception stack trace:
com.caucho.quercus.QuercusErrorException: eval::5: Fatal Error: 'SoapClient' is an unknown class name.
at com.caucho.quercus.env.Env.error(Env.java:4480)
at com.caucho.quercus.env.Env.error(Env.java:4399)
at com.caucho.quercus.env.Env.createErrorException(Env.java:4130)
+ 3 more (set debug level logging or '-Dmule.verbose.exceptions=true' for everything)
It says SoapClient is an unknown class. What is the problem here?
Do i have to include some SoapClient here? If so where can i find it. Please help!!
I'm not sure if mule supports php extensions, but that's what it seems by the error. You could try downloading nusoap into your project,
which doesn't require any php extension. The syntaxis is a little bit different though, but shouldn't be harder to adapt your code.
For what it's worth, this is a simple example of a soap request using nusoap (taken from here http://www.richardkmiller.com/files/msnsearch_nusoap.html):
require_once('nusoap/lib/nusoap.php');
$request = array('Request' => array(
'AppID' => 'MSN_SEARCH_API_KEY',
'Query' => 'Seinfeld',
'CultureInfo' => 'en-US',
'SafeSearch' => 'Strict',
'Flags' => '',
'Location' => '',
'Requests' => array(
'SourceRequest' => array(
'Source' => 'Web',
'Offset' => 0,
'Count' => 50,
'ResultFields' => 'All'))));
$soapClient = new soapclient("http://soap.search.msn.com/webservices.asmx?wsdl", false);
$result = $soapClient->call("Search", $request);
print_r($result);
I hope it helps.
I understand there seems to be a problem with running the soap client inside quercus (rather than Mule).
However instead of focusing on it I would suggest to take a look to the CXF client and the Web services consumer. You are running inside of Mule a powerful opensource ESB, there is no need to write a php script to consume a service, you have all that functinality already present.

PHP Soap call through https

i have a problem with running methods with SOAP. I'm using Apache and PHP.
this is the PHP code:
$opts = array(
'ssl' => array('ciphers'=>'RC4-SHA')
);
ini_set('soap.wsdl_cache_enabled',0);
ini_set('soap.wsdl_cache_ttl',0);
$client = new SoapClient('https://host?wsdl', array (
'stream_context' => stream_context_create($opts),
"trace" => 1,
"exceptions" => 0,
"connection_timeout"=>2000));
var_dump($client->__getFunctions());
$params = array ("key" => "value");
$result = $client->availabeFunction($params);
var_dump($result);
The __getFunctions() It returns me all of the available functions.
Then when i'm trying to call the the available function with parameters.
It returns me a strage error message:
public 'faultstring' => string 'Could not connect to host' (length=25)
public 'faultcode' => string 'HTTP' (length=4)
So i presume it is for some reasons are connecting to through the HTTP, but not through HTTPS.
I've looked up the web, and in some cases they are using a local_cert value with a .pem file.
It it neccecity to have it? Or i'm missing something else?
It's an openssl library bug.
At first try to disable SSL check by adding this params
"stream_context" => stream_context_create(
array(
'ssl' => array(
'verify_peer' => false,
'verify_peer_name' => false,
)
)
)
And next try to not use ?wsdl in location link, try use something like
.wsdl
The solution was much easier as i thoguht it will be:
ini_set('soap.wsdl_cache_enabled',0);
ini_set('soap.wsdl_cache_ttl',0);
$location = 'https://host';
$client = new SoapClient($location . '?wsdl', array (
"trace" => 1,
"exceptions" => 0,
"connection_timeout"=>2000,
"location"=>$location // <- this was the reqiured parameter
));
Everything else is same as before.
This beeing cause by WSDL file configuration, that instead of https URL, it has http.

Categories