Calling Web Services with PHP SoapClient - How to? - php

I am going crazy starting off with Web Services. I am trying to call the following WSDL using PHP and keep getting nowhere:
http://webservices.sabre.com/wsdl/sabreXML1.0.00/usg/SessionCreateRQ.wsdl
I found the following piece of code on the net, from someone with similar problems, but I could not get it to work either:
$soap = new SoapClient('http://webservices.sabre.com/wsdl/sabreXML1.0.00/usg/SessionCreateRQ.wsdl',
array(
'trace' => true,
'soap_version' => SOAP_1_2,
"exceptions" => 0));
$eb = new EbXmlMessage();
$sec = new Security();
$scrq = new SessionCreateRQ();
try {
$omg = $soap->SessionCreateRQ($scrq, $sec,$eb);
}
catch (Exception $e)
{
print_r($e);
}
//debug
print "Request: \n".
htmlspecialchars($soap->__getLastRequestHeaders()) ."\n";
print "Request: \n".
htmlspecialchars($soap->__getLastRequest()) ."\n";
print "Response: \n".
$soap->__getLastResponseHeaders()."\n";
print "Response: \n".
$soap->__getLastResponse()."\n";
print_r($omg);
//the first envelope headers
class EbXmlMessage
{
public $From = array('PartyId' => 'mysite.com');
public $To = array('PartyId' => 'myprovider.com');
public $CPAId = 'ZZZZ';
public $ConversationId = 'myconv#id.com';
public $Service = 'Session';// or SessionCreate?
public $Action = 'SessionCreateRQ';
public $MessageData = array(
'MessageId' => 'messageid',
'Timestamp' => '2009-04-18T15:15:00Z');
}
//the security token
class Security {
public $Username = "xxxxx";
public $Password = "yyyyy";
public $Organization = "ZZZZ";
public $Domain = "DEFAULT";
}
//this is suppoused to be the payload, or the xml i need to send at the end
class SessionCreateRQ
{
public $POS = array(
'Source' => array(
'_'=>"",
'PseudoCityCode'=>'ZZZZ'
));
}
I keep getting the following error:
Response:
HTTP/1.1 500 Internal Server Error
SOAPAction: ""
Content-Type: text/xml;charset=utf-8
Date: Sun, 19 Apr 2009 22:21:34 GMT
Connection: close
Server: SWS
Response:
soap-env:Client.InvalidEbXmlMessageUnable to internalize
messagejavax.xml.soap.SOAPException: Unable to internalize message at
com.sun.xml.messaging.saaj.soap.MessageImpl.(MessageImpl.java:135)
at
com.sun.xml.messaging.saaj.soap.MessageFactoryImpl.createMessage(MessageFactoryImpl.java:32)
at
com.sabre.universalservices.gateway.control.SoapProcessor.getRequest(SoapProcessor.java:263)
at
com.sabre.universalservices.gateway.control.WSGateway.handleRequest(WSGateway.java:380)
at
com.sabre.universalservices.gateway.control.WSGateway.doPost(WSGateway.java:306)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:710) at
javax.servlet.http.HttpServlet.service(HttpServlet.java:803) at
org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
at
org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at
org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
at
org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:175)
at
org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:128)
at
org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
at
org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:563)
at
org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
at
org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:263)
at
org.apache.coyote.http11.Http11AprProcessor.process(Http11AprProcessor.java:852)
at
org.apache.coyote.http11.Http11AprProtocol$Http11ConnectionHandler.process(Http11AprProtocol.java:584)
at
org.apache.tomcat.util.net.AprEndpoint$Worker.run(AprEndpoint.java:1508)
at java.lang.Thread.run(Thread.java:595) Caused by:
javax.xml.soap.SOAPException: Invalid
Content-Type:application/soap+xml at
com.sun.xml.messaging.saaj.soap.MessageImpl.verify(MessageImpl.java:159)
at
com.sun.xml.messaging.saaj.soap.MessageImpl.(MessageImpl.java:91)
... 19 more
SoapFault Object (
[message:protected] => Unable to internalize message
[string:private] => .....
This service should be validating me on the system and returning a security object to be used in later calls - a string(?) which I can then store in a session variable for the following calls.
Any help GREATLY appreciated!!!

One thing I noticed is that there is a faultcode value in the SoapFault Object:
[faultcode] => soap-env:Client.InvalidEbXmlMessage
So that may be a useful avenue to start debugging.
I tried comparing the structure of your EbXmlMessage to the XSD and the schema documentation, but I couldn't see any obvious reason that it was declared invalid.

Have you tried changing the Content-type header to text/xml?

Try using wsdl2php. It makes php classes out of the wsdl file. It uses php's SoapClient to send the data.
Here is a nice post explaining how to do it:
http://itworkarounds.blogspot.com/2011/10/simple-soap-client-with-wsdl2php-using.html

Just use nuSOAP. I don't like PHP native SoapClient. nuSoap generates for you a wsdl so you don't have to worry about how to make one.. Here's nuSOAP and here's a simple example code or you can download whole working code here :
Server :
<?php
// include the SOAP classes
require_once('nuSOAP/lib/nusoap.php');
function HelloWorld(){
return 'HelloWorld'; // Returns HelloWorld string
}
function Hello($name){
return 'Hello '.$name; // Returns Hello with name string parameter
}
// create the server object
$server = new nusoap_server();
// Initialize WSDL support
$server->configureWSDL('webservicenamespace', 'urn:webservicenamespace');
$server->register('HelloWorld', array(), array('result' => 'xsd:string')); //xsd:string; xsd:boolean; xsd:integer and so on..
$server->register('Hello', array('name' => 'xsd:string'), array('result' => 'xsd:string')); // array('parametername' => 'parametertype'),array('result' => 'returntype');
if (isset($error))
{
$fault =
$server->fault('soap:Server','',$error);
}
// send the result as a SOAP response over HTTP $HTTP_RAW_POST_DATA
$post = file_get_contents('php://input');
$server->service($post);
?>
Client :
<?php
// Pull in the NuSOAP code
require_once('nuSOAP/lib/nusoap.php');
// Create the client instance
$client = new nusoap_client('http://pathtourl/sample_webservice.php?wsdl', true);
// Check for an error
$err = $client->getError();
if ($err) {
// Display the error
echo '<h2>Constructor error</h2><pre>' . $err . '</pre>';
// At this point, you know the call that follows will fail
}
// Call the SOAP method
$result = $client->call('Hello', array('name' => 'Scott')); // Call function name, parameters;
// Check for a fault
if ($client->fault) {
echo '<h2>Fault</h2><pre>';
print_r($result);
echo '</pre>';
} else {
// Check for errors
$err = $client->getError();
if ($err) {
// Display the error
echo '<h2>Error</h2><pre>' . $err . '</pre>';
} else {
// Display the result
echo '<h2>Result</h2><pre>';
print_r($result);
echo '</pre>';
}
}
// Display the request and response
echo '<h2>Request</h2>';
echo '<pre>' . htmlspecialchars($client->request, ENT_QUOTES) . '</pre>';
echo '<h2>Response</h2>';
echo '<pre>' . htmlspecialchars($client->response, ENT_QUOTES) . '</pre>';
// Display the debug messages
echo '<h2>Debug</h2>';
echo '<pre>' . htmlspecialchars($client->debug_str, ENT_QUOTES) . '</pre>';
?>
Now when you want to make a client you need your wsdl you can simply get it by adding ?wsdl on your link i.e( webservice.php?wsdl )
Hope this helps :) Good luck with your web service.

