'Calling Web Services with PHP SoapClient - How to?

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 = '[email protected]';
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!!!



Solution 1:[1]

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.

Solution 2:[2]

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

Solution 3:[3]

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

Solution 4:[4]

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.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 JSchaefer
Solution 2
Solution 3 Martin Taleski
Solution 4 Community