tags:

views:

485

answers:

3

Hiya,

I'm trying to teach myself SOAP, just to extend my skillset a bit, but I've hit a wall and I was wondering if a kind developer out there can help?

I've set up my server thus:

http://www.domain1.com/server.php

<?php
// Pull in the NuSOAP code
require_once('soap/nusoap.php');
// Create the server instance
$server = new soap_server();
// Initialize WSDL support
$server->configureWSDL('hellowsdl', 'urn:hellowsdl');
// Register the method to expose
$server->register('hello',    // method name
 array('name' => 'xsd:string'),  // input parameters
 array('return' => 'xsd:string'), // output parameters
 'urn:hellowsdl',     // namespace
 'urn:hellowsdl#hello',    // soapaction
 'rpc',        // style
 'encoded',       // use
 'Says hello to the caller'   // documentation
);
// Define the method as a PHP function
function hello($name) {
        return 'Hello, ' . $name;
}
// 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);
?>

And now I've tried to set up a client on a seperate server:

http://www.domain2.com/client.php

<?php
// Pull in the NuSOAP code
require_once('soap/nusoap.php');
// Create the client instance
$client = new soapclient('http://domain.com/server.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'));
// 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>';
?>

But I can't get the fecking thing working. The server displays just fine - wdsl output the lot. But the client can't/won't connect and complete the transaction. I get this message:

Warning: SoapClient::SoapClient() expects parameter 2 to be array, boolean given in /home/public_html/slidebank_soap_client.php on line 5

Fatal error: Uncaught SoapFault exception: [Client] SoapClient::SoapClient() [<a href='soapclient.soapclient'>soapclient.soapclient</a>]: Invalid parameters in /home/soap/slidebank_soap_client.php:5 Stack trace: #0 /home/soap/slidebank_soap_client.php(5): SoapClient->SoapClient('http://testing....', true) #1 {main} thrown in /home/public_html/soap/slidebank_soap_client.php on line 5

And this is where I'm stumped...

Any ideas?

H

+1  A: 

