Author Topic: Programming with NuSOAP Using WSDL  (Read 8152 times)

Offline admin

  • Administrator
  • Sr. Member
  • *****
  • Posts: 296
    • View Profile
Programming with NuSOAP Using WSDL
« on: July 17, 2008, 09:39:00 AM »
Programming with NuSOAP Using WSDL
NuSOAP is a group of PHP classes that allow developers to create and consume SOAP web services. It does not require any special PHP extensions. The current release version (0.6.7) of NuSOAP at the time this was written (03-November-2004), supports much of the SOAP 1.1 specification. It can generate WSDL 1.1 and also consume it for use in serialization. Both rpc/encoded and document/literal services are supported. However, it must be noted that NuSOAP does not provide coverage of the SOAP 1.1 and WSDL 1.1 that is as complete as some other implementations, such as .NET and Apache Axis.

Hello, World Redux
Showing no imagination whatsoever, I used the ubiquitous "Hello, World" example in Introduction to NuSOAP. In that document, I showed the SOAP request and response exchanged by the client and server. Here, I extend that sample to use WSDL.

A WSDL document provides metadata for a service. NuSOAP allows a programmer to specify the WSDL to be generated for the service programmatically using additional fields and methods of the soap_server class.

The service code must do a number of things in order for correct WSDL to be generated. Information about the service is specified by calling the configureWSDL method. Information about each method is specified by supplying additional parameters to the register method. Service code for using WSDL is shown in the following example.