Related

Why is a parameter empty/broken in SoapClient::__getLastRequest() when attempting to use a Soap web service?

We are attempting to call a function OrderInteractive() defined by a wsdl at https://demo2.mvrs.com/AdrConnect/AdrConnectWebService.svc?singlewsdl. It takes two parameters, a communications block with login info, and an order block with data in it. I know the login info is correct, and we are getting a response from the service, but it gives us the default "unknown error has occurred" message. When checking the result of __getLastRequest(), we get this:
<ns1:OrderInteractive>
<ns1:inCommunications>
<Communications>
<Host>Online</Host>
<Account>xxxxx</Account>
<UserID>01</UserID>
<Password>xxxxxxxxx</Password>
<ReportTypes>
<Type>XML2.02</Type>
</ReportTypes>
</Communications>
</ns1:inCommunications>
<ns1:inOrder/>
</ns1:OrderInteractive>
If you look, the order parameter is just empty. My question is why is SOAP stripping the order block, or why is the order block empty? I also tried 2 other methods of calling the function but both result in this logged in my error log:
"The formatter threw an exception while trying to deserialize the message: Error in deserializing body of request message for operation 'OrderInteractive'. End element 'Body' from namespace 'http://schemas.xmlsoap.org/soap/envelope/' expected. Found element 'InOrder' from namespace ''. Line 2, position 185."
My code is below:
$commsBlock = "<Communications>
<Host>Online</Host>
<Account>xxxxx</Account>
<UserID>01</UserID>
<Password>xxxxxxxxx</Password>
<ReportTypes>
<Type>XML2.02</Type>
</ReportTypes>
</Communications>";
$orderBlock = "<Order>
<Handling>OL</Handling>
<Account>xxxxx</Account>
<ProductID>DL</ProductID>
<State>
<Abbrev>" . $order['state'] . "</Abbrev>
<Full></Full>
</State>
<Subtype>3Y</Subtype>
<Purpose>AA</Purpose>
<License>" . $order['dln'] . "</License>
<FirstName>" . $order['firstname'] . "</FirstName>
<MiddleName>" . $order['middlename'] . "</MiddleName>
<LastName>" . $order['lastname'] . "</LastName>
<DOB>
<Year>" . date('Y', $order['dob']) . "</Year>
<Month>" . date('m', $order['dob']) . "</Month>
<Day>" . date( 'd', $order['dob']) . "</Day>
</DOB>
<Misc>TEST ORDER INTERACTIVE</Misc>
</Order>";
$soap_url = 'https://demo2.mvrs.com/AdrConnect/AdrConnectWebService.svc?singlewsdl'; // test system url
$soap_params = array(
'trace' => true,
'exceptions' => true,
'cache_wsdl' => false
);
$_client = new SoapClient($soap_url, $soap_params);
$params = array("inCommunications" => $commsBlock, "inOrder" => $orderBlock);
// TRY TO SEND
try {
$_client->OrderInteractive($params); // works, but sends broken order node
//$_client->__soapCall('OrderInteractive', $params); // breaks, goes to catch
//$_client->OrderInteractive(new SoapParam($commsBlock, 'InCommunications'), new SoapParam($orderBlock, 'InOrder')); // breaks, goes to catch
} catch(SoapFault $e) {
capDebug(__FILE__, __LINE__, "Error: SoapFault:\n" . $e->getMessage(), '/tmp/SOAP_errors.log');
}
class inOrder {
function inOrder($xml) {
$this->OrderXml = $xml;
}
}
$xml_order = '<Order>
<Handling>OL</Handling>
<ProductID>DL</ProductID>
.
.
.
<Misc>TEST ORDER INTERACTIVE</Misc></Order>';
// create our order object that is needed
$order = new inOrder($xml_order);
// create our OrderInteractive parameters
$parameters = array(
"inCommunications" => $xml_communication,
"inOrder" => $order
);
try {
$xml = $_client->OrderInteractive($parameters);
} catch (Exception $e) {
print $e->getMessage() . "\n"; exit();
}
The code above worked. WSDL expecting a string and an object as params. Created a class for the order and used a string for the communications block, and we are receiving data fine.