I used to be a fan of using nusoap with PHP3/4 (i.e. back when PHP didn't have a built in SOAP client) but with PHP5's SOAP Client I find I don't have any need for nusoap these days.

An advantage PHP5's built in SOAP client is that it's much cleaner and simplier to implement and so mention it as it might be helpful to you (I know some choose to use nusoap instead, but a lot of people apparently just aren't aware it's there in PHP5 as a lot of "HOWTO" guides are out of date and neglect to mention it).

Example usage:

ini_set("soap.wsdl_cache_enabled", "1"); // Set to zero to avoid caching WSDL
$soapClient = new SoapClient('http://www.example.com/webservices/HelloWorldService/?wsdl");     
$result = $soapClient->HelloWorldMethod(array('string' => "hello!"));    
print_r($result);

On a note regarding service types:

When it comes to a SOAP service, ideally you want to implement a Document/Literal service, rather than an RPC/Encoded service, as RPC/Encoded is a difficult format to work with and for that reason has been deprecated by the WS-I in favour of Document/Literal (which is both much easier to work with and more logical in design).

To start with, you might want to try implementing a client against an existing service if you can - that way you know it's at least working properly, which might save you a few headaches.

Unfortunately - while it's excellent at consuming them - PHP doesn't have particularly great support for serving Document/Literal services. There is at least one third party nusoap-like library for this IIRC, but it didn't quite cut it for me.

(If any of this is outdated, corrections welcome.)

Iain Collins
Thanks Iain, that was pretty useful! In the end I used my service code and your client code and the two were seamless! Everything is up and running now, so thanks a lot :)
hfidgen
Glad you found it useful! It seems like nusoap is (still) the best option for creating SOAP services with PHP for now, so looks like you've gone down the best route. Hopefully PHP will at some point get a built-in SOAP server implementation that's as elegant as the client one!
Iain Collins
Yeah it seems a bit of an omission tbh! Why do a half-cocked job and provide one without the other?
hfidgen
+1  A: 

This thread may help you, especially answer #9 and #10.

ccheneson
A: 

Just in case some googlers find this...

I edited the php.ini as ccheneson suggested and this code worked just fine, even on the same dev server.

Client - based in a Drupal page in PHP mode:

<?php
# URL for the service WSDL
ini_set("soap.wsdl_cache_enabled", "0"); // Set to zero to avoid caching WSDL
try {
    // Get a service proxy from the WSDL
    $proxy = new SoapClient('http://testing.domain.com/soap.php?wsdl');
    global $user;
    if (is_array($user->roles) && in_array('group1', array_values($user->roles))) {
        // User is logged in and is in the usergroup, perform login
        $id = $user->uid;
        $key = 1234; 
        $hashgenerator = $key . "xyz" . $id . "randomstringhere";
        $hash = sha1($hashgenerator);
        // Call a method on the service via the proxy
        $result = $proxy->handshake($id, $key, $hash);
        if ($hash==$result) {
            //Send all user details
            profile_load_profile($user);
            $email = $user->mail;
            $fname = $user->{profile_firstname};
            $lname = $user->{profile_lastname};
            $phone = $user->{profile_phone};
            $fax = $user->{profile_fax};
            $dept = "Speakers";
            $role = "Speakers";
            //Send request
            $authresult = $proxy->authlogin($id, $email, $fname, $lname, $phone, $fax, $authgroup);
            if ($authresult=='ok') {
                //Logged in, show them the page
                $_SESSION['loggedin'] = 1;
            } else {
                echo "Error 3";         
            }
        } else {
            echo "Error 2"; 
        }
    } else {
        echo "Error 1"; 
    }
} catch(SoapFault $ex) {
    echo 'Error: ';
    if ($ex->getMessage() != '') {
        echo $ex->getMessage();
    } else {
        echo $ex . "\n";
    }
}
?>

Service:

<?php
//----------------------------------//
// This file is a dummy service It obviously does nothing with the data, but i needed it to build my client scripts and so it might give you a hand returning the correct strings.
//----------------------------------//

// Pull in the NuSOAP code
require_once('nusoap/nusoap.php');
// Create the server instance
$server = new soap_server();
// Initialize WSDL support
$server->configureWSDL('WDSL', 'urn:WDSL');
// Register the methods to expose
$server->register('handshake',              // method name
    array('id' => 'xsd:string', 
          'key' => 'xsd:string',
          'hash' => 'xsd:string'),          
    array('return' => 'xsd:string'),        // output parameters
    'urn:WDSL',                             // namespace
    'urn:WDSL#_handshake',                  // soapaction
    'rpc',                                  // style
    'encoded',                              // use
    'Initial handshake'                     // documentation
);
$server->register('authlogin',              // method name
    array('id' => 'xsd:string',             // User ID
          'email' => 'xsd:string',          // User email address
          'fname' => 'xsd:string',          // User first name
          'lname' => 'xsd:string',          // User last name
          'phone' => 'xsd:string',          // User phone
          'fax' => 'xsd:string',            // User fax 
          'dept' => 'xsd:string',           // SB department
          'role' => 'xsd:string'),          // SB role  
    array('return' => 'xsd:string'),        // output parameters
    'urn:WDSL',                             // namespace
    'urn:WDSL#authlogin',                   // soapaction
    'rpc',                                  // style
    'encoded',                              // use
    'Authentication of a user'              // documentation
);
// Define the method as a PHP function
function slidebank_handshake($uid, $key, $hash) {
    //returns the same hash string for confirmation. No need to pass UID again.
    $hashgenerator = $key . "xyz" . $uid . "randomstringhere";  
    $hash = sha1($hashgenerator);
    return $hash;
}
// Define the method as a PHP function
function slidebank_authlogin($id, $email, $fname, $lname, $phone, $fax, $dept, $role) {
    //logic to log user in and capture details etc
    return 'ok'; //options = ok or fail
}
// 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);
?>
hfidgen