Code: [Select]
<?php
// Pull in the NuSOAP code
require_once('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);
?>
Now for some magic. Point a Web browser at this service, which in my environment is at http://localhost/phphack/hellowsdl.php. The HTML that is returned to your browser gives you links to view the WSDL for the service or view information about each method, in this case the hello method.

So, with just a little code added to the service, NuSOAP provides browsable documentation of the service. But, that is not all. By either clicking the WSDL link on the documentation page, or by pointing the browser at the service with a query string of ?wsdl (e.g. http://localhost/phphack/hellowsdl.php?wsdl), you get the following WSDL.

Code: [Select]
<?xml version="1.0"?>
<definitions 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/"
             xmlns:si="http://soapinterop.org/xsd"
             xmlns:tns="urn:hellowsdl"
             xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
             xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
             xmlns="http://schemas.xmlsoap.org/wsdl/"
             targetNamespace="urn:hellowsdl">
    <types>
        <xsd:schema targetNamespace="urn:hellowsdl">
            <xsd:import namespace="http://schemas.xmlsoap.org/soap/encoding/" />
            <xsd:import namespace="http://schemas.xmlsoap.org/wsdl/" />
        </xsd:schema>
    </types>
    <message name="helloRequest">
        <part name="name" type="xsd:string" />
    </message>
    <message name="helloResponse">
        <part name="return" type="xsd:string" />
    </message>
    <portType name="hellowsdlPortType">
        <operation name="hello">
            <documentation>Says hello to the caller</documentation>
            <input message="tns:helloRequest"/>
            <output message="tns:helloResponse"/>
        </operation>
    </portType>
    <binding name="hellowsdlBinding" type="tns:hellowsdlPortType">
        <soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/>
        <operation name="hello">
            <soap:operation soapAction="urn:hellowsdl#hello" style="rpc"/>
            <input>
                <soap:body use="encoded" namespace="urn:hellowsdl"
                 encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
            </input>
            <output>
                <soap:body use="encoded" namespace="urn:hellowsdl"
                 encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
            </output>
        </operation>
    </binding>
    <service name="hellowsdl">
        <port name="hellowsdlPort" binding="tns:hellowsdlBinding">
            <soap:address location="http://localhost/phphack/hellowsdl.php"/>
        </port>
    </service>
</definitions>
The New Client
Adding a few NuSOAP WSDL calls to the service allows it to generate WSDL and other documentation. By comparison, client support for WSDL is anti-climactic, at least for this simple example. The simple client shown below is not much different than the non-WSDL client. The only difference is that the constructor for the soapclient class is provided the URL of the WSDL, rather than the service endpoint.

Code: [Select]
<?php
// Pull in the NuSOAP code
require_once('nusoap.php');
// Create the client instance
$client = new soapclient('http://localhost/phphack/hellowsdl.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->requestENT_QUOTES) . '</pre>';
echo 
'<h2>Response</h2>';
echo 
'<pre>' htmlspecialchars($client->responseENT_QUOTES) . '</pre>';
// Display the debug messages
echo '<h2>Debug</h2>';
echo 
'<pre>' htmlspecialchars($client->debug_strENT_QUOTES) . '</pre>';
?>

Here are the request and response for this WSDL implementation.

Code: [Select]
POST /phphack/hellowsdl.php HTTP/1.0
Host: localhost
User-Agent: NuSOAP/0.6.8 (1.81)
Content-Type: text/xml; charset=ISO-8859-1
SOAPAction: "urn:hellowsdl#hello"
Content-Length: 550

<?xml version="1.0" encoding="ISO-8859-1"?>
<SOAP-ENV:Envelope SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
                   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/"
                   xmlns:si="http://soapinterop.org/xsd"
                   xmlns:tns="urn:hellowsdl">
    <SOAP-ENV:Body>
        <tns:hello xmlns:tns="urn:hellowsdl">
            <name xsi:type="xsd:string">Scott</name>
        </tns:hello>
    </SOAP-ENV:Body>
</SOAP-ENV:Envelope>
HTTP/1.1 200 OK
Server: Microsoft-IIS/5.0
Date: Wed, 03 Nov 2004 21:05:34 GMT
X-Powered-By: ASP.NET
X-Powered-By: PHP/4.3.4
Server: NuSOAP Server v0.6.8
X-SOAP-Server: NuSOAP/0.6.8 (1.81)
Content-Type: text/xml; charset=ISO-8859-1
Content-Length: 551

<?xml version="1.0" encoding="ISO-8859-1"?>
<SOAP-ENV:Envelope SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
                   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/"
                   xmlns:si="http://soapinterop.org/xsd">
    <SOAP-ENV:Body>
        <ns1:helloResponse xmlns:ns1="urn:hellowsdl">
            <return xsi:type="xsd:string">Hello, Scott</return>
        </helloResponse>
    </SOAP-ENV:Body>
</SOAP-ENV:Envelope>


Defining New Data Structures
An important aspect of WSDL is that it can encapsulate one or more XML Schema, allowing programmers to describe the data structures used by a service. To illustrate how NuSOAP supports this, I will add WSDL code to the SOAP struct example in Programming with NuSOAP Part 2.

The service code gains the changes already shown in the Hello, World example, but it also has code to define the Person data structure.

Code: [Select]
<?php
// Pull in the NuSOAP code
require_once('nusoap.php');
// Create the server instance
$server = new soap_server();
// Initialize WSDL support
$server->configureWSDL('hellowsdl2''urn:hellowsdl2');
// Register the data structures used by the service
$server->wsdl->addComplexType(
    
'Person',
    
'complexType',
    
'struct',
    
'all',
    
'',
    array(
        
'firstname' => array('name' => 'firstname''type' => 'xsd:string'),
        
'age' => array('name' => 'age''type' => 'xsd:int'),
        
'gender' => array('name' => 'gender''type' => 'xsd:string')
    )
);
$server->wsdl->addComplexType(
    
'SweepstakesGreeting',
    
'complexType',
    
'struct',
    
'all',
    
'',
    array(
        
'greeting' => array('name' => 'greeting''type' => 'xsd:string'),
        
'winner' => array('name' => 'winner''type' => 'xsd:boolean')
    )
);
// Register the method to expose
$server->register('hello',                    // method name
    
array('person' => 'tns:Person'),          // input parameters
    
array('return' => 'tns:SweepstakesGreeting'),    // output parameters
    
'urn:hellowsdl2',                         // namespace
    
'urn:hellowsdl2#hello',                   // soapaction
    
'rpc',                                    // style
    
'encoded',                                // use
    
'Greet a person entering the sweepstakes'        // documentation
);
// Define the method as a PHP function
function hello($person) {
    
$greeting 'Hello, ' $person['firstname'] .
                
'. It is nice to meet a ' $person['age'] .
                
' year old ' $person['gender'] . '.';
    
    
$winner $person['firstname'] == 'Scott';

    return array(
                
'greeting' => $greeting,
                
'winner' => $winner
                
);
}
// 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);
?>
Besides the additional code to support WSDL, the code for the service method itself is changed slightly. With WSDL, it is no longer necessary to use the soapval object to specify the name and data type for the return value.

Similarly, the WSDL client does not need to use a soapval to specify the name and data type of the parameter, as shown in the following code.


Code: [Select]
<?php
// Pull in the NuSOAP code
require_once('nusoap.php');
// Create the client instance
$client = new soapclient('http://localhost/phphack/hellowsdl2.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
$person = array('firstname' => 'Willi''age' => 22'gender' => 'male');
$result $client->call('hello', array('person' => $person));
// 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->requestENT_QUOTES) . '</pre>';
echo 
'<h2>Response</h2>';
echo 
'<pre>' htmlspecialchars($client->responseENT_QUOTES) . '</pre>';
// Display the debug messages
echo '<h2>Debug</h2>';
echo 
'<pre>' htmlspecialchars($client->debug_strENT_QUOTES) . '</pre>';
?>

Offline admin

  • Administrator
  • Sr. Member
  • *****
  • Posts: 296
    • View Profile
Re: Programming with NuSOAP Using WSDL
« Reply #1 on: July 17, 2008, 09:43:25 AM »
WSDL enables one more capability on the client. Instead of using the call method of the soapclient class, a proxy can be used. The proxy is a class that mirrors the service, in that it has the same methods with the same parameters as the service. Some programmers prefer to use proxies because the code reads as method calls on object instances, rather than invocations through the call method. A client that uses a proxy is shown below.

Code: [Select]
<?php
// Pull in the NuSOAP code
require_once('nusoap.php');
// Create the client instance
$client = new soapclient('http://localhost/phphack/hellowsdl2.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
}
// Create the proxy
$proxy $client->getProxy();
// Call the SOAP method
$person = array('firstname' => 'Willi''age' => 22'gender' => 'male');
$result $proxy->hello($person);
// Check for a fault
if ($proxy->fault) {
    echo 
'<h2>Fault</h2><pre>';
    
print_r($result);
    echo 
'</pre>';
} else {
    
// Check for errors
    
$err $proxy->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($proxy->requestENT_QUOTES) . '</pre>';
echo 
'<h2>Response</h2>';
echo 
'<pre>' htmlspecialchars($proxy->responseENT_QUOTES) . '</pre>';
// Display the debug messages
echo '<h2>Debug</h2>';
echo 
'<pre>' htmlspecialchars($proxy->debug_strENT_QUOTES) . '</pre>';
?>
Regardless of whether the "regular" or proxy coding style is used, the request and response messages are the same.

Code: [Select]
POST /phphack/hellowsdl2.php HTTP/1.0
Host: localhost
User-Agent: NuSOAP/0.6.8 (1.81)
Content-Type: text/xml; charset=ISO-8859-1
SOAPAction: "urn:hellowsdl2#hello"
Content-Length: 676

<?xml version="1.0" encoding="ISO-8859-1"?>
<SOAP-ENV:Envelope SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
                   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/"
                   xmlns:si="http://soapinterop.org/xsd"
                   xmlns:tns="urn:hellowsdl2">
    <SOAP-ENV:Body>
        <tns:hello xmlns:tns="urn:hellowsdl2">
            <person xsi:type="tns:Person">
                <firstname xsi:type="xsd:string">Willi</firstname>
                <age xsi:type="xsd:int">22</age>
                <gender xsi:type="xsd:string">male</gender>
            </person>
        </tns:hello>
    </SOAP-ENV:Body>
</SOAP-ENV:Envelope>
HTTP/1.1 200 OK
Server: Microsoft-IIS/5.0
Date: Wed, 03 Nov 2004 21:20:44 GMT
X-Powered-By: ASP.NET
X-Powered-By: PHP/4.3.4
Server: NuSOAP Server v0.6.8
X-SOAP-Server: NuSOAP/0.6.8 (1.81)
Content-Type: text/xml; charset=ISO-8859-1
Content-Length: 720

<?xml version="1.0" encoding="ISO-8859-1"?>
<SOAP-ENV:Envelope SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
                   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/"
                   xmlns:si="http://soapinterop.org/xsd"
                   xmlns:tns="urn:hellowsdl2">
    <SOAP-ENV:Body>
        <ns1:helloResponse xmlns:ns1="urn:hellowsdl2">
            <return xsi:type="tns:SweepstakesGreeting">
                <greeting xsi:type="xsd:string">
                    Hello, Willi. It is nice to meet a 22 year old male.
                </greeting>
                <winner xsi:type="xsd:boolean">0</winner>
            </return>
        </helloResponse>
    </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

You can  download the source for these examples as well.

Offline admin

  • Administrator
  • Sr. Member
  • *****
  • Posts: 296
    • View Profile
Re: Programming with NuSOAP Using WSDL
« Reply #2 on: July 17, 2008, 09:46:54 AM »
SOAP Arrays

Showing no imagination whatsoever, I used the ubiquitous "Hello, World" example in Introduction to NuSOAP and Programming with NuSOAP. I will show the use of arrays by changing that sample to say hello to not just one person, but many.

SOAP arrays are numerically-indexed (non-associative), similar to those in many programming languages such as C and FORTRAN. Therefore, our service can access elements of the array using numeric indices, rather than associative keys.

Code: [Select]
<?php
// Pull in the NuSOAP code
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 w/o WSDL
$server->register(
    
'hello'                            // method name
);
// Define the method as a PHP function
function hello($names) {
    for (
$i 0$i count($names); $i++) {
        
$retval[$i] = 'Hello, ' $names[$i];
    }
    
    return 
$retval;
}
// 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);
?>
The client changes only in that it passes a parameter that is an array of names, rather than a single scalar name.

Code: [Select]
<?php
// Pull in the NuSOAP code
require_once('nusoap.php');
// Create the client instance
$client = new soapclient('http://localhost/phphack/helloworld5.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
$names = array('Scott''Albert''Robert''Phyllis');
$result $client->call(
    
'hello',                       // method name
    
array('names' => $names)    // input parameters
);
// 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);
    }
}
?>
The request and response look like the following.

Code: [Select]
POST /phphack/helloworld5.php HTTP/1.0
User-Agent: NuSOAP/0.6.3
Host: localhost:80
Content-Type: text/xml; charset="ISO-8859-1"
Content-Length: 736
SOAPAction: ""

<?xml version="1.0" encoding="ISO-8859-1"?>
<SOAP-ENV:Envelope
 SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
 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/"
 xmlns:si="http://soapinterop.org/xsd">
  <SOAP-ENV:Body>
    <ns1:hello xmlns:ns1="http://testuri.org">
      <names xsi:type="SOAP-ENC:Array" SOAP-ENC:arrayType="xsd:string[4]">
        <item xsi:type="xsd:string">Scott</item>
        <item xsi:type="xsd:string">Albert</item>
        <item xsi:type="xsd:string">Robert</item>
        <item xsi:type="xsd:string">Phyllis</item>
      </names>
    </ns1:hello>
  </SOAP-ENV:Body>
</SOAP-ENV:Envelope>
HTTP/1.1 200 OK
Server: Microsoft-IIS/5.0
Date: Thu, 29 May 2003 18:46:12 GMT
X-Powered-By: PHP/4.0.6
Server: NuSOAP Server v0.6.3
Connection: Close
Content-Type: text/xml; charset=UTF-8
Content-Length: 743

<?xml version="1.0" encoding="ISO-8859-1"?>
<SOAP-ENV:Envelope
 SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
 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/"
 xmlns:si="http://soapinterop.org/xsd">
  <SOAP-ENV:Body>
    <helloResponse>
      <soapVal xsi:type="SOAP-ENC:Array" SOAP-ENC:arrayType="xsd:string[4]">
        <item xsi:type="xsd:string">Hello, Scott</item>
        <item xsi:type="xsd:string">Hello, Albert</item>
        <item xsi:type="xsd:string">Hello, Robert</item>
        <item xsi:type="xsd:string">Hello, Phyllis</item>
      </soapVal>
    </helloResponse>
  </SOAP-ENV:Body>
</SOAP-ENV:Envelope>


Offline admin

  • Administrator
  • Sr. Member
  • *****
  • Posts: 296
    • View Profile
Re: Programming with NuSOAP Using WSDL
« Reply #3 on: July 17, 2008, 09:50:17 AM »
SOAP Structs
To this point, the examples that have been developed have used scalar types and arrays of scalars for parameters and return values. In this section, I will show the use of SOAP Structs, which more-or-less correspond to complex types in XML Schema. The example is yet another variation of Hello, World, this time with a structure for a parameter that provides more information about the person being greeted.

NuSOAP leverages the capabilities of PHP, using associative arrays to represent SOAP Structs. For this example, we will use an array containing the first name, age and gender for a person. In PHP, this will look like

Code: [Select]
$person = array(
             'firstname' => 'Betty',
             'age' => 32,
             'gender' => 'female'
          );
The service accepts a parameter that is an associative array as shown above. It returns another array like the following.

Code: [Select]
$return = array(
             'greeting' => 'Hello...',
             'winner' => false
          );
The code for the service follows.

Code: [Select]
<?php
// Pull in the NuSOAP code
require_once('nusoap.php');
// Create the server instance
$server = new soap_server;
// Register the method to expose
$server->register(
    
'hello'                            // method name
);
// Define the method as a PHP function
function hello($person) {
    
$greeting 'Hello, ' $person['firstname'] .
                
'. It is nice to meet a ' $person['age'] .
                
' year old ' $person['gender'] . '.';
    
    
$winner $person['firstname'] == 'Scott';

    
$retval = array(
                
'greeting' => $greeting,
                
'winner' => $winner
                
);

    return new 
soapval('return''ContestInfo'$retvalfalse'urn:MyURN');
}
// 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);
?>
One thing to notice is that the service method returns a soapval, so that the XML data type, in this case urn:MyURN:ContestInfo, can be specified for the return value.

Here is a client for this.

Code: [Select]
<?php
// Pull in the NuSOAP code
require_once('nusoap.php');
// Create the client instance
$client = new soapclient('http://localhost/phphack/helloworld6.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
$person = array('firstname' => 'Willi''age' => 22'gender' => 'male');
$result $client->call(
    
'hello',                    // method name
    
array('person' => new soapval('person''Person',
                                  
$personfalse'urn:MyURN'))    // input parameters
);
// 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);
    }
}
?>

Like the server, this uses a soapval for a parameter, so that the XML data type of urn:MyURN:Person can be specified.

The request and response look like the following.

Code: [Select]
POST /phphack/helloworld6.php HTTP/1.0
User-Agent: NuSOAP/0.6.3
Host: localhost:80
Content-Type: text/xml; charset="ISO-8859-1"
Content-Length: 688
SOAPAction: ""

<?xml version="1.0" encoding="ISO-8859-1"?>
<SOAP-ENV:Envelope
 SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
 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/"
 xmlns:si="http://soapinterop.org/xsd">
  <SOAP-ENV:Body>
    <ns1:hello xmlns:ns1="http://testuri.org">
      <person xmlns:ns6678="urn:MyURN" xsi:type="ns6678:Person">
        <firstname xsi:type="xsd:string">Willi</firstname>
        <age xsi:type="xsd:int">22</age>
        <gender xsi:type="xsd:string">male</gender>
      </person>
    </ns1:hello>
  </SOAP-ENV:Body>
</SOAP-ENV:Envelope>
HTTP/1.1 200 OK
Server: Microsoft-IIS/5.0
Date: Thu, 29 May 2003 19:50:30 GMT
X-Powered-By: PHP/4.0.6
Server: NuSOAP Server v0.6.3
Connection: Close
Content-Type: text/xml; charset=UTF-8
Content-Length: 679

<?xml version="1.0" encoding="ISO-8859-1"?>
<SOAP-ENV:Envelope
 SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
 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/"
 xmlns:si="http://soapinterop.org/xsd">
  <SOAP-ENV:Body>
    <helloResponse>
      <return xmlns:ns7437="urn:MyURN"
       xsi:type="ns7437:ContestInfo">
        <greeting xsi:type="xsd:string">
          Hello, Willi. It is nice to meet a 22 year old male.
        </greeting>
        <winner xsi:type="xsd:boolean">0</winner>
      </return>
    </helloResponse>
  </SOAP-ENV:Body>
</SOAP-ENV:Envelope>
This example has shown how to send a SOAP Struct as a parameter, and return one as a result. It has also shown how to specify the XML type of each Struct. Without any additional facilities, interoperability of the SOAP client and server using these types might require communication between parties in advance to agree upon these structures. This is one of the great freedoms of the original SOAP 1.1 specification, but it causes interoperability problems. The next document in this series will show how to use WSDL to provide metadata for a Web service, including the data structures in use.

You can download the source for these examples as well.