.Net Soap WSDL webservice call from php not responding

I am getting issue to call brandbank webservice via php by using nusoap.php library.
I have to fetch data from Brandbank webservice which they exposed at
https://www.i-label.net/partners/webservices/datafeedbasic/extractdata.asmx?WSDL
I have made my code in php by using nusoap.php library but getting errors
MY code
require_once "nusoap.php";
$client = new nusoap_client("https://www.i-label.net/partners/webservices/datafeedbasic/extractdata.asmx?WSDL");
$error = $client->getError();
if ($error) {
echo "<h2>Constructor error</h2><pre>" . $error . "</pre>";
}
$param = array('ExternalCallerId'=>' 32 char key ','GTIN'=>'04015400440819','Description'=>'TAMPAX BLUE BOX MINI 20s','OwnLabel'=>'false','Category'=>'HHB','HasImage'=>'false');
$client->setUseCurl(true);
$client->soap_defencoding = 'UTF-8';
$result = $client->call("GetUnsentProductData", $param);
if ($client->fault) {
echo "<h2>Fault</h2><pre>";
print_r($result);
echo "</pre>";
}
else {
$error = $client->getError();
if ($error) {
echo "<h2>Error</h2><pre>" . $error . "</pre>";
}
else {
echo "<h2>Products Info</h2><pre>";
echo $result;
echo "</pre>";
}
}
Here is response of webservice
Array
(
[faultcode] => soap:Server
[faultstring] => Server was unable to process request. ---> An exception has occured whilst processing your request. The details have been logged, and the system administrator has been notified
[detail] =>
)
Brandbank WSDL link: https://www.i-label.net/partners/webservices/datafeedbasic/extractdata.asmx?WSDL
The problem that I am facing I don’t know how to send them product list in parameters along with this soap call.
I can see this ticket is old, but it appears you are trying to send Coverage file information to the GetUnsent endpoint.
The endpoint for Coverage can be found via https://www.i-label.net/partners/webservices/datafeedbasic/extractdata.asmx?WSDL

wsdl error: HTTP ERROR: socket read of chunk terminator timed out

I try to build a connection between data from a CMS and a CRM systems based on web services and using NuSOAP library. But when trying to form a request to a CRM server my web server (http://poseidonexpeditions.ru/soap/) returns this kind of error
wsdl error: Getting http://79.172.60.168/poseidon/soap.php?wsdl - HTTP ERROR: socket read of chunk terminator timed out"
Still, if the request is sent from another server - everything works fine. If the request is sent to another wsdl server - everything is fine:
http://poseidonexpeditions.ru/soap/client.php
The file looks like this:
<?require($_SERVER["DOCUMENT_ROOT"]."/bitrix/modules/main/include/prolog_before.php");
require($_SERVER["DOCUMENT_ROOT"]."/soap/lib/nusoap.php");
//$APPLICATION->IncludeComponent("pex:web.client");
require_once('./lib/nusoap.php');
$proxyhost = isset($_POST['proxyhost']) ? $_POST['proxyhost'] : '';
$proxyport = isset($_POST['proxyport']) ? $_POST['proxyport'] : '';
$proxyusername = isset($_POST['proxyusername']) ? $_POST['proxyusername'] : '';
$proxypassword = isset($_POST['proxypassword']) ? $_POST['proxypassword'] : '';
$client = new nusoap_client('http://79.172.60.168/poseidon/soap.php?wsdl', 'wsdl',
$proxyhost, $proxyport, $proxyusername, $proxypassword);
$err = $client->getError();
if ($err) {
echo '<h2>Constructor error</h2><pre>' . $err . '</pre>';
}
//$myWsdl = 'http://79.172.60.168/poseidon/soap.php?wsdl';
$myAuth = array(
'user_name' => 'foobar',
'password' => MD5('foobar'),
);
//$soapClient = new nusoap_client($myWsdl,true);
//var_dump($soapClient);
//
// Login
$loginParams = array('user_auth' => $myAuth);
$loginResult = $client->call('login', $loginParams);
$sessionId = $loginResult['id'];
$err = $client->getError();
echo $err;
echo '<h2>Отладка</h2>';
echo '<pre>' . htmlspecialchars($client->debug_str, ENT_QUOTES) . '</pre>';
echo $sessionId;
$set_entry = $client->call('set_entry', Array(
'session'=>$sessionId,
'module_name'=>'PsdnProducts',
'name_value_list'=>array(
array("name" => 'ID',"value" => 1),
array("name" => 'name',"value" => 'Test')
)));
echo '<pre>';
var_dump($set_entry);
echo '</pre>';
?>
I am just guessing,
The wsdl you are using to send data to CRM would have lots of sObjects and they will be referring one to another in a recursive manner. Sometimes it couldn't load wsdl properly due to it. So you should use one kind of sObject which is being used to send data, remove other sObjects. May be it will help.
Thanks,ambuj

Retrieve Error Message with array

I have using a version of GoCardless's API in PHP to process payments on my website. However when their API returns an error I would like to display the user more effective errors.
I have got half way there but I was wondering if there is anyway I could do the following:
If I have the following error:
Array ( [error] => Array ( [0] => The resource has already been confirmed ) )
Is there anyway to extract just the The resource has already been confirmed part with PHP?
My Code:
try{
$confirmed_resource = GoCardless::confirm_resource($confirm_params);
}catch(GoCardless_ApiException $e){
$err = 1;
print '<h2>Payment Error</h2>
<p>Server Returned : <code>' . $e->getMessage() . '</code></p>';
}
Thanks.
UPDATE 1:
Code that triggers the exception:
$http_response_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if ($http_response_code < 200 || $http_response_code > 300) {
// Create a string
$message = print_r(json_decode($result, true), true);
// Throw an exception with the error message
throw new GoCardless_ApiException($message, $http_response_code);
}
UPDATE 2 :-> print_r($e->getMessage()) Output:
Array ( [error] => Array ( [0] => The resource has already been confirmed ) )
The method $e->getMessage() appears to return an array with an index 'error' wich is an array again that contains the message text. If you ask me this is bad API design
However you can access the message text like this:
try{
$confirmed_resource = GoCardless::confirm_resource($confirm_params);
}catch(GoCardless_ApiException $e){
$err = 1;
$message = $e->getMessage();
$error = $message['error'];
print '<h2>Payment Error</h2>
<p>Server Returned : <code><' . $error[0] . "</code></p>";
}
If you look into the GoCardless_ApiException class code you'll see that there's a getResponse() method that you could use to access the error element of the response array...
$try{
$confirmed_resource = GoCardless::confirm_resource($confirm_params);
}catch(GoCardless_ApiException $e){
$err = 1;
$response = $e->getResponse();
print '<h2>Payment Error</h2>
<p>Server Returned : <code>' . $response['error'][0] . "</code></p>";
}
I discovered the problem, the output from $e->getMessage() was a plain string, NOT an array.
So I edited the Request.php file to the following:
$http_response_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if ($http_response_code < 200 || $http_response_code > 300) {
// Create a string <<-- THE PROBLEM -->>
// $message = print_r(json_decode($result, true), true);
$message_test = json_decode($result, true);
// Throw an exception with the error message
// OLD - throw new GoCardless_ApiException($message, $http_response_code);
throw new GoCardless_ApiException($message_test[error][0], $http_response_code);
}
and then my php file :
try{
$confirmed_resource = GoCardless::confirm_resource($confirm_params);
}catch(GoCardless_ApiException $e){
$err = 1;
$message = $e->getMessage();
print '<h2>Payment Error</h2>
<p>Server Returned : <code>' . $message . "</code></p>";
}
and the page outputs:
Payment Error
Server Returned : The resource has already been confirmed

SOAP returning "Internal Server Error"

My SOAP application written in NuSOAP returns an http 500 (Internal Server Error) error.
It is working fine on my local machine, I only get this error in live.
How do I diagnose this error?
Server:
require_once('nusoap.php');
// Create the server instance.
$server = new soap_server;
// Register the method to expose.
// Note: with NuSOAP 0.6.3, only method name is used without WSDL.
$server->register(
'hello', // Method name
array('name' => 'xsd:string'), // Input parameters
array('return' => 'xsd:string'), // Output parameters
'uri:helloworld', // Namespace
'uri:helloworld/hello', // SOAPAction
'rpc', // Style
'encoded' // Use
);
// Define the method as a PHP function.
function hello($name) {
require_once 'classes.php';
$db = new Database();
$sql = "select * from notifications where skey = '$name'";
$res = mysql_query($sql);
$row = mysql_fetch_array($res);
//return 'Hello, ' . $row['sales'];
$ret = "<salesdat>
<customername>". $row['sales']. "</customername>
</salesdat>";
return $ret;
}
// Use the request to (try to) invoke the service.
$HTTP_RAW_POST_DATA = isset($HTTP_RAW_POST_DATA) ? $HTTP_RAW_POST_DATA : '';
$server->service($HTTP_RAW_POST_DATA);
Client:
// Pull in the NuSOAP code.
require_once('nusoap.php');
// Create the client instance.
$client = new soapclient('http://----my site url ---/server.php');
//$client = new soapclient('http://localhost/cb/server.php');
// Check for an error.
$err = $client->getError();
if ($err) {
// Display the error.
echo '<p><b>Constructor error: ' . $err . '</b></p>';
// At this point, you know the call that follows will fail.
}
// Call the SOAP method.
$result = $client->call(
'hello', // method name
array('name' => 'shahidkari'), // input parameters
'uri:helloworld', // namespace
'uri:helloworld/hello' // SOAPAction
);
// Strange: the following works just as well!
//$result = $client->call('hello', array('name' => 'Scott'));
// Check for a fault
if ($client->fault) {
echo '<p><b>Fault: ';
print_r($result);
echo '</b></p>';
} else {
// Check for errors
$err = $client->getError();
if ($err) {
// Display the error.
echo '<p><b>Error: ' . $err . '</b></p>';
} else {
// Display the result.
print_r($result);
}
}
This may due to the php error in your server script. Switch on the error reporting. Run the server in a browser.
server.php
error_reporting(-1);
ini_set('display_errors', 'On');
require_once './src/Test.php';
$server = new SoapServer("https://xxxx/Outbound.wsdl");
$server->setClass('Test');
$server->handle();
https://xxxx/server.php // calling this in a browser will throw the error.
In my case it was due to require_once './src/Test.php'; which was not including the class.

Categories